# Moonbeam llms-full.txt Moonbeam. Moonbeam is a smart contract platform that makes it easy to build natively interoperable applications on Polkadot and Ethereum. ## Generated automatically. Do not edit directly. Documentation: https://docs.moonbeam.network/ ## List of doc pages: [AI-Compatible Docs](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/ai-resources/ai-resources.md) (Download LLM-optimized files of the Moonbeam documentation, including full content and category-specific resources for AI agents.) [Historical Updates](Reference): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/build/historical-updates.md) (An overview of the historical updates made on Moonbeam and Moonriver, such as migrations and bug fixes applied to the Moonbeam source code.) [Runtime Upgrades](Reference): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/build/runtime-upgrades.md) (A historical record of each runtime upgrade and the block at which the runtime was executed for Moonbeam, Moonriver, and the Moonbase Alpha TestNet.) [Canonical Contract Addresses on Moonbeam](Reference, Precompiles, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/canonical-contracts.md) (Overview of the canonical contracts available on Moonbeam, Moonriver, & Moonbase Alpha, including common-good contracts and precompiles.) [Deploy Contracts with Ape](Dev Environments, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/dev-env/ape.md) (Use Ape, a Python framework, to compile, deploy, and debug smart contracts using Python on Moonbeam, thanks to its Ethereum compatibility.) [Deploy Contracts with Foundry](Dev Environments, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/dev-env/foundry.md) (Learn how to use Foundry, an Ethereum development environment, to compile, deploy, and debug Solidity smart contracts on Moonbeam.) [Deploy Contracts with Hardhat](Dev Environments, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/dev-env/hardhat.md) (Learn how to use Hardhat, an Ethereum development environment, to compile, deploy, and debug Solidity smart contracts on Moonbeam.) [Ethereum Development Environments](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/dev-env/index.md) (Learn how to use Ethereum tools such as Remix, OpenZeppelin, Hardhat, Waffle & Mars, and more to develop Solidity smart contracts on Moonbeam.) [Deploy OpenZeppelin Contracts](Dev Environments, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/dev-env/openzeppelin/contracts.md) (Learn how to create common OpenZeppelin contracts such as ERC-20, ERC-721, & ERC-1155 tokens with the OpenZeppelin Contracts Wizard and deploy them on Moonbeam.) [Interact with OpenZeppelin](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/dev-env/openzeppelin/index.md) (Use OpenZeppelin contracts and libraries or the Contract Wizard to create and manage your Solidity smart contracts on Moonbeam.) [An Overview of OpenZeppelin on Moonbeam](Basics, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/dev-env/openzeppelin/overview.md) (Learn how to use OpenZeppelin products for creating and managing Solidity smart contracts on Moonbeam, thanks to its Ethereum compatibility features.) [Deploy Smart Contracts with Remix](Dev Environments, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/dev-env/remix.md) (Discover how to deploy and interact with Solidity smart contracts on Moonbeam using the Remix IDE, one of the most widely used Ethereum development tools.) [Create a DApp with Scaffold-ETH 2](Dev Environments, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/dev-env/scaffold-eth.md) (You can deploy a Solidity DApp with a React UI and subgraph on Moonbeam in minutes by using Scaffold-ETH 2. Learn how in this tutorial.) [Tenderly Development Platform](Dev Environments, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/dev-env/tenderly.md) (Learn how to use Tenderly, an Ethereum development platform, to build, debug, and monitor Solidity smart contracts on Moonbeam.) [How to use thirdweb](Dev Environments, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/dev-env/thirdweb.md) (This guide will show you some of thirdweb's features, including building, testing, and deploying smart contract templates to launch dApps on Moonbeam.) [Deploy Smart Contracts with Waffle & Mars](Dev Environments, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/dev-env/waffle-mars.md) (Learn how to use Waffle and Mars to write, compile, test, and deploy Ethereum smart contracts on Moonbeam.) [Ethereum API](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/index.md) (Learn how to use the Ethereum API when developing on Moonbeam. This section includes guides on Ethereum libraries, development environments, and more.) [Debug & Trace Transactions](JSON-RPC APIs, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/json-rpc/debug-trace.md) (Check out the non-standard JSON-RPC methods included in Geth's Debug and Txpool APIs and OpenEthereum's Trace module, which are supported on Moonbeam.) [Standard Ethereum JSON-RPC Methods](JSON-RPC APIs, Reference, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/json-rpc/eth-rpc.md) (Explore a comprehensive list of standard Ethereum JSON-RPC methods that can be used to interface with Moonbeam nodes programmatically.) [JSON RPC API](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/json-rpc/index.md) (The JSON-RPC API for Moonbeam provides a set of methods for interacting with a Moonbeam node programmatically over JSON-RPC (Remote Procedure Call).) [Moonbeam-specific RPC Methods](JSON-RPC APIs, Reference): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/json-rpc/moonbeam-custom-api.md) (Discover Moonbeam's specialized API endpoints, featuring custom JSON-RPC methods designed exclusively for Moonbeam functionality.) [Subscribe to Ethereum-style Events on Moonbeam](JSON-RPC APIs, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/json-rpc/pubsub.md) (Take a look at the non-standard Ethereum JSON-RPC methods supported on Moonbeam that offer publish-subscribe functionality for specific events.) [How to use Ethers.js Ethereum Library](Libraries and SDKs, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/libraries/ethersjs.md) (Follow this tutorial to learn how to use the Ethereum Ethers.js Library to send transactions and deploy Solidity smart contracts to Moonbeam.) [How to use Ethers.rs Ethereum Library](Libraries and SDKs, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/libraries/ethersrs.md) (Learn how to use the Ethereum Ethers.rs Library to send transactions and deploy Solidity smart contracts to Moonbeam via the Rust language.) [Ethereum Libraries](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/libraries/index.md) (Learn how to use JavaScript or Python Ethereum libraries such as Ethers.js, Web3.js, or Web3.py to send transactions or deploy contracts on Moonbeam.) [How to use viem Ethereum Library](Libraries and SDKs, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/libraries/viem.md) (Check out this tutorial to learn how to use the viem TypeScript interface for Ethereum to send transactions and deploy Solidity smart contracts to Moonbeam.) [How to use Web3.js Ethereum Library](Libraries and SDKs, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/libraries/web3js.md) (Follow this tutorial to learn how to use the Ethereum Web3 JavaScript Library to deploy Solidity smart contracts to Moonbeam.) [How to use Web3.py Ethereum Library](Libraries and SDKs, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/libraries/web3py.md) (Follow this tutorial to learn how to use the Ethereum Web3 Python Library to to send transactions and deploy Solidity smart contracts to Moonbeam.) [Identity Precompile](Precompiles, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/account/identity.md) (Learn all you need to know about the Identity Precompile, such as its address, Solidity interface, and how to interact with it using popular Ethereum libraries.) [Account-Related Precompiled Contracts](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/account/index.md) (Efficiently manage accounts on Moonbeam with precompiled contracts designed for creating and managing proxy accounts and on-chain identities.) [Interacting with the Proxy Precompile](Precompiles, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/account/proxy.md) (How to use the Moonbeam proxy Solidity precompile interface to add and remove proxy accounts from Substrate's Proxy Pallet.) [Collective Precompile Contract](Precompiles, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/features/governance/collective.md) (Learn how to use the Moonbeam Collective Precompile to perform democracy functions through any of the collectives on Moonbeam, such as the Treasury Council.) [Conviction Voting Precompile Contract](Precompiles, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/features/governance/conviction-voting.md) (Learn how to vote on referenda, set up voting delegations, and more, directly through a Solidity interface with the Conviction Voting Precompile on Moonbeam.) [Solidity Precompiles](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/features/governance/index.md) (Facilitate decentralized decision-making with Moonbeam's governance precompiles for creating and submitting proposals and voting on referenda.) [Preimage Precompile Contract](Precompiles, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/features/governance/preimage.md) (Learn how to take the first necessary step to submit a proposal on-chain by submitting a preimage that contains the action to be carried out in the proposal.) [Referenda Precompile Contract](Precompiles, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/features/governance/referenda.md) (Learn how to view and submit proposals on-chain to be put forth for referenda, directly through a Solidity interface with the Referenda Precompile on Moonbeam.) [Precompiles For Key Moonbeam Features](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/features/index.md) (Access essential network features on Moonbeam through precompiled contracts for governance, staking, and secure randomness generation.) [Randomness Precompile](Precompiles, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/features/randomness.md) (Learn about the sources of VRF randomness on Moonbeam and how to use the randomness precompile and consumer interface to generate on-chain randomness.) [Staking Precompile Contract](Precompiles, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/features/staking.md) (Unlock the potential of staking with a specialized precompiled contract designed to streamline and optimize participation in Moonbeam.) [Solidity Precompiles](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/index.md) (Discover the precompiled contracts on Moonbeam, your gateway to effortless interaction with Substrate modules and features using the Ethereum API.) [GMP Precompile](Precompiles, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/interoperability/gmp.md) (Learn about the GMP precompile on Moonbeam and how to use it with the Moonbeam Routed Liquidity program provided by bridges like Wormhole.) [Interoperability Precompiles](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/interoperability/index.md) (Unlock cross-chain capabilities with Moonbeam's precompiled contracts designed for interoperability, including GMP and XCM protocols.) [Solidity Precompiles](Reference, Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/overview.md) (An overview of the available Solidity precompiles on Moonbeam. Precompiles enable you to interact with Substrate features using the Ethereum API.) [Ethereum MainNet Precompiles](Precompiles, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/utility/eth-mainnet.md) (Learn how to use the standard precompiled contracts available on Ethereum such as ECRECOVER, SHA256, and more on Moonbeam.) [Utility Precompiles](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/utility/index.md) (Utilize a range of utility functions with precompiles, including Ethereum MainNet hashing algorithms and additional Moonbeam-specific functions.) [Non-Network Specific Precompiles](Precompiles, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/utility/non-specific.md) (Learn how to use precompiled contracts, which are not specific to Ethereum or Moonbeam, yet are supported for use in your application.) [Precompile Registry](Precompiles, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/utility/registry.md) (Learn how to access and interact with the Precompile Registry on Moonbeam, which can be used to check if a given address is a precompile and if it is supported.) [Relay Data Verifier Precompile Contract](Precompiles, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/utility/relay-data-verifier.md) (Learn how to verify data availability and authenticity on the relay chain via a Solidity interface with Moonbeam's Relay Data Verifier Precompile contract.) [Batch Precompile Contract](Precompiles, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/ux/batch.md) (Learn how to transact multiple transfers and contract interactions at once via a Solidity interface with Moonbeam's Batch Precompile contract.) [Call Permit Precompile Contract](Precompiles, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/ux/call-permit.md) (Learn how to use the Call Permit Precompile contract on Moonbeam to sign a permit for any EVM call that can be dispatched by anyone or any smart contract.) [Native Token ERC-20 Precompile](Precompiles, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/ux/erc20.md) (Learn how to access and interact with an ERC-20 representation of the native token on Moonbeam through the precompiled ERC-20 Interface.) [Improve User Experience with Precompiles](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/precompiles/ux/index.md) (Enhance the user experience on Moonbeam with precompiled contracts that allow seamless batch transactions and gasless operations for a smoother workflow.) [Verify Smart Contracts through APIs](Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/verify-contracts/api-verification.md) (Learn how to verify smart contracts on Moonbeam-based networks using one of the available API-based verification methods.) [Verify Smart Contracts on Block Explorers](Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/verify-contracts/block-explorers.md) (Learn how to verify smart contracts on Moonbeam-based networks using one of the available block explorers, such as Moonscan.) [Verify Smart Contracts with Plugins](Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/verify-contracts/etherscan-plugins.md) (Learn how to verify smart contracts on Moonbeam networks using built-in tools from Hardhat and Foundry that support Moonscan’s API.) [Verify Smart Contracts](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/ethereum/verify-contracts/index.md) (Learn how to verify your Solidity smart contracts deployed to Moonbeam manually through block explorers and automatically through Etherscan plugins.) [Create an Account](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/get-started/create-account.md) (To begin developing on Moonbeam, you must create an account. This guide will provide you with the information needed to create one to use on Moonbeam.) [Moonbeam API Providers and Endpoints](JSON-RPC APIs, Reference): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/get-started/endpoints.md) (Use one of the supported API providers to connect to a public endpoint or create custom JSON-RPC and WSS endpoints for Moonbeam-based networks.) [Block Explorers](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/get-started/explorers.md) (An overview of the currently available block explorers that may be used to navigate the Substrate and Ethereum layers of Moonbeam.) [Get Started with Moonbeam](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/get-started/index.md) (Everything you need to know to get started developing, deploying, and interacting with smart contracts on Moonbeam.) [Get Started with Moonbeam-based Networks](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/get-started/networks/index.md) (Learn how to get started developing on a Moonbeam development node, the Moonbase Alpha TestNet, Moonriver, or Moonbeam.) [Moonbase Alpha Get Started Guide](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/get-started/networks/moonbase.md) (The Moonbeam TestNet, named Moonbase Alpha, is the easiest way to get started with a Polkadot environment. Follow this tutorial to connect to the TestNet.) [Run a Moonbeam Development Node](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/get-started/networks/moonbeam-dev.md) (Follow this tutorial to learn how to spin up your first Moonbeam development node, how to configure it for development purposes, and connect to it.) [Get Started with Moonbeam](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/get-started/networks/moonbeam.md) (Learn how to connect to Moonbeam via RPC and WSS endpoints, how to connect MetaMask to Moonbeam, and about the available Moonbeam block explorers.) [Moonriver Get Started Guide](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/get-started/networks/moonriver.md) (Learn how to connect to Moonriver via RPC and WSS endpoints, how to connect MetaMask to Moonriver, and about the available Moonriver block explorers.) [Quickly Get Started](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/get-started/quick-start.md) (Everything you need to know to get started developing, deploying, and interacting with smart contracts on Moonbeam.) [Add Token Information on Moonscan](Tokens and Accounts, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/get-started/token-profile.md) (Add token information and create a token profile on Moonscan for ERC-20, ERC-721, and ERC-1155 tokens deployed to Moonbeam-based networks.) [A Hub for Developers Building on Moonbeam](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/index.md) (Guides for getting started and developing on Moonbeam. Learn how to use the Ethereum & Substrate APIs, XCM interoperability, and available integrations.) [Dapplooker](Integrations): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/analytics/dapplooker.md) (Use Dapplooker to analyze and query on-chain data, and create dashboards to visualize analytics for Moonbeam and Moonriver.) [Analyze On-Chain Data](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/analytics/index.md) (Analyze on-chain smart contract data by building charts and dashboards to visualize data and track metrics for Moonbeam-based networks.) [Portfolio Tracking on Moonbeam with Zapper](Integrations): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/analytics/zapper.md) (Learn how to track your holdings on Moonbeam using Zapper and explore different DeFi platforms in the Moonbeam ecosystem.) [Integrations on Moonbeam](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/index.md) (Learn about the available integrations on Moonbeam to ease your DApp development, including bridges, indexers, oracles, and wallets.) [GoldRush API](Indexers and Queries): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/indexers/covalent.md) (Querying blockchain data such as balances, transactions, transfers, token holders, and event logs on Moonbeam with the GoldRush (formerly Covalent) API.) [Indexers and APIs](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/indexers/index.md) (Learn how to build your own API or consume API endpoints from any of the supported REST or GraphQL-based indexers on Moonbeam.) [Interact with Moralis APIs](Indexers and Queries): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/indexers/moralis.md) (Learn how Moralis' API suite empowers developers to retrieve and leverage various data sets from Moonbeam, Moonriver, and Moonbase Alpha.) [Index Data with SubQuery & GraphQL](Indexers and Queries): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/indexers/subquery.md) (Learn how to use SubQuery to index Substrate and EVM chain data for Moonbeam and Moonriver, and query the data using GraphQL.) [Index Data with SQD (formerly Subsquid)](Indexers and Queries): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/indexers/subsquid.md) (Learn how to use SQD (Subsquid), a query node framework for Substrate-based chains, to index and process Substrate and EVM data for Moonbeam and Moonriver.) [Build APIs with The Graph](Indexers and Queries): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/indexers/thegraph.md) (Learn how to build APIs, called subgraphs, to store and fetch on-chain data for a given smart contract using The Graph indexing protocol on Moonbeam.) [Request Off-Chain Data with API3](Oracle Nodes): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/oracles/api3.md) (Learn how to use API3 to request and receive off-chain data from within your smart contracts using API3 Airnodes and dAPIs (data feeds) on Moonbeam networks.) [Band Protocol Oracle](Oracle Nodes): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/oracles/band-protocol.md) (How to request data from a Band Protocol Oracle in your Moonbeam Ethereum DApp using smart contracts or JavaScript.) [Chainlink Oracle](Oracle Nodes): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/oracles/chainlink.md) (Review price feed contracts for Moonbeam-based networks and learn how to request data from a Chainlink Oracle in your DApp using smart contracts or JavaScript.) [DIA Oracle](Oracle Nodes): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/oracles/dia.md) (Learn how to request a dedicated DIA oracle for your dApp, enabling access to price data for 2500+ tokens, randomness, and more.) [Use an Oracle in your DApp](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/oracles/index.md) (Check out some of the supported oracles and learn how to add an oracle to your DApp to request off-chain data for smart contracts on Moonbeam-based networks.) [Razor Network Oracle](Oracle Nodes): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/oracles/razor-network.md) (How to request data from a Razor Network Oracle in your Moonbeam Ethereum DApp using smart contracts.) [Supra Oracles](Oracle Nodes): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/oracles/supra.md) (Supra's Pull Oracle provides low-latency, on-demand price feed updates for a variety of use cases. Learn how to integrate Supra's oracle on Moonbeam.) [Add Wallet Integrations to DApps](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/wallets/index.md) (Learn how to add wallet integrations, such as MetaMask and WalletConnect, to your DApp on Moonbeam so users can automatically connect to their wallets.) [Add MetaMask to a DApp](Tokens and Accounts): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/wallets/metamask.md) (This tutorial shows you how to integrate MetaMask into a DApp and automatically connect users to Moonbeam with the click of a button.) [Add Particle Network to a dApp](Tokens and Accounts): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/wallets/particle-network.md) (Learn how to integrate Particle Network's Wallet-as-a-Service into a dApp built on Moonbeam to enable MPC-based onboarding and ERC-4337 AA interaction.) [Add RainbowKit to a DApp](Tokens and Accounts): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/wallets/rainbowkit.md) (Learn how to integrate RainbowKit into a dApp to allow users to connect their mobile wallets to Moonbeam, Moonriver, or Moonbase Alpha networks.) [Add WalletConnect to a DApp](Tokens and Accounts): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/integrations/wallets/walletconnect.md) (Learn how to integrate WalletConnect into a DApp built on any of the Moonbeam networks, specifically so users can connect with their mobile wallets.) [Interoperability](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/index.md) (Learn about interoperability on Moonbeam by diving into how cross-consensus messaging (XCM) works and exploring available cross-chain protocols.) [Moonbeam Routed Liquidity](XCM): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/mrl.md) (Learn how to receive Moonbeam Routed Liquidity after establishing a cross-chain integration with a Moonbeam-based network.) [Cross-Chain Via Axelar](GMP Providers): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/protocols/axelar.md) (Learn about Axelar, a GMP protocol for cross-chain asset transfers, and how to get started building cross-chain applications with Axelar on Moonbeam.) [Cross-Chain Via Hyperlane](GMP Providers): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/protocols/hyperlane.md) (Learn about Hyperlane, a GMP protocol for cross-chain asset transfers, and how to get started building cross-chain applications with Hyperlane on Moonbeam.) [Cross-Chain Protocols](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/protocols/index.md) (Learn about the cross-chain protocols you can use to transfer assets and remotely call contracts on any connected blockchain.) [Cross-Chain Via LayerZero](GMP Providers): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/protocols/layerzero.md) (Learn about LayerZero, a GMP protocol for cross-chain asset transfers, and how to get started building cross-chain applications with LayerZero on Moonbeam.) [Cross-Chain via Wormhole](GMP Providers): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/protocols/wormhole.md) (Learn how to bridge assets, set up a relayer, and other ways you can connect your Moonbeam DApp to assets and functions on multiple blockchains using Wormhole.) [Core Concepts in XCM](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/core-concepts/index.md) (Discover some of the fundamental components involved in constructing cross-chain messages, such as XCM instructions and multilocations.) [XCM Instructions](XCM, Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/core-concepts/instructions.md) (When XCM instructions are combined, they form an XCM message that performs a cross-chain action. Take a look at some of the most common instructions.) [XCM Multilocations](XCM): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/core-concepts/multilocations.md) (Learn everything there is to know about multilocations, their role in XCM, and how to format a multilocation to target a specific point in the ecosystem.) [Sovereign Accounts and Reserve-Backed Transfers](XCM): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/core-concepts/sovereign-accounts.md) (Discover how sovereign accounts work on Moonbeam, how to calculate them, and their role in cross-chain asset transfers.) [XCM Execution Fees](XCM): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/core-concepts/weights-fees.md) (Learn about the XCM instructions involved in handling XCM execution fee payments and how to calculate fees on Polkadot, Kusama, and Moonbeam-based networks.) [Cross-Chain Communication](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/index.md) (An overview of how cross-consensus messaging (XCM) works and how you can leverage XCM to transfer assets to and from Moonbeam.) [Cross-Consensus Messaging (XCM)](Basics, XCM): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/overview.md) (An overview of how cross-consensus messaging (XCM) works and how developers can leverage Polkadot/Kusama XCM to gain access to new assets.) [Computed Origin Accounts](XCM Remote Execution): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/remote-execution/computed-origins.md) (Learn about Computed Origin accounts, which can be used to execute remote cross-chain calls through a simple transaction, and how to calculate these accounts.) [Cross-Chain Remote Execution](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/remote-execution/index.md) (Learn about the basics of remote execution and how to perform remote cross-chain execution on other chains in the ecosystem and remote EVM calls on Moonbeam.) [Remote Execution Overview](XCM Remote Execution, Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/remote-execution/overview.md) (Learn the basics of remote execution via XCM messages, which allow users to execute actions on other blockchains using accounts they control remotely via XCM.) [Remote EVM Calls Through XCM](XCM Remote Execution, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/remote-execution/remote-evm-calls.md) (How to do remote calls to smart contracts on Moonbeam EVM through XCM from any Polkadot parachain that has an XCM channel established with Moonbeam.) [Remote Substrate Calls](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/remote-execution/substrate-calls/index.md) (Discover how to use the XCM Transactor Pallet and XCM Transactor Precompile to remotely call Substrate pallets on other chains in the ecosystem from Moonbeam.) [The XCM Transactor Pallet](XCM Remote Execution): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/remote-execution/substrate-calls/xcm-transactor-pallet.md) (This guide provides an introduction to the XCM Transactor Pallet and explains how to send remote calls to another chain using some of the pallet's extrinsics.) [The XCM Transactor Precompile](XCM Remote Execution): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/remote-execution/substrate-calls/xcm-transactor-precompile.md) (This guide describes the XCM Transactor Precompile and shows how to use some of its functions to send remote calls to other chains using Ethereum libraries.) [Send, Execute and Test XCM Messages](XCM): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/send-execute-xcm.md) (Build a custom XCM message, verify its construction and integrity using the XCM Dry Run API, and then execute it locally on Moonbeam to observe the results.) [Register XC Assets](XC-20): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/xc-registration/assets.md) (This guide includes everything you need to know to register local and external XC-20s so you can begin transferring assets cross-chain via XCM.) [Forum Templates for XCM Integrations](XCM, Integrations): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/xc-registration/forum-templates.md) (Learn about and how to craft the two posts you need to make on the Moonbeam Community Forum when creating a cross-chain integration with Moonbeam.) [Register Cross-Chain Channels and Assets](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/xc-registration/index.md) (Learn how to create a cross-chain integration with Moonbeam and how to register cross-chain assets that can be transferred between Moonbeam and another chain.) [Self-Serve Asset Registration](XCM): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/xc-registration/self-serve-asset-registration.md) (This guide shows sibling parachains how to register native tokens as foreign assets on Moonbeam via ForeignAssetOwnerOrigin to unlock ERC-20 UX on Moonbeam.) [Open a Cross-Chain Channel](XCM, Integrations): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/xc-registration/xc-integration.md) (Learn how to establish a cross-chain integration with a Moonbeam-based network. Including opening and accepting an HRMP channel and registering assets.) [Cross-Chain Assets & XC-20s](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/xc20/index.md) (Learn about cross-chain assets, referred to as XC-20s, and how to interact with them through the Ethereum API on Moonbeam.) [Interact with XC-20s](XC-20): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/xc20/interact.md) (Check out the XC-20 Solidity interfaces, including the ERC-20 and ERC-20 Permit interfaces, and how to interact with external XC-20s using these interfaces.) [XC-20s and Cross-Chain Assets](Basics, XC-20): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/xc20/overview.md) (Learn about the types of cross-chain assets on Moonbeam, in particular, local and external XC-20s, and view a list of the external XC-20s on Moonbeam.) [XCM Precompile](XCM, Precompiles): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/xc20/send-xc20s/eth-api.md) (Learn about the XCM Precompile and how to use it to transfer assets from Moonbeam networks to other parachains.) [Send XC-20s via XCM](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/xc20/send-xc20s/index.md) (This section shows you how to send XC-20s cross-chain from Moonbeam to other chains in the ecosystem using the X-Tokens Pallet and X-Tokens Precompile.) [XC-20 Transfers Overview](Basics, XC-20): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/xc20/send-xc20s/overview.md) (Explore the types of asset transfers and some of the fundamentals of remote asset transfers via XCM, including the XCM instructions for asset transfers.) [Send XC-20s to Other Chains](XC-20): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/xc20/send-xc20s/xcm-pallet.md) (This guide introduces the Polkadot XCM Pallet and explains how to send XC-20s to another chain using some of the pallet's extrinsics.) [Send XC-20s to Other Chains](Precompiles, XC-20, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/xc20/send-xc20s/xtokens-precompile.md) (Learn how to send assets cross-chain via Cross-Consensus Messaging (XCM) using the X-Tokens Precompile with familiar Ethereum libraries like Ethers and Web3.) [XCM Utilities Precompile Contract](XCM): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/interoperability/xcm/xcm-utils.md) (Learn the various XCM related utility functions available to smart contract developers with Moonbeam's precompiled XCM Utilities contract.) [How to use Chopsticks to Fork Moonbeam](Substrate Toolkit, Dev Environments): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/dev-env/chopsticks.md) (Learn the basics of how to use Chopsticks to replay blocks, dissect state changes, test XCM interactions, and locally fork the entirety of a Moonbeam network.) [Substrate Development Environments](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/dev-env/index.md) (Explore development environments designed to facilitate access and interaction with the Substrate side of Moonbeam in a local development setting.) [Substrate API](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/index.md) (Learn how to interact with the Substrate API when developing on Moonbeam, including how to use the Polkadot.js API for querying Moonbeam data.) [Identity Pallet](Substrate Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/interfaces/account/identity.md) (This guide covers the available functions in the Identity Pallet on Moonbeam, which are used to create and manage on-chain identities.) [Substrate Interfaces for Account Management](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/interfaces/account/index.md) (Explore low-level Substrate interfaces for advanced account management, including proxy control, identity verification, and multisig transactions.) [Multisig Pallet](Substrate Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/interfaces/account/multisig.md) (Learn about the Multisig Pallet, which taps into Substrate functionality to provide the ability to approve and dispatch calls from a multisig on Moonbeam.) [Proxy Pallet](Substrate Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/interfaces/account/proxy.md) (Learn how to use the available extrinsics, storage methods, and constants in the Proxy Pallet on Moonbeam to make calls on an account's behalf.) [Conviction Voting Pallet](Substrate Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/interfaces/features/governance/conviction-voting.md) (This guide covers the available functions in the Conviction Voting Pallet on Moonbeam, which are used to vote, delegate votes, remove votes, and more.) [Governance-related Substrate Interfaces](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/interfaces/features/governance/index.md) (Utilize low-level Substrate interfaces for robust governance capabilities, including submitting proposals and voting on referenda.) [Parameters Pallet](Substrate Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/interfaces/features/governance/parameters.md) (Learn how Moonbeam's Parameters Pallet safely and dynamically modifies network config items via on-chain governance, removing the need for runtime upgrades.) [Preimage Pallet](Substrate Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/interfaces/features/governance/preimage.md) (Learn about the available extrinsics and storage methods for the Preimage Pallet on Moonbeam, which are used to store and manage on-chain preimages.) [Referenda Pallet](Substrate Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/interfaces/features/governance/referenda.md) (This guide covers the available functions for the Referenda Pallet on Moonbeam, of which are used to view and submit data related to on-chain referenda) [Access Network Features via Substrate](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/interfaces/features/index.md) (Discover low-level Substrate interfaces that unlock functionality for interacting with critical network features like governance, staking, and randomness.) [Randomness Pallet](Substrate Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/interfaces/features/randomness.md) (Learn about the available extrinsics, storage methods, and constants in the Randomness Pallet on Moonbeam to retrieve data on randomness requests and results.) [Parachain Staking Pallet](Substrate Toolkit, Staking): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/interfaces/features/staking.md) (Learn about the Parachain Staking Pallet interface on Moonbeam, which can be used to perform delegator and collator activities and retrieve staking information.) [The Substrate Pallets on Moonbeam](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/interfaces/index.md) (Substrate-based blockchains like Moonbeam utilize modular components to encapsulate specific functionalities. Explore these modules and their interfaces.) [Low-Level Substrate Interfaces for XCM](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/interfaces/interoperability/index.md) (Leverage low-level Substrate interfaces for seamless interoperability via XCM, include interfaces for asset transfers and remote execution.) [The Substrate Pallets on Moonbeam](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/interfaces/utility/index.md) (Implement essential utility functions with low-level Substrate interfaces for batching transactions and sending calls via derivative accounts.) [Utility Pallet](Substrate Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/interfaces/utility/utility.md) (Learn about the available extrinsics for the Utility Pallet on Moonbeam and how to interact with them using Polkadot.js Apps and the Polkadot.js API.) [Substrate Libraries](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/libraries/index.md) (Learn how to use JavaScript or Python Substrate libraries such as Polkadot.js and Py Substrate Interface to interact with the Substrate side of Moonbeam.) [How to use the Polkadot.js API](Substrate Toolkit, Libraries and SDKs): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/libraries/polkadot-js-api.md) (Learn how to use the Polkadot.js API to interact with a Moonbeam node to get chain data and send transactions (extrinsics) via the Substrate side of Moonbeam.) [How to use the Python Substrate Interface](Substrate Toolkit, Libraries and SDKs): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/libraries/py-substrate-interface.md) (Learn the basics of how to use the Python Substrate Interface library to query chain data, send transactions, and more on Moonbeam networks.) [Using Substrate API Sidecar with Moonbeam](Substrate Toolkit, Libraries and SDKs): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/builders/substrate/libraries/sidecar.md) (Learn how to use Sidecar, a Substrate-based REST service, with Moonbeam-based networks to access blocks, account balances, compute gas used, and more.) [Account Balances](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/core-concepts/balances.md) (A description of the main differences that Ethereum developers need to understand in terms of account balances on Moonbeam and how they differ from Ethereum.) [Consensus & Finality](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/core-concepts/consensus-finality.md) (The main differences that Ethereum developers should understand in terms of consensus and finality on Moonbeam and how it differs from Ethereum.) [Core Concepts](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/core-concepts/index.md) (Dive into some of the core concepts and their key differences between Moonbeam, an Ethereum-compatible blockchain, and Ethereum itself.) [Security Considerations](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/core-concepts/security.md) (A description of the main differences that Ethereum developers need to understand in terms of security considerations when developing on Moonbeam.) [Transfer & Monitor Balances on Moonbeam](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/core-concepts/transfers-api.md) (A description of the main differences that developers need to understand in terms of the different balance transfers available on Moonbeam compared to Ethereum.) [Calculating Transaction Fees](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/core-concepts/tx-fees.md) (Learn about the transaction fee model used in Moonbeam and the differences compared to Ethereum that developers should be aware of.) [Unified Accounts](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/core-concepts/unified-accounts.md) (Moonbeam replaced the default Substrate account system with native support for the Ethereum-based H160 accounts and ECDSA keys. Find out more information!) [List your Dapp on the Moonbeam DApp Directory](Reference): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/dapp-directory.md) (Follow this tutorial to learn how to list your Moonbeam or Moonriver project or update a current listing on the Moonbeam Foundation DApp Directory.) [Moonbeam's Nimbus Consensus Framework](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/features/consensus.md) (Learn about all the parts of Moonbeam's Nimbus consensus framework and how it works as part of Polkadot's shared security model.) [Ethereum Compatibility](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/features/eth-compatibility.md) (Transitioning from Ethereum to Moonbeam? Here's a brief overview of the key components and key differences of Moonbeam's Ethereum compatibility.) [Governance](Governance, Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/features/governance.md) (As a Polkadot parachain, Moonbeam uses an on-chain governance system, allowing for a stake-weighted vote on public referenda.) [Features](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/features/index.md) (Learn about some of the main features on Moonbeam, including Ethereum compatibility, interoperability, the consensus framework, staking, governance, and more.) [Randomness](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/features/randomness.md) (Learn about the sources of VRF randomness on Moonbeam, the request and fulfillment process, and some security considerations when using on-chain randomness.) [Staking](Basics, Staking): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/features/staking.md) (Moonbeam provides staking features where token holders delegate collator candidates with their tokens and earn rewards.) [Treasury](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/features/treasury.md) (Moonbeam has an on-chain Treasury controlled by Treasury Council members, enabling stakeholders to submit proposals to further the network.) [Cross-Chain Communication](Basics, XCM): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/features/xchain-plans.md) (This guide covers the ways you can build cross-chain dApps with Moonbeam, including via XCM, cross consensus messaging, and GMP, general message passing.) [Learn About Moonbeam](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/index.md) (Learn all about Moonbeam, including the basics about the Ethereum-compatible smart contract platform and its compelling features.) [Moonbeam Source Code](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/platform/code.md) (Moonbeam is an open source project in the Polkadot ecosystem, with publicly available and auditable source code.) [Glossary](Reference): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/platform/glossary.md) (We've compiled a glossary of terms related to Polkadot that'll make it easier to learn more about the ecosystem.) [Smart Contract Platform](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/platform/index.md) (Learn about the Moonbeam smart contract platform, including the Moonbeam networks, the vision, roadmap, technology, tokens, and more.) [Important Moonbeam Related Links](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/platform/links.md) (If you're new to Moonbeam or the Polkadot network, here are some important links to review, including compatible Ethereum tools.) [Networks](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/platform/networks/index.md) (Learn the basics about each of the Moonbeam networks, including Moonbeam, Moonriver, and the Moonbase Alpha TestNet.) [Moonbase Alpha TestNet Overview](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/platform/networks/moonbase.md) (An overview of the current configuration of the Moonbeam TestNet, Moonbase Alpha, and information on how to start building on it using Solidity.) [Moonbeam Network Overview](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/platform/networks/moonbeam.md) (An overview of the current configuration of the Moonbeam deployment on Polkadot, Moonbeam, and information on how to start building on it using Solidity.) [Moonriver Overview](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/platform/networks/moonriver.md) (An overview of the current configuration of the Moonbeam deployment on Kusama, Moonriver, and information on how to start building on it using Solidity.) [Overview of Networks](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/platform/networks/overview.md) (An overview of all of the MainNet and TestNet deployments of Moonbeam, an Ethereum-compatible smart contract parachain on Polkadot and Kusama.) [Technology & Architecture](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/platform/technology.md) (Moonbeam is built using Rust and Polkadot's Substrate framework, enabling rich tools for implementation while allowing for specialization and optimization.) [Utility Tokens](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/platform/tokens.md) (Each of the Moonbeam networks require a utility token to function. Glimmer (GLMR) for Moonbeam on Polkadot and Moonriver (MOVR) for Moonriver on Kusama.) [The Moonbeam Vision | Multi-chain](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/platform/vision.md) (Moonbeam is designed to enable a multi-chain future, where users and assets can move freely across many specialized and heterogeneous chains.) [Why Polkadot](Basics): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/learn/platform/why-polkadot.md) (Moonbeam is built on the Substrate framework and connected to the Polkadot network, adding speed and security to the platform.) [Node Operators & Collators](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/node-operators/index.md) (Learn how to become a node operator on Moonbeam, including running a Moonbeam full node or collator node, indexer nodes, and oracle nodes.) [Run Indexer Nodes](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/node-operators/indexer-nodes/index.md) (Learn how to run an indexer node, such as a Graph node, on Moonbeam to provide indexing and querying services of on-chain data.) [Run a Graph Node](Indexer Nodes and Queries): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/node-operators/indexer-nodes/thegraph-node.md) (Use Docker to spin up and run your own Graph node to provide indexing and querying services of on-chain data on Moonbeam.) [Collator Account Management](Node Operators and Collators): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/node-operators/networks/collators/account-management.md) (Learn how to manage your collator account, including generating session keys, mapping Nimbus IDs, setting an identity, and creating proxy accounts.) [Moonbeam Collator Activities](Node Operators and Collators): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/node-operators/networks/collators/activities.md) (Instructions on how to dive in and learn about the related activities for becoming and maintaining a collator node in the Moonbeam Network.) [Author Mapping Precompile](Node Operators and Collators): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/node-operators/networks/collators/author-mapping.md) (A guide for collators to learn how to use the Author Mapping Solidity interface to map session keys to a Moonbeam address where block rewards are paid out. ) [Collators FAQ](Node Operators and Collators): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/node-operators/networks/collators/faq.md) (Some FAQs around becoming a collator, collator activities, and things to be aware of when running and operating a collator node on Moonbeam.) [Collators (Block Producers)](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/node-operators/networks/collators/index.md) (Learn how to become a collator and produce blocks on Moonbeam, including requirements, account management, how to join the collator pool, FAQs, and more.) [Orbiter Program for Collators](Node Operators and Collators): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/node-operators/networks/collators/orbiter.md) (Learn about the Moonbeam Orbiter Program for collators, including the eligibility criteria, bond requirements, rewards, performance metrics, and more.) [Run a Collator Node](Basics, Node Operators and Collators): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/node-operators/networks/collators/overview.md) (Instructions on how to dive in and become a collator in the Moonbeam Network once you are running a node.) [Moonbeam Collator Requirements](Node Operators and Collators): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/node-operators/networks/collators/requirements.md) (Learn about the requirements for becoming and maintaining a collator node on Moonbeam networks, including requirements for hardware, bonds, and more.) [Run a Full, Tracing, or Collator Node](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/node-operators/networks/index.md) (Learn how to spin up a full, tracing, or collator node on Moonbeam, as well as the requirements for being a collator (block producer).) [Compile the Binary to Run a Node](Node Operators and Collators): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/node-operators/networks/run-a-node/compile-binary.md) (Learn how to manually compile the binary to run a full Moonbeam node. Compiling the binary can take around 30 minutes and requires at least 32GB of memory.) [Use Docker to Run a Node](Node Operators and Collators): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/node-operators/networks/run-a-node/docker.md) (How to run a full parachain node so you can have your own RPC endpoint or produce blocks for the Moonbeam Network using Docker.) [Run a Node Flags & Options](Node Operators and Collators): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/node-operators/networks/run-a-node/flags.md) (A list of helpful flags for spinning up a full parachain node on Moonbeam. Also learn how to access all of the flags available for node operators.) [Run a Full Parachain Node](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/node-operators/networks/run-a-node/index.md) (Learn how to run a full parachain node on any of the Moonbeam networks using Docker or Systemd, so you can have your own RPC endpoint or produce blocks.) [Run a Node](Basics, Node Operators and Collators): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/node-operators/networks/run-a-node/overview.md) (Learn about all of the necessary details to run a full parachain node for the Moonbeam Network to have your RPC endpoint or produce blocks.) [Run a Node on Moonbeam Using Systemd](Node Operators and Collators): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/node-operators/networks/run-a-node/systemd.md) (How to run a full parachain node so you can have your own RPC endpoint or produce blocks for the Moonbeam Network using Systemd.) [Run a Tracing Node](Node Operators and Collators): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/node-operators/networks/tracing-node.md) (Learn how to leverage Geth's Debug and Txpool APIs, and OpenEthereum's Trace module to run a tracing node on Moonbeam.) [Run Oracle Nodes](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/node-operators/oracle-nodes/index.md) (Run an oracle node, such as a ChainLink node, on Moonbeam and provide off-chain data to smart contracts running on Moonbeam.) [Run a Chainlink Node](Oracle Nodes): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/node-operators/oracle-nodes/node-chainlink.md) (How to set up a Chainlink Oracle node for the Moonbeam Network to feed data on-chain to be used by smart contracts.) [Connect Coinbase Wallet to Moonbeam](Tokens and Accounts): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/connect/coinbase-wallet.md) (This guide walks you through how to configure the Coinbase Wallet extension and mobile app for Moonbeam and how to create a wallet and send funds on Moonbeam.) [Connect your Wallet to Moonbeam](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/connect/index.md) (Learn about some of the supported wallets available for Moonbeam, and how to connect your wallet and use it to interact with Moonbeam networks.) [Ethereum App](Tokens and Accounts, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/connect/ledger/ethereum.md) (This guide walks you through how to use your Ledger hardware wallet to sign transactions in Moonbeam-based networks using the Ethereum app on Ledger Live.) [Connect & Use Ledger](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/connect/ledger/index.md) (Learn how to use your Ledger hardware wallet to sign transactions on Moonbeam networks using the native Moonbeam and Moonriver apps and the Ethereum app.) [Moonbeam App](Tokens and Accounts, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/connect/ledger/moonbeam.md) (This guide walks you through how to use your Ledger hardware wallet to sign transactions in Moonbeam using the native Moonbeam Ledger Live app.) [Using the Moonriver Ledger App](Tokens and Accounts, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/connect/ledger/moonriver.md) (This guide walks you through how to use your Ledger hardware wallet to sign transactions on Moonriver using the native Moonriver Ledger Live app.) [Connect MathWallet](Tokens and Accounts, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/connect/mathwallet.md) (This guide walks you through how to connect Mathwallet, a browser-based wallet that works with Ethereum, to Moonbeam.) [How to Connect MetaMask](Tokens and Accounts, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/connect/metamask.md) (This guide walks you through how to connect MetaMask, a browser-based Ethereum wallet, to Moonbeam-based networks and how to transfer funds.) [Fiat On-Ramps Available for Moonbeam](Tokens and Accounts, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/connect/on-ramps.md) (This guide introduces on-ramps for Moonbeam, including Transak and Onramp, and provides an overview of the process to acquire GLMR from each.) [How to use Polkadot.js Apps](Tokens and Accounts, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/connect/polkadotjs.md) (Follow this quick tutorial to learn how to use Moonbeam’s Ethereum-style H160 addresses and send transactions with Polkadot.js Apps.) [How to Connect SubWallet to Moonbeam](Tokens and Accounts, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/connect/subwallet.md) (This guide walks you through how to connect SubWallet, a comprehensive Polkadot, Substrate, and Ethereum wallet, to Moonbeam.) [Using Talisman with Polkadot JS Apps](Tokens and Accounts, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/connect/talisman.md) (Follow this quick tutorial to learn how to use Moonbeam’s Ethereum-style H160 addresses and send transactions with Polkadot.js Apps and Talisman.) [How to Connect & Use Trezor](Tokens and Accounts): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/connect/trezor.md) (Learn how to import your Trezor hardware wallet to MetaMask and how to use your Trezor to sign transactions on Moonbeam.) [Participate in Governance](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/governance/index.md) (Learn how to participate in Moonbeam's on-chain governance, including how to propose an action to be voted on and how to vote on proposals.) [How to Propose an Action in OpenGov](Governance): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/governance/proposals.md) (Follow these step-by-step instructions to learn how to submit a Democracy proposal for other token holders to vote on in Governance v2 (OpenGov) on Moonbeam.) [How to Propose a Treasury Spend](Governance): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/governance/treasury-spend.md) (Learn about the full life cycle of a Treasury proposal from the initial proposal on Moonbeam's Community Forum to Council approval of the on-chain spend.) [How to Vote on a Proposal in OpenGov](Governance): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/governance/voting.md) (Follow this guide to learn how to vote and lock your tokens to support or reject a proposal put forth for a referendum in Governance v2 (OpenGov) on Moonbeam.) [How to use your GLMR & MOVR Tokens](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/index.md) (A series of guides for using and managing your GLMR & MOVR tokens, including supported wallets, participating in governance and staking, and more.) [Managing an Identity](Tokens and Accounts): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/manage/identity.md) (Learn how to create and manage an on-chain identity, which includes personal information such as your name and social handles, on Moonbeam-based networks.) [Manage & Secure your Account](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/manage/index.md) (Learn how to manage and secure your account on Moonbeam by creating an on-chain identity, and setting up multisig safes and proxy accounts.) [Moonbeam Multisig Safe](Tokens and Accounts): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/manage/multisig-safe.md) (Learn how to use and manage funds with the Moonbeam Safe. Create a new multisig safe and receive and send tokens to the safe, as well as ERC-20s, on Moonbeam.) [Setting up a Proxy Account](Tokens and Accounts): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/manage/proxy-accounts.md) (Learn how to set up a proxy account on Moonbeam-based networks so you can keep your underlying account safe in cold storage.) [How to Stake GLMR & MOVR Tokens](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/staking/index.md) (Learn how to delegate collator candidates and stake your GLMR and MOVR tokens to earn staking rewards on Moonbeam and Moonriver.) [How to Stake your MOVR & GLMR Tokens](Staking): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tokens/staking/stake.md) (A guide that shows how you can stake your tokens and earn rewards on Moonbeam by delegating collator candidates.) [Approve & Swap with the Batch Precompile](Tutorials, Precompiles): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/eth-api/batch-approve-swap.md) (Learn how to use the Batch Precompile on Moonbeam to batch an approval and swap into a single call, so you can approve the exact amount of tokens for the swap.) [Gasless Transactions with the Call Permit Precompile](Tutorials, Precompiles): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/eth-api/call-permit-gasless-txs.md) (Enable gas-less transactions in your DApp with Moonbeam's Call Permit Precompile! Learn how to implement the Call Permit Precompile to improve user experience.) [Use GPT-4 to Develop Smart Contracts](Tutorials): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/eth-api/chat-gpt.md) (Learn how you can use OpenAI's ChatGPT (GPT-4) generative AI LLM to write, debug, and deploy Solidity smart contracts on the Moonbeam network.) [Foundry Development Life Cycle from Start to End](Tutorials, Dev Environments): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/eth-api/foundry-start-to-end.md) (Follow a step-by-step tutorial on how to use Foundry to build a project on Moonbeam, from writing smart contracts and tests to deploying on TestNet and MainNet.) [Write & Deploy Smart Contracts](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/eth-api/get-started.index.md) (Check out these tutorials to learn how to write, test, and deploy Solidity smart contracts on Moonbeam using tools like Ethers, Hardhat, Foundry, and more.) [Hardhat Developer Workflow](Tutorials, Dev Environments): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/eth-api/hardhat-start-to-end.md) (Learn how to develop, test, and deploy smart contracts with Hardhat and how to take your contracts from a local development node to Moonbeam MainNet.) [How to Build a DApp](Tutorials): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/eth-api/how-to-build-a-dapp.md) (Learn about the frontend, smart contracts, and storage system of Decentralized Applications (DApp) by dissecting an entire example project.) [Ethereum API Tutorials](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/eth-api/index.md) (Follow these step-by-step tutorials to learn how to use Ethereum libraries and development frameworks to create and interact with smart contracts on Moonbeam.) [Precompiled Contracts Tutorials](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/eth-api/precompiles.index.md) (Check out these tutorials on interacting with precompiled Solidity contracts on Moonbeam to access Substrate features using Ethereum libraries and tools.) [Create a Lottery with the Randomness Precompile](Tutorials, Precompiles): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/eth-api/randomness-lottery.md) (Looking to create a lottery smart contract? Follow this step-by-step tutorial on using Moonbeam's Randomness Precompile (a Solidity interface) to get started.) [Build an NFT Marketplace DApp with thirdweb](Tutorials): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/eth-api/thirdweb.md) (Learn how to build an NFT marketplace DApp with thirdweb, including both frontend and smart contract components, in an end-to-end fashion.) [Using Tenderly to Debug and Simulate Transactions](Tutorials): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/eth-api/using-tenderly.md) (Follow a step-by-step guide on getting started with Tenderly, including using the debugger, forking and simulating transactions, and monitoring smart contracts.) [Tutorials](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/index.md) (Dive into the Moonbeam smart contract platform through this compiled list of step-by-step tutorials on a variety of subjects.) [Gasless Transactions with 0xGasless](Tutorials): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/integrations/0xgasless.md) (Learn how to implement gasless transactions on Moonbeam using 0xGasless, enabling users to interact with smart contracts without holding native tokens.) [Integration Tutorials](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/integrations/index.md) (Get ahead with third-party integrations on Moonbeam! Our tutorials cover everything you need to know to integrate seamlessly. Explore now and start building!) [Tutorials on Indexing Blockchain Data](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/integrations/indexers.index.md) (Indexers are used to query and process blockchain data efficiently. Follow these tutorials to learn how to use indexers to query blockchain data on Moonbeam.) [Index a Local Development Node](Tutorials, Indexer Nodes and Queries): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/integrations/local-subsquid.md) (Improve your DApp development experience by following this guide to learn how to index a DApp deployed locally on a Moonbeam dev node with SQD (Subsquid)!) [Index NFT Transfers with SQD (Subsquid)](Tutorials, Indexer Nodes and Queries): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/integrations/nft-subsquid.md) (Learn how to use SQD (formerly Subsquid), a query node framework for Substrate-based chains, to index and process NFT transfer data for Moonbeam and Moonriver.) [Tutorials on Using Oracles](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/integrations/oracles.index.md) (Dive into the tutorials featured in this section to gain insights into seamlessly integrating Oracles into your smart contracts or dApps on Moonbeam) [Supra Oracles](Tutorials): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/integrations/supra.md) (In this step-by-step tutorial, learn about Supra's pull model and how to use their price feeds to fetch price data in smart contracts on Moonbeam.) [Build a Cross-Chain DAO with OpenZeppelin's Governor](Tutorials): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/interoperability/cross-chain-dao.md) (In this step-by-step tutorial, you'll learn about connected contracts and how to create a cross-chain DAO using OpenZeppelin's Governor contract on Moonbeam.) [Interoperability Tutorials](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/interoperability/index.md) (Looking to learn about interoperability on Moonbeam? Our tutorials have got you covered! Explore our step-by-step guides today and start building with ease.) [Create Connected Contracts](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/interoperability/protocols.index.md) (Check out these tutorials to learn how to create connected contracts and cross-chain applications with interoperability protocols like LayerZero on Moonbeam.) [Remote Batch EVM Calls via XCM](Tutorials, Ethereum Toolkit): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/interoperability/remote-batched-evm-calls.md) (In this guide, we'll use remote EVM execution via XCM coupled with the Batch Precompile to execute multiple contract calls in Moonbeam's EVM remotely via XCM.) [Remote Staking on Moonbeam from Polkadot via XCM](Tutorials, XCM, Staking): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/interoperability/remote-staking-xcm.md) (In this guide, we'll be leveraging remote execution to remotely stake GLMR on Moonbeam using a series of XCM instructions.) [Uniswap V2 Swap on Moonbeam from Polkadot via XCM](Tutorials, XCM): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/interoperability/uniswapv2-swap-xcm.md) (In this guide, we'll use remote EVM execution via XCM to perform a Uniswap V2 swap to showcase how Moonbeam can be leveraged in a connected contracts approach.) [Mint a Cross-Chain NFT with Axelar](Tutorials, GMP Providers): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/interoperability/using-axelar-sdk.md) (In this step-by-step tutorial, you'll learn how to use the Axelar SDK to send a message from Moonbeam to another connected chain to remotely mint an NFT.) [XCM (Cross-Consensus Messaging) Tutorials](No categories available.): (https://raw.githubusercontent.com/moonbeam-foundation/moonbeam-docs/refs/heads/main/tutorials/interoperability/xcm.index.md) (Check out these tutorials to learn how to use XCM on Moonbeam to create cross-chain applications within the Polkadot and Kusama ecosystems.) ## Full content for each doc page Doc-Content: https://docs.moonbeam.network/ai-resources/ai-resources/ --- BEGIN CONTENT --- --- title: AI-Compatible Docs description: Download LLM-optimized files of the Moonbeam documentation, including full content and category-specific resources for AI agents. --- # AI Resources Moonbeam provides `.txt` files containing the documentation content and navigation structure, optimized for use with large language models (LLMs) and AI tools. These resources help build AI assistants, power code search, or enable custom tooling trained on Moonbeam’s documentation. Each category file includes foundational content from the **Basics** and **Reference** categories to ensure LLMs have the necessary context. ## Download LLM Files | Category | Description | File | Actions | |------------------------------|---------------------------------------------------------------------------------------------------|-----------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Index | Navigation index of all Moonbeam documentation pages | `llms.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms.txt" } [:octicons-download-16:](/llms.txt){ download="llms.txt" } | | Full Documentation | Full content of all documentation pages | `llms-full.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms-full.txt" } [:octicons-download-16:](/llms-full.txt){ download="llms-full.txt" } | | Basics | Moonbeam's framework, architecture, and core components | `llms-basics.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms-basics.txt" } [:octicons-download-16:](/llms-files/llms-basics.txt){ download="llms-basics.txt" } | | Reference | Reference material including network endpoints, JSON-RPC methods, and contract or token addresses | `llms-reference.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms-reference.txt"} [:octicons-download-16:](/llms-files/llms-reference.txt){ download="llms-reference.txt" } | | Ethereum Toolkit | Useful tools and smart contracts to work with Moonbeam's EVM | `llms-ethereum-toolkit.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms-ethereum-toolkit.txt" } [:octicons-download-16:](/llms-files/llms-ethereum-toolkit.txt){ download="llms-ethereum-toolkit.txt" } | | Substrate Toolkit | Useful tools and smart contracts to work with Substrate | `llms-substrate-toolkit.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms-substrate-toolkit.txt" } [:octicons-download-16:](/llms-files/llms-substrate-toolkit.txt){ download="llms-substrate-toolkit.txt" } | | GMP Providers | How to use General Message Passing (GMP) for cross-chain communication | `llms-gmp-providers.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms-gmp-providers.txt" } [:octicons-download-16:](/llms-files/llms-gmp-providers.txt){ download="llms-gmp-providers.txt" } | | XCM | Learn about and use Cross-Consensus Messaging (XCM) | `llms-xcm.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms-xcm.txt" } [:octicons-download-16:](/llms-files/llms-xcm.txt){ download="llms-xcm.txt" } | | XC-20 | Guides for interacting with XC-20 tokens | `llms-xc-20.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms-xc-20.txt" } [:octicons-download-16:](/llms-files/llms-xc-20.txt){ download="llms-xc-20.txt" } | | XCM Remote Execution | How to make cross-chain calls with XCM | `llms-xcm-remote-execution.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms-xcm-remote-execution.txt" } [:octicons-download-16:](/llms-files/llms-xcm-remote-execution.txt){ download="llms-xcm-remote-execution.txt" } | | Precompiles | Guides to using Moonbeam's precompiles | `llms-precompiles.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms-precompiles.txt" } [:octicons-download-16:](/llms-files/llms-precompiles.txt){ download="llms-precompiles.txt" } | | Libraries and SDKs | Resources for commonly used libraries and SDKs | `llms-libraries-and-sdks.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms-libraries-and-sdks.txt" } [:octicons-download-16:](/llms-files/llms-libraries-and-sdks.txt){ download="llms-libraries-and-sdks.txt" } | | Dev Environments | How to set up developer environments such as Hardhat and Foundry | `llms-dev-environments.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms-dev-environments.txt" } [:octicons-download-16:](/llms-files/llms-dev-environments.txt){ download="llms-dev-environments.txt" } | | JSON-RPC APIs | RPC usage and tracing | `llms-json-rpc-apis.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms-json-rpc-apis.txt" } [:octicons-download-16:](/llms-files/llms-json-rpc-apis.txt){ download="llms-json-rpc-apis.txt" } | | Node Operators and Collators | How to run a full node or a block-producing collator | `llms-node-operators-and-collators.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms-node-operators-and-collators.txt" } [:octicons-download-16:](/llms-files/llms-node-operators-and-collators.txt){ download="llms-node-operators-and-collators.txt" } | | Oracle Nodes | How to integrate with oracle node providers | `llms-oracle-nodes.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms-oracle-nodes.txt" } [:octicons-download-16:](/llms-files/llms-oracle-nodes.txt){ download="llms-oracle-nodes.txt" } | | Indexers and Queries | How to integrate with indexer and query node providers | `llms-indexers-and-queries.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms-indexers-and-queries.txt" } [:octicons-download-16:](/llms-files/llms-indexers-and-queries.txt){ download="llms-indexers-and-queries.txt" } | | Tokens and Accounts | How to manage tokens and accounts on Moonbeam | `llms-tokens-and-accounts.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms-tokens-and-accounts.txt" } [:octicons-download-16:](/llms-files/llms-tokens-and-accounts.txt){ download="llms-tokens-and-accounts.txt" } | | Staking | Guides to delegate and collate | `llms-staking.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms-staking.txt" } [:octicons-download-16:](/llms-files/llms-staking.txt){ download="llms-staking.txt" } | | Governance | Guides to governance including voting and treasury | `llms-governance.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms-governance.txt" } [:octicons-download-16:](/llms-files/llms-governance.txt){ download="llms-governance.txt" } | | Integrations | Guides to integrating Moonbeam with various tools such as wallets and analytics | `llms-integrations.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms-integrations.txt" } [:octicons-download-16:](/llms-files/llms-integrations.txt){ download="llms-integrations.txt" } | | Tutorials | Comprehensive, step-by-step, guided project builds | `llms-tutorials.txt` | [:octicons-copy-16:](){ .llms data-action="copy" data-value="llms-tutorials.txt" } [:octicons-download-16:](/llms-files/llms-tutorials.txt){ download="llms-tutorials.txt" } | !!! note The `llms-full.txt` file may exceed the input limits of some language models due to its size. If you encounter limitations, consider using the files by category. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/build/historical-updates/ --- BEGIN CONTENT --- --- title: Historical Updates description: An overview of the historical updates made on Moonbeam and Moonriver, such as migrations and bug fixes applied to the Moonbeam source code. categories: Reference --- # Historical Updates ## Introduction {: #introduction } This page overviews historical updates on Moonbeam and Moonriver, such as bug fixes to the Moonbeam source code and data migrations applied. This page aims to provide information about unexpected behaviors or data inconsistencies associated with updates that require forced data migrations. ## Bugs {: #bugs } #### Invalid Transactions Stored {: #invalid-transactions-stored } For invalid transactions where the transaction cost couldn't be paid, the EVM pallet inserted the transaction metadata into storage instead of discarding it because there was no transaction cost validation. As a result, the runtime storage was unnecessarily bloated with invalid transaction data. This bug only impacted Moonriver and Moonbase Alpha and existed during the following runtimes and block ranges: | Network | Introduced | Fixed | Impacted Block Range | |:--------------:|:----------:|:-----:|:--------------------:| | Moonriver | RT49 | RT600 | 0 - 455106 | | Moonbase Alpha | RT40 | RT600 | 0 - 675175 | For more information, you can review the [relative Frontier PR on GitHub](https://github.com/polkadot-evm/frontier/pull/465){target=\_blank}. --- #### Ethereum Fees Weren't Sent to Treasury {: #ethereum-fees-to-treasury } The Moonbeam transaction fee model before Runtime 3401 and the passage of [MB101](https://forum.moonbeam.network/t/proposal-mb101-burn-100-of-transaction-fees-on-moonbeam/2022){target=\_blank} mandated a 20% allocation of fees sent to the on-chain Treasury and 80% burned as a deflationary force. However, before runtime 800, Ethereum transactions did not correctly allocate 20% of the transaction fees to the on-chain Treasury. This bug only impacted Moonriver and Moonbase Alpha and existed during the following runtimes and block ranges: | Network | Introduced | Fixed | Impacted Block Range | |:--------------:|:----------:|:-----:|:--------------------:| | Moonriver | RT49 | RT800 | 0 - 684728 | | Moonbase Alpha | RT40 | RT800 | 0 - 915684 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/732){target=\_blank}. --- #### Missing Refunds {: #missing-refunds } Moonbeam is configured to set the existential deposit to 0, meaning that accounts do not need a minimum balance to be considered active. For Substrate-based chains with this configuration, some refunds were missing from zeroed accounts because the account was interpreted as not existing. This bug existed during the following runtimes and block ranges: | Network | Introduced | Fixed | Impacted Block Range | |:--------------:|:----------:|:------:|:--------------------:| | Moonbeam | RT900 | RT1001 | 0 - 5164 | | Moonriver | RT49 | RT1001 | 0 - 1052241 | | Moonbase Alpha | RT40 | RT1001 | 0 - 1285915 | For more information, you can review the [relative Frontier PR](https://github.com/polkadot-evm/frontier/pull/509){target=\_blank} and the associated [Substrate PR on GitHub](https://github.com/paritytech/substrate/issues/10117){target=\_blank}. --- #### Incorrect Collator Selection {: #incorrect-collator-selection } The total delegations for collator candidates were not correctly updated when a delegation was increased via the `delegatorBondMore` extrinsic. This led to issues where the increased delegation amount wasn't included in the candidates' total amount bonded, which is used to determine which candidates are in the active set of collators. As a result, some candidates may not have been selected to be in the active set when they should have been, impacting their own and their delegators' rewards. This bug existed during the following runtimes and block ranges: | Network | Introduced | Fixed | Impacted Block Range | |:--------------:|:----------:|:------:|:--------------------:| | Moonbeam | RT900 | RT1300 | 0 - 524762 | | Moonriver | RT49 | RT1300 | 0 - 1541735 | | Moonbase Alpha | RT40 | RT1300 | 0 - 1761128 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/1291){target=\_blank}. --- #### New Account Event Bug {: #new-account-event } The `System.NewAccount` event is emitted when a new account is created. However, a bug prevented this event from being emitted for some accounts at creation time. A hotfix was applied that patched the impacted accounts and emitted the `System.NewAccount` at a later time. The hotfix was applied in the following block ranges: | Network | Block Range | |:--------------:|:-------------------------------------------------------------------------------------------------------------------------------------:| | Moonbeam | [1041355 - 1041358 and 1100752](https://moonbeam.subscan.io/extrinsic?module=evm&call=hotfix_inc_account_sufficients){target=\_blank} | | Moonriver | [1835760 - 1835769](https://moonriver.subscan.io/extrinsic?module=evm&call=hotfix_inc_account_sufficients){target=\_blank} | | Moonbase Alpha | [2097782 - 2097974](https://moonbase.subscan.io/extrinsic?address=&module=evm&call=hotfix_inc_account_sufficients){target=\_blank} | This bug existed during the following runtimes and block ranges: | Network | Introduced | Fixed | Impacted Block Range | |:--------------:|:----------:|:------:|:--------------------:| | Moonbeam | RT900 | RT1401 | 0 - 915320 | | Moonriver | RT49 | RT1401 | 0 - 1705939 | | Moonbase Alpha | RT40 | RT1400 | 0 - 1962557 | For more information, you can review the [relative Frontier PR on GitHub](https://github.com/moonbeam-foundation/frontier/pull/46/files){target=\_blank}. --- #### Incorrect Timestamp Units {: #incorrect-timestamp-units } EIP-2612 and Ethereum blocks deal with timestamps in seconds; however, the Substrate timestamp pallet that Moonbeam implements uses milliseconds. This only affected the EIP-2612 implementation, not the `block.timestamp` value. This bug existed during the following runtimes and block ranges: | Network | Introduced | Fixed | Impacted Block Range | |:--------------:|:----------:|:------:|:--------------------:| | Moonbeam | RT900 | RT1606 | 0 - 1326697 | | Moonriver | RT49 | RT1605 | 0 - 2077598 | | Moonbase Alpha | RT40 | RT1603 | 0 - 2285346 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/1451){target=\_blank}. --- #### Substrate Tips Missing Treasury Distribution {: #substrate-tips } Tips for Substrate-based transactions weren't handled properly. The entire portion of the tip was burned because it was not handled in the runtime code. A fix was applied so that 20% was paid to the Treasury and 80% was burned, consistent with all other fee behavior at that time. Note that RT3401 introduced a parameters pallet fee configuration allowing governance to adjust how fees are split between the Treasury and burning. After this runtime upgrade combined with the passage of [MB101](https://forum.moonbeam.network/t/proposal-mb101-burn-100-of-transaction-fees-on-moonbeam/2022){target=\_blank}, 100% of all transaction fees on both Moonbeam and Moonriver are now burned. This bug existed during the following runtimes and block ranges: | Network | Introduced | Fixed | Impacted Block Range | |:--------------:|:----------:|:------:|:--------------------:| | Moonbeam | RT900 | RT2403 | 0 - 4163078 | | Moonriver | RT49 | RT2401 | 0 - 4668844 | | Moonbase Alpha | RT40 | RT2401 | 0 - 4591616 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/2291){target=\_blank}. --- #### Incorrect Delegation Reward Calculation {: #incorrect-delegation-reward-calculation } The reward payouts for all delegations and collators were underestimated whenever there were pending requests. Delegation rewards are calculated based on the amount of tokens bonded by each delegator with respect to the total stake of the given collator. By counting delegation amounts for pending requests, the rewards to collators and their delegations were less than they should have been. This bug existed during the following runtimes and block ranges: | Network | Introduced | Fixed | Impacted Block Range | |:--------------:|:----------:|:------:|:--------------------:| | Moonbeam | RT1001 | RT1802 | 5165 - 1919457 | | Moonriver | RT1001 | RT1801 | 1052242 - 2572555 | | Moonbase Alpha | RT1001 | RT1800 | 1285916 - 2748785 | You can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/1719){target=\_blank} for more information. --- #### Block Parent Hash Calculated Incorrectly {: #block-parent-hash-calculated-incorrectly } After EIP-1559 support was introduced, which included the transition to new Ethereum transaction types, the block header parent hash was miscalculated to `H256::default`. This bug only impacted Moonbase Alpha and only impacted the following block: | Network | Introduced | Fixed | Impacted Block | |:--------------:|:----------:|:------:|:--------------:| | Moonbase Alpha | RT1200 | RT1201 | 1648995 | While the root issue was fixed in RT1201, the incorrect hash was corrected in RT2601. For more information on the root fix, you can review the [relative Frontier PR on GitHub](https://github.com/polkadot-evm/frontier/pull/570/){target=\_blank}. To take a look at the correction of the parent hash, check out the corresponding [Moonbeam PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/2524){target=\_blank}. --- #### Incorrect Handling of EIP-1559 Gas Fees {: #incorrect-gas-fees-eip1559 } With the introduction of EIP-1559 support, the logic for handling `maxFeePerGas` and `maxPriorityFeePerGas` was implemented incorrectly. As a result, the `maxPriorityFeePerGas` was added to the `baseFee` even if the total amount was over the `maxFeePerGas`. This bug existed during the following runtimes and block ranges: | Network | Introduced | Fixed | Impacted Block Range | |:--------------:|:----------:|:------:|:--------------------:| | Moonbeam | RT1201 | RT1401 | 415946 - 915320 | | Moonriver | RT1201 | RT1401 | 1471037 - 1705939 | | Moonbase Alpha | RT1200 | RT1400 | 1648994 - 1962557 | For more information, you can review the [relative Frontier PR](https://github.com/moonbeam-foundation/frontier/pull/45){target=\_blank}. --- #### Transaction Fees Paid to Collators {: #transaction-fees-paid-to-collators } For blocks that included EIP-1559 transactions where a priority fee was applied, the transaction fees were incorrectly calculated and distributed to the block's collator. The fee model on Moonbeam for transactions and smart contract execution was previously handled so that 20% of the fees went to the on-chain Treasury and 80% were burned as a deflationary force. Due to this bug, the transaction fees of the impacted transactions were not burned as expected. Note that RT3401 introduced a parameters pallet fee configuration allowing governance to adjust how fees are split between the Treasury and burning. After this runtime upgrade combined with the passage of [MB101](https://forum.moonbeam.network/t/proposal-mb101-burn-100-of-transaction-fees-on-moonbeam/2022){target=\_blank}, 100% of all transaction fees on both Moonbeam and Moonriver are now burned. This bug existed during the following runtimes and block ranges: | Network | Introduced | Fixed | Impacted Block Range | |:--------------:|:----------:|:------:|:--------------------:| | Moonbeam | RT1201 | RT1504 | 415946 - 1117309 | | Moonriver | RT1201 | RT1504 | 1471037 - 1910639 | | Moonbase Alpha | RT1200 | RT1504 | 1648994 - 2221772 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/1528){target=\_blank}. --- #### Incorrect State Root Hash {: #incorrect-state-root-hash } The state root hash was miscalculated for non-legacy transactions as the transaction-type byte was not considered. With the support of [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930){target=\_blank} and [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559){target=\_blank}, the transaction types introduced are `0x01` (1) and `0x02` (2), respectively. These transaction types were omitted from the state root hash calculation. This bug existed during the following runtimes and block ranges: | Network | Introduced | Fixed | Impacted Block Range | |:--------------:|:----------:|:------:|:--------------------:| | Moonbeam | RT1201 | RT1701 | 415946 - 1581456 | | Moonriver | RT1201 | RT1701 | 1471037 - 2281722 | | Moonbase Alpha | RT1200 | RT1700 | 1648994 - 2529735 | For more information, you can review the [relative Frontier PR](https://github.com/moonbeam-foundation/frontier/pull/86){target=\_blank} and [Moonbeam PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/1678/files){target=\_blank}. --- #### Ethereum Transactions Duplicated in Storage {: #ethereum-transactions-duplicated-in-storage } An upstream bug was introduced to Frontier in the Ethereum Pallet, causing pending transactions that existed during a runtime upgrade to be duplicated in storage across two different blocks. This only impacted the first two blocks after the runtime upgrade in which this bug was introduced. Only Moonriver and Moonbase Alpha were impacted. The bug was introduced in the following runtimes and affected the following blocks: | Network | Introduced | Impacted Blocks | |:--------------:|:----------:|:-------------------:| | Moonriver | RT1605 | 2077599 and 2077600 | | Moonbase Alpha | RT1603 | 2285347 and 2285348 | The following transactions were duplicated: === "Moonriver" ```js '0x2cceda1436e32ae3b3a2194a8cb5bc4188259600c714789bae1fedc0bbc5125f', '0x3043660e35e89cafd7b0e0dce9636f5fcc218fce2a57d1104cf21aabbff9a1c0', '0x514411fb5c08f7c5aa6c61c38f33edfa74ff7e160831f6140e8dd3783648dbca', '0xf1647c357d8e1b05c522d11cff1f5090a4df114595d0f4b9e4ac5bb746473eea', '0x4be94803fe7839d5ef13ddd2633a293b4a7dddbe526839c15c1646c72e7b0b23', '0x15fceb009bd49692b598859f9146303ed4d8204b38e35c147fcdb18956679dbe', '0xa7460d23d5c633feec3d8e8f4382240d9b71a0d770f7541c3c32504b5403b70c', '0x1c838b4c4e7796a9db5edfd0377aee6e0d89b623bf1d7803f766f4cf71daefb9', '0xfb233a893e62d717ed627585f14b1ee8b3e300ac4e2c3016eb63e546a60820f0', '0xfaf8908838683ad51894eb3c68196afb99ba2e2bb698a40108960ee55417b56a', '0xa53973acbeac9fe948015dcfad6e0cb28d91b93c8115347c178333e73fd332d3', '0x9df769c96c5fdd505c67fee27eaff3714bf8f3d45a2afc02dd2984884b3cecac', '0x8f912ae91b408f082026992a87060ed245dac6e382a84288bd38fc08dbac30fe', '0xb22af459d24cb25bc53785bdd0ae6a573e24f226c94fd8d2e4663b87d3b07a88', '0x8ab9cd2bde7d679f798528b0c75325787f5fc7997e00589445b35b3954a815aa', '0xd08a1f82f4d3dc553b4b559925f997ef8bb85cb24cb4d0b893f017129fb33b78', '0xa1d40bce7cc607c19ca4b37152b6d8d3a408e3de6b9789c5977fcdef7ef14d97', '0xe442227634db10f5d0e8c1da09f8721c2a57267edbf97c4325c4f8432fd48ade', '0x0b4f5d8338a7c2b1604c1c42e96b12dc2a9d5ab264eb74ff730354e9765de13f', '0x0b00fc907701003aad75560d8b1a33cbf4b75f76c81d776b8b92d20e1d2e9d31', '0x9c18bd783f28427d873970ff9deaf1549db2f9a76e3edd6bdeae11358e447ef4', '0x8b2523f163989969dd0ebcac85d14805756bc0075b89da1274fd2c53ccaa396a', '0x47e80a0c533265974a55ea62131814e31b10f42895709f7e531e3e7b69f1387c' ``` === "Moonbase Alpha" ```js '0x006a6843eb35ad35a9ea9a99affa8d81f1ed500253c98cc9c080d84171a0afb3', '0x64c102f664eb435206ad4fcb49b526722176bcf74801c79473c3b5b2c281a243', '0xf546335453b6e35ce7e236ee873c96ba3a22602b3acc4f45f5d68b33a76d79ca', '0x4ed713ccd474fc33d2022a802f064cc012e3e37cd22891d4a89c7ba3d776f2db', '0xa5355f86844bb23fe666b10b509543fa377a9e324513eb221e0a2c926a64cae4', '0xc14791a3a392018fc3438f39cac1d572e8baadd4ed350e0355d1ca874a169e6a' ``` The duplicated transactions belong to the first block. So, on Moonriver, the transactions belong to block 2077599, and on Moonbase Alpha, the impacted transactions belong to block 2285347. For more information, you can review the [relative Frontier PR on GitHub](https://github.com/polkadot-evm/frontier/pull/638){target=\_blank}. --- #### Gas Limit Too High for Non-Transactional Calls {: #gas-limit-too-high-for-non-transactional-calls } When a non-transactional call, such as `eth_call` or `eth_estimateGas`, is made without specifying a gas limit for a past block, the client defaults to using the gas limit multiplier (10x), which causes the gas limit validation to fail as it is validating against an upper bound of the block gas limit. So, if the gas limit is greater than the block gas limit for a given call, a gas limit too high error is returned. This bug existed during the following runtimes and block ranges: | Network | Introduced | Fixed | Impacted Block Range | |:--------------:|:----------:|:------:|:--------------------:| | Moonbeam | RT1701 | RT1802 | 1581457 - 1919457 | | Moonriver | RT1701 | RT1802 | 2281723 - 2616189 | | Moonbase Alpha | RT1700 | RT1802 | 2529736 - 2879402 | You can review the [relative Frontier PR on GitHub](https://github.com/polkadot-evm/frontier/pull/935){target=\_blank} for more information. --- #### Remote EVM Calls Return Identical Transaction Hashes {: #remote-evm-calls-return-identical-tx-hashes } When multiple remote EVM calls were sent from different accounts with the same transaction payload and nonce, the same transaction hash was returned for each call. This was possible because remote EVM calls are executed from a keyless account, so if the senders all had the same nonce and were sending the same transaction object, there was no differentiation in the calculation of the transaction hash. This was fixed by adding a global nonce to the Ethereum XCM Pallet, which is the pallet that makes remote EVM calls possible. This bug only existed on Moonbase Alpha during the following runtimes and block ranges: | Network | Introduced | Fixed | Impacted Block Range | |:--------------:|:----------:|:------:|:--------------------:| | Moonbase Alpha | RT1700 | RT1900 | 2529736 - 3069634 | You can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/1790){target=\_blank} for more information. --- #### Gas Estimation Discrepancy {: #gas-estimation-discrepancy } There was a difference between estimating the gas for a transaction using a non-transaction call, such as `eth_call`, and the execution of it on-chain. The discrepancy occurred because the non-transactional calls were not properly accounting for `maxFeePerGas` and `maxPriorityFeePerGas`, as such, the ([Proof of Validity](https://wiki.polkadot.network/general/glossary/#proof-of-validity){target=\_blank}) consumed by the Ethereum transaction was counted differently. This was fixed by properly accounting for these fields when estimating the size of the on-chain transaction. This bug existed during the following runtimes and block ranges: | Network | Introduced | Fixed | Impacted Block Range | |:--------------:|:----------:|:------:|:--------------------:| | Moonbeam | RT1201 | RT2501 | 415946 - 4543267 | | Moonriver | RT1201 | RT2500 | 1471037 - 5175574 | | Moonbase Alpha | RT1200 | RT2500 | 1648994 - 5053547 | You can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/1790/){target=\_blank} for more information. --- #### Incorrect Effective Gas Price In Transaction Receipts {: #incorrect-effective-gas-price } The `effectiveGasPrice` value returned by `eth_getTransactionReceipt` was different from the on-chain value due to an incorrect calculation of the base fee. Specifically, the transaction receipt's value was computed using the `NextFeeMultiplier` from the block in which the transaction was included rather than the previous block, which is the correct source for computing the base fee. This bug existed during the following runtimes and block ranges: | Network | Introduced | Fixed | Impacted Block Range | |:--------------:|:----------:|:------:|:--------------------:| | Moonbeam | RT1201 | RT2801 | 415946 - 5899847 | | Moonriver | RT1201 | RT2801 | 1471037 - 6411588 | | Moonbase Alpha | RT1200 | RT2801 | 1648994 - 6209638 | You can review the [relative Frontier PR](https://github.com/polkadot-evm/frontier/pull/1280){target=\_blank} and [Moonbeam PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/2610){target=\_blank} for more information. --- #### Skipped Ethereum Transaction Traces {: #skipped-ethereum-transaction-traces } Runtimes with the `evm-tracing` feature enabled introduced additional `ref_time` overhead due to special logic that traces Ethereum transactions (emitting events for each component: gasometer, runtime, EVM) used to fill information for RPC calls like `debug_traceTransaction` and `trace_filter`. Since the real `ref_time` in production runtimes is smaller, this could cause the block weight limits to be reached when replaying a block in an EVM-tracing runtime, resulting in skipped transaction traces. This was observed in Moonbeam block [9770044](https://moonbeam.subscan.io/block/9770044){target=\_blank}. The fix consisted of resetting the previously consumed weight before tracing each Ethereum transaction. It's important to note that this issue only affected code under `evm-tracing`, which is not included in any production runtime. This bug was fixed in the following runtime: | Network | Fixed | Impacted Block | |:--------------:|:------:|:--------------:| | Moonbeam | RT3501 | 9770044 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/3210){target=\_blank}. --- #### Notify Inactive Collator Fails for Long-Inactive Collators {: #notify-inactive-collator-fails } The `notifyInactiveCollator` extrinsic, designed to remove collators from the pool if they haven't produced any blocks in the last two rounds, failed for collators who had been inactive for significantly longer than two rounds. The transaction would only succeed within the first few blocks of a new round. The bug existed during the following runtimes and block ranges: | Network | Introduced | Fixed | Impacted Block Range | |:--------------:|:----------:|:------:|:--------------------:| | Moonbase Alpha | RT2601 | RT3500 | 5474345 – 10750816 | | Moonriver | RT2602 | RT3501 | 5638536 – 10665393 | | Moonbeam | RT2602 | RT3501 | 4977160 – 10056989 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/3128){target=\_blank}. --- ## Migrations {: #migrations } Migrations are necessary when a storage item is changed or added and needs to be populated with data. The migrations listed below have been organized by the impacted pallet(s). ### Author Mapping Pallet {: #author-mapping } #### Update the Mapping Storage Item {: #update-mapping-storage-item } This migration updated the now deprecated `Mapping` storage item of the author mapping pallet to use a more secure hasher type. The hasher type was updated to [Blake2_128Concat](https://paritytech.github.io/substrate/master/frame_support/struct.Blake2_128Concat.html){target=\_blank} instead of [Twox64Concat](https://paritytech.github.io/substrate/master/frame_support/struct.Twox64Concat.html){target=\_blank}. This migration was only applied to Moonriver and Moonbase Alpha and was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonriver | RT800 | 684728 | | Moonbase Alpha | RT800 | 915684 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/679){target=\_blank}. --- #### Add Support for VRF Keys {: #add-support-for-vrf-keys } When VRF key support was introduced, the `MappingWithDeposit` storage item of the author mapping pallet was updated to include a `keys` field to support VRF keys that can be looked up via the Nimbus ID. A migration was applied to update the existing storage items with this new field. This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT1502 | 1107285 | | Moonriver | RT1502 | 1814458 | | Moonbase Alpha | RT1502 | 2112058 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/1407){target=\_blank}. --- #### One Nimbus ID per Account ID {: #one-nimbus-id-per-account-id } A migration was applied to ensure that an account ID can have only one Nimbus ID. The migration accepted the first Nimbus ID owned by a given account and cleared any additional Nimbus IDs associated with the account. For any cleared associations, the bond for the association was returned. This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT1606 | 1326697 | | Moonriver | RT1605 | 2077599 | | Moonbase Alpha | RT1603 | 2285347 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/1525){target=\_blank}. --- ### Base Fee Pallet {: #base-fee } #### Set Elasticity Storage Item Value {: #set-elasticity } This migration sets the `Elasticity` storage item of the base fee pallet to zero, which results in a constant `BaseFeePerGas`. This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT1300 | 524762 | | Moonriver | RT1300 | 1541735 | | Moonbase Alpha | RT1300 | 1761128 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/1744){target=\_blank}. --- ### Democracy Pallet {: #democracy } #### Preimage Storage Moved to New Preimage Pallet A migration was applied, which moved preimages stored in the democracy pallet to a new preimage pallet. This migration on Moonbeam was required as a result of an [upstream change to Polkadot](https://github.com/paritytech/substrate/pull/11649/){target=\_blank}. There was one preimage that was affected in Moonbeam, which was dropped from the scheduler queue and never executed: `0x14262a42aa6ccb3cae0a169b939ca5b185bc317bb7c449ca1741a0600008d306`. This preimage was [manually removed](https://moonbeam.subscan.io/extrinsic/2693398-8){target=\_blank} by the account that initially submitted the preimage. This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT2000 | 3310369 | | Moonriver | RT2000 | 3202604 | | Moonbase Alpha | RT2000 | 2673234 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/1962){target=\_blank}. --- #### Remove Governance V1 Collectives {: #remove-gov-v1-collectives } A migration was applied to remove the governance V1 collectives, which included the Council and Technical Committee. The governance V1 collectives were replaced with the OpenGov (governance V2) Technical Committee. This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT2801 | 5899847 | | Moonriver | RT2801 | 6411588 | | Moonbase Alpha | RT2801 | 6209638 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/2643){target=\_blank}. A follow-up migration was required to properly clear the storage entries associated with the governance V1 collectives, which was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT2901 | 6197065 | | Moonriver | RT2901 | 6699589 | | Moonbase Alpha | RT2901 | 6710531 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/2711){target=\_blank}. --- #### Remove Governance V1 Democracy Pallet {: #remove-gov-v1-collectives } A migration was applied to remove the storage associated with the Democracy Pallet used in governance V1. The Democracy Pallet was replaced with the Preimage, Referenda, and Collective Voting OpenGov (governance V2) pallets. This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT2901 | 6197065 | | Moonriver | RT2901 | 6699589 | | Moonbase Alpha | RT2901 | 6710531 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/2685){target=\_blank}. --- ### EVM Pallet {: evm-pallet } #### EVM Contract Metadata A migration was introduced to automate the manual process of setting EVM contract metadata for contracts deployed more than two years ago that hadn't been interacted with after the introduction of metadata storage item. This migration replaces the need to manually call `createContractMetadata(address)` on these contracts to make them compatible with the current runtime. This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:---------:|:----------------:|:-------------:| | Moonbeam | RT3200 | 7985204 | | Moonriver | RT3200 | 8519187 | --- ### Moonbeam Orbiter Pallet {: #moonbeam-orbiter } #### Remove the Minimum Bond Requirement for Orbiter Collators {: #remove-orbiter-minimum-bond } A migration was applied to the Moonbeam Orbiter Pallet that sets the bonds of the existing orbiter collators to zero. This change enabled payouts to be even for future orbiter program expansions. This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT2602 | 4977160 | | Moonriver | RT2602 | 5638536 | | Moonbase Alpha | RT2601 | 5474345 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/2526){target=\_blank}. --- ### Parachain Staking Pallet {: #parachain-staking } #### Update Collator State Storage Item {: #update-collator-state-storage-item } A migration was applied that updated the `Collator` storage item of the parachain staking pallet to the new `Collator2` storage item. This change updated the collator state to include the following items: - The `nominators` set is a list of all of the nominator (delegator) account IDs without their respective balance bonded - A new `top_nominators` storage item that returns a list of all of the top nominators ordered by greatest bond amount to least - A new `bottom_nominators` storage item that returns a list of all of the bottom nominators ordered by least bond amount to greatest - The `total` storage item was replaced with `total_counted` and `total_backing`. The `total_counted` item returns the sum of the top nominations and the collator's self-bond, whereas the `total_backing` item returns the sum of all of the nominations and the collator's self-bond This migration was only applied to Moonriver and Moonbase Alpha and was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonriver | RT53 | 9696 | | Moonbase Alpha | RT52 | 238827 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/505){target=\_blank}. --- #### Patch Total Staked Amount {: #patch-total-staked-amount } A migration was applied to the `total` staked amount of the `CollatorState` storage item in the Parachain Staking Pallet due to a potential bug that may have led to an incorrect amount. This migration was only applied to Moonriver and Moonbase Alpha and was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonriver | RT53 | 9696 | | Moonbase Alpha | RT52 | 238827 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/502){target=\_blank}. --- #### Support Delayed Nominator (Delegator) Exits {: #support-delayed-nominator-exits } The exit queue for handling candidate exits had been updated to include support for delayed nominator (delegator) exits and revocations, which required a migration to update the `ExitQueue` parachain staking pallet storage item to `ExitQueue2`. The `NominatorState` storage item was also migrated to `NominatorState2` to prevent a nominator from performing more nominations when they already have scheduled an exit. These migrations were only applied to Moonriver and Moonbase Alpha and were executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonriver | RT200 | 259002 | | Moonbase Alpha | RT200 | 457614 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/610){target=\_blank}. --- #### Purge Staking Storage Bloat {: #purge-staking-storage-bloat } A migration was applied to purge staking storage bloat for the `Points` and `AtStake` storage items of the parachain staking pallet that are older than two rounds. This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT1001 | 5165 | | Moonriver | RT1001 | 1052242 | | Moonbase Alpha | RT1001 | 1285916 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/970){target=\_blank}. --- #### Support Manual Exits and DPoS Terminology {: #support-manual-exits-dpos-terminology } The parachain staking pallet was updated to include manual exits. If a candidate or delegator wanted to decrease or revoke their bond or leave the candidate or delegator pool, they would need to schedule a request first, wait for a delay period to pass, and then manually execute the request. As such, a migration was applied to replace the automatic exit queue, including the `ExitQueue2` storage item, with a manual exits API. In addition, a change was made to switch from Nominated Proof of Stake (NPoS) to Delegated Proof of Stake (DPoS) terminology; this marked the sweeping change from "nominate" to "delegate". This required the migration of the following parachain staking pallet storage items: - `CollatorState2` was migrated to `CandidateState` - `NominatorState2` was migrated to `DelegatorState` These migrations were executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT1001 | 5165 | | Moonriver | RT1001 | 1052242 | | Moonbase Alpha | RT1001 | 1285916 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/810){target=\_blank}. --- #### Increase Max Delegations per Candidate {: #increase-max-delegations-per-candidate } A migration was applied to increase the maximum number of delegations per candidate in the parachain staking pallet. It increased the delegations from 100 to 500 on Moonbase Alpha and Moonriver and from 100 to 1000 on Moonbeam. This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT1101 | 171061 | | Moonriver | RT1101 | 1188000 | | Moonbase Alpha | RT1100 | 1426319 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/1096){target=\_blank}. --- #### Split Candidate Delegations into Top and Bottom {: #split-candidate-delegations-top-bottom } This migration splits the deprecated `CandidateState` storage item of the parachain staking pallet into the following three new storage items to avoid unnecessary storage reads: - `CandidateInfo` - `TopDelegations` - `BottomDelegations` This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT1201 | 415946 | | Moonriver | RT1201 | 1471037 | | Moonbase Alpha | RT1200 | 1648994 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/1117){target=\_blank}. --- #### Patch Incorrect Total Delegations {: #patch-incorrect-total-delegations } There was a migration applied to fix the [Incorrect Collator Selection](#incorrect-collator-selection) bug and patch the delegations total for all candidates. This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT1300 | 524762 | | Moonriver | RT1300 | 1541735 | | Moonbase Alpha | RT1300 | 1761128 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/1291){target=\_blank}. --- #### Split Delegator State into Delegation Scheduled Requests {: #split-delegator-state } A migration was applied that moved pending delegator requests from the `DelegatorState` storage item of the parachain staking pallet into a new `DelegationScheduledRequests` storage item. This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT1502 | 1107285 | | Moonriver | RT1502 | 1814458 | | Moonbase Alpha | RT1502 | 2112058 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/1408){target=\_blank}. --- #### Replace Staking Reserves with Locks {: #replace-staking-reserves } A migration was applied that changed users' staking reserved balances to locked balances. The locked balance is the same type as democracy-locked funds, allowing users to use their staked funds to participate in democracy. This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT1701 | 1581457 | | Moonriver | RT1701 | 2281723 | | Moonbase Alpha | RT1700 | 2529736 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/1604){target=\_blank}. --- #### Auto-Compounding Support {: #auto-compounding-support } To support auto-compounding, two migrations were applied to the `AtStake` storage item in the parachain staking pallet: - `RemovePaidRoundsFromAtStake` - to remove any stale `AtStake` entries relating to already paid-out rounds with candidates that didn't produce any blocks. This migration is a prerequisite for the `MigrateAtStakeAutoCompound` migration - `MigrateAtStakeAutoCompound` - migrates the snapshots for unpaid rounds for `AtStake` entries These migrations were executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT1901 | 2317683 | | Moonriver | RT1901 | 2911863 | | Moonbase Alpha | RT1900 | 3069635 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/1878){target=\_blank}. --- #### Switch to Block-Based Staking Rounds {: #block-based-staking-rounds } A migration was applied to switch from time-based staking rounds to fixed block-based rounds. This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT2801 | 5899847 | | Moonriver | RT2801 | 6411588 | | Moonbase Alpha | RT2801 | 6209638 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/2690){target=\_blank}. --- #### Renaming of Parachain Bond Reserve Events {: #renaming-of-parachain-bond-reserve-events } Prior to Runtime 3300, the `ReservedForParachainBond` event was emitted once per round to indicate parachain bond reserve funding through inflation. In Runtime 3300, this same event was renamed to `InflationDistributed`. This change took effect at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT3300 | 8381443 | | Moonriver | RT3300 | 8894417 | | Moonbase Alpha | RT3300 | 9062316 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/2976){target=\_blank}. --- ### Referenda Pallet {: #referenda-pallet } #### Refunds for Submission Deposits {: #refunds-for-submission-deposits } A migration was introduced to support refunds for submission deposits on closed referenda that updated the `ReferendumInfo` type. The following invariants of `ReferendumInfo` were changed so that the second parameter, `Deposit`, is now optional, `Option>`: `Approved`, `Rejected`, `Cancelled`, and `TimedOut`. This stemmed from an upstream change to the [Substrate](https://github.com/paritytech/substrate/pull/12788){target=\_blank} repository. This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT2302 | 3456477 | | Moonriver | RT2302 | 4133065 | | Moonbase Alpha | RT2301 | 4172407 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/2134){target=\_blank}. --- #### Restore Corrupted Referenda Deposits {: restore-corrupted-referenda-deposits } A migration was introduced to support restoring referenda deposits affected by corrupted storage values. The issue arose when a migration was applied twice due to a pallet version error, resulting in invalid values and non-refundable submission deposits. As the number of values to correct was finite and small, this migration created a list to update them by hand. This migration was only applied to Moonbeam and was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------:|:----------------:|:-------------:| | Moonbeam | RT3100 | 7303601 | ### XCM-Related Pallets {: #xcm-related-pallets } #### Update Transact Info Storage Item {: #update-transaction-info } There was a migration applied to the `TransactInfo` storage item of the XCM Transactor Pallet that changed the following items: - `max_weight` is added to prevent transactors from stalling the queue in the destination chain - Removes `fee_per_byte`, `metadata_size`, and `base_weight` as these items are not necessary for XCM transactions - `fee_per_second` replaces `fee_per_weight` to better reflect cases (like Kusama) in which the `fee_per_weight` unit is lower than one This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT1201 | 415946 | | Moonriver | RT1201 | 1471037 | | Moonbase Alpha | RT1200 | 1648994 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/1114){target=\_blank}. --- #### Add Support for Kusama Asset Hub (Statemine) Prefix Breaking Change {: #add-support-statemine-prefix } The following three migrations were added to the asset manager pallet to avoid issues with Kusama Asset Hub's (previously referred to as Statemine) [breaking change to the way it represents assets](https://github.com/paritytech/cumulus/pull/831){target=\_blank} and possible future breaking changes: - `UnitsWithAssetType` - updates the `AssetTypeUnitsPerSecond` storage item to a mapping of the `AssetType` to `units_per_second`, instead of the mapping `AssetId` to `units_per_second`. This is done to avoid additional migrations whenever a breaking change arises - `PopulateAssetTypeIdStorage` - creates a new `AssetTypeId` storage item that holds the `AssetType` to `AssetId` mapping, which allows the decoupling of `assetIds` and `AssetTypes` - `ChangeStateminePrefixes` - updates already registered Kusama Asset Hub (Statemine) assets to their new form These migrations were executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT1201 | 415946 | | Moonriver | RT1201 | 1471037 | | Moonbase Alpha | RT1200 | 1648994 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/1159){target=\_blank}. --- #### Add New Supported Fee Payment Assets Storage Item {: #add-supported-fee-payment-assets } A migration was applied to the asset manager pallet, creating a new `SupportedFeePaymentAssets` storage item by reading the supported asset data from the `AssetTypeUnitsPerSecond` storage item. This storage item will hold all the assets we accept for XCM fee payment. It will be read when an incoming XCM message is received, and if the asset is not in storage, the message will not be processed. This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT1300 | 524762 | | Moonriver | RT1300 | 1541735 | | Moonbase Alpha | RT1300 | 1761128 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/1118){target=\_blank}. --- #### Update the XCM Transactor Storage from V2 to V3 {: #update-xcm-transactor } With the support of XCM V3, a migration was applied to update the XCM Transactor pallet's storage from XCM V2 to V3. The `transactInfoWithWeightLimit` and `destinationAssetFeePerSecond` storage items were updated to support XCM V3 multilocations. This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT2302 | 3456477 | | Moonriver | RT2302 | 4133065 | | Moonbase Alpha | RT2301 | 4172407 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/2145){target=\_blank}. --- #### Remove Mintable XC-20s {: #remove-local-assets } Mintable XC-20s were deprecated in favor of XCM-enabled ERC-20s; as such, a migration was applied to remove the local assets pallet and clear the assets in storage. This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT2801 | 5899847 | | Moonriver | RT2801 | 6411588 | | Moonbase Alpha | RT2801 | 6209638 | For more information, you can review the [relative PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/2634){target=\_blank}. --- #### Manage Foreign Assets via Smart Contracts {: #foreign-assets-migration } A migration was applied to transition existing foreign assets to a new design that manages XCM derivative assets on Moonbeam through EVM smart contracts instead of the previous implementation using the Asset and Asset Manager pallets. The migration process involved several extrinsics in the Moonbeam Lazy Migration pallet: - **`approve_assets_to_migrate`** - sets the list of asset IDs approved for migration - **`start_foreign_asset_migration`** - initiates migration for a specific foreign asset by freezing the original asset and creating a new EVM smart contract - **`migrate_foreign_asset_balances`** - migrates asset balances in batches from old assets pallet to the new system - **`migrate_foreign_asset_approvals`** - migrates asset approvals in batches while unreserving deposits from the old approval system - **`finish_foreign_asset_migration`** - completes migration after all balances and approvals are migrated and performs final cleanup This migration preserves compatibility with existing foreign assets by identifying each foreign asset with the same AssetID integer as before. This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT3501 | 10056989 | | Moonriver | RT3501 | 10665393 | | Moonbase Alpha | RT3500 | 10750816 | For more information, you can review the relative PRs on GitHub: [2869](https://github.com/moonbeam-foundation/moonbeam/pull/2869){target=\_blank} and [3020](https://github.com/moonbeam-foundation/moonbeam/pull/3020){target=\_blank}. --- ### Nimbus Author Filter Pallet {: #nimbus } #### Replace Eligible Ratio with Eligible Count {: #replace-eligible-ratio } A breaking change was applied to the Nimbus repository, deprecating `EligibleRatio` in favor of the `EligibleCount` config. As a result, a migration was applied to the Moonbeam repository, populating the new `EligibleCount` value as a percentage of the potential authors defined at that block height if the `EligibleRatio` value existed. Otherwise, the value was set to a default value of `50`. This migration was executed at the following runtimes and blocks: | Network | Executed Runtime | Block Applied | |:--------------:|:----------------:|:-------------:| | Moonbeam | RT1502 | 1107285 | | Moonriver | RT1502 | 1814458 | | Moonbase Alpha | RT1502 | 2112058 | For more information, you can review the [relative Nimbus PR](https://github.com/moonbeam-foundation/nimbus/pull/45){target=\_blank} and [Moonbeam PR on GitHub](https://github.com/moonbeam-foundation/moonbeam/pull/1400){target=\_blank}. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/build/runtime-upgrades/ --- BEGIN CONTENT --- --- title: Runtime Upgrades description: A historical record of each runtime upgrade and the block at which the runtime was executed for Moonbeam, Moonriver, and the Moonbase Alpha TestNet. categories: Reference --- # Runtime Upgrades ## Introduction {: #introduction } Moonbeam runtime upgrades allow for the maintenance and evolution of the chain logic without the need for a hard fork. These runtime upgrades can introduce new features, improve performance, fix bugs, and respond to changing requirements. This page provides a historical record of runtime upgrades by block for each of the Moonbeam-based networks. ## Runtime Upgrades by Block {: #runtime-upgrades-by-block } The following table contains a list of the runtime upgrades and the block at which the upgrade occurred for each network. Runtime upgrades occur first on Moonbase Alpha before being released on Moonriver and then on Moonbeam. You can read the release notes for each runtime on the [Moonbeam releases GitHub page](https://github.com/moonbeam-foundation/moonbeam/releases){target=\_blank}. Not all runtime upgrades are released on each network, as sometimes after releasing the initial runtime upgrade, the need for a subsequent upgrade arises. If a runtime upgrade version has been skipped or hasn't been released yet (only applicable to the latest runtime upgrade), you'll see a `-` in that row. | Runtime | Moonbeam | Moonriver | Moonbase Alpha | |:----------------------------------------------------------------------------------------:|:----------------------------------------------------------------------:|:-----------------------------------------------------------------------:|:----------------------------------------------------------------------:| | 40 | - | - | [0](https://moonbase.subscan.io/block/0){target=\_blank} | | 44 | - | - | [142863](https://moonbase.subscan.io/block/142863){target=\_blank} | | 47 | - | - | [209144](https://moonbase.subscan.io/block/209144){target=\_blank} | | 49 | - | [0](https://moonriver.subscan.io/block/0){target=\_blank} | - | | 52 | - | - | [238827](https://moonbase.subscan.io/block/238827){target=\_blank} | | 53 | - | [9696](https://moonriver.subscan.io/block/9696){target=\_blank} | - | | 155 | - | [67938](https://moonriver.subscan.io/block/67938){target=\_blank} | [278703](https://moonbase.subscan.io/block/278703){target=\_blank} | | 159 | - | [166749](https://moonriver.subscan.io/block/166749){target=\_blank} | [383465](https://moonbase.subscan.io/block/383465){target=\_blank} | | 200 | - | [259002](https://moonriver.subscan.io/block/259002){target=\_blank} | [457614](https://moonbase.subscan.io/block/457614){target=\_blank} | | 300 | - | [344698](https://moonriver.subscan.io/block/344698){target=\_blank} | [485543](https://moonbase.subscan.io/block/485543){target=\_blank} | | 400 | - | [400458](https://moonriver.subscan.io/block/400458){target=\_blank} | [610935](https://moonbase.subscan.io/block/610935){target=\_blank} | | 501 | - | [430442](https://moonriver.subscan.io/block/430442){target=\_blank} | [653692](https://moonbase.subscan.io/block/653692){target=\_blank} | | 600 | - | [455107](https://moonriver.subscan.io/block/455107){target=\_blank} | [675176](https://moonbase.subscan.io/block/675176){target=\_blank} | | 701 | - | [581187](https://moonriver.subscan.io/block/581187){target=\_blank} | [797200](https://moonbase.subscan.io/block/797200){target=\_blank} | | 800 | - | [684728](https://moonriver.subscan.io/block/684728){target=\_blank} | [915684](https://moonbase.subscan.io/block/915684){target=\_blank} | | 900 | [0](https://moonbeam.subscan.io/block/0){target=\_blank} | [923864](https://moonriver.subscan.io/block/923864){target=\_blank} | [1075626](https://moonbase.subscan.io/block/1075626){target=\_blank} | | 901 | - | - | [1130271](https://moonbase.subscan.io/block/1130271){target=\_blank} | | 902 | - | - | [1175311](https://moonbase.subscan.io/block/1175311){target=\_blank} | | 1001 | [5165](https://moonbeam.subscan.io/block/5165){target=\_blank} | [1052242](https://moonriver.subscan.io/block/1052242){target=\_blank} | [1285916](https://moonbase.subscan.io/block/1285916){target=\_blank} | | 1002 | [32532](https://moonbeam.subscan.io/block/32532){target=\_blank} | [1141593](https://moonriver.subscan.io/block/1141593){target=\_blank} | [1396972](https://moonbase.subscan.io/block/1396972){target=\_blank} | | 1101 | [171061](https://moonbeam.subscan.io/block/171061){target=\_blank} | [1188000](https://moonriver.subscan.io/block/1188000){target=\_blank} | [1426319](https://moonbase.subscan.io/block/1426319){target=\_blank} | | 1102 | [214641](https://moonbeam.subscan.io/block/214641){target=\_blank} | [1295420](https://moonriver.subscan.io/block/1295420){target=\_blank} | [1517440](https://moonbase.subscan.io/block/1517440){target=\_blank} | | 1103 | [312036](https://moonbeam.subscan.io/block/312036){target=\_blank} | [1389122](https://moonriver.subscan.io/block/1389122){target=\_blank} | [1591913](https://moonbase.subscan.io/block/1591913){target=\_blank} | | 1200 | - | - | [1648994](https://moonbase.subscan.io/block/1648994){target=\_blank} | | 1201 | [415946](https://moonbeam.subscan.io/block/415946){target=\_blank} | [1471037](https://moonriver.subscan.io/block/1471037){target=\_blank} | [1679619](https://moonbase.subscan.io/block/1679619){target=\_blank} | | 1300 | [524762](https://moonbeam.subscan.io/block/524762){target=\_blank} | [1541735](https://moonriver.subscan.io/block/1541735){target=\_blank} | [1761128](https://moonbase.subscan.io/block/1761128){target=\_blank} | | 1400 | - | - | [1962557](https://moonbase.subscan.io/block/1962557){target=\_blank} | | 1401 | [915320](https://moonbeam.subscan.io/block/915320){target=\_blank} | [1705939](https://moonriver.subscan.io/block/1705939){target=\_blank} | [1967358](https://moonbase.subscan.io/block/1967358){target=\_blank} | | 1502 | [1107285](https://moonbeam.subscan.io/block/1107285){target=\_blank} | [1814458](https://moonriver.subscan.io/block/1814458){target=\_blank} | [2112058](https://moonbase.subscan.io/block/2112058){target=\_blank} | | 1503 | [1115896](https://moonbeam.subscan.io/block/1115896){target=\_blank} | [1909326](https://moonriver.subscan.io/block/1909326){target=\_blank} | [2220736](https://moonbase.subscan.io/block/2220736){target=\_blank} | | 1504 | [1117310](https://moonbeam.subscan.io/block/1117310){target=\_blank} | [1910640](https://moonriver.subscan.io/block/1910640){target=\_blank} | [2221773](https://moonbase.subscan.io/block/2221773){target=\_blank} | | 1603 | - | - | [2285347](https://moonbase.subscan.io/block/2285347){target=\_blank} | | 1605 | - | [2077599](https://moonriver.subscan.io/block/2077599){target=\_blank} | [2318567](https://moonbase.subscan.io/block/2318567){target=\_blank} | | 1606 | [1326697](https://moonbeam.subscan.io/block/1326697){target=\_blank} | [2105127](https://moonriver.subscan.io/block/2105127){target=\_blank} | [2379759](https://moonbase.subscan.io/block/2379759){target=\_blank} | | 1700 | - | - | [2529736](https://moonbase.subscan.io/block/2529736){target=\_blank} | | 1701 | [1581457](https://moonbeam.subscan.io/block/1581457){target=\_blank} | [2281723](https://moonriver.subscan.io/block/2281723){target=\_blank} | [2534200](https://moonbase.subscan.io/block/2534200){target=\_blank} | | 1702 | [1821212](https://moonbeam.subscan.io/block/1821212){target=\_blank} | [2524247](https://moonriver.subscan.io/block/2524247){target=\_blank} | - | | 1800 | - | - | [2748786](https://moonbase.subscan.io/block/2748786){target=\_blank} | | 1801 | - | [2572556](https://moonriver.subscan.io/block/2572556){target=\_blank} | [2830542](https://moonbase.subscan.io/block/2830542){target=\_blank} | | 1802 | [1919458](https://moonbeam.subscan.io/block/1919458){target=\_blank} | [2616190](https://moonriver.subscan.io/block/2616190){target=\_blank} | [2879403](https://moonbase.subscan.io/block/2879403){target=\_blank} | | 1803 | [2073477](https://moonbeam.subscan.io/block/2073477){target=\_blank} | [2767174](https://moonriver.subscan.io/block/2767174){target=\_blank} | [3004714](https://moonbase.subscan.io/block/3004714){target=\_blank} | | 1900 | - | - | [3069635](https://moonbase.subscan.io/block/3069635){target=\_blank} | | 1901 | [2317683](https://moonbeam.subscan.io/block/2317683){target=\_blank} | [2911863](https://moonriver.subscan.io/block/2911863){target=\_blank} | [3073562](https://moonbase.subscan.io/block/3073562){target=\_blank} | | 2000 | [2673234](https://moonbeam.subscan.io/block/2673234){target=\_blank} | [3202604](https://moonriver.subscan.io/block/3202604){target=\_blank} | [3310369](https://moonbase.subscan.io/block/3310369){target=\_blank} | | 2100 | [3011798](https://moonbeam.subscan.io/block/3011798){target=\_blank} | [3588831](https://moonriver.subscan.io/block/3588831){target=\_blank} | [3609708](https://moonbase.subscan.io/block/3609708){target=\_blank} | | 2201 | [3290853](https://moonbeam.subscan.io/block/3290853){target=\_blank} | [3858885](https://moonriver.subscan.io/block/3858885){target=\_blank} | [3842850](https://moonbase.subscan.io/block/3842850){target=\_blank} | | 2301 | - | - | [4172407](https://moonbase.subscan.io/block/4172407){target=\_blank} | | 2302 | [3456477](https://moonbeam.subscan.io/block/3456477){target=\_blank} | [4133065](https://moonriver.subscan.io/block/4133065){target=\_blank} | [4193323](https://moonbase.subscan.io/block/4193323){target=\_blank} | | 2401 | - | [4668844](https://moonriver.subscan.io/block/4668844){target=\_blank} | [4591616](https://moonbase.subscan.io/block/4591616){target=\_blank} | | 2402 | - | - | [4772817](https://moonbase.subscan.io/block/4772817){target=\_blank} | | 2403 | [4163078](https://moonbeam.subscan.io/block/4163078){target=\_blank} | [4770488](https://moonriver.subscan.io/block/4770488){target=\_blank} | [4804425](https://moonbase.subscan.io/block/4804425){target=\_blank} | | 2500 | - | [5175574](https://moonriver.subscan.io/block/5175574){target=\_blank} | [5053547](https://moonbase.subscan.io/block/5053547){target=\_blank} | | 2501 | [4543267](https://moonbeam.subscan.io/block/4543267){target=\_blank} | [5211264](https://moonriver.subscan.io/block/5211264){target=\_blank} | [5194594](https://moonbase.subscan.io/block/5194594){target=\_blank} | | [2601](https://forum.moonbeam.network/t/runtime-rt2600-schedule/1372/5){target=\_blank} | - | - | [5474345](https://moonbase.subscan.io/block/5474345){target=\_blank} | | [2602](https://forum.moonbeam.network/t/runtime-rt2600-schedule/1372/13){target=\_blank} | [4977160](https://moonbeam.subscan.io/block/4977160){target=\_blank} | [5638536](https://moonriver.subscan.io/block/5638536){target=\_blank} | [5576588](https://moonbase.subscan.io/block/5576588){target=\_blank} | | [2700](https://forum.moonbeam.network/t/runtime-rt2700-schedule/1441/3){target=\_blank} | [5504531](https://moonbeam.subscan.io/block/5504531){target=\_blank} | [6041969](https://moonriver.subscan.io/block/6041969){target=\_blank} | [5860584](https://moonbase.subscan.io/block/5860584){target=\_blank} | | [2801](https://forum.moonbeam.network/t/runtime-rt2801-schedule/1616/4){target=\_blank} | [5899847](https://moonbeam.subscan.io/block/5899847){target=\_blank} | [6411588](https://moonriver.subscan.io/block/6411588){target=\_blank} | [6209638](https://moonbase.subscan.io/block/6209638){target=\_blank} | | [2901](https://forum.moonbeam.network/t/runtime-rt2901-schedule/1695/3){target=\_blank} | [6197065](https://moonbeam.subscan.io/block/6197065){target=\_blank} | [6699589](https://moonriver.subscan.io/block/6699589){target=\_blank} | [6710531](https://moonbase.subscan.io/block/6710531){target=\_blank} | | 2902 | - | - | [6732678](https://moonbase.subscan.io/block/6732678){target=\_blank} | | [3000](https://forum.moonbeam.network/t/runtime-rt3000-schedule/1752/2){target=\_blank} | - | [7043011](https://moonriver.subscan.io/block/7043011){target=\_blank} | [7299818](https://moonbase.subscan.io/block/7299818){target=\_blank} | | 3001 | [6593037](https://moonbeam.subscan.io/block/6593037){target=\_blank} | - | - | | [3100](https://forum.moonbeam.network/t/runtime-rt3100-schedule/1801){target=\_blank} | [7303601](https://moonbeam.subscan.io/block/7303601){target=\_blank} | [7829527](https://moonriver.subscan.io/block/7829527){target=\_blank} | [8034666](https://moonbase.subscan.io/block/8034666){target=\_blank} | | [3102](https://forum.moonbeam.network/t/runtime-rt3100-schedule/1801/10){target=\_blank} | [7586782](https://moonbeam.subscan.io/block/7586782){target=\_blank} | - | - | | [3200](https://forum.moonbeam.network/t/runtime-rt3200-schedule/1881){target=\_blank} | [7985204](https://moonbeam.subscan.io/block/7985204){target=\_blank} | [8519187](https://moonriver.subscan.io/block/8519187){target=\_blank} | [8722328](https://moonbase.subscan.io/block/8722328){target=\_blank} | | [3300](https://forum.moonbeam.network/t/runtime-rt3300-schedule/1897){target=\_blank} | [8381443](https://moonbeam.subscan.io/block/8381443){target=\_blank} | [8894417](https://moonriver.subscan.io/block/8894417){target=\_blank} | [9062316](https://moonbase.subscan.io/block/9062316){target=\_blank} | | [3400](https://forum.moonbeam.network/t/runtime-rt3400-schedule/1954){target=\_blank} | [9376921](https://moonbeam.subscan.io/block/9376921){target=\_blank} | [9774989](https://moonriver.subscan.io/block/9774989){target=\_blank} | [9830392](https://moonbase.subscan.io/block/9830392){target=\_blank} | | [3401](https://forum.moonbeam.network/t/runtime-rt3400-schedule/1954/6){target=\_blank} | [9661355](https://moonbeam.subscan.io/block/9661355){target=\_blank} | [10269872](https://moonriver.subscan.io/block/10269872){target=\_blank} | [10422450](https://moonbase.subscan.io/block/10422450){target=\_blank} | | [3500](https://forum.moonbeam.network/t/runtime-rt3501-schedule/2010){target=\_blank} | - | - | [10750816](https://moonbase.subscan.io/block/10750816){target=\_blank} | | [3501](https://forum.moonbeam.network/t/runtime-rt3501-schedule/2010){target=\_blank} | [10056989](https://moonbeam.subscan.io/block/10056989){target=\_blank} | [10665393](https://moonriver.subscan.io/block/10665393){target=\_blank} | [10833906](https://moonbase.subscan.io/block/10833906){target=\_blank} | | [3600](https://forum.moonbeam.network/t/runtime-rt3600-schedule/2071){target=\_blank} | [10746745](https://moonbeam.subscan.io/block/10746745){target=\_blank} | [11251274](https://moonriver.subscan.io/block/11251274){target=\_blank} | [11452321](https://moonbase.subscan.io/block/11452321){target=\_blank} | | [3601](https://forum.moonbeam.network/t/proposals-mr77-mb110-whitelisted-authorize-upgrade-to-rt3601-on-moonriver-and-moonbeam/2139){target=\_blank} | [10999397](https://moonbeam.subscan.io/block/10999397){target=\_blank} | [11692212](https://moonriver.subscan.io/block/11692212){target=\_blank} | - | | [3700](https://forum.moonbeam.network/t/runtime-rt3700-schedule/2129){target=\_blank} | - | - | [12152458](https://moonbase.subscan.io/block/12152458){target=\_blank} | | [3701](https://forum.moonbeam.network/t/runtime-rt3700-schedule/2129){target=\_blank} | [11426910](https://moonbeam.subscan.io/block/11426910) | [12003279](https://moonriver.subscan.io/block/12003279){target=\_blank} | [12242104](https://moonbase.subscan.io/block/12242104){target=\_blank} | | [3702](https://forum.moonbeam.network/t/proposals-mr81-mb118-authorize-upgrade-to-rt3702-on-moonriver-and-moonbeam-via-whitelist/2173){target=\_blank} | [11499659](https://moonbeam.subscan.io/block/11499659){target=\_blank} | [12156948](https://moonriver.subscan.io/block/12156948){target=\_blank} | [12683255](https://moonbase.subscan.io/block/12683255){target=\_blank} | | [3800](https://forum.moonbeam.network/t/runtime-rt3800-schedule/2188){target=\_blank} | - | [12540836](https://moonriver.subscan.io/block/12540836){target=\_blank} | [12853655](https://moonbase.subscan.io/block/12853655){target=\_blank} | --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/canonical-contracts/ --- BEGIN CONTENT --- --- title: Canonical Contract Addresses on Moonbeam description: Overview of the canonical contracts available on Moonbeam, Moonriver, & Moonbase Alpha, including common-good contracts and precompiles. keywords: canonical, ethereum, moonbeam, precompiled, contracts categories: Reference, Precompiles, Ethereum Toolkit --- # Canonical Contracts ## Common-good Contracts {: #common-goods-contracts } The following contracts addresses have been established: === "Moonbeam" | Contract | Address | |:------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------:| | [WGLMR](https://moonbeam.moonscan.io/address/0xAcc15dC74880C9944775448304B263D191c6077F#code){target=\_blank} | 0xAcc15dC74880C9944775448304B263D191c6077F | | [Multicall](https://moonbeam.moonscan.io/address/0x83e3b61886770de2F64AAcaD2724ED4f08F7f36B#code){target=\_blank} | 0x83e3b61886770de2F64AAcaD2724ED4f08F7f36B | | [Multicall2](https://moonbeam.moonscan.io/address/0x6477204E12A7236b9619385ea453F370aD897bb2#code){target=\_blank} | 0x6477204E12A7236b9619385ea453F370aD897bb2 | | [Multicall3](https://moonbeam.moonscan.io/address/0xca11bde05977b3631167028862be2a173976ca11#code){target=\_blank} | 0xcA11bde05977b3631167028862bE2a173976CA11 | | [Multisig Factory](https://moonbeam.moonscan.io/address/0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2#code){target=\_blank} | 0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2 | | [EIP-1820](https://eips.ethereum.org/EIPS/eip-1820){target=\_blank} | 0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24 | === "Moonriver" | Contract | Address | |:-------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------:| | [WMOVR](https://moonriver.moonscan.io/token/0x98878b06940ae243284ca214f92bb71a2b032b8a#code){target=\_blank} | 0x98878B06940aE243284CA214f92Bb71a2b032B8A | | [Multicall](https://moonriver.moonscan.io/address/0x30f283Cc0284482e9c29dFB143bd483B5C19954b#code){target=\_blank}* | 0x30f283Cc0284482e9c29dFB143bd483B5C19954b | | [Multicall2](https://moonriver.moonscan.io/address/0xaef00a0cf402d9dedd54092d9ca179be6f9e5ce3#code){target=\_blank} | 0xaef00a0cf402d9dedd54092d9ca179be6f9e5ce3 | | [Multicall3](https://moonriver.moonscan.io/address/0xca11bde05977b3631167028862be2a173976ca11#code){target=\_blank} | 0xcA11bde05977b3631167028862bE2a173976CA11 | | [Multisig Factory](https://moonriver.moonscan.io/address/0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2#code){target=\_blank} | 0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2 | | [EIP-1820](https://eips.ethereum.org/EIPS/eip-1820){target=\_blank} | 0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24 | _*Deployed by SushiSwap_ === "Moonbase Alpha" | Contract | Address | |:------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------:| | [WDEV](https://moonbase.moonscan.io/address/0xD909178CC99d318e4D46e7E66a972955859670E1#code){target=\_blank} | 0xD909178CC99d318e4D46e7E66a972955859670E1 | | [Multicall](https://moonbase.moonscan.io/address/0x4E2cfca20580747AdBA58cd677A998f8B261Fc21#code){target=\_blank}* | 0x4E2cfca20580747AdBA58cd677A998f8B261Fc21 | | [Multicall2](https://moonbase.moonscan.io/address/0x37084d0158C68128d6Bc3E5db537Be996f7B6979#code){target=\_blank} | 0x37084d0158C68128d6Bc3E5db537Be996f7B6979 | | [Multicall3](https://moonbase.moonscan.io/address/0xca11bde05977b3631167028862be2a173976ca11#code){target=\_blank} | 0xcA11bde05977b3631167028862bE2a173976CA11 | | [Multisig Factory](https://moonbase.moonscan.io/address/0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2#code){target=\_blank} | 0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2 | | [EIP-1820](https://eips.ethereum.org/EIPS/eip-1820){target=\_blank} | 0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24 | _*Deployed in the [UniswapV2 Demo Repo](https://github.com/papermoonio/moonbeam-uniswap/tree/main/uniswap-contracts-moonbeam){target=\_blank}_ ## Precompiled Contracts {: #precompiled-contracts } There are a set of precompiled contracts included on Moonbeam, Moonriver, and Moonbase Alpha that are categorized by address and based on the origin network. If you were to convert the precompiled addresses to decimal format, and break them into categories by numeric value, the categories are as follows: - **0-1023** - [Ethereum MainNet precompiles](#ethereum-mainnet-precompiles) - **1024-2047** - precompiles that are [not in Ethereum and not Moonbeam specific](#non-moonbeam-specific-nor-ethereum-precomiles) - **2048-4095** - [Moonbeam specific precompiles](#moonbeam-specific-precompiles) ### Ethereum MainNet Precompiles {: #ethereum-mainnet-precompiles } === "Moonbeam" | Contract | Address | |:---------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------:| | [ECRECOVER](/builders/ethereum/precompiles/utility/eth-mainnet/#verify-signatures-with-ecrecover){target=\_blank} | 0x0000000000000000000000000000000000000001 | | [SHA256](/builders/ethereum/precompiles/utility/eth-mainnet/#hashing-with-sha256){target=\_blank} | 0x0000000000000000000000000000000000000002 | | [RIPEMD160](/builders/ethereum/precompiles/utility/eth-mainnet/#hashing-with-ripemd-160){target=\_blank} | 0x0000000000000000000000000000000000000003 | | [Identity](/builders/ethereum/precompiles/utility/eth-mainnet/#the-identity-function){target=\_blank} | 0x0000000000000000000000000000000000000004 | | [Modular Exponentiation](/builders/ethereum/precompiles/utility/eth-mainnet/#modular-exponentiation){target=\_blank} | 0x0000000000000000000000000000000000000005 | | [BN128Add](/builders/ethereum/precompiles/utility/eth-mainnet/#bn128add){target=\_blank} | 0x0000000000000000000000000000000000000006 | | [BN128Mul](/builders/ethereum/precompiles/utility/eth-mainnet/#bn128mul){target=\_blank} | 0x0000000000000000000000000000000000000007 | | [BN128Pairing](/builders/ethereum/precompiles/utility/eth-mainnet/#bn128pairing){target=\_blank} | 0x0000000000000000000000000000000000000008 | | [Blake2](https://polkadot-evm.github.io/frontier/rustdocs/pallet_evm_precompile_blake2/struct.Blake2F.html){target=\_blank} | 0x0000000000000000000000000000000000000009 | | [P256Verify](https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md){target=\_blank} | 0x0000000000000000000000000000000000000100 | === "Moonriver" | Contract | Address | |:---------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------:| | [ECRECOVER](/builders/ethereum/precompiles/utility/eth-mainnet/#verify-signatures-with-ecrecover){target=\_blank} | 0x0000000000000000000000000000000000000001 | | [SHA256](/builders/ethereum/precompiles/utility/eth-mainnet/#hashing-with-sha256){target=\_blank} | 0x0000000000000000000000000000000000000002 | | [RIPEMD160](/builders/ethereum/precompiles/utility/eth-mainnet/#hashing-with-ripemd-160){target=\_blank} | 0x0000000000000000000000000000000000000003 | | [Identity](/builders/ethereum/precompiles/utility/eth-mainnet/#the-identity-function){target=\_blank} | 0x0000000000000000000000000000000000000004 | | [Modular Exponentiation](/builders/ethereum/precompiles/utility/eth-mainnet/#modular-exponentiation){target=\_blank} | 0x0000000000000000000000000000000000000005 | | [BN128Add](/builders/ethereum/precompiles/utility/eth-mainnet/#bn128add){target=\_blank} | 0x0000000000000000000000000000000000000006 | | [BN128Mul](/builders/ethereum/precompiles/utility/eth-mainnet/#bn128mul){target=\_blank} | 0x0000000000000000000000000000000000000007 | | [BN128Pairing](/builders/ethereum/precompiles/utility/eth-mainnet/#bn128pairing){target=\_blank} | 0x0000000000000000000000000000000000000008 | | [Blake2](https://polkadot-evm.github.io/frontier/rustdocs/pallet_evm_precompile_blake2/struct.Blake2F.html){target=\_blank} | 0x0000000000000000000000000000000000000009 | | [P256Verify](https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md){target=\_blank} | 0x0000000000000000000000000000000000000100 | === "Moonbase Alpha" | Contract | Address | |:---------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------:| | [ECRECOVER](/builders/ethereum/precompiles/utility/eth-mainnet/#verify-signatures-with-ecrecover){target=\_blank} | 0x0000000000000000000000000000000000000001 | | [SHA256](/builders/ethereum/precompiles/utility/eth-mainnet/#hashing-with-sha256){target=\_blank} | 0x0000000000000000000000000000000000000002 | | [RIPEMD160](/builders/ethereum/precompiles/utility/eth-mainnet/#hashing-with-ripemd-160){target=\_blank} | 0x0000000000000000000000000000000000000003 | | [Identity](/builders/ethereum/precompiles/utility/eth-mainnet/#the-identity-function){target=\_blank} | 0x0000000000000000000000000000000000000004 | | [Modular Exponentiation](/builders/ethereum/precompiles/utility/eth-mainnet/#modular-exponentiation){target=\_blank} | 0x0000000000000000000000000000000000000005 | | [BN128Add](/builders/ethereum/precompiles/utility/eth-mainnet/#bn128add){target=\_blank} | 0x0000000000000000000000000000000000000006 | | [BN128Mul](/builders/ethereum/precompiles/utility/eth-mainnet/#bn128mul){target=\_blank} | 0x0000000000000000000000000000000000000007 | | [BN128Pairing](/builders/ethereum/precompiles/utility/eth-mainnet/#bn128pairing){target=\_blank} | 0x0000000000000000000000000000000000000008 | | [Blake2](https://polkadot-evm.github.io/frontier/rustdocs/pallet_evm_precompile_blake2/struct.Blake2F.html){target=\_blank} | 0x0000000000000000000000000000000000000009 | | [P256Verify](https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md){target=\_blank} | 0x0000000000000000000000000000000000000100 | ### Non-Moonbeam Specific nor Ethereum Precompiles {: #non-moonbeam-specific-nor-ethereum-precompiles } === "Moonbeam" | Contract | Address | |:--------------------------------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------:| | [SHA3FIPS256](/builders/ethereum/precompiles/utility/eth-mainnet/#hashing-with-sha3fips256){target=\_blank} | 0x0000000000000000000000000000000000000400 | | Dispatch [Removed] | 0x0000000000000000000000000000000000000401 | | [ECRecoverPublicKey](https://polkadot-evm.github.io/frontier/rustdocs/pallet_evm_precompile_simple/struct.ECRecoverPublicKey.html){target=\_blank} | 0x0000000000000000000000000000000000000402 | === "Moonriver" | Contract | Address | |:--------------------------------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------:| | [SHA3FIPS256](/builders/ethereum/precompiles/utility/eth-mainnet/#hashing-with-sha3fips256){target=\_blank} | 0x0000000000000000000000000000000000000400 | | Dispatch [Removed] | 0x0000000000000000000000000000000000000401 | | [ECRecoverPublicKey](https://polkadot-evm.github.io/frontier/rustdocs/pallet_evm_precompile_simple/struct.ECRecoverPublicKey.html){target=\_blank} | 0x0000000000000000000000000000000000000402 | === "Moonbase Alpha" | Contract | Address | |:-------------------------------------------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------:| | [SHA3FIPS256](/builders/ethereum/precompiles/utility/eth-mainnet/#hashing-with-sha3fips256){target=\_blank} | 0x0000000000000000000000000000000000000400 | | Dispatch [Removed] | 0x0000000000000000000000000000000000000401 | | [ECRecoverPublicKey](https://polkadot-evm.github.io/frontier/rustdocs/pallet_evm_precompile_simple/struct.ECRecoverPublicKey.html){target=\_blank} | 0x0000000000000000000000000000000000000402 | ### Moonbeam-Specific Precompiles {: #moonbeam-specific-precompiles } === "Moonbeam" | Contract | Address | |:-------------------------------------------------------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------:| | [Parachain Staking](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/parachain-staking/StakingInterface.sol){target=\_blank} | {{networks.moonbeam.precompiles.staking}} | | [Crowdloan Rewards](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/crowdloan-rewards/CrowdloanInterface.sol){target=\_blank} | {{networks.moonbeam.precompiles.crowdloan}} | | [ERC-20 Interface](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/balances-erc20/ERC20.sol){target=\_blank} | {{networks.moonbeam.precompiles.erc20}} | | Democracy [Removed] | {{networks.moonbeam.precompiles.democracy}} | | [X-Tokens](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xtokens/Xtokens.sol){target=\_blank} | {{networks.moonbeam.precompiles.xtokens}} | | [Relay Encoder](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/relay-encoder/RelayEncoder.sol){target=\_blank} | {{networks.moonbeam.precompiles.relay_encoder}} | | [XCM Transactor V1](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-transactor/src/v1/XcmTransactorV1.sol){target=\_blank} | {{networks.moonbeam.precompiles.xcm_transactor_v1}} | | [Author Mapping](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/author-mapping/AuthorMappingInterface.sol){target=\_blank} | {{networks.moonbeam.precompiles.author_mapping}} | | [Batch](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/batch/Batch.sol){target=\_blank} | {{networks.moonbeam.precompiles.batch}} | | [Randomness](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/randomness/Randomness.sol){target=\_blank} | {{networks.moonbeam.precompiles.randomness}} | | [Call Permit](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/call-permit/CallPermit.sol){target=\_blank} | {{networks.moonbeam.precompiles.call_permit}} | | [Proxy](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/proxy/Proxy.sol){target=\_blank} | {{networks.moonbeam.precompiles.proxy}} | | [XCM Utilities](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-utils/XcmUtils.sol){target=\_blank} | {{networks.moonbeam.precompiles.xcm_utils}} | | [XCM Transactor V2](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-transactor/src/v2/XcmTransactorV2.sol){target=\_blank} | {{networks.moonbeam.precompiles.xcm_transactor_v2}} | | [Council Collective [Removed]](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonbeam.precompiles.collective_council}} | | [Technical Committee Collective [Removed]](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonbeam.precompiles.collective_tech_committee}} | | [Treasury Council Collective](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonbeam.precompiles.collective_treasury}} | | [Referenda](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/referenda/Referenda.sol){target=\_blank} | {{networks.moonbeam.precompiles.referenda}} | | [Conviction Voting](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/conviction-voting/ConvictionVoting.sol){target=\_blank} | {{networks.moonbeam.precompiles.conviction_voting}} | | [Preimage](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/preimage/Preimage.sol){target=\_blank} | {{networks.moonbeam.precompiles.preimage}} | | [OpenGov Tech Committee](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonbeam.precompiles.collective_opengov_tech_committee}} | | [Precompile Registry](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/precompile-registry/PrecompileRegistry.sol){target=\_blank} | {{networks.moonbeam.precompiles.registry}} | | [GMP](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/gmp/Gmp.sol){target=\_blank} | {{networks.moonbeam.precompiles.gmp}} | | [XCM Transactor V3](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-transactor/src/v3/XcmTransactorV3.sol){target=\_blank} | {{networks.moonbeam.precompiles.xcm_transactor_v3}} | | [Identity](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/identity/Identity.sol){target=\_blank} | {{networks.moonbeam.precompiles.identity}} | | [XCM Interface](https://github.com/Moonsong-Labs/moonkit/blob/main/precompiles/pallet-xcm/XcmInterface.sol){target=\_blank} | {{networks.moonbeam.precompiles.xcm_interface}} | === "Moonriver" | Contract | Address | |:-------------------------------------------------------------------------------------------------------------------------------------------------------------:|:--------------------------------------------------------------------:| | [Parachain Staking](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/parachain-staking/StakingInterface.sol){target=\_blank} | {{networks.moonriver.precompiles.staking}} | | [Crowdloan Rewards](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/crowdloan-rewards/CrowdloanInterface.sol){target=\_blank} | {{networks.moonriver.precompiles.crowdloan}} | | [ERC-20 Interface](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/balances-erc20/ERC20.sol){target=\_blank} | {{networks.moonriver.precompiles.erc20}} | | Democracy [Removed] | {{networks.moonriver.precompiles.democracy}} | | [X-Tokens](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xtokens/Xtokens.sol){target=\_blank} | {{networks.moonriver.precompiles.xtokens}} | | [Relay Encoder](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/relay-encoder/RelayEncoder.sol){target=\_blank} | {{networks.moonriver.precompiles.relay_encoder}} | | [XCM Transactor V1](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-transactor/src/v1/XcmTransactorV1.sol){target=\_blank} | {{networks.moonriver.precompiles.xcm_transactor_v1}} | | [Author Mapping](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/author-mapping/AuthorMappingInterface.sol){target=\_blank} | {{networks.moonriver.precompiles.author_mapping}} | | [Batch](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/batch/Batch.sol){target=\_blank} | {{networks.moonriver.precompiles.batch}} | | [Randomness](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/randomness/Randomness.sol){target=\_blank} | {{networks.moonriver.precompiles.randomness}} | | [Call Permit](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/call-permit/CallPermit.sol){target=\_blank} | {{networks.moonriver.precompiles.call_permit}} | | [Proxy](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/proxy/Proxy.sol){target=\_blank} | {{networks.moonriver.precompiles.proxy}} | | [XCM Utilities](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-utils/XcmUtils.sol){target=\_blank} | {{networks.moonriver.precompiles.xcm_utils}} | | [XCM Transactor V2](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-transactor/src/v2/XcmTransactorV2.sol){target=\_blank} | {{networks.moonriver.precompiles.xcm_transactor_v2}} | | [Council Collective [Removed]](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonriver.precompiles.collective_council}} | | [Technical Committee Collective [Removed]](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonriver.precompiles.collective_tech_committee}} | | [Treasury Council Collective](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonriver.precompiles.collective_treasury}} | | [Referenda](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/referenda/Referenda.sol){target=\_blank} | {{networks.moonriver.precompiles.referenda}} | | [Conviction Voting](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/conviction-voting/ConvictionVoting.sol){target=\_blank} | {{networks.moonriver.precompiles.conviction_voting}} | | [Preimage](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/preimage/Preimage.sol){target=\_blank} | {{networks.moonriver.precompiles.preimage}} | | [OpenGov Tech Committee](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonriver.precompiles.collective_opengov_tech_committee}} | | [Precompile Registry](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/precompile-registry/PrecompileRegistry.sol){target=\_blank} | {{networks.moonriver.precompiles.registry}} | | [GMP](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/gmp/Gmp.sol){target=\_blank} | {{networks.moonriver.precompiles.gmp}} | | [XCM Transactor V3](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-transactor/src/v3/XcmTransactorV3.sol){target=\_blank} | {{networks.moonriver.precompiles.xcm_transactor_v3}} | | [Identity](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/identity/Identity.sol){target=\_blank} | {{networks.moonriver.precompiles.identity}} | | [XCM Interface](https://github.com/Moonsong-Labs/moonkit/blob/main/precompiles/pallet-xcm/XcmInterface.sol){target=\_blank} | {{networks.moonriver.precompiles.xcm_interface}} | === "Moonbase Alpha" | Contract | Address | |:-------------------------------------------------------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------:| | [Parachain Staking](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/parachain-staking/StakingInterface.sol){target=\_blank} | {{networks.moonbase.precompiles.staking}} | | [Crowdloan Rewards](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/crowdloan-rewards/CrowdloanInterface.sol){target=\_blank} | {{networks.moonbase.precompiles.crowdloan}} | | [ERC-20 Interface](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/balances-erc20/ERC20.sol){target=\_blank} | {{networks.moonbase.precompiles.erc20}} | | Democracy [Removed] | {{networks.moonbase.precompiles.democracy}} | | [X-Tokens](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xtokens/Xtokens.sol){target=\_blank} | {{networks.moonbase.precompiles.xtokens}} | | [Relay Encoder](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/relay-encoder/RelayEncoder.sol){target=\_blank} | {{networks.moonbase.precompiles.relay_encoder}} | | [XCM Transactor V1](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-transactor/src/v1/XcmTransactorV1.sol){target=\_blank} | {{networks.moonbase.precompiles.xcm_transactor_v1}} | | [Author Mapping](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/author-mapping/AuthorMappingInterface.sol){target=\_blank} | {{networks.moonbase.precompiles.author_mapping}} | | [Batch](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/batch/Batch.sol){target=\_blank} | {{networks.moonbase.precompiles.batch}} | | [Randomness](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/randomness/Randomness.sol){target=\_blank} | {{networks.moonbase.precompiles.randomness}} | | [Call Permit](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/call-permit/CallPermit.sol){target=\_blank} | {{networks.moonbase.precompiles.call_permit}} | | [Proxy](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/proxy/Proxy.sol){target=\_blank} | {{networks.moonbase.precompiles.proxy}} | | [XCM Utilities](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-utils/XcmUtils.sol){target=\_blank} | {{networks.moonbase.precompiles.xcm_utils}} | | [XCM Transactor V2](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-transactor/src/v2/XcmTransactorV2.sol){target=\_blank} | {{networks.moonbase.precompiles.xcm_transactor_v2}} | | [Council Collective [Removed]](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonbase.precompiles.collective_council}} | | [Technical Committee Collective [Removed]](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonbase.precompiles.collective_tech_committee}} | | [Treasury Council Collective](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonbase.precompiles.collective_treasury}} | | [Referenda](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/referenda/Referenda.sol){target=\_blank} | {{networks.moonbase.precompiles.referenda}} | | [Conviction Voting](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/conviction-voting/ConvictionVoting.sol){target=\_blank} | {{networks.moonbase.precompiles.conviction_voting}} | | [Preimage](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/preimage/Preimage.sol){target=\_blank} | {{networks.moonbase.precompiles.preimage}} | | [OpenGov Tech Committee](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonbase.precompiles.collective_opengov_tech_committee}} | | [Precompile Registry](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/precompile-registry/PrecompileRegistry.sol){target=\_blank} | {{networks.moonbase.precompiles.registry}} | | [GMP](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/gmp/Gmp.sol){target=\_blank} | {{networks.moonbase.precompiles.gmp}} | | [XCM Transactor V3](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-transactor/src/v3/XcmTransactorV3.sol){target=\_blank} | {{networks.moonbase.precompiles.xcm_transactor_v3}} | | [Identity](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/identity/Identity.sol){target=\_blank} | {{networks.moonbase.precompiles.identity}} | | [XCM Interface](https://github.com/Moonsong-Labs/moonkit/blob/main/precompiles/pallet-xcm/XcmInterface.sol){target=\_blank} | {{networks.moonbase.precompiles.xcm_interface}} | --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/dev-env/ape/ --- BEGIN CONTENT --- --- title: Deploy Contracts with Ape description: Use Ape, a Python framework, to compile, deploy, and debug smart contracts using Python on Moonbeam, thanks to its Ethereum compatibility. categories: Dev Environments, Ethereum Toolkit --- # Using Ape to Deploy To Moonbeam ## Introduction {: #introduction } [Ape](https://docs.apeworx.io/ape/stable){target=\_blank} is an Ethereum development environment that helps Python developers manage and automate the recurring tasks inherent to building smart contracts and DApps. Ape can directly interact with Moonbeam's Ethereum API, so you can also use Ape to deploy smart contracts on Moonbeam. This guide will walk you through using Ape to compile, deploy, and interact with Ethereum smart contracts on the Moonbase Alpha TestNet. You can adapt this guide for Moonbeam, Moonriver, or a Moonbeam development node. ## Checking Prerequisites {: #checking-prerequisites } To get started, ensure you have the following: - MetaMask installed and [connected to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank} - An account with funds. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} - To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank} ## Creating an Ape Project {: #creating-an-ape-project } If you don't already have an Ape project, you must install Ape and create a new one. You can follow the steps below to get started and create an empty project: 1. Create a directory for your project ```bash mkdir ape && cd ape ``` 2. If you don't have `pipx` installed, install it ```bash python3 -m pip install --user pipx python3 -m pipx ensurepath ``` 3. [Install Ape using `pipx`](https://ape.readthedocs.io/en/stable/install.html){target=\_blank} ```bash pipx install eth-ape ``` 4. Create a project ```bash ape init ``` 5. Enter a name for your project
ape init Please enter project name: ape-demo
SUCCESS: ape-demo is written in ape-config.yaml
ls ape-config.yaml contracts scripts tests
Your Ape project contains a bare-bones `ape-config.yaml` file for customizing specific settings and the following empty directories: - `contracts` - an empty directory for storing smart contracts - `scripts` - an empty directory for storing Python scripts, such as deployment scripts and scripts to interact with your deployed contracts - `tests` - an empty directory for pytest testing scripts ## Configure Accounts {: #configure-accounts } You'll need to import an account before you can deploy smart contracts or interact with previously deployed contracts from your Ape project. You can run the following command, which will import your account and give it a name: ```bash ape accounts import INSERT_ACCOUNT_NAME ``` You'll then be prompted to enter your private key and add a password to encrypt your account.
ape accounts import alice Enter Private Key: Create Passphrase to encrypt account: Repeat for confirmation: SUCCESS: A new account '0x097D9Eea23DE2D3081169e0225173d0C55768338' has been added with the id 'alice'
!!! note If you wish to use a mnemonic instead, you can append the `--use-mnemonic` option to the import command. ## Create Smart Contracts {: #the-contract-file } Now that you have set up your account, you can start writing smart contracts. As a basic example, you can use the following `Box` contract to store a value you can retrieve later. Start by creating a file named `Box.sol` inside the contracts directory: ```bash touch contracts/Box.sol ``` Open the file and add the following contract to it: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.1; contract Box { uint256 private value; event ValueChanged(uint256 newValue); function store(uint256 newValue) public { value = newValue; emit ValueChanged(newValue); } function retrieve() public view returns (uint256) { return value; } } ``` You can store any additional contracts in the `contracts` directory. ## Compile the Solidity Contract {: #compiling-solidity } Before compiling the Solidity, you must install the Solidity compiler plugin. Running the following command will install the latest version of the plugin: ```bash ape plugins install solidity ``` To use a specific version of Solidity or a specific EVM version, you can modify your `ape-config.yaml` file as follows: ```yaml solidity: version: INSERT_VERSION evm_version: INSERT_VERSION ``` For more information on the Solidity plugin, please refer to the [README of the `ape-solidity` repository on GitHub](https://github.com/ApeWorX/ape-solidity/blob/main/README.md){target=_blank}. With the Solidity plugin installed, the next step is to compile the smart contract: ```bash ape compile ```
ape compile INFO: Compiling 'Box.sol'. INFO: Compiling using Solidity compiler '0.8.23+commit.f704f362'.
After compilation, you can find the bytecode and ABI for your contracts in the `.build` directory. ## Test the Contract {: #test-the-contract } Before you deploy your contract, you can test it out directly inside your Ape project using the [pytest framework](https://docs.pytest.org/en/latest){target=\_blank} to make sure it works as you expect. You should already have a `tests` directory where you'll create your tests, but if not, please create one, as all tests must be located in a directory named `tests`. Additionally, each test file name must start with `test_` and end with `.py`. So, first, you can create a test file for the `Box.sol` contract: ```bash touch tests/test_box.py ``` In addition to the test file, you can create a `conftest.py` file that will define a couple of essential [fixtures](https://docs.pytest.org/en/stable/explanation/fixtures.html){target=\_blank}. Fixtures allow you to define functions that set up the necessary environment or resources to run your tests. Note that while the `Box.sol` contract is simple, incorporating fixtures into your testing process is good practice. To create the file, you can run the following command: ```bash touch tests/conftest.py ``` Since your tests will rely on the injection of the fixtures, you must define the fixtures first. When defining fixtures, you need to apply the `pytest.fixture` decorator above each function. For this example, you'll create two fixtures: one that defines the owner of the contract and one that deploys the contract from the owner's account. The `owner` fixture will use the built-in `accounts` fixture to take the first account in the list of test accounts provided by Ape and return it. The `box` fixture will deploy the `Box` contract type using the built-in `project` fixture, you simply have to provide the name of the contract and use the `owner` fixture to deploy it. ```python title="tests/conftest.py" import pytest @pytest.fixture def owner(accounts): return accounts[0] @pytest.fixture def box(owner, project): return owner.deploy(project.Box) ``` Now that you've created the fixtures, you can start creating your tests. Each test function name must start with `test_` and describe what the test does. For this example, you can use `test_store_value`, as you'll create a test for the `store` function. The test will store a value and then retrieve it, asserting that the retrieved value is equal to the value passed into the `store` function. To use the `owner` and `box` fixtures, you must pass them into your test function, which will inject the fixtures automatically for you to use. The `owner` account will be used to call the `store` function of the `box` contract instance. ```py title="tests/test_box.py" def test_store_value(box, owner): new_value = 5 box.store(new_value, sender=owner) assert box.retrieve() == new_value ``` And that's it! That's all you'll need inside your test file. You can use the following command to run the test: ```bash ape test ``` The results of running the test will be printed to the terminal.
ape test ===================== test session starts ====================== platform darwin -- Python 3.10.4, pytest-7.2.1, pluggy-1.4.0 rootdir: /Users/moonbeam/ape plugins: eth-ape-0.7.7, web3-6.15.1 collected 1 item
tests/test_box.py . [100%]
====================== 1 passed in 0.70s =======================
Now that you have confidence in your contract, the next step is to deploy it. ## Deploy the Contract {: #deploy-the-contract } To deploy your contracts, create a deployment script named `deploy.py` inside of the `scripts` directory: ```bash touch scripts/deploy.py ``` Next, you'll need to write the deployment script. You'll need to load the account you will use to deploy the contract and access it by its name using the project manager. ```python title="scripts/deploy.py" from ape import project, accounts def main(): # Load your account by its name account = accounts.load("alice") # Deploy the contract using your account return account.deploy(project.Box) ``` Now you're ready to deploy the `Box` contract! To configure your project for Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. Take the following steps to initiate and send the deployment transaction. Note that there are some nuances associated with [using Ape with a local Moonbeam node](#using-ape-with-a-local-node). 1. Run the deployment script using the `ape run deploy` command === "Moonbeam" ```bash ape run deploy --network moonbeam:mainnet ``` === "Moonriver" ```bash ape run deploy --network moonbeam:moonriver ``` === "Moonbase Alpha" ```bash ape run deploy --network moonbeam:moonbase ``` === "Moonbeam Dev Node" ```bash ape run deploy --network ethereum:local_moonbeam:http://127.0.0.1:9944 ``` !!! note For the `ape run deploy` command to work as intended, the deployment script must be named `deploy.py` and stored in the `scripts` directory, and the script must define a `main()` method. 2. Review the transaction details and enter **y** to sign the transaction 3. Enter your passphrase for your account 4. Enter **y** to leave your account unlocked or **n** to lock it After you follow the prompts and submit the transaction, the transaction hash, total fees paid, and contract address will be displayed in the terminal.
ape run deploy --network https://rpc.api.moonbase.moonbeam.network INFO: Connecting to a 'moonbase' node.
DynamicFeeTransaction: chainId: 1287 from: 0x097D9Eea23DE2D3081169e0225173d0C55768338 gas: 123964 nonce: 372 value: 0 data: 0x307836...303333 type: 2 maxFeePerGas: 125000000 maxPriorityFeePerGas: 0 accessList: []
Sign: [y/N]: y Enter passphrase to unlock 'alice' []: Leave 'alice' unlocked? [y/N]: n INFO: Confirmed 0x365cd903e7fac5ad1f815d7a6f211b1aa32bd7d78630c2e81d67514cfb9e55bb (total fees paid = 15326250000000) SUCCESS: Contract 'Box' deployed to: 0x68039277300E8B104dDf848029dCA04C2EFe8610
Congratulations! Your contract is live! Save the address to interact with your contract in the following section. ## Interact with the Contract {: #interact-with-the-contract } You can interact with contracts using the Ape console for quick debugging and testing, or write a script. ### Using The Ape Console {: #using-ape-console } To interact with your newly deployed contract, you can launch the Ape console by running: === "Moonbeam" ```bash ape console --network moonbeam:mainnet ``` === "Moonriver" ```bash ape console --network moonbeam:moonriver ``` === "Moonbase Alpha" ```bash ape console --network moonbeam:moonbase ``` === "Moonbeam Dev Node" ```bash ape console --network ethereum:local_moonbeam:http://127.0.0.1:9944 ``` Next, you'll need to create a contract instance using the contract's address: ```bash box = Contract("INSERT_CONTRACT_ADDRESS") ```
ape console --network https://rpc.api.moonbase.moonbeam.network INFO: Connecting to a 'moonbase' node.
alice = accounts.load("alice") box = Contract("0x68039277300E8B104dDf848029dCA04C2EFe8610")
Now, you can interact with your contract instance! For example, you can set the variable to be stored in the `Box` contract using the following commands: 1. Call the `store` method by passing in a value to store and the account you want to use to send the transaction: ```bash box.store(5, sender=alice) ``` 2. Review the transaction details and enter **y** to sign the transaction 3. If you previously locked your account, you must enter your passphrase to unlock it. Otherwise, Ape will use the cached key for your account 4. If you unlocked your account in the previous step, you'll be asked if you want to leave your account unlocked. You can enter **y** to leave it unlocked or **n** to lock it After you follow the prompts and submit the transaction, the transaction hash and total fees paid will be displayed in the terminal.
box.store(4, sender=alice) DynamicFeeTransaction: chainId: 1287 to: 0x68039277300E8B104dDf848029dCA04C2EFe8610 from: 0x097D9Eea23DE2D3081169e0225173d0C55768338 gas: 45668 nonce: 373 value: 0 data: 0x307836...303034 type: 2 maxFeePerGas: 125000000 maxPriorityFeePerGas: 0 accessList: []
Sign: [y/N]: y Enter passphrase to unlock 'alice' []: Leave 'alice' unlocked? [y/N]: n INFO: Confirmed 0xd2e8305f22f33c1ab8ccaaef94252a93ff0f69c9bf98503fc2744bf257f1ef67 (total fees paid = 5573750000000) Receipt 0xd2e8305f22f33c1ab8ccaaef94252a93ff0f69c9bf98503fc2744bf257f1ef67
Then, you can retrieve the stored value by calling the `retrieve` method: ```bash box.retrieve() ``` The number you just stored in the previous steps will be printed to the console.
contract.retrieve() 5
### Using a Script {: #using-a-script } You can also write a script to interact with your newly deployed contract. To get started, you can create a new file in the `scripts` directory: ```bash touch scripts/store-and-retrieve.py ``` Next, you can write a script that stores and retrieves a value. Note that when creating a contract instance to interact with, you must pass in the address of the deployed contract. ```python title="scripts/store-and-retrieve.py" from ape import Contract, accounts def main(): account = accounts.load("alice") box = Contract("INSERT_CONTRACT_ADDRESS") store = box.store(4, sender=account) print("Transaction hash for updating the stored value:", store.txn_hash) retrieve = box.retrieve() print("Stored value:", retrieve) ``` Now, you can run the script to set the stored value and retrieve it: 1. Run the script === "Moonbeam" ```bash ape run store-and-retrieve --network moonbeam:mainnet ``` === "Moonriver" ```bash ape run store-and-retrieve --network moonbeam:moonriver ``` === "Moonbase Alpha" ```bash ape run store-and-retrieve --network moonbeam:moonbase ``` === "Moonbeam Dev Node" ```bash ape run store-and-retrieve --network ethereum:local_moonbeam:http://127.0.0.1:9944 ``` 2. Review the transaction details and enter **y** to sign the transaction 3. If you previously locked your account, you must enter your passphrase to unlock it. Otherwise, Ape will use the cached key for your account 4. If you unlocked your account in the previous step, you'll be asked if you want to leave your account unlocked. You can enter **y** to leave it unlocked or **n** to lock it Once completed, you should see a transaction hash and a value of `5` printed to the console.
ape run store-and-retrieve --network https://rpc.api.moonbase.moonbeam.network DynamicFeeTransaction: chainId: 1287 to: 0x68039277300E8B104dDf848029dCA04C2EFe8610 from: 0x097D9Eea23DE2D3081169e0225173d0C55768338 gas: 25974 nonce: 374 value: 0 data: 0x307836...303035 type: 2 maxFeePerGas: 125000000 maxPriorityFeePerGas: 0 accessList: []
Sign: [y/N]: y Enter passphrase to unlock 'alice' []: Leave 'alice' unlocked? [y/N]: n INFO: Confirmed 0x6d74e48c23fd48438bf48baad34e235693c737bd880ef0077c0fb996f3896f5f (total fees paid = 3086250000000) Transaction hash for updating the stored value: 0x6d74e48c23fd48438bf48baad34e235693c737bd880ef0077c0fb996f3896f5f Stored value: 5
Congratulations! You have successfully deployed and interacted with a contract using Ape! ## Using Ape with a Local Node {: #using-ape-with-a-local-node } There are some nuances associated with using Ape with a local Moonbeam node. As a Moonbeam local node is not included as a preset network with Ape, you'll need to customize your `ape-config.yaml` before using Ape with a local Moonbeam node. Adjust your `ape-config.yaml` as follows: ```bash # ape-config.yaml name: ape-demo default_ecosystem: ethereum ethereum: default_network: local_moonbeam local_moonbeam: default_transaction_type: 0 gas_limit: "auto" block_time: 6 transaction_acceptance_timeout: 60 max_receipt_retries: 10 networks: custom: - name: local_moonbeam chain_id: 1281 ecosystem: ethereum base_ecosystem_plugin: ethereum default_provider: node node: ethereum: local_moonbeam: uri: http://127.0.0.1:9944 ``` After configuring your `ape-config.yaml`, you can target your local Moonbeam node by appending the following network configuration flag to your Ape command: ```bash --network ethereum:local_moonbeam:http://127.0.0.1:9944 ``` Additionally, when deploying or interacting with contracts on a local Moonbeam node using Ape, the CLI will, by default, wait for two block confirmations before allowing you to proceed. However, because a local Moonbeam node employs instant sealing, only producing blocks when new transactions occur, this can lead to a stalemate situation that may lead you to think something is wrong. To circumvent this, you can run your local Moonbeam node with a sealing flag to produce blocks at a set interval, such as every `6` seconds, with the command: `--sealing 6000`. Alternatively, you can submit dummy transactions to your local Moonbeam node to force new blocks to be authored.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/dev-env/foundry/ --- BEGIN CONTENT --- --- title: Deploy Contracts with Foundry description: Learn how to use Foundry, an Ethereum development environment, to compile, deploy, and debug Solidity smart contracts on Moonbeam. categories: Dev Environments, Ethereum Toolkit --- # Using Foundry to Deploy To Moonbeam ## Introduction {: #introduction } [Foundry](https://github.com/foundry-rs/foundry){target=\_blank} is an Ethereum development environment written in Rust that helps developers manage dependencies, compile projects, run tests, deploy contracts, and interact with blockchains from the command line. Foundry can directly interact with Moonbeam's Ethereum API so it can be used to deploy smart contracts into Moonbeam. Four tools make up Foundry: - **[Forge](https://getfoundry.sh/forge/overview/){target=\_blank}** - compiles, tests, and deploys contracts - **[Cast](https://getfoundry.sh/cast/overview/){target=\_blank}** - a command line interface for interacting with contracts - **[Anvil](https://getfoundry.sh/anvil/overview/){target=\_blank}** - a local TestNet node for development purposes that can fork preexisting networks - **[Chisel](https://getfoundry.sh/chisel/overview/){target=\_blank}** - a Solidity REPL for quickly testing Solidity snippets This guide will cover how to use Foundry to compile, deploy, and debug Ethereum smart contracts on the Moonbase Alpha TestNet. This guide can also be adapted for Moonbeam, Moonriver, or a Moonbeam development node. ## Checking Prerequisites {: #checking-prerequisites } To get started, you will need the following: - Have an account with funds. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} - To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank} - Have [Foundry installed](https://getfoundry.sh/introduction/installation/){target=\_blank} ## Creating a Foundry Project {: #creating-a-foundry-project } You will need to create a Foundry project if you don't already have one. You can create one by completing the following steps: 1. Install Foundry if you haven't already. If on Linux or MacOS, you can run these commands: ```bash curl -L https://foundry.paradigm.xyz | bash foundryup ``` If on Windows, you'll have to install Rust and then build Foundry from source: ```bash curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs/ | sh cargo install --git https://github.com/foundry-rs/foundry foundry-cli anvil --bins --locked ``` 2. Create the project, which will create a folder with three folders within it, and open it: ```bash forge init foundry && cd foundry ``` With the default project created, you should see three folders. - `lib` - all of the project's dependencies in the form of git submodules - `src` - where to put your smart contracts (with functionality) - `test` - where to put the forge tests for your project, which are written in Solidity In addition to these three folders, a git project will also be created along with a prewritten `.gitignore` file with relevant file types and folders ignored. ## The Source Folder {: #the-src-folder } The `src` folder may already contain `Counter.sol`, a minimal Solidity contract. Feel free to delete it. To avoid errors, you should also delete the `Counter.s.sol` file in the `scripts` folder and the `Counter.t.sol` file in the `test` folder. In the following steps, you will be deploying an ERC-20 contract. In the contracts directory, you can create the `MyToken.sol` file: ```bash cd src touch MyToken.sol ``` Open the file and add the following contract to it: ```solidity pragma solidity ^0.8.0; // Import OpenZeppelin Contract import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; // This ERC-20 contract mints the specified amount of tokens to the contract creator contract MyToken is ERC20 { constructor(uint256 initialSupply) ERC20("MyToken", "MYTOK") { _mint(msg.sender, initialSupply); } } ``` Before you attempt to compile, install OpenZeppelin contracts as a dependency. You may have to commit previous changes to git beforehand. By default, Foundry uses git submodules instead of npm packages, so the traditional npm import path and command are not used. Instead, use the name of OpenZeppelin's GitHub repository: ```bash forge install OpenZeppelin/openzeppelin-contracts ``` ## Compiling Solidity {: #compiling-solidity } Once all dependencies have been installed, you can compile the contract: ```bash forge build ```
forge build [⠒] Compiling... [⠰] Compiling 30 files with 0.8.23 [⠔] Solc 0.8.23 finished in 2.29s Compiler run successful!
After compilation, two folders will be created: `out` and `cache`. The ABI and bytecode for your contracts will be contained within the `out` folder. These two folders are already ignored by the `.gitignore` included in the default Foundry project initialization. ## Deploying the Contract {: #deploying-the-contract } There are two primary ways to deploy contracts using Foundry. The first is the straightforward command `forge create`. There's also the more flexible and powerful option of foundry scripting, which runs simulations before any deployments. In the following sections, `forge create` and foundry scripting will both be covered. ### Using Forge Create {: #using-forge-create } Before deploying, you'll need to set up your keystore by importing your private key. You can do this using the `cast wallet import` command as follows: ```bash cast wallet import deployer --interactive ``` This will prompt you to: 1. Enter your private key 2. Enter a password to encrypt the keystore The account will be saved as "deployer" in your keystore. You can then use this account name in the deployment commands. You'll be prompted for your keystore password when deploying contracts or sending transactions. Deploying the contract with `forge create` takes a single command, but you must include an RPC endpoint and constructor arguments. `MyToken.sol` asks for an initial supply of tokens in its constructor, so each of the following commands includes 100 as a constructor argument. You can deploy the `MyToken.sol` contract using the following command for the correct network: === "Moonbeam" ```bash forge create src/MyToken.sol:MyToken \ --rpc-url {{ networks.moonbeam.rpc_url }} \ --account deployer \ --constructor-args 100 ``` === "Moonriver" ```bash forge create src/MyToken.sol:MyToken \ --rpc-url {{ networks.moonriver.rpc_url }} \ --account deployer \ --constructor-args 100 ``` === "Moonbase Alpha" ```bash forge create src/MyToken.sol:MyToken \ --rpc-url {{ networks.moonbase.rpc_url }} \ --account deployer \ --constructor-args 100 ``` === "Moonbeam Dev Node" ```bash forge create src/MyToken.sol:MyToken \ --rpc-url {{ networks.development.rpc_url }} \ --account deployer \ --constructor-args 100 ``` After you've deployed the contract and a few seconds have passed, you should see the address in the terminal.
forge create src/MyToken.sol:MyToken \ --rpc-url https://rpc.api.moonbase.moonbeam.network \ --account deployer \ --constructor-args 100
[⠒] Compiling... No files changed, compilation skipped Deployer: 0x3B939FeaD1557C741Ff06492FD0127bd287A421e Deployed to: 0xc111402Aa1136ff6224106709ae51864512eC68f Transaction hash: 0xd77fc26aa296e81f35718b5878cda98e8371f6bf33b0f57e7d92997a36cf6465
Congratulations! Your contract is live! Save the address, as you will use it to interact with this contract instance in the next step. ### Deploying via Solidity Scripting {: #deploying-via-solidity-scripting } Solidity scripting is a more powerful and flexible way to deploy contracts than [`forge create`](#deploying-the-contract). Writing a Solidity script is identical to writing a typical Solidity smart contract, though you won't ever deploy this contract. You can tailor the behavior of `forge script` with various parameters. All components are optional except for local simulation, which is a required part of every run. The `forge script` command will attempt to execute all applicable steps in the following order: 1. **Local simulation** - simulate the transaction(s) in a local EVM 2. **Onchain simulation** - simulate the transaction(s) via the provided RPC URL 3. **Broadcasting** - when the `--broadcast` flag is provided, and simulations succeed, the transaction(s) are dispatched 4. **Verification** - API-based smart contract verification when the `--verify` flag and a valid API key are provided Now, go ahead and write the script. In the script folder, create a file named `MyToken.s.sol`. Copy and paste the contents of the below file. ```solidity // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; import "forge-std/Script.sol"; import "../src/MyToken.sol"; contract MyScript is Script { function run() external { vm.startBroadcast(); MyToken mytoken = new MyToken(1000000000); vm.stopBroadcast(); } } ``` Notice that even though the above script is not being deployed, it still requires all the typical formatting for a Solidity contract, such as the pragma statement. For this example, Foundry will first attempt a local simulation and a simulation against the provided RPC before deploying the contract. Remember that it will execute all relevant steps in order. Foundry won't proceed with the deployment if any of the simulations fail. You can deploy the `MyToken.sol` contract with this command. ```bash forge script script/MyToken.s.sol --rpc-url {{ networks.moonbase.rpc_url }} --broadcast --account deployer ``` If your script's execution succeeds, your terminal should resemble the output below.
forge script script/MyToken.s.sol --rpc-url https://rpc.api.moonbase.moonbeam.network --broadcast --account deployer --sender 0x3b939fead1557c741ff06492fd0127bd287a421e [⠒] Compiling... No files changed, compilation skipped EIP-3855 is not supported in one or more of the RPCs used. Unsupported Chain IDs: 1287. Contracts deployed with a Solidity version equal or higher than 0.8.20 might not work properly. For more information, please see https://eips.ethereum.org/EIPS/eip-3855 Script ran successfully. ## Setting up 1 EVM. ==========================
Chain 1287 Estimated gas price: 0.0625 gwei Estimated total gas used for script: 1196500 Estimated amount required: 0.00007478125 ETH ==========================
Enter keystore password: ## Sending transactions [0 - 0]. ⠁ [00:00:00] [########################################################################################################] 1/1 txes (0.0s)## Waiting for receipts. ⠉ [00:00:07] [#########################################################################################################################] 1/1 receipts (0.0s) ##### moonbase
✅ [Success]Hash: 0xb70942942d731486872e7faba8a800e86809f44c2c3bd3f6306373562712e9d3 Contract Address: 0x98c3fC51d3487c1689e39ee63Ba110cfD8e1F552 Block: 11847291 Paid: 0.000027472875 ETH (879132 gas * 0.03125 gwei) ========================== ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. Total Paid: 0.000027472875 ETH (879132 gas * avg 0.03125 gwei) Transactions saved to: /Users/ubuntu-jammy/foundry/foundry/broadcast/MyToken.s.sol/1287/run-latest.json Sensitive values saved to: /Users/ubuntu-jammy/foundry/foundry/cache/MyToken.s.sol/1287/run-latest.json
And that's it! For more information about Solidity scripting with Foundry, be sure to check out [Foundry's documentation site](https://getfoundry.sh/guides/scripting-with-solidity/){target=\_blank}. ## Interacting with the Contract {: #interacting-with-the-contract } Foundry includes cast, a CLI for performing Ethereum RPC calls. Try to retrieve your token's name using Cast, where `INSERT_YOUR_CONTRACT_ADDRESS` is the address of the contract that you deployed in the previous section: === "Moonbeam" ```bash cast call INSERT_YOUR_CONTRACT_ADDRESS "name()" --rpc-url {{ networks.moonbeam.rpc_url }} ``` === "Moonriver" ```bash cast call INSERT_YOUR_CONTRACT_ADDRESS "name()" --rpc-url {{ networks.moonriver.rpc_url }} ``` === "Moonbase Alpha" ```bash cast call INSERT_YOUR_CONTRACT_ADDRESS "name()" --rpc-url {{ networks.moonbase.rpc_url }} ``` === "Moonbeam Dev Node" ```bash cast call INSERT_YOUR_CONTRACT_ADDRESS "name()" --rpc-url {{ networks.development.rpc_url }} ``` You should get this data in hexadecimal format: ```text 0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000074d79546f6b656e00000000000000000000000000000000000000000000000000 ``` This is far from readable, but you can use Cast to convert it into your desired format. In this case, the data is text, so you can convert it into ASCII characters to see "My Token":
cast --to-ascii 0x000000000000000000000000000000000000000000000000000000000000002000 000000000000000000000000000000000000000000000000000000000000074d7954 6f6b656e00000000000000000000000000000000000000000000000000
MyToken
```bash cast --to-ascii 0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000074d79546f6b656e00000000000000000000000000000000000000000000000000 ``` You can also mutate data with cast as well. Try burning tokens by sending them to the zero address. === "Moonbeam" ```bash cast send --private-key INSERT_YOUR_PRIVATE_KEY \ --rpc-url {{ networks.moonbeam.rpc_url }} \ --chain {{ networks.moonbeam.chain_id }} \ INSERT_YOUR_CONTRACT_ADDRESS \ "transfer(address,uint256)" 0x0000000000000000000000000000000000000001 1 ``` === "Moonriver" ```bash cast send --private-key INSERT_YOUR_PRIVATE_KEY \ --rpc-url {{ networks.moonriver.rpc_url }} \ --chain {{ networks.moonriver.chain_id }} \ INSERT_YOUR_CONTRACT_ADDRESS \ "transfer(address,uint256)" 0x0000000000000000000000000000000000000001 1 ``` === "Moonbase Alpha" ```bash cast send --private-key INSERT_YOUR_PRIVATE_KEY \ --rpc-url {{ networks.moonbase.rpc_url }} \ --chain {{ networks.moonbase.chain_id }} \ INSERT_YOUR_CONTRACT_ADDRESS \ "transfer(address,uint256)" 0x0000000000000000000000000000000000000001 1 ``` === "Moonbeam Dev Node" ```bash cast send --private-key INSERT_YOUR_PRIVATE_KEY \ --rpc-url {{ networks.development.rpc_url }} \ --chain {{ networks.development.chain_id }} \ INSERT_YOUR_CONTRACT_ADDRESS \ "transfer(address,uint256)" 0x0000000000000000000000000000000000000001 1 ``` The transaction will be signed by your Moonbase account and be broadcast to the network. The output should look similar to:
cast send --private-key INSERT_PRIVATE_KEY \ --rpc-url https://rpc.api.moonbase.moonbeam.network \ --chain 1287 \ INSERT_CONTRACT_ADDRESS \ "transfer(address,uint256)" 0x0000000000000000000000000000000000000001 1

blockHash 0x6f99fac1bb49feccb7b0476e0ffcd3cef4c456aa9111e193ce11c7a1ab62314e blockNumber 5892860 contractAddress cumulativeGasUsed 51332 effectiveGasPrice 3125000000 gasUsed 51332 logs [{"address":"0xc111402aa1136ff6224106709ae51864512ec68f","topics":["0xddf252ad1be2c89b69 c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x0000000000000000000000003b939fead155 7c741ff06492fd0127bd287a421e", "0x0000000000000000000000000000000000000000000000000000000000000001"], "data":"0x0000000000000000000000000000000000000 000000000000000000000000001", "blockHash":"0x6f99fac1bb49feccb7b0476e0ffcd3cef4c4 56aa9111e193ce11c7a1ab62314e", "blockNumber":"0x59eafc", "transactionHash":"0xdd5f11be68d5 2967356ccf34b9a4b2632d0d5ac8932ff27e72c544320dec33e3", "transactionIndex":"0x0","logIndex":"0x0","transactionLogIndex":"0x0","removed":false}] logsBloom 0x000000000000000000000000000000000000000000000000000000000000000000000000000000004 00000000000000000000000000000000000000000040000000000000000000000000008000000000000 00000004000000000000000000000000000000000000000100000000000000000000000000000000001 00000010000000000000000000000000000000000000000000000000000000002000000040000000000 00000000000000000000000000000000000000000000000000000000002000000000000000000000000 00000000000000000000000000004000000000000000000000000000000000000000000000000000000 0001000000 root status 1 transactionHash 0xdd5f11be68d52967356ccf34b9a4b2632d0d5ac8932ff27e72c544320dec33e3 transactionIndex 0 type 2
Congratulations, you have successfully deployed and interacted with a contract using Foundry! ## Forking with Anvil {: #forking-with-cast-anvil } As previously mentioned, [Anvil](https://getfoundry.sh/anvil/overview/#anvil){target=\_blank} is a local TestNet node for development purposes that can fork preexisting networks. Forking Moonbeam allows you to interact with live contracts deployed on the network. There are some limitations to be aware of when forking with Anvil. Since Anvil is based on an EVM implementation, you cannot interact with any of the Moonbeam precompiled contracts and their functions. Precompiles are a part of the Substrate implementation and therefore cannot be replicated in the simulated EVM environment. This prohibits you from interacting with cross-chain assets on Moonbeam and Substrate-based functionality such as staking and governance. To fork Moonbeam or Moonriver, you will need to have your own endpoint and API key which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. To fork Moonbeam from the command line, you can run the following command from within your Foundry project directory: === "Moonbeam" ```bash anvil --fork-url {{ networks.moonbeam.rpc_url }} ``` === "Moonriver" ```bash anvil --fork-url {{ networks.moonriver.rpc_url }} ``` === "Moonbase Alpha" ```bash anvil --fork-url {{ networks.moonbase.rpc_url }} ``` Your forked instance will have 10 development accounts that are pre-funded with 10,000 test tokens. The forked instance is available at `http://127.0.0.1:8545/`. The output in your terminal should resemble the following:
anvil --fork-url https://rpc.api.moonbase.moonbeam.network

Available Accounts ================== (0) "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" (10000.000000000000000000 ETH) (1) "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" (10000.000000000000000000 ETH) (2) "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" (10000.000000000000000000 ETH) (3) "0x90F79bf6EB2c4f870365E785982E1f101E93b906" (10000.000000000000000000 ETH) (4) "0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65" (10000.000000000000000000 ETH) (5) "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc" (10000.000000000000000000 ETH) (6) "0x976EA74026E726554dB657fA54763abd0C3a0aa9" (10000.000000000000000000 ETH) (7) "0x14dC79964da2C08b23698B3D3cc7Ca32193d9955" (10000.000000000000000000 ETH) (8) "0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f" (10000.000000000000000000 ETH) (9) "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720" (10000.000000000000000000 ETH)
Private Keys ================== (0) 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 (1) 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d (2) 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a (3) 0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6 (4) 0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a (5) 0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba (6) 0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e (7) 0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356 (8) 0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97 (9) 0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6
Wallet ================== Mnemonic: test test test test test test test test test test test junk Derivation path: m/44'/60'/0'/0/
Fork ================== Endpoint: https://rpc.api.moonbase.moonbeam.network Block number: 5892944 Block hash: 0xc9579299f55d507c305d5357d4c1b9d9c550788ddb471b0231d8d0146e7144b7 Chain ID: 1287
Base Fee ================== 125000000
Gas Limit ================== 30000000
Genesis Timestamp ================== 1705278817
Listening on 127.0.0.1:8545
To verify you have forked the network, you can query the latest block number: ```bash curl --data '{"method":"eth_blockNumber","params":[],"id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST localhost:8545 ``` If you convert the `result` from [hex to decimal](https://www.rapidtables.com/convert/number/hex-to-decimal.html){target=\_blank}, you should get the latest block number from the time you forked the network. You can cross reference the block number using a [block explorer](/builders/get-started/explorers/){target=\_blank}. From here you can deploy new contracts to your forked instance of Moonbeam or interact with contracts already deployed. Building off of the previous example in this guide, you can make a call using Cast to check the balance of the minted MYTOK tokens in the account you deployed the contract with: ```bash cast call INSERT_CONTRACT_ADDRESS "balanceOf(address)(uint256)" INSERT_YOUR_ADDRESS --rpc-url http://localhost:8545 ``` ## Using Chisel {: #using-chisel } Chisel is a Solidity REPL or shell. It allows a developer to write Solidity directly in the console for testing small snippets of code, letting developers skip the project setup and contract deployment steps for what should be a quick process. Since Chisel is mainly useful for quick testing, it can be used outside of a Foundry project. But, if executed within a Foundry project, it will keep the configurations within `foundry.toml` when running. For this example, you will be testing out some of the features of `abi` within Solidity because it is complex enough to demonstrate how Chisel could be useful. To get started using Chisel, run the following in the command line to start the shell: ```bash chisel ``` In the shell, you can write Solidity code as if it were running within a function: ```solidity bytes memory myData = abi.encode(100, true, "Develop on Moonbeam"); ``` Let's say you were interested in how `abi` encoded data because you're looking into how to most efficiently store data on the blockchain and thus save gas. To view how the `myData` is stored in memory, you can use the following command while in the Chisel shell: ```bash !memdump ``` `memdump` will dump all of the data in your current session. You'll likely see something like this below. If you aren't good at reading hexadecimal or if you don't know how ABI encoding works, then you might not be able to find where the `myData` variable has been stored.
chisel
Welcome to Chisel! Type `!help` to show available commands. bytes memory myData = abi.encode(100, true, "Develop on Moonbeam");
!memdump [0x00:0x20]: 0x0000000000000000000000000000000000000000000000000000000000000000 [0x20:0x40]: 0x0000000000000000000000000000000000000000000000000000000000000000 [0x40:0x60]: 0x0000000000000000000000000000000000000000000000000000000000000140 [0x60:0x80]: 0x0000000000000000000000000000000000000000000000000000000000000000 [0x80:0xa0]: 0x00000000000000000000000000000000000000000000000000000000000000a0 [0xa0:0xc0]: 0x0000000000000000000000000000000000000000000000000000000000000064 [0xc0:0xe0]: 0x0000000000000000000000000000000000000000000000000000000000000001 [0xe0:0x100]: 0x0000000000000000000000000000000000000000000000000000000000000060 [0x100:0x120]: 0x0000000000000000000000000000000000000000000000000000000000000013 [0x120:0x140]: 0x446576656c6f70206f6e204d6f6f6e6265616d00000000000000000000000000
Fortunately, Chisel lets you easily figure out where this information is stored. Using the `!rawstack` command, you can find the location in the stack where the value of a variable: ```bash !rawstack myData ``` In this situation, since bytes is over 32 bytes in length, the memory pointer is displayed instead. But that's exactly what's needed since you already know the entirety of the stack from the `!memdump` command.
chisel
Welcome to Chisel! Type `!help` to show available commands. bytes memory myData = abi.encode(100, true, "Develop on Moonbeam");
!memdump [0x00:0x20]: 0x0000000000000000000000000000000000000000000000000000000000000000 [0x20:0x40]: 0x0000000000000000000000000000000000000000000000000000000000000000 [0x40:0x60]: 0x0000000000000000000000000000000000000000000000000000000000000140 [0x60:0x80]: 0x0000000000000000000000000000000000000000000000000000000000000000 [0x80:0xa0]: 0x00000000000000000000000000000000000000000000000000000000000000a0 [0xa0:0xc0]: 0x0000000000000000000000000000000000000000000000000000000000000064 [0xc0:0xe0]: 0x0000000000000000000000000000000000000000000000000000000000000001 [0xe0:0x100]: 0x0000000000000000000000000000000000000000000000000000000000000060 [0x100:0x120]: 0x0000000000000000000000000000000000000000000000000000000000000013 [0x120:0x140]: 0x446576656c6f70206f6e204d6f6f6e6265616d00000000000000000000000000 !rawstack myData
Type: bytes32 └ Data: 0x0000000000000000000000000000000000000000000000000000000000000080
The `!rawstack` command shows that the `myData` variable is stored at `0x80`, so when comparing this with the memory dump retrieved from the `!memdump` command, it looks like `myData` is stored like this: ```text [0x80:0xa0]: 0x00000000000000000000000000000000000000000000000000000000000000a0 [0xa0:0xc0]: 0x0000000000000000000000000000000000000000000000000000000000000064 [0xc0:0xe0]: 0x0000000000000000000000000000000000000000000000000000000000000001 [0xe0:0x100]: 0x0000000000000000000000000000000000000000000000000000000000000060 [0x100:0x120]: 0x0000000000000000000000000000000000000000000000000000000000000013 [0x120:0x140]: 0x446576656c6f70206f6e204d6f6f6e6265616d00000000000000000000000000 ``` At first glance, this makes sense, since `0xa0` has a value of `0x64` which is equal to 100, and `0xc0` has a value of `0x01` which is equal to true. If you want to learn more about how ABI-encoding works, the [Solidity documentation for ABI is helpful](https://docs.soliditylang.org/en/v0.8.18/abi-spec.html){target=\_blank}. In this case, there are a lot of zeros in this method of data packing, so as a smart contract developer you might instead try to use structs or pack the data together more efficiently with bitwise code. Since you're done with this code, you can clear the state of Chisel so that it doesn't mess with any future logic that you want to try out (while running the same instance of Chisel): ```bash !clear ``` There's an even easier way to test with Chisel. When writing code that ends with a semicolon (`;`), Chisel will run it as a statement, storing its value in Chisel's runtime state. But if you only needed to see how the ABI-encoded data was represented, then you could get away with running the code as an expression. To try this out with the same `abi` example, write the following in the Chisel shell: ```bash abi.encode(100, true, "Develop on Moonbeam") ``` You should see something like the following:
!clear Cleared session! abi.encode(100, true, "Develop on Moonbeam") Type: dynamic bytes ├ Hex (Memory): ├─ Length ([0x00:0x20]): 0x00000000000000000000000000000000000000000000000000000000000000a0 ├─ Contents ([0x20:..]): 0x0000000000000000000000000000000000000000000000000000000000000064 0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000060 0000000000000000000000000000000000000000000000000000000000000001 34446576656c6f70206f6e204d6f6f6e6265616d00000000000000000000000000 ├ Hex (Tuple Encoded): ├─ Pointer ([0x00:0x20]): 0x0000000000000000000000000000000000000000000000000000000000000020 ├─ Length ([0x20:0x40]): 0x00000000000000000000000000000000000000000000000000000000000000a0 └─ Contents ([0x40:..]): 0x0000000000000000000000000000000000000000000000000000000000000064 0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000060 0000000000000000000000000000000000000000000000000000000000000001 34446576656c6f70206f6e204d6f6f6e6265616d00000000000000000000000000
While it doesn't display the data in the same way, you still get the contents of the data, and it also further breaks down how the information is coded, such as letting you know that the `0xa0` value defines the length of the data. By default, when you leave the Chisel shell, none of the data is persisted. But you can instruct chisel to do so. For example, you can take the following steps to store a variable: 1. Store a `uint256` in Chisel ```bash uint256 myNumber = 101; ``` 2. Store the session with `!save`. For this example, you can use the number `1` as a save ID ```bash !save 1 ``` 3. Quit the session ```bash !quit ``` Then to view and interact with your stored Chisel states, you can take the following steps: 1. View a list of saved Chisel states ```bash chisel list ``` 2. Load your stored states ```bash chisel load 1 ``` 3. View the `uint256` saved in Chisel from the previous set of steps ```bash !rawstack myNumber ```
uint256 myNumber = 101; !save 1 Saved session to cache with ID = 1 !quit chisel list ⚒️ Chisel Sessions ├─ "2024-01-15 01:17:34" - chisel-1.json chisel load 1 Welcome to Chisel! Type `!help` to show available commands. !rawstack myNumber Type: bytes32 └ Data: 0x0000000000000000000000000000000000000000000000000000000000000065
You can even fork networks while using Chisel: ```bash !fork {{ networks.moonbase.rpc_url }} ``` Then, for example, you can query the balance of one of Moonbase Alpha's collators: ```text {{ networks.moonbase.staking.candidates.address1 }}.balance ```
!fork https://rpc.api.moonbase.moonbeam.network Set fork URL to https://rpc.api.moonbase.moonbeam.network 0x12E7BCCA9b1B15f33585b5fc898B967149BDb9a5.balance Type: uint ├ Hex: 0x000000000000000000000000000000000000000000000358affd3d76ebb78555 └ Decimal: 15803094286802091476309
If you want to learn more about Chisel, download Foundry and refer to its [official reference page](https://getfoundry.sh/chisel/reference/){target=\_blank}. ## Foundry With Hardhat {: #foundry-with-hardhat } Often, there will be the case where a project that you wish to integrate with has all of its setup within [Hardhat](/builders/ethereum/dev-env/hardhat/){target=\_blank}, making it an arduous task to convert the entirety of the project into Foundry. This additional work is avoidable by creating a hybrid project that uses both Hardhat and Foundry features together. This is possible with Hardhat's [hardhat-foundry plugin](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-foundry){target=\_blank}. To convert your preexisting Foundry project to a hybrid project, you will essentially have to install a Hardhat project into the same folder: ```bash npm init npm install --save-dev hardhat @nomicfoundation/hardhat-foundry npx hardhat init ``` For more information, please refer to our documentation on [Creating a Hardhat Project](/builders/ethereum/dev-env/hardhat/#creating-a-hardhat-project){target=\_blank}. After initializing the new Hardhat project, a few new folders and files should appear: `contracts`, `hardhat.config.js`, `scripts`, and `test/Lock.js`. You'll need to make a few modifications to create a hybrid project: 1. Edit the `hardhat.config.js` file within your repository. Open it up, and at the top, add the following: ```javascript require("@nomicfoundation/hardhat-foundry"); ``` After adding the `hardhat-foundry` plugin, the typical `contracts` folders for Hardhat will not work because now Hardhat expects all smart contracts to be stored within Foundry's `src` folder 2. Move all smart contracts within the `contracts` folder into the `src` folder, and then delete the `contracts` folder 3. Edit the `foundry.toml` file to ensure that dependencies installed via Git submodules and npm can be compiled by the Forge tool. Edit the `profile.default` to ensure that the `libs` entry has both `lib` and `node_modules`: ```toml [profile.default] src = 'src' out = 'out' libs = ['lib', 'node_modules'] solc = '0.8.20' evm_version = 'london' ``` Now both `forge build` and `npx hardhat compile` should work regardless of the dependencies. Both `forge test` and `npx hardhat test` should now be able to access all smart contracts and dependencies. `forge test` will only test the Solidity tests, whereas `npx hardhat test` will only test the JavaScript tests. If you would like to use them in conjunction, then you can create a new script within your `package.json` file: ```json "scripts": { "test": "npx hardhat test && forge test" } ``` You can run this command with: ```bash npm run test ``` Finally, while not necessary, it could be worthwhile to move all JavaScript scripts from the `scripts` folder into Foundry's `script` folder and delete the `scripts` folder so that you don't have two folders that serve the same purpose.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/dev-env/hardhat/ --- BEGIN CONTENT --- --- title: Deploy Contracts with Hardhat description: Learn how to use Hardhat, an Ethereum development environment, to compile, deploy, and debug Solidity smart contracts on Moonbeam. categories: Dev Environments, Ethereum Toolkit --- # Using Hardhat to Deploy To Moonbeam ## Introduction {: #introduction } [Hardhat](https://hardhat.org){target=\_blank} is a flexible and extensible Ethereum development environment that streamlines the smart contract development process. Since Moonbeam is Ethereum-compatible, you can use Hardhat to develop and deploy smart contracts on Moonbeam. Hardhat takes a task-based approach to development, where you can define and execute [tasks](https://hardhat.org/hardhat-runner/docs/advanced/create-task){target=\_blank} that perform specific actions. These actions include compiling and deploying contracts, running tests, and more. Tasks are highly configurable, so you can create, customize, and execute tasks that are tailored to meet your needs. You can also extend Hardhat's functionality through the use of [plugins](https://hardhat.org/hardhat-runner/plugins){target=\_blank}. Plugins are external extensions that integrate with Hardhat to provide additional features and tools for your workflow. For example, there are plugins for common Ethereum libraries, like [Ethers.js](/builders/ethereum/libraries/ethersjs/){target=\_blank} and [viem](/builders/ethereum/libraries/viem/){target=\_blank}, a plugin that extends the Chai assertion library to include Ethereum-specific functionality, and more. All of these plugins can be used to extend your Hardhat project on Moonbeam. This guide will provide a brief introduction to Hardhat and show you how to use Hardhat to compile, deploy, and debug Ethereum smart contracts on the Moonbase Alpha TestNet. This guide can also be adapted for Moonbeam, Moonriver, or a Moonbeam development node. Please note that although Hardhat comes with a [Hardhat Network](https://hardhat.org/docs#hardhat-network){target=\_blank} component, which provides a local development environment, you should use a [local Moonbeam development node](/builders/get-started/networks/moonbeam-dev/){target=\_blank} instead. You can connect a Moonbeam development node to Hardhat just like you would with any other network. ## Checking Prerequisites {: #checking-prerequisites } To get started, you will need the following: - Have [MetaMask installed](/tokens/connect/metamask/#install-the-metamask-extension){target=\_blank} and [connected to Moonbase Alpha](/tokens/connect/metamask/#connect-metamask-to-moonbeam){target=\_blank} - Have an account with funds. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} - To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank} ## Create a Hardhat Project {: #creating-a-hardhat-project } You will need to create a Hardhat project if you don't already have one. You can create one by completing the following steps: 1. Create a directory for your project ```sh mkdir hardhat && cd hardhat ``` 2. Initialize the project, which will create a `package.json` file ```sh npm init -y ``` 3. Install Hardhat ```sh npm install hardhat@3.0.0-next.5 ``` 4. Create a Hardhat project ```sh npx hardhat --init ``` !!! note `npx` is used to run executables installed locally in your project. Although Hardhat can be installed globally, installing it locally in each project is recommended so you can control the version on a project-by-project basis. 5. You'll be prompted with a series of questions to set up your project: - Choose where to initialize the project (default is current directory) - Confirm converting to ESM (required for Hardhat v3) - Select the type of project to initialize: - A TypeScript Hardhat project using Node Test Runner and Viem - A TypeScript Hardhat project using Mocha and Ethers.js For this example, you can choose either option based on your preference. If you choose the Mocha and Ethers.js option, you'll get a project structure with: - A sample contract in `contracts/Counter.sol` - A test file in `test/Counter.ts` - TypeScript configuration - Mocha and Ethers.js dependencies The project will be set up with all necessary dependencies and configurations for you to start developing.
npx hardhat init 888    888                      888 888               888 888    888                      888 888               888 888    888                      888 888               888 8888888888  8888b.  888d888 .d88888 88888b.   8888b.  888888 888    888     "88b 888P"  d88" 888 888 "88b     "88b 888 888    888 .d888888 888    888  888 888  888 .d888888 888 888    888 888  888 888    Y88b 888 888  888 888  888 Y88b. 888    888 "Y888888 888     "Y88888 888  888 "Y888888  "Y888
👷 Welcome to Hardhat v3.0.0-next.5 👷‍
 Where would you like to initialize the project?  .  Hardhat only supports ESM projects. Would you like to change "package.json" to turn your project into ESM? (Y/n) · true  What type of project would you like to initialize? …   A TypeScript Hardhat project using Node Test Runner and Viem  A TypeScript Hardhat project using Mocha and Ethers.js
## Hardhat Configuration File {: #hardhat-configuration-file } The Hardhat configuration file is the entry point into your Hardhat project. It defines various settings and options for your Hardhat project, such as the Solidity compiler version to use and the networks you can deploy your contracts to. To start, your `hardhat.config.js` should resemble the following: ```js /** @type import('hardhat/config').HardhatUserConfig */ module.exports = { solidity: '0.8.28', }; ``` For this example, you can leave the Solidity compiler version to `0.8.28`; however, if you are using a different contract that requires a newer version, don't forget to update the version here. Next, you'll need to modify your configuration file to add the network configurations for the network you want to deploy your contract to. For Moonbeam networks, you'll need to specify the following: - `url` - the [RPC endpoint](/builders/get-started/endpoints/){target=\_blank} of the node - `chainId` - the chain ID, which is used to validate the network - `accounts` - the accounts that can be used to deploy and interact with contracts. You can either enter an array of the private keys for your accounts or use an [HD Wallet](https://github.com/ethereumbook/ethereumbook/blob/develop/05wallets.asciidoc#hierarchical-deterministic-wallets-bip-32bip-44){target=\_blank} Hardhat 3 includes an encrypted secrets manager that makes it easier to handle sensitive information like private keys. This ensures you don't have to hardcode secrets in your source code or store them in plain text. !!! note The encrypted secrets manager is only available in Hardhat 3 or higher. As of writing this guide, Hardhat 3 is in alpha. You can install the latest alpha version with: ```bash npm install hardhat@3.0.0-next.5 ``` For the latest releases and updates, check the [Hardhat releases page](https://github.com/NomicFoundation/hardhat/releases/). To use encrypted secrets, you'll need to: 1. Install Hardhat 3 or later: ```bash npm install hardhat@3.0.0-next.5 ``` 2. Set up your secrets using the keystore: === "Moonbeam" ```bash npx hardhat keystore set MOONBEAM_RPC_URL npx hardhat keystore set MOONBEAM_PRIVATE_KEY ``` === "Moonriver" ```bash npx hardhat keystore set MOONRIVER_RPC_URL npx hardhat keystore set MOONRIVER_PRIVATE_KEY ``` === "Moonbase Alpha" ```bash npx hardhat keystore set MOONBASE_RPC_URL npx hardhat keystore set MOONBASE_PRIVATE_KEY ``` === "Moonbeam Dev Node" ```bash npx hardhat keystore set DEV_RPC_URL npx hardhat keystore set DEV_PRIVATE_KEY ``` Then, update your configuration file to use the encrypted secrets: === "Moonbeam" ```js module.exports = { solidity: '0.8.28', networks: { moonbeam: { type: "http", chainType: "generic", url: configVariable("MOONBEAM_RPC_URL"), chainId: {{ networks.moonbeam.chain_id }}, // (hex: {{ networks.moonbeam.hex_chain_id }}), accounts: [configVariable("MOONBEAM_PRIVATE_KEY")], }, }, }; ``` === "Moonriver" ```js module.exports = { solidity: '0.8.28', networks: { moonriver: { type: "http", chainType: "generic", url: configVariable("MOONRIVER_RPC_URL"), chainId: {{ networks.moonriver.chain_id }}, // (hex: {{ networks.moonriver.hex_chain_id }}), accounts: [configVariable("MOONRIVER_PRIVATE_KEY")], }, }, }; ``` === "Moonbase Alpha" ```js module.exports = { solidity: '0.8.28', networks: { moonbase: { type: "http", chainType: "generic", url: configVariable("MOONBASE_RPC_URL"), chainId: {{ networks.moonbase.chain_id }}, // (hex: {{ networks.moonbase.hex_chain_id }}), accounts: [configVariable("MOONBASE_PRIVATE_KEY")], }, }, }; ``` === "Moonbeam Dev Node" ```js module.exports = { solidity: '0.8.28', networks: { dev: { type: "http", chainType: "generic", url: configVariable("DEV_RPC_URL"), chainId: {{ networks.development.chain_id }}, // (hex: {{ networks.development.hex_chain_id }}), accounts: [configVariable("DEV_PRIVATE_KEY")], }, }, }; ``` When you run tasks that require these secrets, Hardhat will prompt you for the password to decrypt them. The secrets are only decrypted when needed, meaning you only need to enter the password if a Hardhat task uses a secret. If you are planning on using any plugins with your project, you'll need to install the plugin and import it into the `hardhat.config.js` file. Once a plugin has been imported, it becomes part of the [Hardhat Runtime Environment](https://hardhat.org/hardhat-runner/docs/advanced/hardhat-runtime-environment){target=\_blank}, and you can leverage the plugin's functionality within tasks, scripts, and more. For this example, you can install the `hardhat-ethers` plugin and import it into the configuration file. This plugin provides a convenient way to use the [Ethers.js](/builders/ethereum/libraries/ethersjs/){target=\_blank} library to interact with the network. ```bash npm install @nomicfoundation/hardhat-ethers ethers ``` Additionally, you'll need to install the `hardhat-ignition-ethers` plugin to enable deployment of smart contracts with Hardhat Ignition. You can install it with the following command: ```sh npm install --save-dev @nomicfoundation/hardhat-ignition-ethers ``` To import both plugins, add the following `require` statements to the top of the Hardhat configuration file: ```js hl_lines="2 3" /** @type import('hardhat/config').HardhatUserConfig */ require('@nomicfoundation/hardhat-ethers'); require('@nomicfoundation/hardhat-ignition-ethers'); module.exports = { solidity: '0.8.28', networks: { moonbase: { url: configVariable("MOONBASE_RPC_URL"), chainId: 1287, // 0x507 in hex, accounts: [configVariable("MOONBASE_PRIVATE_KEY")] } } }; ``` For more information on the available configuration options, please refer to Hardhat's documentation on [Configuration](https://hardhat.org/hardhat-runner/docs/config#networks-configuration){target=\_blank}. ## The Contract File {: #the-contract-file } Now that you've configured your project, you can begin the development process by creating your smart contract. The contract will be a simple one that will let you store a value that can be retrieved later, called `Box`. To add the contract, you'll take the following steps: 1. Change into the `contracts` directory ```sh cd contracts ``` 2. Create a `Box.sol` file ```sh touch Box.sol ``` 3. Open the file and add the following contract to it: ```solidity // contracts/Box.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.1; contract Box { uint256 private value; // Emitted when the stored value changes event ValueChanged(uint256 newValue); // Stores a new value in the contract function store(uint256 newValue) public { value = newValue; emit ValueChanged(newValue); } // Reads the last stored value function retrieve() public view returns (uint256) { return value; } } ``` ## Compile the Contract {: #compiling-solidity } The next step is to compile the `Box.sol` smart contract. For this, you can use the built-in `compile` task, which will look for Solidity files in the `contracts` directory and compile them using the version and compiler settings defined in the `hardhat.config.js` file. To use the `compile` task, all you have to do is run: ```sh npx hardhat compile ```
npx hardhat compile Compiled 1 Solidity files successfully (evm target: paris). ls -l artifacts cache contracts hardhat.config.js node_modules package.json package-lock.json
After compilation, an `artifacts` directory is created that holds the bytecode and metadata of the contract, which are `.json` files. It's a good idea to add this directory to a `.gitignore` file. If you make changes to the contract after you've compiled it, you can compile it again using the same command. Hardhat will look for any changes and recompile the contract. If no changes are found, nothing will be compiled. If needed, you can force a compilation using the `clean` task, which will clear the cache and delete the old artifacts. ## Deploy the Contract {: #deploying-the-contract } To deploy the contract, you'll use Hardhat Ignition, a declarative framework for deploying smart contracts. Hardhat Ignition is designed to make it easy to manage recurring tasks surrounding smart contract deployment and testing. For more information, be sure to check out the [Hardhat Ignition docs](https://hardhat.org/ignition/docs/getting-started#overview){target=\_blank}. To set up the proper file structure for your Ignition module, create a folder named `ignition` and a subdirectory called `modules`. Then add a new file to it called `Box.js`. You can take all three of these steps with the following command: ```sh cd ignition/modules && touch Box.js ``` Next, you can write your Hardhat Ignition module. To get started, take the following steps: 1. Import the `buildModule` function from the Hardhat Ignition module 2. Export a module using `buildModule` 3. Use the `getAccount` method to select the deployer account 4. Deploy the `Box` contract 5. Return an object from the module. This makes the `Box` contract accessible for interaction in Hardhat tests and scripts ```js // 1. Import the `buildModule` function from the Hardhat Ignition module import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; // 2. Export a module using `buildModule` // Use `export default` instead of `module.exports` export default buildModule("BoxModule", (m) => { // 3. Use the `getAccount` method to select the deployer account const deployer = m.getAccount(0); // 4. Deploy the `Box` contract const box = m.contract("Box", [], { from: deployer, }); // 5. Return an object from the module return { box }; }); ``` To run the script and deploy the `Box.sol` contract, use the following command, which requires you to specify the network name as defined in your `hardhat.config.js`. If you don't specify a network, hardhat will deploy the contract to a local Hardhat network by default. ```sh npx hardhat ignition deploy ./Box.js --network moonbase ``` !!! note If you're using another Moonbeam network, make sure that you specify the correct network. The network name needs to match the one defined in the `hardhat.config.js` file. You'll be prompted to enter your password for the Hardhat secrets manager. Next, you'll be prompted to confirm the network you wish to deploy to. A few seconds after you confirm, the contract is deployed, and you'll see the contract address in the terminal.
npx hardhat ignition deploy ./Box.js --network moonbase
✅ Confirm deploy to network moonbase (1287)? … yes Hardhat Ignition 🚀
Deploying [ BoxModule ]
Batch #1 Executed BoxModule#Box
[ BoxModule ] successfully deployed 🚀
Deployed Addresses
BoxModule#Box - 0xfBD78CE8C9E1169851119754C4Ea2f70AB159289
Congratulations, your contract is live! Save the address, as you will use it to interact with this contract instance in the next step. ## Interact with the Contract {: #interacting-with-the-contract } There are a couple of ways that you can interact with your newly deployed contract using Hardhat: you can use the `console` task, which spins up an interactive JavaScript console, or you can create another script and use the `run` task to execute it. ### Using the Hardhat Console {: #hardhat-console } The [Hardhat console](https://hardhat.org/hardhat-runner/docs/guides/hardhat-console){target=\_blank} uses the same execution environment as the tasks and scripts, so it automatically uses the configurations and plugins defined in the `hardhat.config.js`. To launch the Hardhat `console`, you can run: ```sh npx hardhat console --network moonbase ``` Next, you can take the following steps, entering one line at a time: 1. Create a local instance of the `Box.sol` contract ```js const Box = await ethers.getContractFactory('Box'); ``` 2. Connect the local instance to the deployed contract, using the address of the contract shown in the prior step under **Deployed Addresses** ```js const box = await Box.attach('INSERT-CONTRACT-ADDRESS'); ``` 3. Interact with the attached contract. For this example, you can call the `store` method and store a simple value ```js await box.store(5); ``` The transaction will be signed by your account configured in the `hardhat.config.js` file and broadcasted to the network. The output should look similar to:
npx hardhat console --network moonbase
Welcome to Node.js v20.9.0. Type ".help" for more information. const Box = await ethers.getContractFactory('Box'); undefined
const box = await Box.attach('0xfBD78CE8C9E1169851119754C4Ea2f70AB159289'); undefined
await box.store(5); ContractTransactionResponse {
provider: HardhatEthersProvider { ... },
blockNumber: null,
blockHash: null,
index: undefined,
hash: '0x1c49a64a601fc5dd184f0a368a91130cb49203ec0f533c6fcf20445c68e20264',
type: 2,
to: '0xa84caB60db6541573a091e5C622fB79e175E17be',
from: '0x3B939FeaD1557C741Ff06492FD0127bd287A421e',
nonce: 87,
gasLimit: 45881n,
gasPrice: 1107421875n,
maxPriorityFeePerGas: 1n,
maxFeePerGas: 1107421875n,
data: '0x6057361d0000000000000000000000000000000000000000000000000000000000000005',
value: 0n,
chainId: 5678n,
signature: Signature { r: "0x9233b9cc4ae6879b7e08b9f1a4bfb175c8216eee0099966eca4a305c7f369ecc", s: "0x7663688633006b5a449d02cb08311569fadf2f9696bd7fe65417860a3b5fc57d", yParity: 0, networkV: null },
accessList: [],
blobVersionedHashes: null
}
await box.retrieve(); 5n
Notice your address labeled `from`, the address of the contract, and the `data` that is being passed. Now, you can retrieve the value by running: ```js await box.retrieve(); ``` You should see `5`, or the value you initially stored. ### Using a Script {: #using-a-script } Similarly to the deployment script, you can create a script to interact with your deployed contract, store it in the `scripts` directory, and run it using the built-in `run` task. To get started, create a `set-value.js` file in the `scripts` directory: ```sh cd scripts && touch set-value.js ``` Now paste the following contract into the `set-value.js` file: ```js // scripts/set-value.js async function main() { // Create instance of the Box contract const Box = await ethers.getContractFactory('Box'); // Connect the instance to the deployed contract const box = await Box.attach('INSERT-CONTRACT-ADDRESS'); // Store a new value await box.store(2); // Retrieve the value const value = await box.retrieve(); console.log(`The new value is: ${value}`); } main() .then(() => process.exit(0)) .catch(error => { console.error(error); process.exit(1); }); ``` To run the script, you can use the following command: ```sh npx hardhat run --network moonbase set-value.js ``` The script should return `2` as the value.
npx hardhat run --network moonbase scripts/set-value.js
The new value is: 2
## Hardhat Forking {: #hardhat-forking } You can [fork](https://hardhat.org/hardhat-network/docs/guides/forking-other-networks){target=\_blank} any EVM-compatible chain using Hardhat, including Moonbeam. Forking simulates the live Moonbeam network locally, enabling you to interact with deployed contracts on Moonbeam in a local test environment. Since Hardhat forking is based on an EVM implementation, you can interact with the fork using standard [Ethereum JSON-RPC methods supported by Moonbeam](/builders/ethereum/json-rpc/eth-rpc/){target=\_blank} and [Hardhat](https://hardhat.org/hardhat-network/docs/reference#json-rpc-methods-support){target=\_blank}. There are some limitations to be aware of when using Hardhat forking. You cannot interact with any of the Moonbeam precompiled contracts or their functions. Precompiles are a part of the Substrate implementation and therefore cannot be replicated in the simulated EVM environment. This prohibits you from interacting with cross-chain assets on Moonbeam and Substrate-based functionality such as staking and governance. There is currently an issue related to forking Moonbeam, so in order to fix the issue, you'll need to manually patch Hardhat first. You can find out more information by following the [issue on GitHub](https://github.com/NomicFoundation/hardhat/issues/2395#issuecomment-1043838164){target=\_blank} as well as the related [PR](https://github.com/NomicFoundation/hardhat/pull/2313){target=\_blank}. ### Patching Hardhat {: #patching-hardhat } Before getting started, you'll need to apply a temporary patch to workaround an RPC error until Hardhat fixes the root issue. The error is as follows: ```sh Error HH604: Error running JSON-RPC server: Invalid JSON-RPC response's result. Errors: Invalid value null supplied to : RpcBlockWithTransactions | null/transactions: RpcTransaction Array/0: RpcTransaction/accessList: Array<{ address: DATA, storageKeys: Array | null }> | undefined, Invalid value null supplied to : RpcBlockWithTransactions | null/transactions: RpcTransaction Array/1: RpcTransaction/accessList: Array<{ address: DATA, storageKeys: Array | null }> | undefined, Invalid value null supplied to : RpcBlockWithTransactions | null/transactions: RpcTransaction Array/2: RpcTransaction/accessList: Array<{ address: DATA, storageKeys: Array | null }> | undefined ``` To patch Hardhat, you'll need to open the `node_modules/hardhat/internal/hardhat-network/jsonrpc/client.js` file of your project. Next, you'll add an `addAccessList` function and update the `_perform` and `_performBatch` functions. To get started, you can remove the preexisting `_perform` and `_performBatch` functions and, in their place, add the following code snippet: ```js addAccessList(method, rawResult) { if ( method.startsWith('eth_getBlock') && rawResult && rawResult.transactions?.length ) { rawResult.transactions.forEach((t) => { if (t.accessList == null) t.accessList = []; }); } } async _perform(method, params, tType, getMaxAffectedBlockNumber) { const cacheKey = this._getCacheKey(method, params); const cachedResult = this._getFromCache(cacheKey); if (cachedResult !== undefined) { return cachedResult; } if (this._forkCachePath !== undefined) { const diskCachedResult = await this._getFromDiskCache( this._forkCachePath, cacheKey, tType ); if (diskCachedResult !== undefined) { this._storeInCache(cacheKey, diskCachedResult); return diskCachedResult; } } const rawResult = await this._send(method, params); this.addAccessList(method, rawResult); const decodedResult = (0, decodeJsonRpcResponse_1.decodeJsonRpcResponse)( rawResult, tType ); const blockNumber = getMaxAffectedBlockNumber(decodedResult); if (this._canBeCached(blockNumber)) { this._storeInCache(cacheKey, decodedResult); if (this._forkCachePath !== undefined) { await this._storeInDiskCache(this._forkCachePath, cacheKey, rawResult); } } return decodedResult; } async _performBatch(batch, getMaxAffectedBlockNumber) { // Perform Batch caches the entire batch at once. // It could implement something more clever, like caching per request // but it's only used in one place, and those other requests aren't // used anywhere else. const cacheKey = this._getBatchCacheKey(batch); const cachedResult = this._getFromCache(cacheKey); if (cachedResult !== undefined) { return cachedResult; } if (this._forkCachePath !== undefined) { const diskCachedResult = await this._getBatchFromDiskCache( this._forkCachePath, cacheKey, batch.map((b) => b.tType) ); if (diskCachedResult !== undefined) { this._storeInCache(cacheKey, diskCachedResult); return diskCachedResult; } } const rawResults = await this._sendBatch(batch); const decodedResults = rawResults.map((result, i) => { this.addAccessList(batch[i].method, result); return (0, decodeJsonRpcResponse_1.decodeJsonRpcResponse)( result, batch[i].tType ); }); const blockNumber = getMaxAffectedBlockNumber(decodedResults); if (this._canBeCached(blockNumber)) { this._storeInCache(cacheKey, decodedResults); if (this._forkCachePath !== undefined) { await this._storeInDiskCache(this._forkCachePath, cacheKey, rawResults); } } return decodedResults; } ``` Then you can use [patch-package](https://www.npmjs.com/package/patch-package){target=\_blank} to automatically patch the package by running the following command: ```sh npx patch-package hardhat ``` A `patches` directory will be created, and now you should be all set to fork Moonbeam without running into any errors. ### Forking Moonbeam {: #forking-moonbeam } You can fork Moonbeam from the command line or configure your Hardhat project to always run the fork from your `hardhat.config.js` file. To fork Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. To fork Moonbeam from the command line, you can run the following command from within your Hardhat project directory: === "Moonbeam" ```sh npx hardhat node --fork {{ networks.moonbeam.rpc_url }} ``` === "Moonriver" ```sh npx hardhat node --fork {{ networks.moonriver.rpc_url }} ``` === "Moonbase Alpha" ```sh npx hardhat node --fork {{ networks.moonbase.rpc_url }} ``` If you prefer to configure your Hardhat project, you can update your `hardhat.config.js` file with the following configurations: === "Moonbeam" ```js ... networks: { hardhat: { forking: { url: '{{ networks.moonbeam.rpc_url }}', }, }, }, ... ``` === "Moonriver" ```js ... networks: { hardhat: { forking: { url: '{{ networks.moonriver.rpc_url }}', }, }, }, ... ``` === "Moonbase Alpha" ```js ... networks: { hardhat: { forking: { url: '{{ networks.moonbase.rpc_url }}', }, }, }, ... ``` When you spin up the Hardhat fork, you'll have 20 development accounts that are pre-funded with 10,000 test tokens. The forked instance is available at `http://127.0.0.1:8545/`. The output in your terminal should resemble the following:
Private Key: Oxdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97 Account #9: Oxa0Ee7A142d267C1f36714E4a8F75612F20a79720 (10000 ETH) Private Key: 0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6 Account #10: OxBcd4042DE499D14e55001CcbB24a551F3b954096 (10000 ETH) Private Key: Oxf214f2b2cd398c806f84e317254e0f0b801d0643303237d97a22a48e01628897 Account #11: 0x71bE63f3384f5fb98995898A86B02Fb2426c5788 (10000 ETH) Private Key: 0x701b615bbdfb9de65240bc28bd21bbc0d996645a3dd57e7b12bc2bdf6f192c82 Account #12: OxFABBOac9d68B0B445fB7357272F202C5651694a (10000 ETH) Private Key: Oxa267530f49f8280200edf313ee7af6b827f2a8bce2897751d06a843f644967b1 Account #13: 0x1CBd3b2770909D4e10f157cABC84C7264073C9Ec (10000 ETH) Private Key: 0x47c99abed3324a2707c28affff1267e45918ec8c3f20b8aa892e8b065d2942dd Account #14: OxdF3e18d64BC6A983f673Ab319CCaE4f1a5707097 (10000 ETH) Private Key: Oxc526ee95bf44d8fc405a158bb884d9d1238d990612e9f33d006bb0789009aaa Account #15: Oxcd3B766CCDd6AE721141F452C550Ca635964ce71 (10000 ETH) Private Key: 0x8166f546bab6da521a8369cab06c5d2b9e46670292d85c875ee9ec20e84ffb61 Account #16: 0×2546BcD3c84621e976D8185a91A922aE77ECEc30 (10000 ETH) Private Key: Oxea6c44ac03bff858b476bba40716402b03e41b8e97e276d1baec7c37d42484a0 Account #17: OxbDA5747bFD65F08deb54cb465eB87D40e51B197E (10000 ETH) Private Key: 0x689af8efa8c651a91ad287602527f3af2fe9f6501a7ac4b06166765a93e037fd Account #18: OxdD2FD4581271e230360230F9337D5c0430Bf44C0 (10000 ETH) Private Key: Oxde9be858da4a475276426320d5e9262ecfc3ba460bfac56360bfa6c4c28b4ee0 Account #19: 0×8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199 (10000 ETH) Private Key: Oxdf57089febbacf7ba0bc227dafbffa9fc08a93fdc68e1e42411a14efcf23656e WARNING: These accounts, and their private keys, are publicly known.
Any funds sent to them on Mainnet or any other live network WILL BE LOST.
To verify you have forked the network, you can query the latest block number: ```sh curl --data '{"method":"eth_blockNumber","params":[],"id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST localhost:8545 ``` If you convert the `result` from [hex to decimal](https://www.rapidtables.com/convert/number/hex-to-decimal.html){target=\_blank}, you should get the latest block number from the time you forked the network. You can cross-reference the block number using a [block explorer](/builders/get-started/explorers/){target=\_blank}. From here, you can deploy new contracts to your forked instance of Moonbeam or interact with contracts already deployed by creating a local instance of the deployed contract. To interact with an already deployed contract, you can create a new script in the `scripts` directory using `ethers`. Because you'll be running it with Hardhat, you don't need to import any libraries. Inside the script, you can access a live contract on the network using the following snippet: ```js const hre = require('hardhat'); async function main() { const provider = new ethers.JsonRpcProvider( 'http://127.0.0.1:8545/' ); const contract = new ethers.Contract( 'INSERT_CONTRACT_ADDRESS', 'INSERT_CONTRACT_ABI', provider ); } main().catch((error) => { console.error(error); process.exitCode = 1; }); ```
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/dev-env/ --- BEGIN CONTENT --- --- title: Ethereum Development Environments description: Learn how to use Ethereum tools such as Remix, OpenZeppelin, Hardhat, Waffle & Mars, and more to develop Solidity smart contracts on Moonbeam. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/dev-env/openzeppelin/contracts/ --- BEGIN CONTENT --- --- title: Deploy OpenZeppelin Contracts description: Learn how to create common OpenZeppelin contracts such as ERC-20, ERC-721, & ERC-1155 tokens with the OpenZeppelin Contracts Wizard and deploy them on Moonbeam. categories: Dev Environments, Ethereum Toolkit --- # Using OpenZeppelin Contracts and Remix To Deploy To Moonbeam ## Introduction {: #introduction } [OpenZeppelin](https://www.openzeppelin.com){target=\_blank} contracts and libraries have become a standard in the industry. They help developers minimize risk, as their open-source code templates are battle-tested for Ethereum and other blockchains. Their code includes the most used implementations of ERC standards and add-ons and often appears in guides and tutorials around the community. Because Moonbeam is fully Ethereum compatible, all of OpenZeppelin's contracts and libraries can be implemented without any changes. This guide is divided into two sections. The first part describes the OpenZeppelin Contracts Wizard, a great online tool to help you create smart contracts using OpenZeppelin code. The second section provides a step-by-step guide on how you can deploy these contracts using [Remix](https://remix.ethereum.org){target=\_blank} on Moonbeam. ## OpenZeppelin Contract Wizard {: #openzeppelin-contract-wizard } OpenZeppelin has developed an online web-based interactive contract generator tool that is probably the easiest and fastest way to write your smart contract using OpenZeppelin code, called [Contracts Wizard](https://docs.openzeppelin.com/contracts/5.x/wizard){target=\_blank}.
In this video, Open Zeppelin Wizard is used to deploy an ERC-20 token to Moonbase Alpha
Currently, the Contracts Wizard support the following ERC standards: - [**ERC-20**](https://ethereum.org/en/developers/docs/standards/tokens/erc-20){target=\_blank} — a fungible token standard that follows [EIP-20](https://eips.ethereum.org/EIPS/eip-20){target=\_blank}. Fungible means that all tokens are equivalent and interchangeable that is, of equal value. One typical example of fungible tokens is fiat currencies, where each equal-denomination bill has the same value - [**ERC-721**](https://ethereum.org/en/developers/docs/standards/tokens/erc-721){target=\_blank} — a non-fungible token contract that follows [EIP-721](https://eips.ethereum.org/EIPS/eip-721){target=\_blank}. Non-fungible means that each token is different, and therefore, unique. An ERC-721 token can represent ownership of that unique item, whether it is a collectible item in a game, real estate, and so on - [**ERC-1155**](https://docs.openzeppelin.com/contracts/5.x/erc1155){target=\_blank} — also known as the multi-token contract, because it can represent both fungible and non-fungible tokens in a single smart contract. It follows [EIP-1155](https://eips.ethereum.org/EIPS/eip-1155){target=\_blank} The wizard is comprised of the following sections: 1. **Token standard selection** — shows all the different standards supported by the wizard 2. **Settings** — provides the baseline settings for each token standard, such as token name, symbol, pre-mint (token supply when the contract is deployed), and URI (for non-fungible tokens) 3. **Features** — list of all features available for each token standard. You can find more information about the different features in the following links: - [ERC-20](https://docs.openzeppelin.com/contracts/5.x/api/token/erc20){target=\_blank} - [ERC-721](https://docs.openzeppelin.com/contracts/5.x/api/token/erc721){target=\_blank} - [ERC-1155](https://docs.openzeppelin.com/contracts/5.x/api/token/erc1155){target=\_blank} 4. **Access Control** — list of all the available [access control mechanisms](https://docs.openzeppelin.com/contracts/5.x/access-control){target=\_blank} for each token standard 5. **Interactive code display** — shows the smart contract code with the configuration as set by the user ![OpenZeppelin Contracts Wizard](/images/builders/ethereum/dev-env/openzeppelin/contracts/oz-wizard-1.webp) Once you have set up your contract with all the settings and features, it is just as easy as copying and pasting the code into your contract file. ## Deploying OpenZeppelin Contracts on Moonbeam {: #deploying-openzeppelin-contracts-on-moonbeam } This section goes through the steps for deploying OpenZeppelin contracts on Moonbeam. It covers the following contracts: - ERC-20 (fungible tokens) - ERC-721 (non-fungible tokens) - ERC-1155 (multi-token standard) All the code of the contracts was obtained using OpenZeppelin [Contract Wizard](https://docs.openzeppelin.com/contracts/5.x/wizard){target=\_blank}. ### Checking Prerequisites {: #checking-prerequisites } The steps described in this section assume you have [MetaMask](https://metamask.io){target=\_blank} installed and connected to the Moonbase Alpha TestNet. If you're adapting this guide for Moonbeam or Moonriver, make sure you're connected to the correct network. Contract deployment is done using the [Remix IDE](https://remix.ethereum.org){target=\_blank} via the **Injected Provider** environment. You can find corresponding tutorials in the following links: - [Interacting with Moonbeam using MetaMask](/tokens/connect/metamask/){target=\_blank} - [Interacting with Moonbeam using Remix](/builders/ethereum/dev-env/remix/){target=\_blank} ### Deploying an ERC-20 Token {: #deploying-an-erc-20-token } For this example, an ERC-20 token will be deployed to Moonbase Alpha. The final code used combines different contracts from OpenZeppelin: - **`ERC20.sol`** — ERC-20 token implementation with the optional features from the base interface. Includes the supply mechanism with a `mint` function but needs to be explicitly called from within the main contract - **`Ownable.sol`** — extension to restrict access to certain functions The mintable ERC-20 OpenZeppelin token contract provides a `mint` function that the owner of the contract can only call. By default, the owner is the contract's deployer address. There is also a premint of `1000` tokens sent to the contract's deployer configured in the `constructor` function. The first step is to go to [Remix](https://remix.ethereum.org) and take the following steps: 1. Click on the **Create New File** icon and set a file name. For this example, it was set to `ERC20.sol` 2. Make sure the file was created successfully. Click on the file to open it up in the text editor 3. Write your smart contract using the file editor. For this example, the following code was used: ```solidity // SPDX-License-Identifier: MIT // Compatible with OpenZeppelin Contracts ^5.0.0 pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; contract MyToken is ERC20, Ownable, ERC20Permit { constructor(address initialOwner) ERC20("MyToken", "MTK") Ownable(initialOwner) ERC20Permit("MyToken") { _mint(msg.sender, 1000 * 10 ** decimals()); } function mint(address to, uint256 amount) public onlyOwner { _mint(to, amount); } } ``` This ERC-20 token smart contract was extracted from the [Contract Wizard](#openzeppelin-contract-wizard), setting a premint of `1000` tokens and activating the `Mintable` and `Permit` features. ![Getting Started with Remix](/images/builders/ethereum/dev-env/openzeppelin/contracts/oz-contracts-2.webp) Once your smart contract is written, you can compile it by taking the following steps: 1. Head to the **Solidity Compiler** 2. Click on the compile button 3. Alternatively, you can check the **Auto compile** feature ![Compile ERC-20 Contract with Remix](/images/builders/ethereum/dev-env/openzeppelin/contracts/oz-contracts-3.webp) With the contract compiled, you are ready to deploy it taking the following steps: 1. Head to the **Deploy & Run Transactions** tab 2. Change the environment to **Injected Provider**. This will use MetaMask's injected provider. Consequently, the contract will be deployed to whatever network MetaMask is connected to. MetaMask might show a pop-up outlining that Remix is trying to connect to your wallet 3. Select the proper contract to deploy. In this example, it is the `MyToken` contract inside the `ERC20.sol` file 4. Enter the address of the initial owner and click on the **Deploy** button. Review the transaction information in MetaMask and confirm it 5. After a few seconds, the transaction should get confirmed, and you should see your contract under **Deployed Contracts** ![Deploy ERC-20 Contract with Remix](/images/builders/ethereum/dev-env/openzeppelin/contracts/oz-contracts-4.webp) And that is it! You've deployed an ERC-20 token contract using OpenZeppelin's contracts and libraries. Next, you can interact with your token contract via Remix, or add it to MetaMask. ### Deploying an ERC-721 Token {: #deploying-an-erc-721-token } For this example, an ERC-721 token will be deployed to Moonbase Alpha. The final code used combines different contracts from OpenZeppelin: - **`ERC721.sol`** — ERC-721 token implementation with the optional features from the base interface. Includes the supply mechanism with a `_mint` function but needs to be explicitly called from within the main contract - **`ERC721Burnable.sol`** — extension to allow tokens to be destroyed by their owners (or approved addresses) - **`ERC721Enumerable.sol`** — extension to allow on-chain enumeration of tokens - **`Ownable.sol`** — extension to restrict access to certain functions The mintable ERC-721 OpenZeppelin token contract provides a `mint` function that can only be called by the owner of the contract. By default, the owner is the contract's deployer address. As with the [ERC-20 contract](#deploying-an-erc-20-token), the first step is to go to [Remix](https://remix.ethereum.org){target=\_blank} and create a new file. For this example, the file name will be `ERC721.sol`. Next, you'll need to write the smart contract and compile it. For this example, the following code is used: ```solidity // SPDX-License-Identifier: MIT // Compatible with OpenZeppelin Contracts ^5.0.0 pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract MyToken is ERC721, ERC721Enumerable, ERC721Burnable, Ownable { constructor(address initialOwner) ERC721("MyToken", "MTK") Ownable(initialOwner) {} function _baseURI() internal pure override returns (string memory) { return "Test"; } function safeMint(address to, uint256 tokenId) public onlyOwner { _safeMint(to, tokenId); } // The following functions are overrides required by Solidity function _update(address to, uint256 tokenId, address auth) internal override(ERC721, ERC721Enumerable) returns (address) { return super._update(to, tokenId, auth); } function _increaseBalance(address account, uint128 value) internal override(ERC721, ERC721Enumerable) { super._increaseBalance(account, value); } function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC721Enumerable) returns (bool) { return super.supportsInterface(interfaceId); } } ``` This ERC-721 token smart contract was extracted from the [Contract Wizard](#openzeppelin-contract-wizard), setting the `Base URI` as `Test` and activating the `Mintable`, `Burnable`, and `Enumerable` features. With the contract compiled, next you will need to: 1. Head to the **Deploy & Run Transactions** tab 2. Change the environment to **Injected Provider**. This will use MetaMask's injected provider. Consequently, the contract will be deployed to whatever network MetaMask is connected to. MetaMask might show a pop-up outlining that Remix is trying to connect to your wallet 3. Select the proper contract to deploy. In this example, it is the `MyToken` contract inside the `ERC721.sol` file 4. Enter the address of the initial owner and click on the **Deploy** button. Review the transaction information in MetaMask and confirm it 5. After a few seconds, the transaction should get confirmed, and you should see your contract under **Deployed Contracts** ![Deploy ERC-721 Contract with Remix](/images/builders/ethereum/dev-env/openzeppelin/contracts/oz-contracts-5.webp) And that is it! You've deployed an ERC-721 token contract using OpenZeppelin's contracts and libraries. Next, you can interact with your token contract via Remix, or add it to MetaMask. ### Deploying an ERC-1155 Token {: #deploying-an-erc-1155-token } For this example, an ERC-1155 token will be deployed to Moonbase Alpha. The final code used combines different contracts from OpenZeppelin: - **`ERC1155.sol`** — ERC-1155 token implementation with the optional features from the base interface. Includes the supply mechanism with a `_mint` function but needs to be explicitly called from within the main contract - **`Pausable.sol`** — extension to allows pausing tokens transfer, mintings and burnings - **`Ownable.sol`** — extension to restrict access to certain functions OpenZeppelin's ERC-1155 token contract provides a `_mint` function that can only be called in the `constructor` function. Therefore, this example creates 1000 tokens with an ID of `0`, and 1 unique token with an ID of `1`. The first step is to go to [Remix](https://remix.ethereum.org){target=\_blank} and create a new file. For this example, the file name will be `ERC1155.sol`. As shown for the [ERC-20 token](#deploying-an-erc-20-token), you'll need to write the smart contract and compile it. For this example, the following code is used: ```solidity // SPDX-License-Identifier: MIT // Compatible with OpenZeppelin Contracts ^5.0.0 pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Pausable.sol"; contract MyToken is ERC1155, Ownable, ERC1155Pausable { constructor() ERC1155("") Ownable() { _mint(msg.sender, 0, 1000 * 10 ** 18, ""); _mint(msg.sender, 1, 1, ""); } function setURI(string memory newuri) public onlyOwner { _setURI(newuri); } function pause() public onlyOwner { _pause(); } function unpause() public onlyOwner { _unpause(); } // The following function is an override required by Solidity function _update(address from, address to, uint256[] memory ids, uint256[] memory values) internal override(ERC1155, ERC1155Pausable) { super._update(from, to, ids, values); } } ``` This ERC-1155 token smart contract was extracted from the [Contract Wizard](#openzeppelin-contract-wizard), setting no `Base URI` and activating `Pausable` feature. The constructor function was modified to include the minting of both a fungible and a non-fungible token. With the contract compiled, next you will need to: 1. Head to the **Deploy & Run Transactions** tab 2. Change the environment to **Injected Provider**. This will use MetaMask's injected provider. Consequently, the contract will be deployed to whatever network MetaMask is connected to. MetaMask might show a pop-up outlining that Remix is trying to connect to your wallet 3. Select the proper contract to deploy. In this example, it is the `MyToken` contract inside the `ERC1155.sol` file 4. Enter the address of the initial owner and click on the **Deploy** button. Review the transaction information in MetaMask and confirm it 5. After a few seconds, the transaction should get confirmed, and you should see your contract under **Deployed Contracts** ![Deploy ERC-1155 Contract with Remix](/images/builders/ethereum/dev-env/openzeppelin/contracts/oz-contracts-6.webp) And that is it! You've deployed an ERC-1155 token contract using OpenZeppelin's contracts and libraries. Next, you can interact with your token contract via Remix.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/dev-env/openzeppelin/ --- BEGIN CONTENT --- --- title: Interact with OpenZeppelin description: Use OpenZeppelin contracts and libraries or the Contract Wizard to create and manage your Solidity smart contracts on Moonbeam. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/dev-env/openzeppelin/overview/ --- BEGIN CONTENT --- --- title: An Overview of OpenZeppelin on Moonbeam description: Learn how to use OpenZeppelin products for creating and managing Solidity smart contracts on Moonbeam, thanks to its Ethereum compatibility features. categories: Basics, Ethereum Toolkit --- # OpenZeppelin ## Introduction {: #introduction } [OpenZeppelin](https://www.openzeppelin.com){target=\_blank} is well known in the Ethereum developer community as their set of audited smart contracts and libraries are a standard in the industry. For example, most of the tutorials that show developers how to deploy an ERC-20 token use OpenZeppelin contracts. You can find more information about OpenZeppelin on their [documentation site](https://docs.openzeppelin.com){target=\_blank}. As part of its Ethereum compatibility features, OpenZeppelin products can be seamlessly used on Moonbeam. This page will provide information on different OpenZeppelin solutions that you can test. ## OpenZeppelin on Moonbeam {: #openzeppelin-on-moonbeam } Currently, the following OpenZeppelin products/solutions work on the different networks available on Moonbeam: | **Product** | **Moonbeam** | **Moonriver** | **Moonbase Alpha** | **Moonbase Dev Node** | |:---------------------:|:------------:|:-------------:|:------------------:|:---------------------:| | Contracts & libraries | ✓ | ✓ | ✓ | ✓ | | Contracts Wizard | ✓ | ✓ | ✓ | ✓ | You will find a corresponding tutorial for each product in the following links: - [**Contracts Wizard**](/builders/ethereum/dev-env/openzeppelin/contracts/#openzeppelin-contract-wizard) — where you'll find a guide on how to use OpenZeppelin web-based wizard to create different token contracts with different functionalities - [**Contracts & libraries**](/builders/ethereum/dev-env/openzeppelin/contracts/#deploying-openzeppelin-contracts-on-moonbeam) — where you'll find tutorials to deploy the most common token contracts using OpenZeppelin's templates: ERC-20, ERC-721 and ERC-1155
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/dev-env/remix/ --- BEGIN CONTENT --- --- title: Deploy Smart Contracts with Remix description: Discover how to deploy and interact with Solidity smart contracts on Moonbeam using the Remix IDE, one of the most widely used Ethereum development tools. categories: Dev Environments, Ethereum Toolkit --- # Using Remix to Deploy to Moonbeam
## Introduction {: #introduction } [Remix](https://remix.ethereum.org){target=\_blank} is an integrated development environment (IDE) for developing smart contracts on Ethereum and Ethereum-compatible chains. It provides an easy-to-use interface for writing, compiling, and deploying smart contracts. Given Moonbeam’s Ethereum compatibility features, you can use Remix directly with any Moonbeam network. This guide walks through the process of creating and deploying a Solidity smart contract to a [Moonbeam development node](/builders/get-started/networks/moonbeam-dev/){target=\_blank} using the Remix IDE. This guide can be adapted for [Moonbeam](/builders/get-started/networks/moonbeam/){target=\_blank}, [Moonriver](/builders/get-started/networks/moonriver/){target=\_blank}, or [Moonbase Alpha](/builders/get-started/networks/moonbase/){target=\_blank}. If you're familiar with Remix, you can skip ahead to the [Connect Remix to Moonbeam](#connect-remix-to-moonbeam){target=\_blank} section to learn how to use Remix with Moonbeam. ## Checking Prerequisites {: #checking-prerequisites } For the purposes of this guide, you'll need to have the following: - A locally running [Moonbeam development node](/builders/get-started/networks/moonbeam-dev/){target=\_blank} - [MetaMask installed and connected](/tokens/connect/metamask/){target=\_blank} to your development node If you followed the guides above, you should have a local Moonbeam node, which will begin to author blocks as transactions arrive. ![The terminal logs of for a local Moonbeam development node that is producing blocks.](/images/builders/ethereum/dev-env/remix/remix-1.webp) Your development node comes with 10 pre-funded accounts. You should have MetaMask connected to your Moonbeam development node and have imported at least one of the pre-funded accounts. You can refer to the [Import Accounts](/tokens/connect/metamask/#import-accounts){target=\_blank} section of the MetaMask docs for step-by-step instructions on how to import a development account. ![The main screen of MetaMask, which shows an account connected to a Moonbeam development node and its balance.](/images/builders/ethereum/dev-env/remix/remix-2.webp) If you're adapting this guide for Moonbeam, Moonriver, or Moonbase Alpha, make sure you are connected to the correct network and have an account with funds. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank}. ## Get Familiar with Remix {: #get-familiar-with-remix } If you navigate to [https://remix.ethereum.org/](https://remix.ethereum.org){target=\_blank}, you'll see that the layout of Remix is split into four sections: 1. The plugin panel 2. The side panel 3. The main panel 4. The terminal ![The layout of Remix IDE and its four sections.](/images/builders/ethereum/dev-env/remix/remix-3.webp) The plugin panel displays icons for each of the preloaded plugins, the plugin manager, and the settings menu. You'll see a few icons there for each of the preloaded plugins, which are the **File explorer**, **Search in files**, **Solidity compiler**, and **Deploy and run transactions** plugins. As additional plugins are activated, their icons will appear in this panel. The side panel displays the content of the plugin that is currently being viewed. By default, you'll see the File explorer plugin, which displays the default workspace and some preloaded files and folders. However, if you select one of the other icons from the plugin panel, you'll see the content for the selected plugin. The main panel is automatically loaded with the **Home** tab, which contains links to a variety of resources. You can close this tab at any time and reopen it by clicking on the blue Remix icon in the top left corner of the plugin panel. The main panel is where you'll be able to see each of the files you're working with. For example, you can double-click on any file in the **File explorer** side panel and it will appear as a tab in the main panel. The terminal panel is similar to a standard terminal that you have on your OS; you can execute scripts from it, and logs are printed to it. All transactions and contract interactions are automatically logged to the terminal. You can also interact with the [Ethers](https://docs.ethers.org/v6){target=\_blank} and [Web3](https://web3js.org/#){target=\_blank} JavaScript libraries directly from the terminal. ## Add a Smart Contract to the File Explorer {: #add-a-smart-contract-to-the-file-explorer } For this example, you will create a new file that contains an ERC-20 token contract. This will be a simple ERC-20 contract based on the current [OpenZeppelin ERC-20 template](https://docs.openzeppelin.com/contracts/4.x/erc20){target=\_blank}. The contract will create a `MyToken` token with the `MYTOK` symbol that mints the entirety of the initial supply to the creator of the contract. From the **File explorer** tab on the plugin panel, you can create a new file by taking the following steps: 1. Click on the file icon 2. Enter the name of the contract: `MyToken.sol` ![Create a new file using the File explorer plugin in Remix.](/images/builders/ethereum/dev-env/remix/remix-4.webp) The main panel will switch to an empty file where you can add the Solidity code for the contract. Paste the `MyToken.sol` smart contract into the new file: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract MyToken is ERC20 { constructor(uint256 initialSupply) ERC20("MyToken", "MYTOK") { _mint(msg.sender, initialSupply); } } ``` ![Add the contract code to the newly created file in the main panel of Remix.](/images/builders/ethereum/dev-env/remix/remix-5.webp) ## Compile a Solidity Smart Contract {: #compile-a-solidity-smart-contract } Before you compile a contract, make sure you've selected the file of the contract from the **File explorer** tab. Then, select the **Solidity Compiler** option from the plugin panel. Make sure that the compiler version in the top-left corner meets the version defined in your contract and the version defined in [OpenZeppelin's `ERC20.sol` contract](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol){target=\_blank}. For example, the `MyToken.sol` contract requires Solidity ^0.8.0, but at the time of writing, OpenZeppelin's `ERC20.sol` contract requires ^0.8.20, so the compiler needs to be set to version 0.8.20 or newer. The Solidity compiler plugin also lets you change some settings and apply advanced configurations for the compiler. If you're planning on iterating over the smart contract, you can check the **Auto compile** box, and whenever you make a change, the contract will automatically be recompiled. Additionally, from the **Advanced Configurations** menu, you can change the EVM version, enable optimizations, and set the number of times the bytecode is expected to be run throughout the contract's lifetime; the default is set to 200 times. For more information on contract optimization, please refer to the [Solidity docs on The Optimizer](https://docs.soliditylang.org/en/latest/using-the-compiler.html#optimizer-options){target=\_blank}. For this example, no additional configurations are needed. To compile the `MyToken.sol` contract, simply click on the **Compile MyToken.sol** contract. If the compilation was successful, you'll see a green check mark appear on the plugin panel next to the **Solidity compiler** plugin. ![The Solidity compiler plugin shown in the side panel in Remix.](/images/builders/ethereum/dev-env/remix/remix-6.webp) ### Debug Compilation Errors {: #debug-compilation-errors } If you tried to compile your smart contract but there was an error or warning, you can easily debug the issue with the help of ChatGPT directly from the Solidity compiler plugin in Remix. For example, if you only provided the token name to the ERC-20 constructor but forgot the token symbol and tried to compile the contract, an error would appear in the side panel. You can scroll down to read the error, and you'll see that there is also an **ASK GPT** button. To get help debugging the issue, you can click on **ASK GPT**, and a response will be returned in the Remix terminal that will guide you in the right direction to try and fix the issue. If you need additional help, you can go straight to the source and ask [ChatGPT](https://chatgpt.com/){target=\_blank} directly. ![An error message shown in the side panel for the Solidity compiler plugin with an ASK GPT button for debugging.](/images/builders/ethereum/dev-env/remix/remix-7.webp) Once you successfully fix the issue and recompile the contract, you'll see a green check mark appear on the plugin panel next to the **Solidity compiler** plugin. ![The green check mark next to the Solidity compiler plugin in the plugin panel.](/images/builders/ethereum/dev-env/remix/remix-8.webp) ## Deploy a Solidity Smart Contract {: #deploy-a-solidity-smart-contract } The **Deploy and run transactions** plugin enables you to configure contract deployment options, deploy contracts, and interact with deployed contracts. The side panel consists of the following deployment options: - Environment - allows you to choose the execution environment for deployment - Account - the account from which the deployment transaction will be sent - Gas Limit - the maximum amount of gas that the deployment transaction can consume - Value - the amount of the native asset to send along with the deployment transaction - Contract - the contract to deploy - Deploy - sends the deployment transaction to the specified environment using the selected account, gas limit, value, and the values for any constructor arguments - At Address - allows you to interact with an existing contract by specifying its address The following section will cover how to configure the environment for deployment to be Moonbeam. ### Connect Remix to Moonbeam {: #connect-remix-to-moonbeam } To deploy the smart contract to Moonbeam, you'll need to make sure that you've connected your wallet to your Moonbeam development node or the Moonbeam network of your choice. Then, from the **Deploy and run transactions** tab, you can connect Remix to your wallet by selecting your wallet from the **ENVIRONMENT** dropdown. For example, if you have Trust Wallet installed, you'll see **Injected Provider - TrustWallet** from the dropdown. Aside from injected providers, you can also connect to Moonbeam via WalletConnect. For this example, MetaMask will be used. You should already have MetaMask installed and connected to your local Moonbeam development node. If not, please refer to the [Interacting with Moonbeam Using MetaMask](/tokens/connect/metamask/){target=\_blank} guide for step-by-step instructions. From the **ENVIRONMENT** dropdown, select **Injected Provider - MetaMask**. ![The environment dropdown on the Deploy and run transactions side panel expanded to reveal all of the available options.](/images/builders/ethereum/dev-env/remix/remix-9.webp) MetaMask will pop up automatically and prompt you to connect to Remix. You'll need to: 1. Select the account you want to connect to Remix 2. Click **Next** 3. Click **Connect** to connect your account to Remix ![Two MetaMask screens that you must go through to connect to Remix: one that prompts you to choose an account to connect to and another that grants Remix permissions.](/images/builders/ethereum/dev-env/remix/remix-10.webp) Once you've connected MetaMask to Remix, the side panel will update to reveal the network and account you're connected to. For a Moonbeam development node, you should see **Custom (1281) network**. ![The Deploy and run transactions side panel in Remix showing the environment connected to MetaMask, the connected network as 1281, and the connected account address.](/images/builders/ethereum/dev-env/remix/remix-11.webp) ### Deploy the Contract to Moonbeam {: #deploy-the-contract-to-moonbeam } Now that you've connected your wallet, you're ready to deploy the contract. Since you're deploying a simple ERC-20 token smart contract, the default gas limit set by Remix of 3 million is more than enough, and you don't need to specify a value to send along with the deployment. As such, you can take the following steps to deploy the contract: 1. Make sure the **ENVIRONMENT** is set to **Injected Provider - MetaMask** 2. Make sure the connected account is the one you want to deploy the transaction from 3. Use the default **GAS LIMIT** of `3000000` 4. Leave the **VALUE** as `0` 5. Make sure `MyToken.sol` is the selected contract 6. Expand the **DEPLOY** dropdown 7. Specify the initial supply. For this example, you can set it to 8 million tokens. Since this contract uses the default of 18 decimals, the value to put in the box is `8000000000000000000000000` 8. Click **transact** to send the deployment transaction 9. MetaMask will pop up, and you can click **Confirm** to deploy the contract ![The Deploy and run transactions side panel completely filled out to perform a contract deployment.](/images/builders/ethereum/dev-env/remix/remix-12.webp) Once the transaction has been deployed, you'll see details about the deployment transaction in the Remix terminal. Additionally, the contract will appear under the **Deployed Contracts** section of the side panel. ## Interact with Deployed Smart Contracts {: #interact-with-deployed-smart-contracts } Once you've deployed a smart contract or accessed an existing contract via the **At Address** button, the contract will appear under the **Deployed Contracts** section of the side panel. You can expand the contract to view all of the contract's functions you can interact with. To interact with a given function, you can click on the function name, which will be contained in an orange, red, or blue button. Orange buttons are for functions that write to the blockchain and are non-payable; red buttons are for functions that write to the blockchain and are payable; and blue buttons are for functions that read data from the blockchain. Depending on the function you're interacting with, you may need to input parameter values. If the function requires inputs, you'll be able to enter them by expanding the function and entering a value for each of the parameters. If the function you're interacting with is payable, you'll be able to enter an amount in the **VALUE** field towards the top of the side panel, in the same value field used for contracts that have payable constructors. ### Call the Smart Contract Functions {: #call-the-smart-contract-functions } If you expand the **MYTOKEN** contract dropdown, you'll be able to see all of the available functions you can interact with. To interact with a given function, you can provide any inputs, if needed, and then click on the button containing the function name you want to interact with. For example, if you wanted to call the `totalSupply` function, you wouldn't need to sign a transaction, as you'd get a response right away. ![A view of the functions available in the deployed ERC-20 contract and the response from calling the totalSupply function.](/images/builders/ethereum/dev-env/remix/remix-13.webp) On the other hand, if you call the `approve` function, which will approve an account as a spender of a given amount of MYTOK tokens, you'll need to submit the approval in MetaMask. To test this out, you can take the following steps: 1. Set the **spender** to an account that you want to be able to spend tokens on your behalf. For this example, you can use Bob's account (one of the pre-funded development accounts): `0x3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0` 2. Enter the amount the spender can spend. For this example, you can approve Bob to spend 10 MYTOK by entering in `10000000000000000000` 3. Press **transact** 4. MetaMask will pop up and you'll need to review the details of the approval and submit the approval ![The inputs for the approve function of the ERC-20 contract and the MetaMask pop-up for the approval.](/images/builders/ethereum/dev-env/remix/remix-14.webp) To view your balance or approvals, or transfer MYTOKs, you can add the MYTOK to your wallet. For information on how to add a token to MetaMask, you can refer to the [Add an ERC-20 Token](/tokens/connect/metamask/#add-erc20){target=\_blank} section of [our MetaMask documentation](/tokens/connect/metamask/){target=\_blank}.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/dev-env/scaffold-eth/ --- BEGIN CONTENT --- --- title: Create a DApp with Scaffold-ETH 2 description: You can deploy a Solidity DApp with a React UI and subgraph on Moonbeam in minutes by using Scaffold-ETH 2. Learn how in this tutorial. categories: Dev Environments, Ethereum Toolkit --- # Using Scaffold-ETH 2 to Deploy a DApp on Moonbeam ## Introduction {: #introduction } [Scaffold-ETH 2](https://github.com/scaffold-eth/scaffold-eth-2){target=\_blank} is a collection of commonly used Ethereum development tools to quickly deploy a Solidity smart contract and launch a DApp with a React frontend. Scaffold-ETH 2 consists of several sub-components, including [Hardhat](https://hardhat.org/docs){target=\_blank} for creating, deploying, and testing smart contracts and [Next.js](https://nextjs.org/docs){target=\_blank} for building a React frontend. These components can be used on Moonbeam networks with some slight modifications. This guide will walk through the steps to deploy and run the default example contract and DApp that Scaffold-ETH 2 comes with on a Moonbeam network. ## Checking Prerequisites {: #checking-prerequisites } To get started, you will need the following: - An account with funds. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} - An [Etherscan API key](/builders/ethereum/verify-contracts/etherscan-plugins/#generating-an-etherscan-api-key){target=\_blank} - To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank} ### Installing Scaffold-ETH 2 {: #installing-scaffold-eth } First, download [Scaffold-ETH 2 from GitHub](https://github.com/scaffold-eth/scaffold-eth-2){target=\_blank}. From the command line, enter: ```bash git clone https://github.com/scaffold-eth/scaffold-eth-2.git ``` After the download completes, run: ```bash yarn install ``` ## The Development Process with Scaffold-ETH 2 {: #development-process } The process for developing a project with Scaffold-ETH 2 can be outlined as follows: 1. Update the network configurations in Hardhat for Moonbeam 2. Add your smart contracts to the `packages/hardhat/contracts` 3. Edit your deployment scripts in the `packages/hardhat/deploy` 4. Deploy your smart contracts to Moonbeam 5. Verify your smart contracts with the Etherscan plugin and your Etherscan API key 6. Configure your frontend to target Moonbeam in the `packages/nextjs/scaffold.config.ts` file 7. Edit your frontend as needed in the `packages/nextjs/pages` directory In this guide, you can use the default contract and frontend that you get out of the box when you clone the Scaffold-ETH 2 repository. All you'll have to do is modify these components for Moonbeam. ## The Hardhat Component {: #hardhat-component } In the following sections, you'll update the network configurations in the Hardhat configuration file to target the Moonbeam-based network you want to interact with, and deploy and verify the example contract to that network. ### Configure Hardhat for Moonbeam {: #configure-hardhat-for-moonbeam } You can begin by making modifications to the Hardhat component under the `packages/hardhat` folder. You'll primarily be editing the `hardhat.config.js` file to configure it for Moonbeam. However, you'll also need to create a `.env` file to store a couple of variables that will be consumed by the `hardhat.config.js` file. You can refer to the `.env.example` file for the variables that are already used in the `hardhat.config.js` file. For Moonbeam, you'll only need to manually create one variable, the `ETHERSCAN_API_KEY`. Check out the [Etherscan Plugins](/builders/ethereum/verify-contracts/etherscan-plugins/#generating-an-etherscan-api-key){target=\_blank} documentation to learn how to generate an Etherscan API key. To get started, create a `.env` file: ```bash touch packages/hardhat/.env ``` Edit your `.env` file to include the following variables: ```text ETHERSCAN_API_KEY=INSERT_ETHERSCAN_API_KEY ``` Next, import your deployment account by either generating a new one with `yarn generate` or importing an existing one using `yarn account:import`. If importing, you'll need to provide your private key and create a password to encrypt it. The encrypted key will be saved in your `.env` file. Keep your password safe as you'll need it to decrypt the private key for future deployments. Remember to never share or commit your private keys or `.env` file. For this example, we'll import an existing private key with the following command: ```bash yarn account:import ```
yarn account:import 👛 Importing Wallet Paste your private key: [hidden] Enter a password to encrypt your private key: [hidden] Confirm password: [hidden] 📄 Encrypted Private Key saved to packages/hardhat/.env file 🪄 Imported wallet address: 0x3B939FeaD1557C741Ff06492FD0127bd287A421e ⚠️ Make sure to remember your password! You'll need it to decrypt the private key.
The private key you add in the account import workflow corresponds to the account that will deploy and interact with the smart contracts in your Hardhat project. Additionally, the Etherscan API key will correspond to your Etherscan API key and will be used to verify your deployed smart contracts. To learn how to generate an Etherscan API key, check out the [Etherscan Plugins](/builders/ethereum/verify-contracts/etherscan-plugins/#generating-an-etherscan-api-key){target=\_blank} documentation. With the deployment account and the Etherscan API key taken care of, next you can modify the `hardhat.config.js` file for Moonbeam: 1. Set the constant `defaultNetwork` to the network you are deploying the smart contract to === "Moonbeam" ```js defaultNetwork = 'moonbeam'; ``` === "Moonriver" ```js defaultNetwork = 'moonriver'; ``` === "Moonbase Alpha" ```js defaultNetwork = 'moonbaseAlpha'; ``` === "Moonbeam Dev Node" ```js defaultNetwork = 'moonbeamDevNode'; ``` 2. Add the network configurations for the Moonbeam network you want to interact with under the `networks` configuration object === "Moonbeam" ```js moonbeam: { url: "{{ networks.moonbeam.rpc_url }}", accounts: [deployerPrivateKey], }, ``` === "Moonriver" ```js moonriver: { url: "{{ networks.moonriver.rpc_url }}", accounts: [deployerPrivateKey], }, ``` === "Moonbase Alpha" ```js moonbaseAlpha: { url: "{{ networks.moonbase.rpc_url }}", accounts: [deployerPrivateKey], }, ``` === "Moonbeam Dev Node" ```js moonbeamDevNode: { url: "{{ networks.development.rpc_url }}", accounts: [deployerPrivateKey], }, ``` To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. For more information on using Hardhat with Moonbeam, please check the dedicated [Hardhat page](/builders/ethereum/dev-env/hardhat/){target=\_blank} for more details. ### Deploy Your Contract to Moonbeam {: #deploy-contract } After all the modifications to the configuration files are done, you can deploy your contract to the configured Moonbeam-based network. First, you can compile your contract by running: ```bash yarn compile ```
yarn compile Generating typings for: 2 artifacts in dir: typechain-types for target: ethers-v6 Successfully generated 6 typings! Compiled 2 Solidity files successfully (evm target: paris).
Then, you can run the following command from the root directory of your project: ```bash yarn deploy ```
yarn deploy Enter password to decrypt private key: [hidden] Nothing to compile No need to generate any newer typings. deploying "YourContract" (tx: 0xda4b71904cae30fad60669b321e1dd51b28a6cf197fc7ea13b5d85035b41d92c)...: deployed at 0xB527D4Ed38249d35cfCBAb92b51f45895622c6Eb with 837042 gas 👋 Initial greeting: Building Unstoppable Apps!!! 📝 Updated TypeScript contract definition file on ../nextjs/contracts/deployedContracts.ts
!!! note If you did not set the `defaultNetwork` config in the `hardhat.config.js` file, you can append `--network INSERT_NETWORK` to the command. For example, the following command would deploy a contract to Moonbeam. ```bash yarn deploy --network moonbeam ``` ### Verify Your Deployed Contract {: #verify-contracts } If you would also like to use Scaffold-ETH 2 to verify the deployed smart contract and have entered your Etherscan API key into the `.env` file, you can go ahead and verify your deployed contract. If the smart contract you are verifying has constructor method parameters, you will also need to append the parameters used to the end of the command. You can use the following command to verify the smart contract: === "Moonbeam" ```bash yarn verify --api-url https://api-moonbeam.moonscan.io ``` === "Moonriver" ```bash yarn verify --api-url https://api-moonriver.moonscan.io ``` === "Moonbase Alpha" ```bash yarn verify --api-url https://api-moonbase.moonscan.io ``` !!! note If you did not set the `defaultNetwork` configuration in the `hardhat.config.js` file, you can append `--network INSERT_NETWORK` to the command. For example, the following command would verify a contract on Moonbeam. ```bash yarn verify --network moonbeam --api-url https://api-moonbeam.moonscan.io ``` After a short wait, the console output will display the verification result and, if successful, the URL to the verified contract on Moonscan.
yarn verify --api-url https://api-moonbase.moonscan.io verifying YourContract (0xB527D4Ed38249d35cfCBAb92b51f45895622c6Eb) ... waiting for result... => contract YourContract is now verified
For more information about verifying smart contracts on Moonbeam using the Hardhat Etherscan plugin, please refer to the [Etherscan Plugins page](/builders/ethereum/verify-contracts/etherscan-plugins/#using-the-hardhat-etherscan-plugin){target=\_blank}. ## The Next.js Component {: #nextjs-component } In the following sections, you'll modify the Next.js configuration so that it targets the Moonbeam-based network that your contract has been deployed to, and then you'll launch the dApp. ### Configure the DApp for Moonbeam {: #configure-dapp } To target the Moonbeam-based network that you deployed your smart contract to, you'll need to edit the configurations in the `packages/nextjs/scaffold.config.ts` file. More specifically, you'll need to modify the `targetNetworks` array in the `scaffoldConfig` object. You can use the [list of chains that viem provides](https://github.com/wevm/viem/blob/main/src/chains/index.ts){target=\_blank} to specify the chain(s) you've deployed your contract to. === "Moonbeam" ```js targetNetworks: [chains.moonbeam], ``` === "Moonriver" ```js targetNetworks: [chains.moonriver], ``` === "Moonbase Alpha" ```js targetNetworks: [chains.moonbaseAlpha], ``` === "Moonbeam Dev Node" ```js targetNetworks: [chains.moonbeamDev], ``` That's all you have to do to configure Next.js! Next, you can launch the dApp. ### Launch the DApp {: #launch-the-dapp } After all the modifications to the configuration files are done, you can launch the example dApp. To do so, you can run: ```bash yarn start ```
yarn start ▲ Next.js 14.2.11 - Local: http://localhost:3000 ✓ Starting... Downloading swc package @next/swc-darwin-arm64... ✓ Ready in 3.7s ○ Compiling / ... 🌼 daisyUI 4.12.10 ├─ ✔︎ 2 themes added https://daisyui.com/docs/themes ╰─ ★ Star daisyUI on GitHub https://github.com/saadeghi/daisyui ✓ Compiled / in 10.8s (7727 modules) GET / 200 in 11353ms HEAD / 200 in 31ms
This will launch the React-based DApp frontend at `http://localhost:3000/` by default. You can then point your browser to `http://localhost:3000/` and interact with the React frontend by connecting your wallet or checking out the contract debugger page. ![The frontend of the DApp on the browser.](/images/builders/ethereum/dev-env/scaffold-eth/new/scaffold-eth-1.webp) And that's it! Now that you have the basics down, feel free to create and deploy your own smart contracts and modify the frontend to fit your dApp's needs! For more information, you can check out the [Scaffold-ETH 2 docs](https://docs.scaffoldeth.io){target=\_blank}.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/dev-env/tenderly/ --- BEGIN CONTENT --- --- title: Tenderly Development Platform description: Learn how to use Tenderly, an Ethereum development platform, to build, debug, and monitor Solidity smart contracts on Moonbeam. categories: Dev Environments, Ethereum Toolkit --- # Using Tenderly on Moonbeam ## Introduction {: #introduction } [Tenderly](https://tenderly.co){target=\_blank} is a Web3 development platform that contains a suite of tools designed to help developers throughout the DApp development life cycle. With Tenderly, you can build, debug, test, optimize, monitor, set up alerts, and view analytics for your smart contracts on Moonbeam and Moonriver. The Tenderly platform provides the following features: - **[Contract Verification](https://docs.tenderly.co/contract-verification){target=\_blank}** - as it is essential to verify your smart contracts to take full advantage of all of Tenderly's features, Tenderly provides several methods of verification. You can verify smart contracts through [the Tenderly dashboard](https://docs.tenderly.co/contract-verification/dashboard){target=\_blank}, [the Tenderly CLI and Foundry](https://docs.tenderly.co/contract-verification/foundry){target=\_blank}, or [the Tenderly Hardhat plugin](https://docs.tenderly.co/contract-verification/hardhat){target=\_blank} - **[Debugger](https://docs.tenderly.co/debugger){target=\_blank}** - use the visual debugger to inspect transactions and get better insight into the behavior of your code. With the debugger, you can review a transaction's stack trace, view the calls made in a transaction, step through a contract, and review decoded inputs, outputs, and state variables. You can use the debugger on the Tenderly dashboard or the [Tenderly Debugger Chrome Extension](https://docs.tenderly.co/debugger/dev-toolkit-browser-extension){target=\_blank} - **[Gas Profiler](https://docs.tenderly.co/debugger/gas-profiler){target=\_blank}** - view how much gas you're spending on a granular level, so you can optimize your smart contracts and reduce transaction gas costs - **[Simulator](https://docs.tenderly.co/simulator-ui){target=\_blank}** - simulate transactions in a TestNet development environment to learn how your transactions will behave without having to send them on-chain. This way, you can know the transaction's outcome and ensure it works as expected before sending it to the network. You can experiment with different parameters, simulate historical and current transactions, and edit the contract source code. You can access the simulator from the Tenderly dashboard, or you can use the [Tenderly Simulation API](https://docs.tenderly.co/reference/api#tag/Simulations){target=\_blank} to take advantage of the simulator programmatically - **[Virtual TestNets](https://docs.tenderly.co/virtual-testnets){target=\_blank}** - simulate the live Moonbeam network in an isolated environment to interact with deployed contracts and real-time on-chain data. These test environments enable controlled development, testing, and debugging across smart contracts, UI, backend, and data indexing. They support sequential transaction simulations for complex scenarios. There are some limitations to be aware of when using this feature. [Moonbeam precompiled contracts](/builders/ethereum/precompiles/overview){target=\_blank} are not supported, as they are part of the Substrate implementation and cannot be replicated in the simulated EVM environment, prohibiting you from interacting with cross-chain assets, staking, and governance. - **[Alerting](https://docs.tenderly.co/alerts/intro-to-alerts){target=\_blank}** - configure real-time alerts to notify you whenever a specific event occurs, allowing you to stay informed about what's going on with your smart contracts - **[Web3 Actions](https://docs.tenderly.co/web3-actions/intro-to-web3-actions){target=\_blank}** - create programmable functions in JavaScript or TypeScript that are executed automatically by Tenderly when a specific smart contract or chain event occurs !!! note Tenderly supports Moonbeam, Moonriver, and Moonbase Alpha, except for the Web3 Gateway. For more information, check out Tenderly's documentation on [Supported Networks](https://docs.tenderly.co/supported-networks#supported-networks){target=\_blank}. ## Getting Started The Tenderly dashboard provides access to an all-in-one Web3 development platform. To get started with the dashboard, you'll need to [sign up](https://dashboard.tenderly.co/register){target=\_blank} for an account. Once you've signed up, you'll be able to start exploring your Tenderly dashboard. ![Tenderly dashboard](/images/builders/ethereum/dev-env/tenderly/tenderly-1.webp) If you prefer not to set up an account, you can also access limited features using [Tenderly's explorer](https://dashboard.tenderly.co/explorer){target=\_blank}. Without an account, you can still gain insights into contracts and transactions. However, you won't be able to simulate transactions or create Virtual TestNets. To interact with Tenderly's features programmatically, you can check out the [Tenderly CLI](https://github.com/Tenderly/tenderly-cli){target=\_blank} GitHub repository for more information. The following sections will show you how to get started with Tenderly on Moonbeam. For more detailed documentation, please refer to [Tenderly's documentation site](https://docs.tenderly.co){target=\_blank}. ### Add a Contract {: #add-a-contract } A good place to start with the Tenderly dashboard is to add a deployed smart contract. Once you've added a contract, you'll be able to create transaction simulations and Virtual TestNets, use the debugger, set up monitoring and alerts, and more. To add a new contract, you can click on **Contracts** on the left-side panel and click **Add Contract**. A pop-up will appear, and you can take the following steps: 1. Enter the contract address 2. (Optional) You can give your contract a name 3. Choose **Moonbeam**, **Moonriver**, or **Moonbase Alpha** as the network, depending on which network you've deployed your smart contract to 4. (Optional) Toggle the **Add more** slider to add additional contracts after the initial one 5. Finally, to add the contract to the dashboard, click **Save** ![Add a contract](/images/builders/ethereum/dev-env/tenderly/tenderly-2.webp) After a contract has been added, it will appear in the list of contracts on the **Contracts** dashboard. If the contract hasn't been verified yet, the dashboard will display an **Unverified** status along with a **Verify** button. ![Contract in list of contracts](/images/builders/ethereum/dev-env/tenderly/tenderly-3.webp) To take full advantage of the Tenderly tool set, it is recommended that you verify your smart contracts, which you can do by clicking on **Verify**. You can choose to verify your contract by uploading the contract's JSON, ABI, or source code. For more information, please refer to Tenderly's documentation on [Smart Contract Verification](https://docs.tenderly.co/contract-verification#verifying-a-smart-contract){target=\_blank}. ### Create a Virtual TestNet {: #virtual-testnets-moonbeam } Tenderly's Virtual TestNets feature simulates the live Moonbeam network in an isolated environment, which enables you to interact with deployed contracts and live on-chain data. There are some limitations to be aware of when using this feature. You cannot interact with any of the [Moonbeam precompiled contracts](/builders/ethereum/precompiles/){target=\_blank} and their functions. Precompiles are a part of the Substrate implementation and, therefore, cannot be replicated in the simulated EVM environment. This prohibits you from interacting with cross-chain assets on Moonbeam and Substrate-based functionality such as staking and governance. Tenderly makes creating a TestNet through the dashboard quite simple. To get started, click on **Virtual TestNets** on the left-side menu and then click **Create Virtual TestNet**. From there, you can take the following steps: 1. Select **Moonbeam**, **Moonriver**, or **Moonbase Alpha** from the **Parent network** dropdown 2. (Optional) Give your TestNet a name 3. Select your **Chain ID**; you can use a custom one or the original network ID. It is recommended to set a custom Chain ID to prevent replay attacks and avoid issues when adding the Virtual TestNet to wallets 4. Choose whether to turn on or off the **Public Explorer** 5. Enable **State Sync** if you want to keep your Virtual TestNet updated in real-time with the parent network 6. To limit data, disable **Use latest block** and enter a block number, or keep it enabled to include all blocks 7. Click **Create** ![Virtual TestNet Moonbeam](/images/builders/ethereum/dev-env/tenderly/tenderly-4.webp) Once you've created your Virtual TestNet, you can start using it by deploying a contract or creating a transaction simulation. To deploy a contract, go to Contracts in the left menu. Use one from **Watched Contracts** or add a new one via **Watch Contract**. Once added, it will appear in **Contracts**, where you can view its details. To create a simulation, click the **Simulation** button and enter the configurations for the simulation. For more information on simulations, please refer to Tenderly's [Simulator UI Overview](https://docs.tenderly.co/simulator-ui/using-simulation-ui){target=\_blank} documentation. ![TestNet simulations](/images/builders/ethereum/dev-env/tenderly/tenderly-5.webp) Now that you've learned how to get started with a few of Tenderly's features on Moonbeam, please feel free to dive in and check out the other tools available in their development platform. You can visit [Tenderly's documentation site](https://docs.tenderly.co){target=\_blank} for more information. You can also check out Moonbeam's tutorial on [Using Tenderly to Simulate and Debug Transactions](/tutorials/eth-api/using-tenderly/){target=\_blank}.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/dev-env/thirdweb/ --- BEGIN CONTENT --- --- title: How to use thirdweb description: This guide will show you some of thirdweb's features, including building, testing, and deploying smart contract templates to launch dApps on Moonbeam. categories: Dev Environments, Ethereum Toolkit --- # Using thirdweb on Moonbeam ## Introduction {: #introduction } [thirdweb](https://thirdweb.com){target=\_blank} is a complete Web3 development framework that provides everything you need to develop smart contracts, build dApps, and more. With thirdweb, you can access tools to help you through every phase of the dApp development cycle. You can create your own custom smart contracts or use any of thirdweb's prebuilt contracts to get started quickly. From there, you can use thirdweb's CLI to deploy your smart contracts. Then you can interact with your smart contracts by creating a Web3 application using the language of your choice, including but not limited to React and TypeScript. This guide will show you some of the thirdweb features you can use to develop smart contracts and dApps on Moonbeam. To check out all of the features thirdweb has to offer, please refer to the [thirdweb documentation site](https://portal.thirdweb.com){target=\_blank}. For a comprehensive step-by-step tutorial for building a dApp on Moonbeam with thirdweb, be sure to check out Moonbeam's [thirdweb tutorial in the tutorials section](/tutorials/eth-api/thirdweb/). ## Create Contract {: #create-contract } To create a new smart contract using the [thirdweb CLI](https://portal.thirdweb.com/cli){target=\_blank}, follow these steps: 1. In your CLI, run the following command: ```bash npx thirdweb create contract ``` 2. Input your preferences for the command line prompts: 1. Give your project a name 2. Choose your preferred framework: **Hardhat** or **Foundry** 3. Name your smart contract 4. Choose the type of base contract: **Empty**, [**ERC20**](https://portal.thirdweb.com/tokens/build/base-contracts/erc-20/base){target=\_blank}, [**ERC721**](https://portal.thirdweb.com/tokens/build/base-contracts/erc-721/base){target=\_blank}, or [**ERC1155**](https://portal.thirdweb.com/tokens/build/base-contracts/erc-1155/base){target=\_blank} 5. Add any desired [extensions](https://portal.thirdweb.com/tokens/build/extensions){target=\_blank} 3. Once created, navigate to your project’s directory and open in your preferred code editor 4. If you open the `contracts` folder, you will find your smart contract; this is your smart contract written in Solidity The following is code for an `ERC721Base` contract without specified extensions. It implements all of the logic inside the [`ERC721Base.sol`](https://github.com/thirdweb-dev/contracts/blob/main/contracts/base/ERC721Base.sol){target=\_blank} contract; which implements the [`ERC721A`](https://github.com/thirdweb-dev/contracts/blob/main/contracts/eip/ERC721A.sol){target=\_blank} standard. ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import '@thirdweb-dev/contracts/base/ERC721Base.sol'; contract Contract is ERC721Base { constructor( string memory _name, string memory _symbol, address _royaltyRecipient, uint128 _royaltyBps ) ERC721Base(_name, _symbol, _royaltyRecipient, _royaltyBps) {} } ``` This contract inherits the functionality of `ERC721Base` through the following steps: - Importing the `ERC721Base` contract - Inheriting the contract by declaring that your contract is an `ERC721Base` contract - Implementing any required methods, such as the constructor 5. After modifying your contract with your desired custom logic, you can deploy it to Moonbeam. That will be covered in the next section! Alternatively, you can deploy a prebuilt contract for NFTs, tokens, or marketplace directly from the thirdweb Explore page: 1. Go to the [thirdweb Explore page](https://thirdweb.com/explore){target=\_blank} ![thirdweb Explore](/images/builders/ethereum/dev-env/thirdweb/thirdweb-1.webp) 2. Choose the type of contract you want to deploy from the available options: NFTs, tokens, marketplace, and more 3. Follow the on-screen prompts to configure and deploy your contract For more information on different contracts available on Explore, check out [thirdweb’s documentation on prebuilt contracts](https://portal.thirdweb.com/contracts){target=\_blank}. ## Deploy a Contract {: #deploy-contract } thirdweb allows you to easily deploy a smart contract to any EVM compatible network without configuring RPC URLs, exposing your private keys, writing scripts, and other additional setup such as verifying your contract. 1. To deploy your smart contract using the CLI, navigate to the `contracts` directory of your project and execute the following command: ```bash npx thirdweb deploy ``` Executing this command will trigger the following actions: - Compiling all the contracts in the current directory - Providing the option to select which contract(s) you wish to deploy - Uploading your contract source code (ABI) to IPFS 2. When it is completed, it will open a dashboard interface to finish filling out the parameters - `_name` - contract name - `_symbol` - symbol or "ticker" - `_royaltyRecipient` - wallet address to receive royalties from secondary sales - `_royaltyBps` - basis points (bps) that will be given to the royalty recipient for each secondary sale, e.g. 500 = 5% 3. Select the desired Moonbeam network, e.g., Moonbeam, Moonriver, or Moonbase Alpha 4. Manage additional settings on your contract’s dashboard as needed such as uploading NFTs, configuring permissions, and more ![thirdweb deploy](/images/builders/ethereum/dev-env/thirdweb/thirdweb-2.webp) For additional information on deploying contracts, please reference [thirdweb’s documentation](https://portal.thirdweb.com/contracts/deploy){target=\_blank}. ## Create Application {: #create-application } thirdweb offers SDKs for a range of programming languages, such as React, React Native, TypeScript, and Unity. You'll start off by creating an application and then you can choose which SDK to use: 1. In your CLI run the following command: ```bash npx thirdweb create --app ``` 2. Input your preferences for the command line prompts: 1. Give your project a name 2. Choose your preferred framework: **Next.js**, **Vite**, or **React Native**. For this example, select **Vite** 3. Use the React or TypeScript SDK to interact with your application’s functions. This will be covered in the following section on interacting with a contract ### Specify Client ID {: #specify-client-id } Before you launch your dApp (locally or publicly deployed), you must have a thirdweb Client ID associated with your project. A thirdweb Client ID is synonymous with an API key. You can create a free API key by [signing into your thirdweb account, navigating to **Settings**, and clicking on **API Keys**](https://thirdweb.com/dashboard/settings/api-keys){target=\_blank}. Press **Create API Key** then take the following steps: 1. Give your API key a name 2. Enter the allowed domains that the API key should accept requests from. It's recommended that you allow only necessary domains, but for development purposes, you can select **Allow all domains** 3. Press **Next** and confirm the prompt on the next page ![thirdweb create API key](/images/builders/ethereum/dev-env/thirdweb/thirdweb-3.webp) !!! note The respective name for your Client ID variable will vary with the framework you've chosen, e.g., Vite will be `VITE_TEMPLATE_CLIENT_ID`, Next.js will be `NEXT_PUBLIC_TEMPLATE_CLIENT_ID`, and React Native will be `EXPO_PUBLIC_THIRDWEB_CLIENT_ID`. Finally, specify your Client ID (API Key) in your `.env` file. Your `.env` file must be located at the root directory of the project (e.g., not the `src` folder). If you generated your thirdweb app with Vite, you'll have a `client.ts` file that looks like the below. As long you've created a `.env` file with your thirdweb API Key (Client ID) defined in `VITE_TEMPLATE_CLIENT_ID`, you can leave the `client.ts` as is and proceed to the next section. ```typescript title="client.ts" import { createThirdwebClient } from 'thirdweb'; // Replace this with your client ID string. // Refer to https://portal.thirdweb.com/typescript/v5/client on how to get a client ID const clientId = import.meta.env.VITE_TEMPLATE_CLIENT_ID; export const client = createThirdwebClient({ clientId: clientId, }); ``` !!! note If you don't create a Client ID and specify is correctly in your `.env` file, you'll get a blank screen when trying to build the web app. There is no error message shown without digging into the console, so ensure you've set your Client ID correctly first and foremost. ### Run Locally {: #run-locally } To run your dApp locally for testing and debugging purposes, use the command: ```bash yarn dev ``` The app will compile and specify the localhost and port number for you to visit in your browser. ![thirdweb run locally](/images/builders/ethereum/dev-env/thirdweb/thirdweb-4.webp) ### Configure Chain {: #configure-chain } thirdweb offers a small number of chains from `@thirdweb/chains` and does not include Moonbeam networks in that list, so you'll need to specify the network details including chain ID and RPC URL. You can create a custom chain with [`defineChain`](https://portal.thirdweb.com/references/typescript/v5/defineChain){target=\_blank} as follows: === "Moonbeam" ```typescript title="chains.ts" import { defineChain } from 'thirdweb'; const moonbeam = defineChain({ id: {{ networks.moonbeam.chain_id }}, rpc: '{{ networks.moonbeam.public_rpc_url }}', }); ``` === "Moonriver" ```typescript title="chains.ts" import { defineChain } from 'thirdweb'; const moonriver = defineChain({ id: {{ networks.moonriver.chain_id }}, rpc: '{{ networks.moonriver.public_rpc_url }}', }); ``` === "Moonbase Alpha" ```typescript title="chains.ts" import { defineChain } from 'thirdweb'; const moonbase = defineChain({ id: {{ networks.moonbase.chain_id }}, rpc: '{{ networks.moonbase.rpc_url }}', }); ``` ## thirdweb SDK {: #thirdweb-sdk } The following sections will provide an overview of fundamental methods of the thirdweb SDK and how to interact with them. Each code snippet will showcase the relevant import statements and demonstrate using the method in a typical scenario. This guide is intended to be a quick reference guide to the most common thirdweb methods that dApp developers will use. However, it does not include information on each and every thirdweb offering. For details on the entirety of thirdweb's offerings, be sure to visit the [thirdweb documentation site](https://portal.thirdweb.com/){target=\_blank}. For a comprehensive, step-by-step guide to building a dApp with thirdweb be sure to check out Moonbeam's [thirdweb tutorial in the tutorials section](/tutorials/eth-api/thirdweb/). The following sections will cover everything from connecting wallets, to preparing transactions, and more. ### Accounts and Wallets {: #accounts-and-wallets } thirdweb distinguishes between accounts and wallets in the SDK. In the eyes of the thirdweb SDK, an account always has a single blockchain address and can sign messages, transactions, and typed data, but it cannot be "connected" or "disconnected." In contrast, a wallet contains one or more accounts, can be connected or disconnected, and delegates the signing tasks to its accounts. The below code snippet demonstrates how to initialize and connect a MetaMask wallet using the thirdweb SDK, then sign and send a transaction, retrieving the transaction hash. This process is applicable to any of the 300+ wallet connectors supported by the SDK. ???+ code "initialize.ts" ```typescript import { sendTransaction } from 'thirdweb'; // MetaMask wallet used for example, the pattern is the same for all wallets import { createWallet } from 'thirdweb/wallets'; // Initialize the wallet. thirdweb supports 300+ wallet connectors const wallet = createWallet('io.metamask'); // Connect the wallet. This returns a promise that resolves to the connected account const account = await wallet.connect({ // Pass the client you created with `createThirdwebClient()` client, }); // Sign and send a transaction with the account. Returns the transaction hash const { transactionHash } = await sendTransaction({ // Assuming you have called `prepareTransaction()` or `prepareContractCall()` before, which returns the prepared transaction to send transaction, // Pass the account to sign the transaction with account, }); ``` ### Get Contract {: #get-contract } To connect to your contract, use the SDK’s [`getContract`](https://portal.thirdweb.com/references/typescript/v5/getContract){target=\_blank} method. As an example, you could fetch data from an [incrementer contract on Moonbase Alpha](https://moonbase.moonscan.io/address/0xa72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8){target=\_blank}. ```typescript import { getContract } from 'thirdweb'; import { client } from './client'; const myContract = getContract({ client, chain: moonbase, address: 0xa72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8, // Incrementer contract address on Moonbase Alpha abi: '[{"inputs":[],"name":"increment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"number","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"timestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]'; }); ``` ### Calling Contract Functions {: #calling-contract-functions } To call a contract in the latest version of the SDK, you can use [`prepareContractCall`](https://portal.thirdweb.com/typescript/v5/transactions/prepare){target=\_blank}. ```typescript import { prepareContractCall, toWei } from 'thirdweb'; const tx = prepareContractCall({ contract, // Pass the method signature that you want to call method: 'function mintTo(address to, uint256 amount)', // Pass the params for that method. // Their types are automatically inferred based on the method signature params: ['0x123...', toWei('100')], }); ``` Returning to our [incrementer contract](https://moonbase.moonscan.io/address/0xa72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8){target=\_blank}, preparing a call to increment the contract looks like the following: ```typescript import { prepareContractCall } from 'thirdweb'; const tx = prepareContractCall({ contract, // Pass the method signature that you want to call method: 'function increment()', // Increment takes no params so we are leaving an empty array params: [], }); ``` ### Preparing Raw Transactions {: #preparing-raw-transactions } You can also prepare a transaction directly with encoded data. To do so, you'll use thirdweb's [`prepareTransaction` method](https://portal.thirdweb.com/typescript/v5/transactions/prepare){target=\_blank} and specify the `to`, `value`, `chain`, and `client` values directly. ```typescript import { prepareTransaction, toWei } from 'thirdweb'; const transaction = prepareTransaction({ // The account that will be the receiver to: '0x456...', // The value is the amount of ether you want to send with the transaction value: toWei('1'), // The chain to execute the transaction on. This assumes you already set up // moonbase as a custom chain as shown in the configure chain section chain: moonbase, // Your thirdweb client client, }); ``` ### Reading Contract State {: #read-contract-state } Use the [`readContract` function](https://portal.thirdweb.com/typescript/v5/transactions/read){target=\_blank} to call any read functions on your contract by passing in the Solidity method signature and any parameters. ```typescript import { readContract } from 'thirdweb'; const balance = await readContract({ contract: contract, method: 'function balanceOf(address) view returns (uint256)', params: ['0x123...'], }); ``` For a function that takes no parameters, such as the number function that returns the current number stored in the [incrementer contract](https://moonbase.moonscan.io/address/0xa72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8){target=\_blank}, you simply need to provide the function name as follows: ```typescript import { readContract } from 'thirdweb'; const number = await readContract({ contract: contract, method: 'number', params: [], }); ``` Did you know? With the [thirdweb CLI](https://portal.thirdweb.com/cli){target=\_blank}, you can easily and generate functions for all of the possible calls to a contract. To do so, run the following command in the command line: ```bash npx thirdweb generate INSERT_CHAIN_ID/INSERT_CONTRACT_ADDRESS ``` Both the chain ID and the contract address are required. As an example, if you wanted to generate the functions for the [incrementer contract on Moonbase Alpha](https://moonbase.moonscan.io/address/0xa72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8){target=\_blank} , you would use the following command: ```bash npx thirdweb generate 1287/0xa72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8 ``` The file generated with all of the corresponding methods will be placed in a directory labelled `thirdweb/CHAIN_ID/CONTRACT_ADDRESS`. In the example shown above, the output file is located at `thirdweb/1287/0xa72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8.ts`. For more information, see the [thirdweb's docs on the CLI](https://portal.thirdweb.com/cli/generate){target=\_blank}. ### Sending a Transaction {: #sending-a-transaction } Every transaction sent using the SDK must first be prepared. This preparation process is synchronous and lightweight, requiring no network requests. Additionally, it provides type-safe definitions for your contract calls. You can prepare a transaction as follows: ```typescript title="Prepare a transaction" import { prepareTransaction, toWei } from 'thirdweb'; const transaction = prepareTransaction({ to: '0x1234567890123456789012345678901234567890', chain: moonbase, client: thirdwebClient, value: toWei('1.0'), gasPrice: 150n, }); ``` After the transaction is prepared, you can send it as follows: ```typescript title="Send a transaction" import { sendTransaction } from 'thirdweb'; const { transactionHash } = await sendTransaction({ account, transaction, }); ``` You can optionally use `sendAndConfirmTransaction` to wait for the transaction to be mined. This is relevant if you want to block the user from continuing until the transaction is confirmed. ```typescript title="Send and Confirm a Transaction" import { sendAndConfirmTransaction } from 'thirdweb'; import { createWallet } from 'thirdweb/wallets'; const wallet = createWallet('io.metamask'); const account = await wallet.connect({ client }); const receipt = await sendAndConfirmTransaction({ transaction, account, }); ``` ### Transaction Utilities {: #transaction-utilities } thirdweb provides a number of helpful utility methods surrounding preparing and sending transactions. You can estimate the gas used by a transaction as follows: ```typescript title="Estimating gas" import { estimateGas } from 'thirdweb'; const gasEstimate = await estimateGas({ transaction }); console.log('estmated gas used', gasEstimate); ``` You can estimate the gas cost in Ether and Wei as follows: ```typescript title="Estimating gas cost" import { estimateGas } from 'thirdweb'; const gasCost = await estimateGasCost({ transaction }); console.log('cost in ether', gasCost.ether); ``` thirdweb also provides a handy way to simulate transactions and verify their integrity before actually submitting it to the blockchain. You can simulate a transaction as follows: ```typescript title="Simulate a transaction" import { simulateTransaction } from 'thirdweb'; const result = await simulateTransaction({ transaction }); console.log('simulation result', result); ``` You can encode transaction data to act on later by taking the following steps: ```typescript title="Encode transaction data" import { encode } from 'thirdweb'; const data = await encode(transaction); console.log('encoded data', data); ``` ### ConnectButton {: #connect-button } Perhaps the first and most important interaction users will have with your dApp is connecting their wallet. thirdweb provides an easy and highly customizable way for you to enable this. thirdweb provides a highly customizable [`ConnectButton`](https://portal.thirdweb.com/react/v5/components/ConnectButton){target=\_blank} to tailor it to your desired wallets. The `ConnectButton` accepts an optional `wallets` parameter with an array of wallets. You can add or remove wallets from the `wallets` array to change the options available to users. thirdweb also offers a [`ConnectButton` Playground](https://thirdweb.com/dashboard/connect/playground){target=\_blank} to customize and view changes for the `ConnectButton` in real-time, given the button's high degree of flexibility. ```typescript title="ConnectButton" import { ConnectButton } from 'thirdweb/react'; import { createWallet, inAppWallet } from 'thirdweb/wallets'; const wallets = [ inAppWallet(), createWallet('io.metamask'), createWallet('com.coinbase.wallet'), createWallet('me.rainbow'), ]; function Example() { return (
); } ``` ## Deploy Application {: #deploy-application } As a reminder, you can build your example project locally by running: ```bash yarn dev ``` To host your static web application on decentralized storage, run: ```bash npx thirdweb deploy --app ``` By running this command, your application is built for production and stored using [Storage](https://portal.thirdweb.com/infrastructure/storage/overview){target=\_blank}, thirdweb's decentralized file management solution. The built application is uploaded to IPFS, a decentralized storage network, and a unique URL is generated for your application. This URL serves as a permanent hosting location for your application on the web. If you have any further questions or encounter any issues during the process, please reach out to thirdweb support at [support.thirdweb.com](http://support.thirdweb.com){target=\_blank}.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/dev-env/waffle-mars/ --- BEGIN CONTENT --- --- title: Deploy Smart Contracts with Waffle & Mars description: Learn how to use Waffle and Mars to write, compile, test, and deploy Ethereum smart contracts on Moonbeam. categories: Dev Environments, Ethereum Toolkit --- # Using Waffle & Mars to Deploy to Moonbeam ## Introduction {: #introduction } [Waffle](https://getwaffle.io){target=\_blank} is a library for compiling and testing smart contracts, and [Mars](https://github.com/TrueFiEng/Mars){target=\_blank} is a deployment manager. Together, Waffle and Mars can be used to write, compile, test, and deploy Ethereum smart contracts. Since Moonbeam is Ethereum compatible, Waffle and Mars can be used to deploy smart contracts to a [Moonbeam development node](/builders/get-started/networks/moonbeam-dev/){target=\_blank} or the [Moonbase Alpha TestNet](/builders/get-started/networks/moonbase/){target=\_blank}. Waffle uses minimal dependencies, has syntax that is easy to learn and extend, and provides fast execution times when compiling and testing smart contracts. Furthermore, it is [TypeScript](https://www.typescriptlang.org){target=\_blank} compatible and uses [Chai matchers](https://ethereum-waffle.readthedocs.io/en/latest/matchers.html){target=\_blank} to make tests easy to read and write. Mars provides a simple, TypeScript compatible framework for creating advanced deployment scripts and staying in sync with state changes. Mars focuses on infrastructure-as-code, allowing developers to specify how their smart contracts should be deployed and then using those specifications to automatically handle state changes and deployments. In this guide, you'll be creating a TypeScript project to write, compile, and test a smart contract using Waffle, then deploy it on to the Moonbase Alpha TestNet using Mars. ## Checking Prerequisites {: #checking-prerequisites } You will need to have the following: - MetaMask installed and [connected to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank} - An account with funds. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} - To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank} Once you've created an account you'll need to export the private key to be used in this guide. ## Create a TypeScript Project with Waffle & Mars {: #create-a-typescript-project-with-waffle-mars } To get started, you'll create a TypeScript project and install and configure a few dependencies. 1. Create the project directory and change to it: ```bash mkdir waffle-mars && cd waffle-mars ``` 2. Initialize the project. Which will create a `package.json` in the directory: ```bash npm init -y ``` 3. Install the following dependencies: ```bash npm install ethereum-waffle ethereum-mars ethers \ @openzeppelin/contracts typescript ts-node chai \ @types/chai mocha @types/mocha ``` - [Waffle](https://github.com/TrueFiEng/Waffle) - for writing, compiling, and testing smart contracts - [Mars](https://github.com/TrueFiEng/Mars) - for deploying smart contracts to Moonbeam - [Ethers](https://github.com/ethers-io/ethers.js) - for interacting with Moonbeam's Ethereum API - [OpenZeppelin Contracts](https://github.com/OpenZeppelin/openzeppelin-contracts) - the contract you'll be creating will use OpenZeppelin's ERC-20 base implementation - [TypeScript](https://github.com/microsoft/TypeScript) - the project will be a TypeScript project - [TS Node](https://github.com/TypeStrong/ts-node) - for executing the deployment script you'll create later in this guide - [Chai](https://github.com/chaijs/chai) - an assertion library used alongside Waffle for writing tests - [@types/chai](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/chai) - contains the type definitions for chai - [Mocha](https://github.com/mochajs/mocha) - a testing framework for writing tests alongside Waffle - [@types/mocha](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/mocha) - contains the type definitions for mocha 4. Create a [TypeScript configuration](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) file: ```bash touch tsconfig.json ``` 5. Add a basic TypeScript configuration: ```json { "compilerOptions": { "strict": true, "target": "ES2019", "moduleResolution": "node", "resolveJsonModule": true, "esModuleInterop": true, "module": "CommonJS", "composite": true, "sourceMap": true, "declaration": true, "noEmit": true } } ``` Now, you should have a basic TypeScript project with the necessary dependencies to get started building with Waffle and Mars. ## Add a Contract {: #add-a-contract } For this guide, you will create an ERC-20 contract that mints a specified amount of tokens to the contract creator. It's based on the OpenZeppelin ERC-20 template. 1. Create a directory to store your contracts and a file for the smart contract: ```bash mkdir contracts && cd contracts && touch MyToken.sol ``` 2. Add the following contract to `MyToken.sol`: ```solidity pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract MyToken is ERC20 { constructor() ERC20("MyToken", "MYTOK") {} function initialize(uint initialSupply) public { _mint(msg.sender, initialSupply); } } ``` In this contract, you are creating an ERC-20 token called MyToken with the symbol MYTOK, that allows you, as the contract creator, to mint as many MYTOKs as desired. ## Use Waffle to Compile and Test {: #use-waffle-to-compile-and-test } ### Compile with Waffle {: #compile-with-waffle } Now that you have written a smart contract, the next step is to use Waffle to compile it. Before diving into compiling your contract, you will need to configure Waffle: 1. Go back to the root project directory and create a `waffle.json` file to configure Waffle: ```bash cd .. && touch waffle.json ``` 2. Edit the `waffle.json` to specify compiler configurations, the directory containing your contracts, and more. For this example, we'll use `solcjs` and the Solidity version you used for the contract, which is `0.8.0`: ```json { "compilerType": "solcjs", "compilerVersion": "0.8.0", "compilerOptions": { "optimizer": { "enabled": true, "runs": 20000 } }, "sourceDirectory": "./contracts", "outputDirectory": "./build", "typechainEnabled": true } ``` 3. Add a script to run Waffle in the `package.json`: ```json "scripts": { "build": "waffle" }, ``` That is all you need to do to configure Waffle, now you're all set to compile the `MyToken` contract using the `build` script: ```bash npm run build ```
npm run build >waffle-mars@1.0.0 build >waffle Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: «SPDX-License>" to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. --> contracts/MyToken.sol
After compiling your contracts, Waffle stores the JSON output in the `build` directory. Since the contract in this guide is based on OpenZeppelin's ERC-20 template, relevant ERC-20 JSON files will appear in the `build` directory too. ### Test with Waffle {: #test-with-waffle } Before deploying your contract and sending it off into the wild, you should test it first. Waffle provides an advanced testing framework and has plenty of tools to help you with testing. You'll be running tests against the Moonbase Alpha TestNet and will need the corresponding RPC URL to connect to it: `{{ networks.moonbase.rpc_url }}`. To configure your project for Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. Since you will be running tests against the TestNet, it might take a couple minutes to run all of the tests. If you want a more efficient testing experience, you can [spin up a Moonbeam development node](/builders/get-started/networks/moonbeam-dev/){target=\_blank} using [`instant seal`](/builders/get-started/networks/moonbeam-dev/#node-options){target=\_blank}. Running a local Moonbeam development node with the `instant seal` feature is similar to the quick and iterative experience you would get with [Hardhat Network](https://hardhat.org/hardhat-network/docs/overview){target=\_blank}. 1. Create a directory to contain your tests and a file to test your `MyToken` contract: ```bash mkdir test && cd test && touch MyToken.test.ts ``` 2. Open the `MyToken.test.ts` file and setup your test file to use Waffle's Solidity plugin and use Ethers custom JSON-RPC provider to connect to Moonbase Alpha: ```typescript import { use, expect } from 'chai'; import { Provider } from '@ethersproject/providers'; import { solidity } from 'ethereum-waffle'; import { ethers, Wallet } from 'ethers'; import { MyToken, MyTokenFactory } from '../build/types'; // Tell Chai to use Waffle's Solidity plugin use(solidity); describe ('MyToken', () => { // Use custom provider to connect to Moonbase Alpha let provider: Provider = new ethers.providers.JsonRpcProvider( '{{ networks.moonbase.rpc_url }}' ); let wallet: Wallet; let walletTo: Wallet; let token: MyToken; beforeEach(async () => { // Logic for setting up the wallet and deploying MyToken will go here }); // Tests will go here }) ``` 3. Before each test is run, you'll want to create wallets and connect them to the provider, use the wallets to deploy an instance of the `MyToken` contract, and then call the `initialize` function once with an initial supply of 10 tokens: ```typescript beforeEach(async () => { // This is for demo purposes only. Never store your private key in a JavaScript/TypeScript file const privateKey = 'INSERT_PRIVATE_KEY' // Create a wallet instance using your private key & connect it to the provider wallet = new Wallet(privateKey).connect(provider); // Create a random account to transfer tokens to & connect it to the provider walletTo = Wallet.createRandom().connect(provider); // Use your wallet to deploy the MyToken contract token = await new MyTokenFactory(wallet).deploy(); // Mint 10 tokens to the contract owner, which is you let contractTransaction = await token.initialize(10); // Wait until the transaction is confirmed before running tests await contractTransaction.wait(); }); ``` 4. Now you can create your first test. The first test will check your initial balance to ensure you received the initial supply of 10 tokens. However, to follow good testing practices, write a failing test first: ```typescript it('Mints the correct initial balance', async () => { expect(await token.balanceOf(wallet.address)).to.equal(1); // This should fail }); ``` 5. Before you can run your first test, you'll need to go back to the root direction and add a `.mocharc.json` Mocha configuration file: ```bash cd .. && touch .mocharc.json ``` 6. Now edit the `.mocharc.json` file to configure Mocha: ```json { "require": "ts-node/register/transpile-only", "timeout": 600000, "extension": "test.ts" } ``` 7. You'll also need to add a script in the `package.json` to run your tests: ```json "scripts": { "build": "waffle", "test": "mocha" }, ``` 8. You're all set to run the tests, simply use the `test` script you just created and run: ```bash npm run test ``` Please note that it could take a few minutes to process because the tests are running against Moonbase Alpha, but if all worked as expected, you should have one failing test. 9. Next, you can go back and edit the test to check for 10 tokens: ```typescript it('Mints the correct initial balance', async () => { expect(await token.balanceOf(wallet.address)).to.equal(10); // This should pass }); ``` 10. If you run the tests again, you should now see one passing test: ```bash npm run test ``` 11. You've tested the ability to mint tokens, next you'll test the ability to transfer the minted tokens. If you want to write a failing test first again that is up to, however the final test should look like this: ```typescript it('Should transfer the correct amount of tokens to the destination account', async () => { // Send the destination wallet 7 tokens await (await token.transfer(walletTo.address, 7)).wait(); // Expect the destination wallet to have received the 7 tokens expect(await token.balanceOf(walletTo.address)).to.equal(7); }); ``` Congratulations, you should now have two passing tests! Altogether, your test file should look like this: ```typescript import { use, expect } from 'chai'; import { Provider } from '@ethersproject/providers'; import { solidity } from 'ethereum-waffle'; import { ethers, Wallet } from 'ethers'; import { MyToken, MyTokenFactory } from '../build/types'; use(solidity); describe('MyToken', () => { let provider: Provider = new ethers.providers.JsonRpcProvider( '{{ networks.moonbase.rpc_url }}' ); let wallet: Wallet; let walletTo: Wallet; let token: MyToken; beforeEach(async () => { // For demo purposes only. Never store your private key in a JavaScript/TypeScript file const privateKey = 'INSERT_PRIVATE_KEY'; wallet = new Wallet(privateKey).connect(provider); walletTo = Wallet.createRandom().connect(provider); token = await new MyTokenFactory(wallet).deploy(); let contractTransaction = await token.initialize(10); await contractTransaction.wait(); }); it('Mints the correct initial balance', async () => { expect(await token.balanceOf(wallet.address)).to.equal(10); }); it('Should transfer the correct amount of tokens to the destination account', async () => { await (await token.transfer(walletTo.address, 7)).wait(); expect(await token.balanceOf(walletTo.address)).to.equal(7); }); }); ``` If you want to write more tests on your own, you could consider testing transfers from accounts without any funds or transfers from accounts without enough funds. ## Use Mars to Deploy to Moonbase Alpha {: #use-mars-to-deploy-to-moonbase-alpha } After you compile your contracts and before deployment, you will have to generate contract artifacts for Mars. Mars uses the contract artifacts for typechecks in deployments. Then you'll need to create a deployment script and deploy the `MyToken` smart contract. Remember, you will be deploying to Moonbase Alpha and will need to use the TestNet RPC URL: ```text {{ networks.moonbase.rpc_url }} ``` To configure your project for Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. The deployment will be broken up into three sections: [generate artifacts](#generate-artifacts), [create a deployment script](#create-a-deployment-script), and [deploy with Mars](#deploy-with-mars). ### Generate Artifacts {: #generate-artifacts } Artifacts need to be generated for Mars so that typechecks are enabled within deployment scripts. 1. Update existing script to run Waffle in the `package.json` to include Mars: ```json "scripts": { "build": "waffle && mars", "test": "mocha" }, ``` 2. Generate the artifacts and create the `artifacts.ts` file needed for deployments: ```bash npm run build ```
npm run build
> waffle-mars@1.0.0 build > waffle && mars
Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. --> contracts/MyToken.sol
If you open the `build` directory, you should now see an `artifacts.ts` file containing the artifact data needed for deployments. To continue on with the deployment process, you'll need to write a deployment script. The deployment script will be used to tell Mars which contract to deploy, to what network, and which account is to be used to trigger the deployment. ### Create a Deployment Script {: #create-a-deployment-script } Now you need to configure the deployment for the `MyToken` contract to the Moonbase Alpha TestNet. In this step, you'll create the deployment script which will define how the contract should be deployed. Mars offers a `deploy` function that you can pass options to such as the private key of the account to deploy the contract, the network to deploy to, and more. Inside of the `deploy` function is where the contracts to be deployed are defined. Mars has a `contract` function that accepts the `name`, `artifact`, and `constructorArgs`. This function will be used to deploy the `MyToken` contract with an initial supply of 10 MYTOKs. 1. Create a `src` directory to contain your deployment scripts and create the script to deploy the `MyToken` contract: ```bash mkdir src && cd src && touch deploy.ts ``` 2. In `deploy.ts`, use Mars' `deploy` function to create a script to deploy to Moonbase Alpha using your account's private key: ```javascript import { deploy } from 'ethereum-mars'; // For demo purposes only. Never store your private key in a JavaScript/TypeScript file const privateKey = 'INSERT_PRIVATE_KEY'; deploy( { network: '{{ networks.moonbase.rpc_url }}', privateKey }, (deployer) => { // Deployment logic will go here } ); ``` 3. Set up the `deploy` function to deploy the `MyToken` contract created in the previous steps: ```javascript import { deploy, contract } from 'ethereum-mars'; import { MyToken } from '../build/artifacts'; // For demo purposes only. Never store your private key in a JavaScript/TypeScript file const privateKey = 'INSERT_PRIVATE_KEY'; deploy({ network: '{{ networks.moonbase.rpc_url }}', privateKey }, () => { contract('myToken', MyToken); }); ``` 4. Add a deploy script to the `scripts` object in the `package.json`: ```json "scripts": { "build": "waffle && mars", "test": "mocha", "deploy": "ts-node src/deploy.ts" } ``` So far, you should have created a deployment script in `deploy.ts` that will deploy the `MyToken` contract to Moonbase Alpha, and added the ability to easily call the script and deploy the contract. ### Deploy with Mars {: #deploy-with-mars } You've configured the deployment, now it's time to actually deploy to Moonbase Alpha. 1. Deploy the contract using the script you just created: ```bash npm run deploy ``` 2. In your Terminal, Mars will prompt you to press `ENTER` to send your transaction
npm run deploy
> waffle-mars@1.0.0 deploy > ts-node src/deploy.ts
Transaction: Deploy myToken Fee: $0.00, Ξ0.0 Balance: $4142380208.17,Ξ1207925.819614629174706176 ENTER to submit, Ctrl+C to exit...
If successful, you should see details about your transaction including its hash, the block it was included in, and it's address.
npm run deploy
> waffle-mars@1.0.0 deploy > ts-node src/deploy.ts
Transaction: Deploy myToken Fee: $0.00,Ξ0.0 Balance: Sending Block: 1 $4142380208.17, Ξ1207925.819614629174706176 Hash: Oxfa8bcad89cb8efdabfc@e5575dbe7151ce1c38f8aa67229fd5122bbdafe8b2f9 Address: 0xC2Bf5F29a4384b1aB0C063e1c666f02121B6084a
Congratulations! You've deployed a contract to Moonbase Alpha using Waffle and Mars! ## Example Project {: #example-project } If you want to see a completed example of a Waffle and Mars project on Moonbeam, check out the [moonbeam-waffle-mars-example](https://github.com/EthWorks/moonbeam-waffle-mars-example){target=\_blank} created by the team behind Waffle and Mars, EthWorks.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/ --- BEGIN CONTENT --- --- title: Ethereum API description: Learn how to use the Ethereum API when developing on Moonbeam. This section includes guides on Ethereum libraries, development environments, and more. dropdown_description: Ethereum libraries, tools, and contracts template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/json-rpc/debug-trace/ --- BEGIN CONTENT --- --- title: Debug & Trace Transactions description: Check out the non-standard JSON-RPC methods included in Geth's Debug and Txpool APIs and OpenEthereum's Trace module, which are supported on Moonbeam. categories: JSON-RPC APIs, Ethereum Toolkit --- # Debug API & Trace Module ## Introduction {: #introduction } Geth's [debug](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-debug){target=\_blank} and [txpool](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-txpool){target=\_blank} APIs and OpenEthereum's [trace](https://openethereum.github.io/JSONRPC-trace-module){target=\_blank} module provide non-standard RPC methods for deeper insight into transaction processing. Some of these non-standard RPC methods are supported as part of Moonbeam's goal of providing a seamless Ethereum experience for developers. Supporting these RPC methods is an essential milestone because many projects like [The Graph](https://thegraph.com){target=\_blank} rely on them to index blockchain data. This guide will cover the supported RPC methods available on Moonbeam and how to invoke them using curl commands against a tracing node with the debug, txpool, and tracing flags enabled. You can access a tracing node in one of two ways: through a supported tracing RPC provider or by spinning up a tracing node of your own. To view a list of tracing RPC providers, please check out the [Network Endpoints](/builders/get-started/endpoints/#tracing-providers){target=\_blank} page. If you wish to set up your own tracing node, you can follow the [Running a Tracing Node](/node-operators/networks/tracing-node/){target=\_blank} guide. The RPC HTTP endpoint of your tracing node should be at `{{ networks.development.rpc_url }}` and your node should display similar logs to the following:
docker run --network host \
-u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam-tracing:v0.45.0-3701-a160 \
--name="Moonbean-Tracing-Tutorial" \
--unsafe-rpc-external \
--ethapi=debug,trace,txpool \
--wasm-runtime-overrides=/moonbeam/moonbase-substitutes-tracing \
--runtime-cache-size 64 \
--dev

2025-07-10 09:04:26 Moonbeam Parachain Collator
2025-07-10 09:04:26 ✌️ version 0.46.0-d7df89e7161
2025-07-10 09:04:26 ❤️ by PureStake, 2019-2025
2025-07-10 09:04:26 📋 Chain specification: Moonbase Development Testnet
2025-07-10 09:04:26 🏷 Node name: Moonbean-Tracing-Tutorial
2025-07-10 09:04:26 👤 Role: AUTHORITY
2025-07-10 09:04:26 💾 Database: RocksDb at /tmp/substrateO3YeRz/chains/moonbase_dev/db/full
2025-07-10 09:04:26 Found wasm override. version=moonbase-300 (moonbase-0.tx2.au3) file=/moonbeam/moonbase-substitutes-tracing/moonbase-runtime-300-substitute-tracing.wasm
...
2025-07-10 09:04:26 💤 Idle (0 peers), best: #0 (0x18e6…2eb1), finalized #0 (0x18e6…2eb1), ⬇ 0 ⬆ 0
## Supported Debug and Trace JSON-RPC Methods {: #supported-methods } ???+ function "debug_traceTransaction" This method attempts to replay a transaction in the same manner as it was executed on the network. Refer to [Geth's documentation](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-debug#debugtracetransaction){target=\_blank} for more information. === "Parameters" - `transaction_hash` *string* - the hash of the transaction to be traced - `tracer_config` *string* - (optional) a JSON object for configuring the tracer that contains the following field: - `tracer` *string* - sets the type of tracer If no `tracer_config` is provided, the opcode logger will be the default tracer. The opcode logger provides the following additional fields: - `opcode_config` *string* - (optional) a JSON object for configuring the opcode logger: - `disableStorage` *boolean* — (optional, default: `false`) setting this to `true` disables storage capture - `disableMemory` *boolean* — (optional, default: `false`) setting this to `true` disables memory capture - `disableStack` *boolean* — (optional, default: `false`) setting this to `true` disables stack capture === "Returns" If you supplied a `tracer_config`, the `result` object contains the following fields: - `type` - the type of the call - `from` - the address the transaction is sent from - `to` - the address the transaction is directed to - `value` - the integer of the value sent with this transaction - `gas` - the integer of the gas provided for the transaction execution - `gasUsed` - the integer of the gas used - `input` - the data given at the time of input - `output` - the data which is returned as an output - `error` - the type of error, if any - `revertReason` - the type solidity revert reason, if any - `calls` - a list of sub-calls, if any
If you used the default opcode logger, the `result` object contains the following fields: - `gas`- the integer of the gas provided for the transaction execution - `returnValue` - the output produced by the execution of the transaction - `structLogs` - an array of [objects containing a detailed log of each opcode](https://geth.ethereum.org/docs/developers/evm-tracing/built-in-tracers#struct-opcode-logger){target=\_blank} executed during the transaction - `failed` - a boolean indicating whether the transaction execution failed or succeeded === "Example" Using the `tracer_config`: ```bash curl {{ networks.development.rpc_url }} -H "Content-Type:application/json;charset=utf-8" -d \ '{ "jsonrpc":"2.0", "id": 1, "method": "debug_traceTransaction", "params": ["INSERT_TRANSACTION_HASH", {"tracer": "callTracer"}] }' ```
Using the default opcode logger: ```bash curl {{ networks.development.rpc_url }} -H "Content-Type:application/json;charset=utf-8" -d \ '{ "jsonrpc":"2.0", "id": 1, "method": "debug_traceTransaction", "params": ["INSERT_TRANSACTION_HASH"] }' ``` ???+ function "debug_traceBlockByNumber" This method attempts to replay a block in the same manner as it was executed on the network. Refer to [Geth's documentation](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-debug#debugtraceblockbynumber){target=\_blank} for more information. === "Parameters" - `block_number` *string* - the block number of the block to be traced - `tracer_config` *string* - a JSON object for configuring the tracer that contains the following field: - `tracer` *string* - sets the type of tracer. This must be set to `callTracer`, which only returns transactions and sub-calls. Otherwise, the tracer will attempt to default to the opcode logger, which is not supported at this time due to the heavy nature of the call === "Returns" The method returns a JSON object with a top-level result property that is an array. Each element in this array corresponds to a single transaction in the block and includes a `txHash` and a `result` object as follows: - `txHash` - the transaction hash The `result` object contains the following fields: - `type` - the type of the call - `from` - the address the transaction is sent from - `to` - the address the transaction is directed to - `value` - the integer of the value sent with this transaction - `gas` - the integer of the gas provided for the transaction execution - `gasUsed` - the integer of the gas used - `input` - the data given at the time of input - `output` - the data which is returned as an output - `error` - the type of error, if any - `revertReason` - the type solidity revert reason, if any - `calls` - a list of sub-calls, if any === "Example" ```bash curl {{ networks.development.rpc_url }} -H "Content-Type:application/json;charset=utf-8" -d \ '{ "jsonrpc": "2.0", "id": 1, "method": "debug_traceBlockByNumber", "params": ["INSERT_BLOCK_NUMBER", {"tracer": "callTracer"}] }' ``` ???+ function "debug_traceBlockByHash" This method attempts to replay a block in the same manner as it was executed on the network. Refer to [Geth's documentation](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-debug#debugtraceblockbyhash){target=\_blank} for more information. === "Parameters" - `block_hash` *string* - the block hash of the block to be traced - `tracer_config` *string* - a JSON object for configuring the tracer that contains the following field: - `tracer` *string* - sets the type of tracer. This must be set to `callTracer`, which only returns transactions and sub-calls. Otherwise, the tracer will attempt to default to the opcode logger, which is not supported at this time due to the heavy nature of the call === "Returns" The method returns a JSON object with a top-level result property that is an array. Each element in this array corresponds to a single transaction in the block and includes a `txHash` and a `result` object as follows: - `txHash` - the transaction hash The `result` object contains the following fields: - `type` - the type of the call - `from` - the address the transaction is sent from - `to` - the address the transaction is directed to - `value` - the integer of the value sent with this transaction - `gas` - the integer of the gas provided for the transaction execution - `gasUsed` - the integer of the gas used - `input` - the data given at the time of input - `output` - the data which is returned as an output - `error` - the type of error, if any - `revertReason` - the type solidity revert reason, if any - `calls` - a list of sub-calls === "Example" ```bash curl {{ networks.development.rpc_url }} -H "Content-Type:application/json;charset=utf-8" -d \ '{ "jsonrpc": "2.0", "id": 1, "method": "debug_traceBlockByHash", "params": ["INSERT_BLOCK_HASH", {"tracer": "callTracer"}] }' ``` ???+ function "debug_traceCall" This method executes an eth_call within the context of the given block using the final state of the parent block as the base. Refer to [Geth's documentation](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-debug#debugtracecall){target=\_blank} for more information. === "Parameters" - `call_object` *object* the transaction object to be executed - `block_hash` *string* - the block hash of the base block === "Returns" - `gas`- the integer of the gas provided for the transaction execution - `returnValue` - the output produced by the execution of the transaction - `structLogs` - an array of [objects containing a detailed log of each opcode](https://geth.ethereum.org/docs/developers/evm-tracing/built-in-tracers#struct-opcode-logger){target=\_blank} executed during the transaction === "Example" ```bash curl {{ networks.development.rpc_url }} -H "Content-Type:application/json;charset=utf-8" -d \ '{ "jsonrpc": "2.0", "id": 1, "method": "debug_traceCall", "params": [{ "from": "INSERT_FROM_ADDRESS", "to":"INSERT_TO_ADDRESS", "data":"INSERT_CALL_DATA" }, "INSERT_BLOCK_HASH"] }' ``` ???+ function "trace_filter" This method returns matching traces for the given filters. Refer to [Open Ethereum's documentation](https://openethereum.github.io/JSONRPC-trace-module#trace_filter){target=\_blank} for more information. === "Parameters" - `fromBlock` *string* — (optional) either block number (hex), `earliest`, which is the genesis block, or `latest` (default), which is the best block available. The trace starting block - `toBlock` *string* — (optional) either block number (hex), `earliest`, which is the genesis block, or `latest`, which is the best block available. The trace-ending block - `fromAddress` *array* — (optional) filter transactions from these addresses only. If an empty array is provided, no filtering is done with this field - `toAddress` *array* — (optional) filter transactions to these addresses only. If an empty array is provided, no filtering is done with this field - `after` *uint* — (optional) the default offset is `0`. The trace offset (or starting) number - `count` *uint* — (optional) number of traces to display in a batch There are a couple of default values that you should be aware of: - The maximum number of trace entries a single request of `trace_filter` is allowed to return is `500`. A request exceeding this limit will return an error - Blocks processed by requests are temporarily stored in the cache for `300` seconds, after which they are deleted You can configure [additional flags](/node-operators/networks/tracing-node/#additional-flags){target=\_blank} when spinning up your tracing node to change the default values. === "Returns" The `result` array contains an array of objects for the block traces. All objects will contain the following fields: - `blockHash`- the hash of the block where this transaction was in - `blockNumber` - the block number where this transaction was in - `subtraces` - the traces of contract calls made by the transaction - `traceAddress` - the list of addresses where the call was executed, the address of the parents, and the order of the current sub-call - `transactionHash` - the hash of the transaction - `transactionPosition` - the transaction position - `type` - the value of the method, such as `call` or `create`
If the `type` of the transaction is a `call`, these additional fields will exist: - `action` - an object containing the call information: - `from` - the address of the sender - `callType` - the type of method, such as `call` and `delegatecall` - `gas` - the gas provided by the sender, encoded as hexadecimal - `input` - the data sent along with the transaction - `to` - the address of the receiver - `value` - the integer of the value sent with this transaction, encoded as hexadecimal - `result` - an object containing the result of the transaction - `gasUsed`- the amount of gas used by this specific transaction alone - `output`- the value returned by the contract call, and it only contains the actual value sent by the return method. If the return method was not executed, the output is empty bytes If the `type` of the transaction is a `create`, these additional fields will exist: - `action` - an object containing information on the contract creation: - `from` - the address of the sender - `creationMethod` - the creation method, such as `create` - `gas` - the gas provided by the sender, encoded as hexadecimal - `init` - the initialization code of the contract - `value` - the integer of the value sent with this transaction, encoded as hexadecimal - `result` - an object containing the result of the transaction - `address` - the address of the contract - `code` - the bytecode of the contract - `gasUsed`- the amount of gas used by this specific transaction alone === "Example" This example starts with a zero offset and provides the first 20 traces: ```sh curl {{ networks.development.rpc_url }} -H "Content-Type:application/json;charset=utf-8" -d \ '{ "jsonrpc": "2.0", "id": 1, "method": "trace_filter", "params": [{ "fromBlock": "INSERT_FROM_BLOCK", "toBlock": "INSERT_TO_BLOCK", "toAddress": ["INSERT_ADDRESS_TO_FILTER"], "after": 0, "count": 20 }] }' ``` ???+ function "txpool_content" Returns the details for all currently pending transactions waiting to be included in the next block(s) and all queued transactions for future execution. Refer to [Geth's documentation](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-txpool#txpool-content){target=\_blank} for more information. === "Parameters" None === "Returns" The `result` object contains the following fields: - `pending` - an object containing the pending transaction details, which maps an address to a batch of scheduled transactions - `address` - the address initiating a transaction, which maps the addresses' associating nonces with their transactions - `nonce` - the nonce of the sending address - `blockHash` - the hash of the block where this transaction was included. For pending transactions, this is an empty 32-byte string in hexadecimal format - `blockNumber` - the block number where this transaction was added encoded as a hexadecimal. For pending transactions, this is `null` - `from` - the address of the sender - `gas` - the total amount of gas units used in the transaction - `gasPrice` - the total amount in Wei the sender is willing to pay for the transaction - `maxFeePerGas` - the maximum amount of gas willing to be paid for the transaction - `maxPriorityFeePerGas` - the maximum amount of gas to be included as a tip to the miner - `hash` - the hash of the transaction - `input` - the encoded transaction input data - `nonce` - the number of transactions the sender has sent till now - `to` - the address of the receiver. `null` when it's a contract creation transaction - `transactionIndex` - an integer of the transactions index position in the block encoded as a hexadecimal format. For pending transactions, this is `null` - `value` - the value transferred in Wei encoded as a hexadecimal format - `queued` - an object containing the queued transaction details, which maps an address to a batch of scheduled transactions - `address` - the address initiating a transaction, which maps the addresses' associating nonces with their transactions - `nonce` - the nonce of the sending address - `blockHash` - the hash of the block where this transaction was included. For queued transactions, this is an empty 32-byte string in hexadecimal format - `blockNumber` - the block number where this transaction was added encoded as a hexadecimal. For queued transactions, this is `null` - `from` - the address of the sender - `gas` - the total amount of gas units used in the transaction - `gasPrice` - the total amount in wei the sender is willing to pay for the transaction - `maxFeePerGas` - the maximum amount of gas willing to be paid for the transaction - `maxPriorityFeePerGas` - the maximum amount of gas to be included as a tip to the miner - `hash` - the hash of the transaction - `input` - the encoded transaction input data - `nonce` - the number of transactions the sender has sent till now - `to` - the address of the receiver. `null` when it's a contract creation transaction - `transactionIndex` - an integer of the transactions index position in the block encoded as a hexadecimal format. For queued transactions, this is `null` - `value` - the value transferred in Wei encoded as a hexadecimal format === "Example" ```sh curl {{ networks.development.rpc_url }} -H "Content-Type:application/json;charset=utf-8" -d \ '{ "jsonrpc": "2.0", "id": 1, "method": "txpool_content", "params":[] }' ``` ???+ function "txpool_inspect" Returns a summary for all currently pending transactions waiting to be included in the next block(s) and all queued transactions for future execution. Refer to [Geth's documentation](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-txpool#txpool-inspect){target=\_blank} for more information. === "Parameters" None === "Returns" The `result` object contains the following fields: - `pending` - an object containing the pending transaction summary strings, which maps an address to a batch of scheduled transactions - `address` - the address initiating a transaction, which maps the addresses' associating nonces with their transaction summary strings - `queued` - an object containing the queued transaction summary strings, which maps an address to a batch of scheduled transactions - `address` - the address initiating a transaction, which maps the addresses' associating nonces with their transaction summary strings === "Example" ```sh curl {{ networks.development.rpc_url }} -H "Content-Type:application/json;charset=utf-8" -d \ '{ "jsonrpc": "2.0", "id": 1, "method": "txpool_inspect", "params":[] }' ``` ???+ function "txpool_status" Returns the total number of transactions currently pending transactions waiting to be included in the next block(s) and all queued transactions for future execution. Refer to [Geth's documentation](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-txpool#txpool-status){target=\_blank} for more information. === "Parameters" None === "Returns" The `result` object contains the following fields: - `pending` - a counter representing the number of pending transactions - `queued` - a counter representing the number of queued transactions === "Example" ```sh curl {{ networks.development.rpc_url }} -H "Content-Type:application/json;charset=utf-8" -d \ '{ "jsonrpc": "2.0", "id": 1, "method": "txpool_status", "params":[] }' ``` --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/json-rpc/eth-rpc/ --- BEGIN CONTENT --- --- title: Standard Ethereum JSON-RPC Methods description: Explore a comprehensive list of standard Ethereum JSON-RPC methods that can be used to interface with Moonbeam nodes programmatically. categories: JSON-RPC APIs, Reference, Ethereum Toolkit --- # Supported Ethereum RPC Methods ## Introduction {: #introduction } The Moonbeam team has collaborated closely with [Parity](https://www.parity.io){target=\_blank} on developing [Frontier](/learn/platform/technology/#frontier){target=\_blank}, an Ethereum compatibility layer for Substrate-based chains. This layer enables developers to run unmodified Ethereum dApps on Moonbeam seamlessly. Nevertheless, not all Ethereum JSON-RPC methods are supported; some of those supported return default values (those related to Ethereum's PoW consensus mechanism in particular). This guide provides a comprehensive list of supported Ethereum JSON-RPC methods on Moonbeam. Developers can quickly reference this list to understand the available functionality for interfacing with Moonbeam's Ethereum-compatible blockchain. ## Standard Ethereum JSON-RPC Methods {: #basic-rpc-methods } The basic JSON-RPC methods from the Ethereum API supported by Moonbeam are: - **[eth_protocolVersion](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_protocolversion){target=\_blank}** — returns `1` by default - **[eth_syncing](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_syncing){target=\_blank}** — returns an object with data about the sync status or `false` - **[eth_hashrate](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_hashrate){target=\_blank}** — returns `"0x0"` by default - **[eth_coinbase](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_coinbase){target=\_blank}** — returns the latest block author. Not necessarily a finalized block - **[eth_mining](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_mining){target=\_blank}** — returns `false` by default - **[eth_chainId](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_chainid){target=\_blank}** — returns the chain ID used for signing at the current block - **[eth_gasPrice](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gasprice){target=\_blank}** — returns the base fee per unit of gas used. This is currently the minimum gas price for each network - **[eth_accounts](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_accounts){target=\_blank}** — returns a list of addresses owned by the client - **[eth_blockNumber](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_blocknumber){target=\_blank}** — returns the highest available block number - **[eth_getBalance](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getbalance){target=\_blank}** — returns the balance of the given address. Instead of providing a block number as a parameter, you can provide a [default block parameter](#default-block-parameters) - **[eth_getStorageAt](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getstorageat){target=\_blank}** — returns the content of the storage at a given address. Instead of providing a block number as a parameter, you can provide a [default block parameter](#default-block-parameters) - **[eth_getBlockByHash](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbyhash){target=\_blank}** — returns information about the block of the given hash, including `baseFeePerGas` on post-London blocks - **[eth_getBlockByNumber](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbynumber){target=\_blank}** — returns information about the block specified by block number, including `baseFeePerGas` on post-London blocks. Instead of providing a block number as the first parameter, you can provide a [default block parameter](#default-block-parameters) - **[eth_getBlockReceipts](https://www.alchemy.com/docs/node/ethereum/ethereum-api-endpoints/eth-get-block-receipts){target=\_blank}** — returns all transaction receipts for a given block - **[eth_getTransactionCount](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactioncount){target=\_blank}** — returns the number of transactions sent from the given address (nonce). Instead of providing a block number as a parameter, you can provide a [default block parameter](#default-block-parameters) - **[eth_getBlockTransactionCountByHash](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblocktransactioncountbyhash){target=\_blank}** — returns the number of transactions in a block with a given block hash - **[eth_getBlockTransactionCountByNumber](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblocktransactioncountbynumber){target=\_blank}** — returns the number of transactions in a block with a given block number - **[eth_getUncleCountByBlockHash](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getunclecountbyblockhash){target=\_blank}** — returns `"0x0"` by default - **[eth_getUncleCountByBlockNumber](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getunclecountbyblocknumber){target=\_blank}** — returns `"0x0"` by default - **[eth_getCode](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getcode){target=\_blank}** — returns the code at the given address at the given block number. Instead of providing a block number as a parameter, you can provide a [default block parameter](#default-block-parameters) - **[eth_sendTransaction](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendtransaction){target=\_blank}** — creates a new message call transaction or a contract creation, if the data field contains code. Returns the transaction hash or the zero hash if the transaction is not yet available - **[eth_sendRawTransaction](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendrawtransaction){target=\_blank}** — creates a new message call transaction or a contract creation for signed transactions. Returns the transaction hash or the zero hash if the transaction is not yet available - **[eth_call](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call){target=\_blank}** — executes a new message call immediately without creating a transaction on the blockchain, returning the value of the executed call - Moonbeam supports the use of the optional _state override set_ object. This address-to-state mapping object allows the user to specify some state to be ephemerally overridden before executing a call to `eth_call`. The state override set is commonly used for tasks like debugging smart contracts. Visit the [go-ethereum](https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-eth#:~:text=Object%20%2D%20State%20override%20set){target=\_blank} documentation to learn more - Instead of providing a block number as a parameter, you can provide a [default block parameter](#default-block-parameters) - **[eth_estimateGas](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_estimategas){target=\_blank}** — returns an estimated amount of gas necessary for a given transaction to succeed. You can optionally specify a `gasPrice` or `maxFeePerGas` and `maxPriorityFeePerGas`. Instead of providing a block number as a parameter, you can provide a [default block parameter](#default-block-parameters) - **[eth_maxPriorityFeePerGas](https://www.alchemy.com/docs/node/ethereum/ethereum-api-endpoints/eth-max-priority-fee-per-gas){target=\_blank}** - returns an estimate of how much priority fee, in Wei, is needed for inclusion in a block - **[eth_feeHistory](https://www.alchemy.com/docs/node/ethereum/ethereum-api-endpoints/eth-fee-history){target=\_blank}** — returns `baseFeePerGas`, `gasUsedRatio`, `oldestBlock`, and `reward` for a specified range of up to 1024 blocks - **[eth_getTransactionByHash](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionbyhash){target=\_blank}** — returns the information about a transaction with a given hash. EIP-1559 transactions have `maxPriorityFeePerGas` and `maxFeePerGas` fields - **[eth_getTransactionByBlockHashAndIndex](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionbyblockhashandindex){target=\_blank}** — returns information about a transaction at a given block hash and a given index position. EIP-1559 transactions have `maxPriorityFeePerGas` and `maxFeePerGas` fields - **[eth_getTransactionByBlockNumberAndIndex](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionbyblocknumberandindex){target=\_blank}** — returns information about a transaction at a given block number and a given index position. EIP-1559 transactions have `maxPriorityFeePerGas` and `maxFeePerGas` fields. Instead of providing a block number as a parameter, you can provide a [default block parameter](#default-block-parameters) - **[eth_getTransactionReceipt](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionreceipt){target=\_blank}** — returns the transaction receipt of a given transaction hash - **[eth_getUncleByBlockHashAndIndex](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getunclebyblockhashandindex){target=\_blank}** — returns `null` by default - **[eth_getUncleByBlockNumberAndIndex](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getunclebyblocknumberandindex){target=\_blank}** — returns `null` by default - **[eth_getLogs](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getlogs){target=\_blank}** — returns an array of all logs matching a given filter object. Instead of providing a block number as a parameter, you can provide a [default block parameter](#default-block-parameters) - **[eth_newFilter](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newfilter){target=\_blank}** — creates a filter object based on the input provided. Returns a filter ID - **[eth_newBlockFilter](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newblockfilter){target=\_blank}** — creates a filter in the node to notify when a new block arrives. Returns a filter ID - **[eth_newPendingTransactionFilter](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_newpendingtransactionfilter){target=\_blank}** - creates a filter in the node to notify when new pending transactions arrive. Returns a filter ID - **[eth_getFilterChanges](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getfilterchanges){target=\_blank}** — polling method for filters (see methods above). Returns an array of logs that occurred since the last poll - **[eth_getFilterLogs](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getfilterlogs){target=\_blank}** — returns an array of all the logs matching the filter with a given ID - **[eth_uninstallFilter](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_uninstallfilter){target=\_blank}** — uninstall a filter with a given ID. It should be used when polling is no longer needed. Filters timeout when they are not requested using `eth_getFilterChanges` after some time ## Default Block Parameters {: #default-block-parameters } Moonbeam supports several default block parameters that allow you to query a subset of JSON-RPC methods at significant block heights. Moonbeam supports the following default block parameters: - `finalized` - Refers to the most recent block that Polkadot validators have finalized - `safe` - Synonymous with `finalized` in Moonbeam. In Ethereum, `safe` refers to the most recent block that is considered safe by the network, meaning it is unlikely to be reverted but has not yet been finalized. With Moonbeam's fast and deterministic finality, `finalized` and `safe` refer to the same blocks. - `earliest` - Refers to the genesis block of the blockchain - `pending` - Represents the latest state, including pending transactions that have not yet been mined into a block. This is a live view of the mempool - `latest` - Refers to the latest confirmed block in the blockchain, which may not be finalized ## Unsupported Ethereum JSON-RPC Methods {: #unsupported-rpc-methods } Moonbeam does not support the following Ethereum API JSON-RPC methods: - **[eth_getProof](https://www.alchemy.com/docs/node/ethereum/ethereum-api-endpoints/eth-get-proof){target=\_blank}** - returns the account and storage values of the specified account including the Merkle-proof - **[eth_blobBaseFee](https://www.quicknode.com/docs/ethereum/eth_blobBaseFee){target=\_blank}** - returns the expected base fee for blobs in the next block - **[eth_createAccessList](https://www.alchemy.com/docs/node/ethereum/ethereum-api-endpoints/eth-create-access-list){target=\_blank}** - creates an EIP-2930 type `accessList` based on a given transaction object - **[eth_sign](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign){target=\_blank}** - allows the user to sign an arbitrary hash to be sent at a later time. Presents a [security risk](https://support.metamask.io/privacy-and-security/what-is-eth_sign-and-why-is-it-a-risk/){target=\_blank} as the arbitrary hash can be fraudulently applied to other transactions - **[eth_signTransaction](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_signtransaction){target=\_blank}** - allows the user to sign a transaction to be sent at a later time. It is rarely used due to associated security risks ## Additional RPC Methods {: #additional-rpc-methods } Check out some of the non-standard Ethereum and Moonbeam-specific RPC methods: - [Debug and Trace](/builders/ethereum/json-rpc/debug-trace/) - [Event Subscription](/builders/ethereum/json-rpc/pubsub/) - [Custom Moonbeam](/builders/ethereum/json-rpc/moonbeam-custom-api/) --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/json-rpc/ --- BEGIN CONTENT --- --- title: JSON RPC API description: The JSON-RPC API for Moonbeam provides a set of methods for interacting with a Moonbeam node programmatically over JSON-RPC (Remote Procedure Call). dropdown_description: Methods you can interact with over JSON-RPC template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/json-rpc/moonbeam-custom-api/ --- BEGIN CONTENT --- --- title: Moonbeam-specific RPC Methods description: Discover Moonbeam's specialized API endpoints, featuring custom JSON-RPC methods designed exclusively for Moonbeam functionality. categories: JSON-RPC APIs, Reference --- # Moonbeam Custom API ## Introduction {: #introduction } Moonbeam nodes include support for custom JSON-RPC endpoints: - `moon_isBlockFinalized` - `moon_isTxFinalized` - `moon_getEthSyncBlockRange` These endpoints provide valuable functionality for checking the finality of on-chain events. To begin exploring Moonbeam's custom JSON-RPC endpoints, you can try out the provided curl examples below. These examples demonstrate how to query the public RPC endpoint of Moonbase Alpha. However, you can easily modify them to use with your own Moonbeam or Moonriver endpoint by changing the URL and API key. If you haven't already, you can obtain your endpoint and API key from one of our supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. ## Supported Custom RPC Methods {: #rpc-methods } ???+ function "moon_isBlockFinalized" Checks for the finality of the block given by its block hash. === "Parameters" - `block_hash` *string* - the hash of the block, accepts either Substrate-style or Ethereum-style block hash as its input === "Returns" Returns a boolean: `true` if the block is finalized, `false` if the block is not finalized or not found. === "Example" ```bash curl -H "Content-Type: application/json" -X POST --data '{ "jsonrpc": "2.0", "id": "1", "method": "moon_isBlockFinalized", "params": ["INSERT_BLOCK_HASH"] }' {{ networks.moonbase.rpc_url }} ``` ???+ function "moon_isTxFinalized" Checks for the finality of a transaction given its EVM transaction hash. === "Parameters" - `tx_hash` *string* - the EVM transaction hash of the transaction === "Returns" Returns a boolean: `true` if the transaction is finalized, `false` if the transaction is not finalized or not found. === "Example" ```bash curl -H "Content-Type: application/json" -X POST --data '{ "jsonrpc": "2.0", "id": "1", "method": "moon_isTxFinalized", "params": ["INSERT_TRANSACTION_HASH"] }' {{ networks.moonbase.rpc_url }} ``` ???+ function "moon_getEthSyncBlockRange" Returns the range of blocks that are fully indexed in Frontier's backend. === "Parameters" None === "Returns" Returns the range of blocks that are fully indexed in Frontier's backend. An example response below includes the Substrate block hashes of block `0` and the latest fully indexed block: ```[ "0x91bc6e169807aaa54802737e1c504b2577d4fafedd5a02c10293b1cd60e39527", "0xb1b49bd709ca9fe0e751b8648951ffbb2173e1258b8de8228cfa0ab27003f612" ]``` === "Example" ```bash curl -H "Content-Type: application/json" -X POST --data '{ "jsonrpc": "2.0", "id": "1", "method": "moon_getEthSyncBlockRange", "params": [] }' {{ networks.moonbase.rpc_url }} ``` --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/json-rpc/pubsub/ --- BEGIN CONTENT --- --- title: Subscribe to Ethereum-style Events on Moonbeam description: Take a look at the non-standard Ethereum JSON-RPC methods supported on Moonbeam that offer publish-subscribe functionality for specific events. categories: JSON-RPC APIs, Ethereum Toolkit --- # Subscribe to Events ## Introduction {: #introduction } Moonbeam supports event subscriptions for Ethereum-style events, which allows you to wait for events and handle them accordingly instead of polling for them. It works by subscribing to particular events; an ID is returned for each subscription. For each event that matches the subscription, a notification with relevant data is sent together with the subscription ID. In this guide, you will learn how to subscribe to event logs, incoming pending transactions, and incoming block headers on Moonbase Alpha. This guide can also be adapted for Moonbeam or Moonriver. ## Supported Pubsub JSON-RPC Methods {: #filter-rpc-methods } Please note that the examples in this section require installing [wscat](https://github.com/websockets/wscat){target=\_blank}. ???+ function "eth_subscribe" Creates a subscription for a given subscription name. === "Parameters" - `subscription_name` *string* - the type of the event to subscribe to. The [supported subscription](https://geth.ethereum.org/docs/interacting-with-geth/rpc/pubsub#create-subscriptions#supported-subscriptions){target=\_blank} types are: - [`newHeads`](https://geth.ethereum.org/docs/interacting-with-geth/rpc/pubsub#newheads){target=\_blank} — triggers a notification each time a new header is appended to the chain - [`logs`](https://geth.ethereum.org/docs/interacting-with-geth/rpc/pubsub#logs){target=\_blank} — returns logs that are included in new imported blocks and match a given filter criteria - [`newPendingTransactions`](https://geth.ethereum.org/docs/interacting-with-geth/rpc/pubsub#newpendingtransactions){target=\_blank} — returns the hash for all transactions that are added to the pending state - [`syncing`](https://geth.ethereum.org/docs/interacting-with-geth/rpc/pubsub#syncing){target=\_blank} — indicates when the node starts or stops synchronizing with the network === "Returns" The `result` returns the subscription ID. === "Example" ```bash wscat -c {{ networks.moonbase.wss_url }} -x ' { "jsonrpc": "2.0", "id": 1, "method": "eth_subscribe", "params": ["INSERT_SUBSCRIPTION_NAME"] }' ``` ???+ function "eth_unsubscribe" Cancels an existing subscription given its subscription ID. === "Parameters" - `subscription_id` *string* - the subscription ID === "Returns" The `result` returns a boolean indicating whether or not the subscription was successfully canceled. === "Example" ```bash wscat -c {{ networks.moonbase.wss_url }} -x ' { "jsonrpc": "2.0", "id": 1, "method": "eth_unsubscribe", "params": ["INSERT_SUBSCRIPTION_ID"] }' ``` ## Subscribe to Events Using Ethereum Libraries {: #subscribe-to-events } This section will show you how to use [Ethereum libraries](/builders/ethereum/libraries/){target=\_blank}, like [Web3.js](/builders/ethereum/libraries/web3js/){target=\_blank}, to programmatically subscribe to events on Moonbeam. ### Checking Prerequisites {: #checking-prerequisites } The examples in this guide are based on an Ubuntu 22.04 environment. You will also need the following: - MetaMask installed and [connected to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank} - An account with funds. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} - To deploy your own ERC-20 token on Moonbase Alpha. You can do this by following [our Remix tutorial](/builders/ethereum/dev-env/remix/){target=\_blank} while first pointing MetaMask to Moonbase Alpha - Web3.js or the Ethereum library of your choice installed. You can install Web3.js via npm: ```bash npm install web3 ``` ### Subscribe to Event Logs {: #subscribing-to-event-logs-in-moonbase-alpha } Any contract that follows the ERC-20 token standard emits an event related to a token transfer, that is, `event Transfer(address indexed from, address indexed to, uint256 value)`. In this section, you'll learn how to subscribe to these events using the Web3.js library. Use the following code snippet to set up a subscription to listen for token transfer events: ```js const { Web3 } = require('web3'); const web3 = new Web3('wss://wss.api.moonbase.moonbeam.network'); const main = async () => { const subscsription = await web3.eth.subscribe( 'logs', { address: 'INSERT_CONTRACT_ADDRESS', topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', ], }, (error, result) => { if (error) console.error(error); } ); console.log('🕔 Subscription set up. Waiting for new logs'); subscsription.on('connected', function (subscriptionId) { console.log(subscriptionId); }); subscsription.on('data', function (log) { console.log(log); }); }; main(); ``` !!! note Make sure to replace `'INSERT_CONTRACT_ADDRESS'` with the actual address of the ERC-20 token contract that you should have already deployed (as a [prerequisite](#checking-prerequisites)). In the provided code: - A subscription is set up using the [`web3.subscribe('logs', options)`](https://docs.web3js.org/libdocs/Web3Eth/#subscribelogs-options){target=\_blank} method to receive logs emitted by the contract, which listens for new data and logs it to the console - The `topics` array filters logs to include only events with the specified event signature. For this example, logs are filtered using the signature of the `Transfer` event, which can be calculated as follows: ```js EventSignature = keccak256(Transfer(address,address,uint256)) ``` This translates to `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef`, as seen in the code snippet. If you do not provide any topics, you subscribe to all events emitted by the contract. More information about topics can be found in the [Understanding event logs on the Ethereum blockchain](https://medium.com/mycrypto/understanding-event-logs-on-the-ethereum-blockchain-f4ae7ba50378){target=\_blank} Medium post. By executing this code, you'll establish a subscription to monitor ERC-20 token transfer events on Moonbeam. The terminal will display a subscription ID indicating a successful setup and await any new events emitted by the contract.
node contract-events.js 0x35547a6f7777444f35306f5353556271
#### Understanding Event Logs {: #understanding-event-logs } To illustrate the process, assume that an ERC-20 token transfer has been sent with the following parameters: - **From address** - `0x44236223aB4291b93EEd10E4B511B37a398DEE55` - **To address** - `0x8841701Dba3639B254D9CEe712E49D188A1e941e` - **Value (tokens)** - `1000000000000000000` (1 DEV in Wei) The event logs emitted by the transaction are as follows:
node contract-events.js 0x35547a6f7777444f35306f5353556271 { address: '0xCc17F1FAEAab9Fe70Dc2D616Ea768a4336f3c506', blockHash: '0x12d1f37db14f8d4efa2540ecb63d7f8b95236bb11c405e58691a45070d2c7e7f', blockNumber: 16736, data: '0x0000000000000000000000000000000000000000000000000d0b6b3a7640000', logIndex: 0, removed: false, topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x00000000000000000000000044236223ab4291b93eed10e4b511b37a398dee55', '0x0000000000000000000000008841701dba3639b254d9cee712e49d188a1e941e' ], transactionHash: '0xd53891693a731e0bca3287adc6375d04fe3b6605d00b186a669c6bbc8d22e88d', transactionIndex: 0, transactionLogIndex: '0x0', id: 'log_83c933b0' }
If you look at the `topics` array, there are a total of three topics present (in this order): 1. The event signature of the `Transfer` event 2. The `from` address 3. The `to` address As there are a total of three topics (the maximum is four), this corresponds to the LOG3 opcode: ![Description of LOG3](/images/builders/ethereum/json-rpc/pubsub/pubsub-1.webp) Indexed topics, such as the `from` and `to` addresses, are typically represented by 256-bit (64 hexadecimal character) values. If necessary, they are padded with zeros to reach the full length. Unindexed data, such as the value of tokens transferred, is not included in the `topics` array. Instead, it is returned within the logs' `data` field, encoded in bytes32/hex format. To decode it, you can use, for example, this [Web3 Type Converter tool](https://web3-type-converter.onbrn.com){target=\_blank} and verify that the `data` is 1 DEV token formatted in Wei. If the event returns multiple unindexed values, they will be appended one after the other in the same order the event emits them. Therefore, each value is obtained by deconstructing data into separate 32-byte (or 64-hex-character-long) pieces. #### Use Wildcards and Conditional Formatting {: #using-wildcards-and-conditional-formatting } Using the same example as in the previous section, you can subscribe to all of the events of the token contract with the following code: ```js const { Web3 } = require('web3'); const web3 = new Web3('wss://wss.api.moonbase.moonbeam.network'); const main = async () => { const subscription = await web3.eth.subscribe( 'logs', { address: 'INSERT_CONTRACT_ADDRESS', topics: [ null, [ '0x00000000000000000000000044236223aB4291b93EEd10E4B511B37a398DEE55', '0x0000000000000000000000008841701Dba3639B254D9CEe712E49D188A1e941e', ], ], }, (error, result) => { if (error) console.error(error); } ); console.log("🕔 Subscription set up. Waiting for new logs") subscription.on('connected', function (subscriptionId) { console.log(subscriptionId); }); subscription.on('data', function (log) { console.log(log); }); }; main(); ``` Here, by using the wildcard `null` in place of the event signature, you'll filter to listen to all events emitted by the contract you subscribe to. However, with this configuration, you can also use a second input field (`topic_1`) to filter by address. In the case of this subscription, you are notifying that you want to only receive events where `topic_1` is one of the addresses you are providing. Note that addresses need to be in H256 format. For example, the address `0x44236223aB4291b93EEd10E4B511B37a398DEE55` needs to be entered as `0x00000000000000000000000044236223aB4291b93EEd10E4B511B37a398DEE55`. As before, this subscription's output will display the event signature in `topic_0` to tell you which event the contract emitted.
node contract-events.js 0x51583364703338703441507476516675 { address: '0xCc17F1FAEAab9Fe70Dc2D616Ea768a4336f3c506', blockHash: '0xc7fa1139a35fb7a634514907feeb771e6aac7717906922a8589f029f709dcaef', blockNumber: 16739, data: '0x0000000000000000000000000000000000000000000000000de0b6b3a7640000', logIndex: 0, removed: false, topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x00000000000000000000000044236223ab4291b93eed10e4b511b37a398dee55', '0x0000000000000000000000008841701dba3639b254d9cee712e49d188a1e941e' ], transactionHash: '0x84154ea6ee44a4ffc446acd17579966691105694ce370f01de09d3a9f1b9506', transactionIndex: 0, transactionLogIndex: '0x0', id: 'log_188dbef1' } { address: '0xCc17F1FAEAab9Fe70Dc2D616Ea768a4336f3c506', blockHash: '0xf21ded1bc724d2be74bc97c2045e31754d5326f3964796d62a1cba3e1d06203', blockNumber: 16740, data: '0x0000000000000000000000000000000000000000000000000de0b6b3a7640000', logIndex: 0, removed: false, topics: [ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '0x0000000000000000000000008841701dba3639b254d9cee712e49d188a1e941e', '0x00000000000000000000000044236223ab4291b93eed10e4b511b37a398dee55' ], transactionHash: '0x091b736bd31457a9b0725a98926dc3ebfb0608e71197c10d4d9ccb80de6d9ac3', transactionIndex: 0, transactionLogIndex: '0x0', id: 'log_401c7925' }
As shown, after you provided the two addresses with conditional formatting, you should have received two logs with the same subscription ID. Events emitted by transactions from different addresses will not throw any logs to this subscription. This example showed how you could subscribe to just the event logs of a specific contract, but the Web3.js library provides other subscription types that will be covered in the following sections. ### Subscribe to Incoming Pending Transactions {: #subscribe-to-incoming-pending-transactions } To subscribe to pending transactions, you can use the [`web3.eth.subscribe('pendingTransactions')`](https://docs.web3js.org/libdocs/Web3Eth/#subscribependingtransactions){target=\_blank} method, implementing the same callback function to check for the response. The transaction hash of the pending transactions is returned.
node pending-tx.js 0x3350757676747651354e4553724e7269 0x5e3870e2c38274f4344cb86f3719dad84193b610a13b7e60c7ee65868b7ebc9a 0x54a28da6915df1ec83af4aafeab57364bbf4239d5ba71b596faabc76ba355eab
You can try this by sending a transaction and verifying that the transaction hash returned by the subscription is the same one returned by the development tool or wallet you are using. ### Subscribe to Incoming Block Headers {: #subscribe-to-incoming-block-headers } You can also subscribe to new block headers using the [`web3.eth.subscribe('newHeads')`](https://docs.web3js.org/libdocs/Web3Eth/#subscribenewheads){target=\_blank} method, implementing the same callback function to check for the response. This subscription provides incoming block headers and can be used to track changes in the blockchain.
node block-headers.js 0x6472456d30776b636c615a317158514e { author: '0x0000000000000000000000000000000000000000', difficulty: '0', extraData: '0x', gasLimit: 0, gasUsed: 0, hash: '0x1a28a9a7a176ed0d627f1bc521bda4eaca1e8186bf6642f089578067b713da43', logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', miner: '0x0000000000000000000000000000000000000000', number: 16756, parentHash: '0x89401a45d6226a5eb509fd3abfd90cb74aa5d7b5f747ef2506013d1afa36a418', receiptsRoot: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', sealFields: [ '0x0000000000000000000000000000000000000000000000000000000000000000', '0x0000000000000000' ], sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', size: 509, stateRoot: '0x92f3417ed90a81fecb2587fd820c1479f88f27228b8f508dfde601061d14371d', timestamp: 1607710710159, transactionsRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421' }
Note that only one block header is shown in the image. These messages are displayed for every block produced so they can quickly fill up the terminal. ### Check If a Node Is Synchronized with the Network {: #check-if-a-node-is-synchronized-with-the-network } With pubsub, checking whether a particular node is currently synchronizing with the network is also possible. You can use the [`web3.eth.subscribe('syncing')`](https://docs.web3js.org/libdocs/Web3Eth/#subscribesyncing){target=\_blank} method, implementing the same callback function to check for the response. This subscription will either return a boolean when `syncing` is false or an object describing the syncing progress when `syncing` is true, as seen below.
node syncing.js 0x3252615570630563274436770446371 { syncing: true, startingBlock: 120237, currentBlock: 146952, highestBlock: 2553484 }
!!! note The pubsub implementation in [Frontier](https://github.com/polkadot-evm/frontier){target=\_blank} is still in active development. This current version allows users to subscribe to specific event types, but there may still be some limitations. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/libraries/ethersjs/ --- BEGIN CONTENT --- --- title: How to use Ethers.js Ethereum Library description: Follow this tutorial to learn how to use the Ethereum Ethers.js Library to send transactions and deploy Solidity smart contracts to Moonbeam. categories: Libraries and SDKs, Ethereum Toolkit --- # Ethers.js JavaScript Library ## Introduction {: #introduction } The [Ethers.js](https://docs.ethers.org/v6){target=\_blank} library provides a set of tools to interact with Ethereum Nodes with JavaScript, similar to Web3.js. Moonbeam has an Ethereum-like API available that is fully compatible with Ethereum-style JSON-RPC invocations. Therefore, developers can leverage this compatibility and use the Ethers.js library to interact with a Moonbeam node as if they were doing so on Ethereum. For more information on Ethers.js, check their [documentation site](https://docs.ethers.org/v6){target=\_blank}. In this guide, you'll learn how to use the Ethers.js library to send a transaction and deploy a contract on Moonbase Alpha. This guide can be adapted for [Moonbeam](/builders/get-started/networks/moonbeam/){target=\_blank}, [Moonriver](/builders/get-started/networks/moonriver/){target=\_blank}, or a [Moonbeam development node](/builders/get-started/networks/moonbeam-dev/){target=\_blank}. ## Checking Prerequisites {: #checking-prerequisites } For the examples in this guide, you will need to have the following: - An account with funds. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} - To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank} !!! note The examples in this guide assume you have a MacOS or Ubuntu 22.04-based environment and will need to be adapted accordingly for Windows. ## Installing Ethers.js {: #install-ethersjs } To get started, you'll need to start a basic JavaScript project. First, create a directory to store all of the files you'll be creating throughout this guide and initialize the project with the following command: ```bash mkdir ethers-examples && cd ethers-examples && npm init --y ``` For this guide, you'll need to install the Ethers.js library and the Solidity compiler. To install both NPM packages, you can run the following command: === "npm" ```bash npm install ethers solc@0.8.0 ``` === "yarn" ```bash yarn add ethers solc@0.8.0 ``` ## Setting up the Ethers Provider {: #setting-up-the-ethers-provider } Throughout this guide, you'll be creating a bunch of scripts that provide different functionality such as sending a transaction, deploying a contract, and interacting with a deployed contract. In most of these scripts you'll need to create an [Ethers provider](https://docs.ethers.org/v6/api/providers/){target=\_blank} to interact with the network. To configure your project for Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. To create a provider, you can take the following steps: 1. Import the `ethers` library 2. Define the `providerRPC` object, which can include the network configurations for any of the networks you want to send a transaction on. You'll include the `name`, `rpc`, and `chainId` for each network 3. Create the `provider` using the `ethers.JsonRpcProvider` method === "Moonbeam" ```js // 1. Import ethers const ethers = require('ethers'); // 2. Define network configurations const providerRPC = { moonbeam: { name: 'moonbeam', rpc: '{{ networks.moonbeam.rpc_url }}', // Insert your RPC URL here chainId: {{ networks.moonbeam.chain_id }}, // {{ networks.moonbeam.hex_chain_id }} in hex, }, }; // 3. Create ethers provider const provider = new ethers.JsonRpcProvider(providerRPC.moonbeam.rpc, { chainId: providerRPC.moonbeam.chainId, name: providerRPC.moonbeam.name, }); ``` === "Moonriver" ```js // 1. Import ethers const ethers = require('ethers'); // 2. Define network configurations const providerRPC = { moonriver: { name: 'moonriver', rpc: '{{ networks.moonriver.rpc_url }}', // Insert your RPC URL here chainId: {{ networks.moonriver.chain_id }}, // {{ networks.moonriver.hex_chain_id }} in hex, }, }; // 3. Create ethers provider const provider = new ethers.JsonRpcProvider(providerRPC.moonriver.rpc, { chainId: providerRPC.moonriver.chainId, name: providerRPC.moonriver.name, }); ``` === "Moonbase Alpha" ```js // 1. Import ethers const ethers = require('ethers'); // 2. Define network configurations const providerRPC = { moonbase: { name: 'moonbase-alpha', rpc: '{{ networks.moonbase.rpc_url }}', chainId: {{ networks.moonbase.chain_id }}, // {{ networks.moonbase.hex_chain_id }} in hex, }, }; // 3. Create ethers provider const provider = new ethers.JsonRpcProvider(providerRPC.moonbase.rpc, { chainId: providerRPC.moonbase.chainId, name: providerRPC.moonbase.name, }); ``` === "Moonbeam Dev Node" ```js // 1. Import ethers const ethers = require('ethers'); // 2. Define network configurations const providerRPC = { dev: { name: 'moonbeam-development', rpc: '{{ networks.development.rpc_url }}', chainId: {{ networks.development.chain_id }}, // {{ networks.development.hex_chain_id }} in hex, }, }; // 3. Create ethers provider const provider = new ethers.JsonRpcProvider(providerRPC.dev.rpc, { chainId: providerRPC.dev.chainId, name: providerRPC.dev.name, }); ``` Save this code snippet as you'll need it for the scripts that are used in the following sections. ## Send a Transaction {: #send-a-transaction } During this section, you'll be creating a couple of scripts. The first one will be to check the balances of your accounts before trying to send a transaction. The second script will actually send the transaction. You can also use the balance script to check the account balances after the transaction has been sent. ### Check Balances Script {: #check-balances-script } You'll only need one file to check the balances of both addresses before and after the transaction is sent. To get started, you can create a `balances.js` file by running: ```bash touch balances.js ``` Next, you will create the script for this file and complete the following steps: 1. [Set up the Ethers provider](#setting-up-the-ethers-provider) 2. Define the `addressFrom` and `addressTo` variables 3. Create the asynchronous `balances` function which wraps the `provider.getBalance` method 4. Use the `provider.getBalance` function to fetch the balances for the `addressFrom` and `addressTo` addresses. You can also leverage the `ethers.formatEther` function to transform the balance into a more readable number in ETH 5. Lastly, run the `balances` function ```js // 1. Add the Ethers provider logic here: // {...} // 2. Create address variables const addressFrom = 'INSERT_FROM_ADDRESS'; const addressTo = 'INSERT_TO_ADDRESS'; // 3. Create balances function const balances = async () => { // 4. Fetch balances const balanceFrom = ethers.formatEther(await provider.getBalance(addressFrom)); const balanceTo = ethers.formatEther(await provider.getBalance(addressTo)); console.log(`The balance of ${addressFrom} is: ${balanceFrom} DEV`); console.log(`The balance of ${addressTo} is: ${balanceTo} DEV`); }; // 5. Call the balances function balances(); ``` ??? code "View the complete script" ```js // Import ethers const ethers = require('ethers'); // Define network configurations const providerRPC = { development: { name: 'moonbeam-development', rpc: 'http://localhost:9944', chainId: 1281, }, moonbase: { name: 'moonbase-alpha', rpc: 'https://rpc.api.moonbase.moonbeam.network', chainId: 1287, }, }; // Create ethers provider const provider = new ethers.JsonRpcProvider(providerRPC.moonbase.rpc, { chainId: providerRPC.moonbase.chainId, name: providerRPC.moonbase.name, }); // Change to correct network // Define addresses const addressFrom = 'INSERT_FROM_ADDRESS'; const addressTo = 'INSERT_TO_ADDRESS'; // Create balances function const balances = async () => { // Fetch balances const balanceFrom = ethers.formatEther( await provider.getBalance(addressFrom) ); const balanceTo = ethers.formatEther(await provider.getBalance(addressTo)); console.log(`The balance of ${addressFrom} is: ${balanceFrom} DEV`); console.log(`The balance of ${addressTo} is: ${balanceTo} DEV`); }; // Call the balances function balances(); ``` To run the script and fetch the account balances, you can run the following command: ```bash node balances.js ``` If successful, the balances for the origin and receiving address will be displayed in your terminal in DEV. ### Send Transaction Script {: #send-transaction-script } You'll only need one file for executing a transaction between accounts. For this example, you'll be transferring 1 DEV token from an origin address (from which you hold the private key) to another address. To get started, you can create a `transaction.js` file by running: ```bash touch transaction.js ``` Next, you will create the script for this file and complete the following steps: 1. [Set up the Ethers provider](#setting-up-the-ethers-provider) 2. Define the `privateKey` and the `addressTo` variables. The private key is required to create a wallet instance. **Note: This is for example purposes only. Never store your private keys in a JavaScript file** 3. Create a wallet using the `privateKey` and `provider` from the previous steps. The wallet instance is used to sign transactions 4. Create the asynchronous `send` function which wraps the transaction object and the `wallet.sendTransaction` method 5. Create the transaction object which only requires the recipient's address and the amount to send. Note that `ethers.parseEther` can be used, which handles the necessary unit conversions from Ether to Wei - similar to using `ethers.parseUnits(value, 'ether')` 6. Send the transaction using the `wallet.sendTransaction` method and then use `await` to wait until the transaction is processed and the transaction receipt is returned 7. Lastly, run the `send` function ```js // 1. Add the Ethers provider logic here: // {...} // 2. Create account variables const accountFrom = { privateKey: 'INSERT_YOUR_PRIVATE_KEY', }; const addressTo = 'INSERT_TO_ADDRESS'; // 3. Create wallet let wallet = new ethers.Wallet(accountFrom.privateKey, provider); // 4. Create send function const send = async () => { console.log(`Attempting to send transaction from ${wallet.address} to ${addressTo}`); // 5. Create tx object const tx = { to: addressTo, value: ethers.parseEther('1'), }; // 6. Sign and send tx - wait for receipt const createReceipt = await wallet.sendTransaction(tx); await createReceipt.wait(); console.log(`Transaction successful with hash: ${createReceipt.hash}`); }; // 7. Call the send function send(); ``` ??? code "View the complete script" ```js // Import ethers const ethers = require('ethers'); // Define network configurations const providerRPC = { development: { name: 'moonbeam-development', rpc: 'http://localhost:9944', chainId: 1281, }, moonbase: { name: 'moonbase-alpha', rpc: 'https://rpc.api.moonbase.moonbeam.network', chainId: 1287, }, }; // Create ethers provider const provider = new ethers.JsonRpcProvider(providerRPC.moonbase.rpc, { chainId: providerRPC.moonbase.chainId, name: providerRPC.moonbase.name, }); // Change to correct network // Define accounts and wallet const accountFrom = { privateKey: 'INSERT_YOUR_PRIVATE_KEY', }; const addressTo = 'INSERT_TO_ADDRESS'; const wallet = new ethers.Wallet(accountFrom.privateKey, provider); // Create send function const send = async () => { console.log( `Attempting to send transaction from ${wallet.address} to ${addressTo}` ); // Create transaction const tx = { to: addressTo, value: ethers.parseEther('1'), }; // Send transaction and get hash const createReceipt = await wallet.sendTransaction(tx); await createReceipt.wait(); console.log(`Transaction successful with hash: ${createReceipt.hash}`); }; // Call the send function send(); ``` To run the script, you can run the following command in your terminal: ```bash node transaction.js ``` If the transaction was successful, in your terminal you'll see the transaction hash has been printed out. You can also use the `balances.js` script to check that the balances for the origin and receiving accounts have changed. The entire workflow would look like this:
node balances.js The balance of 0x3B939FeaD1557C741Ff06492FD0127bd287A421e is: 3604.673685275447543445 DEV The balance of 0xFFA0352d300cdd8aCdA5c947D87CbCc3f0B3485A is: 0 DEV node transaction.js Attempting to send transaction from 0x3B939FeaD1557C741Ff06492FD0127bd287A421e to 0xFFA0352d300cdd8aCdA5c947D87CbCc3f0B3485A Transaction successful with hash: 0x01e42c627fe79b1d5649a64d39fceec34aba3904e37d768e74ec71fcd62b897f node balances.js The balance of 0x3B939FeaD1557C741Ff06492FD0127bd287A421e is: 3603.673682650447543445 DEV The balance of 0xFFA0352d300cdd8aCdA5c947D87CbCc3f0B3485A is: 1.0 DEV
## Deploy a Contract {: #deploy-a-contract } The contract you'll be compiling and deploying in the next couple of sections is a simple incrementer contract, arbitrarily named `Incrementer.sol`. You can get started by creating a file for the contract: ```bash touch Incrementer.sol ``` Next, you can add the Solidity code to the file: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Incrementer { uint256 public number; constructor(uint256 _initialNumber) { number = _initialNumber; } function increment(uint256 _value) public { number = number + _value; } function reset() public { number = 0; } } ``` The `constructor` function, which runs when the contract is deployed, sets the initial value of the number variable stored on-chain (the default is `0`). The `increment` function adds the `_value` provided to the current number, but a transaction needs to be sent, which modifies the stored data. Lastly, the `reset` function resets the stored value to zero. !!! note This contract is a simple example for illustration purposes only and does not handle values wrapping around. ### Compile Contract Script {: #compile-contract-script } In this section, you'll create a script that uses the Solidity compiler to output the bytecode and interface (ABI) for the `Incrementer.sol` contract. To get started, you can create a `compile.js` file by running: ```bash touch compile.js ``` Next, you will create the script for this file and complete the following steps: 1. Import the `fs` and `solc` packages 2. Using the `fs.readFileSync` function, you'll read and save the file contents of `Incrementer.sol` to `source` 3. Build the `input` object for the Solidity compiler by specifying the `language`, `sources`, and `settings` to be used 4. Using the `input` object, you can compile the contract using `solc.compile` 5. Extract the compiled contract file and export it to be used in the deployment script ```js // 1. Import packages const fs = require('fs'); const solc = require('solc'); // 2. Get path and load contract const source = fs.readFileSync('Incrementer.sol', 'utf8'); // 3. Create input object const input = { language: 'Solidity', sources: { 'Incrementer.sol': { content: source, }, }, settings: { outputSelection: { '*': { '*': ['*'], }, }, }, }; // 4. Compile the contract const tempFile = JSON.parse(solc.compile(JSON.stringify(input))); const contractFile = tempFile.contracts['Incrementer.sol']['Incrementer']; // 5. Export contract data module.exports = contractFile; ``` ### Deploy Contract Script {: #deploy-contract-script } With the script for compiling the `Incrementer.sol` contract in place, you can then use the results to send a signed transaction that deploys it. To do so, you can create a file for the deployment script called `deploy.js`: ```bash touch deploy.js ``` Next, you will create the script for this file and complete the following steps: 1. Import the contract file from `compile.js` 2. [Set up the Ethers provider](#setting-up-the-ethers-provider) 3. Define the `privateKey` for the origin account. The private key is required to create a wallet instance. **Note: This is for example purposes only. Never store your private keys in a JavaScript file** 4. Create a wallet using the `privateKey` and `provider` from the previous steps. The wallet instance is used to sign transactions 5. Load the contract `bytecode` and `abi` for the compiled contract 6. Create a contract instance with signer using the `ethers.ContractFactory` function, providing the `abi`, `bytecode`, and `wallet` as parameters 7. Create the asynchronous `deploy` function that will be used to deploy the contract 8. Within the `deploy` function, use the `incrementer` contract instance to call `deploy` and pass in the initial value. For this example, you can set the initial value to `5`. This will send the transaction for contract deployment. To wait for a transaction receipt you can use the `deployed` method of the contract deployment transaction 9. Lastly, run the `deploy` function ```js // 1. Import the contract file const contractFile = require('./compile'); // 2. Add the Ethers provider logic here: // {...} // 3. Create account variables const accountFrom = { privateKey: 'INSERT_YOUR_PRIVATE_KEY', }; // 4. Create wallet let wallet = new ethers.Wallet(accountFrom.privateKey, provider); // 5. Load contract information const bytecode = contractFile.evm.bytecode.object; const abi = contractFile.abi; // 6. Create contract instance with signer const incrementer = new ethers.ContractFactory(abi, bytecode, wallet); // 7. Create deploy function const deploy = async () => { console.log(`Attempting to deploy from account: ${wallet.address}`); // 8. Send tx (initial value set to 5) and wait for receipt const contract = await incrementer.deploy(5); const txReceipt = await contract.deploymentTransaction().wait(); console.log(`Contract deployed at address: ${txReceipt.contractAddress}`); }; // 9. Call the deploy function deploy(); ``` ??? code "View the complete script" ```js // Import ethers and compile const ethers = require('ethers'); const contractFile = require('./compile'); // Define network configurations const providerRPC = { development: { name: 'moonbeam-development', rpc: 'http://localhost:9944', chainId: 1281, }, moonbase: { name: 'moonbase-alpha', rpc: 'https://rpc.api.moonbase.moonbeam.network', chainId: 1287, }, }; // Create ethers provider const provider = new ethers.JsonRpcProvider(providerRPC.moonbase.rpc, { chainId: providerRPC.moonbase.chainId, name: providerRPC.moonbase.name, }); // Change to correct network // Define accounts and wallet const accountFrom = { privateKey: 'INSERT_YOUR_PRIVATE_KEY', }; let wallet = new ethers.Wallet(accountFrom.privateKey, provider); // Load contract info const bytecode = contractFile.evm.bytecode.object; const abi = contractFile.abi; // Create contract instance with signer const incrementer = new ethers.ContractFactory(abi, bytecode, wallet); // Create deploy function const deploy = async () => { console.log(`Attempting to deploy from account: ${wallet.address}`); // Send tx (initial value set to 5) and wait for receipt const contract = await incrementer.deploy(5); const txReceipt = await contract.deploymentTransaction().wait(); console.log(`Contract deployed at address: ${txReceipt.contractAddress}`); }; // Call the deploy function deploy(); ``` To run the script, you can enter the following command into your terminal: ```bash node deploy.js ``` If successful, the contract's address will be displayed in the terminal.
node deploy.js Attempting to deploy from account: 0x3B939FeaD1557C741Ff06492FD0127bd287A421e Contract deployed at address: 0x2B9c71fc2730B7353Dd3865ae26881Fa38FE598A
### Read Contract Data (Call Methods) {: #read-contract-data } Call methods are the type of interaction that don't modify the contract's storage (change variables), meaning no transaction needs to be sent. They simply read various storage variables of the deployed contract. To get started, you can create a file and name it `get.js`: ```bash touch get.js ``` Then you can take the following steps to create the script: 1. Import the `abi` from the `compile.js` file 2. [Set up the Ethers provider](#setting-up-the-ethers-provider) 3. Create the `contractAddress` variable using the address of the deployed contract 4. Create an instance of the contract using the `ethers.Contract` function and passing in the `contractAddress`, `abi`, and `provider` 5. Create the asynchronous `get` function 6. Use the contract instance to call one of the contract's methods and pass in any inputs if necessary. For this example, you will call the `number` method which doesn't require any inputs. You can use `await` which will return the value requested once the request promise resolves 7. Lastly, call the `get` function ```js // 1. Import the ABI const { abi } = require('./compile'); // 2. Add the Ethers provider logic here: // {...} // 3. Contract address variable const contractAddress = 'INSERT_CONTRACT_ADDRESS'; // 4. Create contract instance const incrementer = new ethers.Contract(contractAddress, abi, provider); // 5. Create get function const get = async () => { console.log(`Making a call to contract at address: ${contractAddress}`); // 6. Call contract const data = await incrementer.number(); console.log(`The current number stored is: ${data}`); }; // 7. Call get function get(); ``` ??? code "View the complete script" ```js // Import ethers and compile const ethers = require('ethers'); const { abi } = require('./compile'); // Define network configurations const providerRPC = { development: { name: 'moonbeam-development', rpc: 'http://localhost:9944', chainId: 1281, }, moonbase: { name: 'moonbase-alpha', rpc: 'https://rpc.api.moonbase.moonbeam.network', chainId: 1287, }, }; const provider = new ethers.JsonRpcProvider(providerRPC.moonbase.rpc, { chainId: providerRPC.moonbase.chainId, name: providerRPC.moonbase.name, }); // Change to correct network // Contract address variable const contractAddress = 'INSERT_CONTRACT_ADDRESS'; // Create contract instance const incrementer = new ethers.Contract(contractAddress, abi, provider); // Create get function const get = async () => { console.log(`Making a call to contract at address: ${contractAddress}`); // Call contract const data = await incrementer.number(); console.log(`The current number stored is: ${data}`); }; // Call get function get(); ``` To run the script, you can enter the following command in your terminal: ```bash node get.js ``` If successful, the value will be displayed in the terminal. ### Interact with Contract (Send Methods) {: #interact-with-contract } Send methods are the type of interaction that modify the contract's storage (change variables), meaning a transaction needs to be signed and sent. In this section, you'll create two scripts: one to increment and one to reset the incrementer. To get started, you can create a file for each script and name them `increment.js` and `reset.js`: ```bash touch increment.js reset.js ``` Open the `increment.js` file and take the following steps to create the script: 1. Import the `abi` from the `compile.js` file 2. [Set up the Ethers provider](#setting-up-the-ethers-provider) 3. Define the `privateKey` for the origin account, the `contractAddress` of the deployed contract, and the `_value` to increment by. The private key is required to create a wallet instance. **Note: This is for example purposes only. Never store your private keys in a JavaScript file** 4. Create a wallet using the `privateKey` and `provider` from the previous steps. The wallet instance is used to sign transactions 5. Create an instance of the contract using the `ethers.Contract` function and passing in the `contractAddress`, `abi`, and `provider` 6. Create the asynchronous `increment` function 7. Use the contract instance to call one of the contract's methods and pass in any inputs if necessary. For this example, you will call the `increment` method which requires the value to increment by as an input. You can use `await` which will return the value requested once the request promise resolves 8. Lastly, call the `increment` function ```js // 1. Import the contract ABI const { abi } = require('./compile'); // 2. Add the Ethers provider logic here: // {...} // 3. Create variables const accountFrom = { privateKey: 'INSERT_YOUR_PRIVATE_KEY', }; const contractAddress = 'INSERT_CONTRACT_ADDRESS'; const _value = 3; // 4. Create wallet let wallet = new ethers.Wallet(accountFrom.privateKey, provider); // 5. Create contract instance with signer const incrementer = new ethers.Contract(contractAddress, abi, wallet); // 6. Create increment function const increment = async () => { console.log( `Calling the increment by ${_value} function in contract at address: ${contractAddress}` ); // 7. Sign and send tx and wait for receipt const createReceipt = await incrementer.increment(_value); await createReceipt.wait(); console.log(`Tx successful with hash: ${createReceipt.hash}`); }; // 8. Call the increment function increment(); ``` ??? code "View the complete script" ```js // Import ethers and compile const ethers = require('ethers'); const { abi } = require('./compile'); // Define network configurations const providerRPC = { development: { name: 'moonbeam-development', rpc: 'http://localhost:9944', chainId: 1281, }, moonbase: { name: 'moonbase-alpha', rpc: 'https://rpc.api.moonbase.moonbeam.network', chainId: 1287, }, }; // Create ethers provider const provider = new ethers.JsonRpcProvider(providerRPC.moonbase.rpc, { chainId: providerRPC.moonbase.chainId, name: providerRPC.moonbase.name, }); // Change to correct network // Create variables const accountFrom = { privateKey: 'INSERT_YOUR_PRIVATE_KEY', }; const contractAddress = 'INSERT_CONTRACT_ADDRESS'; const _value = 3; // Create wallet let wallet = new ethers.Wallet(accountFrom.privateKey, provider); // Create contract instance with signer const incrementer = new ethers.Contract(contractAddress, abi, wallet); // Create reset function const increment = async () => { console.log( `Calling the increment by ${_value} function in contract at address: ${contractAddress}` ); // Sign and send tx and wait for receipt const createReceipt = await incrementer.increment(_value); await createReceipt.wait(); console.log(`Tx successful with hash: ${createReceipt.hash}`); }; // Call the reset function increment(); ``` To run the script, you can enter the following command in your terminal: ```bash node increment.js ``` If successful, the transaction hash will be displayed in the terminal. You can use the `get.js` script alongside the `increment.js` script to make sure that value is changing as expected:
node get.js Making a call to contract at address: 0x2B9c71fc2730B7353Dd3865ae26881Fa38FE598A The current number stored is: 5 node increment.js Calling the increment by 3 function in contract at address: 0x2B9c71fc2730B7353Dd3865ae26881Fa38FE598A Tx successful with hash: 0xc7fe935db03cfacf56c5649cd79a566d1a7b68417f904f0095a1b1c203875bf2 node get.js Making a call to contract at address: 0x2B9c71fc2730B7353Dd3865ae26881Fa38FE598A The current number stored is: 8
Next you can open the `reset.js` file and take the following steps to create the script: 1. Import the `abi` from the `compile.js` file 2. [Set up the Ethers provider](#setting-up-the-ethers-provider) 3. Define the `privateKey` for the origin account and the `contractAddress` of the deployed contract. The private key is required to create a wallet instance. **Note: This is for example purposes only. Never store your private keys in a JavaScript file** 4. Create a wallet using the `privateKey` and `provider` from the previous steps. The wallet instance is used to sign transactions 5. Create an instance of the contract using the `ethers.Contract` function and passing in the `contractAddress`, `abi`, and `provider` 6. Create the asynchronous `reset` function 7. Use the contract instance to call one of the contract's methods and pass in any inputs if necessary. For this example, you will call the `reset` method which doesn't require any inputs. You can use `await` which will return the value requested once the request promise resolves 8. Lastly, call the `reset` function ```js // 1. Import the contract ABI const { abi } = require('./compile'); // 2. Add the Ethers provider logic here: // {...} // 3. Create variables const accountFrom = { privateKey: 'INSERT_YOUR_PRIVATE_KEY', }; const contractAddress = 'INSERT_CONTRACT_ADDRESS'; // 4. Create wallet let wallet = new ethers.Wallet(accountFrom.privateKey, provider); // 5. Create contract instance with signer const incrementer = new ethers.Contract(contractAddress, abi, wallet); // 6. Create reset function const reset = async () => { console.log( `Calling the reset function in contract at address: ${contractAddress}` ); // 7. sign and send tx and wait for receipt const createReceipt = await incrementer.reset(); await createReceipt.wait(); console.log(`Tx successful with hash: ${createReceipt.hash}`); }; // 8. Call the reset function reset(); ``` ??? code "View the complete script" ```js // Import ethers and compile const ethers = require('ethers'); const { abi } = require('./compile'); // Define network configurations const providerRPC = { development: { name: 'moonbeam-development', rpc: 'http://localhost:9944', chainId: 1281, }, moonbase: { name: 'moonbase-alpha', rpc: 'https://rpc.api.moonbase.moonbeam.network', chainId: 1287, }, }; // Create ethers provider const provider = new ethers.JsonRpcProvider(providerRPC.moonbase.rpc, { chainId: providerRPC.moonbase.chainId, name: providerRPC.moonbase.name, }); // Change to correct network // Create variables const accountFrom = { privateKey: 'INSERT_YOUR_PRIVATE_KEY', }; const contractAddress = 'INSERT_CONTRACT_ADDRESS'; // Create wallet let wallet = new ethers.Wallet(accountFrom.privateKey, provider); // Create contract instance with signer const incrementer = new ethers.Contract(contractAddress, abi, wallet); // Create reset function const reset = async () => { console.log( `Calling the reset function in contract at address: ${contractAddress}` ); // Sign and send tx and wait for receipt const createReceipt = await incrementer.reset(); await createReceipt.wait(); console.log(`Tx successful with hash: ${createReceipt.hash}`); }; // Call the reset function reset(); ``` To run the script, you can enter the following command in your terminal: ```bash node reset.js ``` If successful, the transaction hash will be displayed in the terminal. You can use the `get.js` script alongside the `reset.js` script to make sure that value is changing as expected:
node get.js Making a call to contract at address: 0x2B9c71fc2730B7353Dd3865ae26881Fa38FE598A The current number stored is: 8 node reset.js Calling the reset function in contract at address: 0x2B9c71fc2730B7353Dd3865ae26881Fa38FE598A Tx successful with hash: 0xc452d21d8c2be6b81aadab7414103d68149c94a6399149ab8b79a58f0a3b5db7 node get.js Making a call to contract at address: 0x2B9c71fc2730B7353Dd3865ae26881Fa38FE598A The current number stored is: 0
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/libraries/ethersrs/ --- BEGIN CONTENT --- --- title: How to use Ethers.rs Ethereum Library description: Learn how to use the Ethereum Ethers.rs Library to send transactions and deploy Solidity smart contracts to Moonbeam via the Rust language. categories: Libraries and SDKs, Ethereum Toolkit --- # Ethers.rs Rust Library ## Introduction {: #introduction } The [Ethers.rs](https://ethers.rs){target=\_blank} library provides a set of tools to interact with Ethereum Nodes via the Rust programming language that works similar to [Ethers.js](/builders/ethereum/libraries/ethersjs/){target=\_blank}. Moonbeam has an Ethereum-like API available that is fully compatible with Ethereum-style JSON-RPC invocations. Therefore, developers can leverage this compatibility and use the Ethers.rs library to interact with a Moonbeam node as if they were doing so on Ethereum. You can read more about how to use Ethers.rs on their [official crate documentation](https://docs.rs/crate/ethers/latest){target=\_blank}. In this guide, you'll learn how to use the Ethers.rs library to send a transaction and deploy a contract on Moonbase Alpha. This guide can be adapted for [Moonbeam](/builders/get-started/networks/moonbeam/){target=\_blank}, [Moonriver](/builders/get-started/networks/moonriver/){target=\_blank}, or a [Moonbeam development node](/builders/get-started/networks/moonbeam-dev/){target=\_blank}. ## Checking Prerequisites {: #checking-prerequisites } For the examples in this guide, you will need to have the following: - An account with funds. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} - To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank} - Have [Rust installed](https://www.rust-lang.org/tools/install){target=\_blank} on your device - Have [solc installed](https://docs.soliditylang.org/en/v0.8.9/installing-solidity.html) on your device. Using [solc-select](https://github.com/crytic/solc-select){target=\_blank} is recommended by the Ethers.rs package !!! note The examples in this guide assumes you have a MacOS or Ubuntu 20.04-based environment and will need to be adapted accordingly for Windows. ## Create a Rust Project {: #create-a-rust-project } To get started, you can create a new Rust project with the Cargo tool: ```bash cargo init ethers-examples && cd ethers-examples ``` For this guide, you'll need to install the Ethers.rs library among others. To tell the Rust project to install it, you must edit the `Cargo.toml` file that was created with the project: ```toml [package] name = "ethers-examples" version = "0.1.0" edition = "2021" [dependencies] ethers = "1.0.2" ethers-solc = "1.0.2" tokio = { version = "1", features = ["full"] } serde_json = "1.0.89" serde = "1.0.149" ``` This example is using the `ethers` and `ethers-solc` crate versions `1.0.2` for RPC interactions and Solidity compiling. It also includes the `tokio` crate to run asynchronous Rust environments, since interacting with RPCs requires asynchronous code. Finally, it includes the `serde_json` and `serde` crates to help serialize/deserialize this example's code. If this is your first time using `solc-select`, you'll need to install and configure the Solidity version using the following commands: ```bash solc-select install 0.8.17 && solc-select use 0.8.17 ``` ## Setting up the Ethers Provider and Client {: #setting-up-the-ethers-provider-and-client } Throughout this guide, you'll be writing multiple functions that provide different functionality such as sending a transaction, deploying a contract, and interacting with a deployed contract. In most of these scripts you'll need to use an [Ethers provider](https://docs.rs/ethers-providers/latest/ethers_providers/index.html){target=\_blank} or an [Ethers signer client](https://docs.rs/ethers/1.0.2/ethers/middleware/struct.SignerMiddleware.html){target=\_blank} to interact with the network. To configure your project for Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. There are multiple ways to create a provider and signer, but the easiest way is through `try_from`. In the `src/main.rs` file, you can take the following steps: 1. Import `Provider` and `Http` from the `ethers` crate 2. Add a `Client` type for convenience, which will be used once you start to create the functions for sending a transaction and deploying a contract 3. Add a `tokio` attribute above `async fn main()` for asynchronous execution 4. Use `try_from` to attempt to instantiate a JSON-RPC provider object from an RPC endpoint 5. Use a private key to create a wallet object (the private key will be used to sign transactions). **Note: This is for example purposes only. Never store your private keys in a plain Rust file** 6. Wrap the provider and wallet together into a client by providing them to a `SignerMiddleware` object === "Moonbeam" ```rust // 1. Import ethers crate use ethers::providers::{Provider, Http}; // 2. Add client type type Client = SignerMiddleware, Wallet>; // 3. Add annotation #[tokio::main] async fn main() -> Result<(), Box> { // 4. Use try_from with RPC endpoint let provider = Provider::::try_from( "{{ networks.moonbeam.rpc_url }}" )?; // 5. Use a private key to create a wallet // Do not include the private key in plain text in any production code // This is just for demonstration purposes // Do not include '0x' at the start of the private key let wallet: LocalWallet = "INSERT_YOUR_PRIVATE_KEY" .parse::()? .with_chain_id(Chain::Moonbeam); // 6. Wrap the provider and wallet together to create a signer client let client = SignerMiddleware::new(provider.clone(), wallet.clone()); Ok(()) } ``` === "Moonriver" ```rust // 1. Import ethers crate use ethers::providers::{Provider, Http}; // 2. Add client type type Client = SignerMiddleware, Wallet>; // 3. Add annotation #[tokio::main] async fn main() -> Result<(), Box> { // 4. Use try_from with RPC endpoint let provider = Provider::::try_from( "{{ networks.moonriver.rpc_url }}" )?; // 5. Use a private key to create a wallet // Do not include the private key in plain text in any production code // This is just for demonstration purposes // Do not include '0x' at the start of the private key let wallet: LocalWallet = "INSERT_YOUR_PRIVATE_KEY" .parse::()? .with_chain_id(Chain::Moonriver); // 6. Wrap the provider and wallet together to create a signer client let client = SignerMiddleware::new(provider.clone(), wallet.clone()); Ok(()) } ``` === "Moonbase Alpha" ```rust // 1. Import ethers crate use ethers::providers::{Provider, Http}; // 2. Add client type type Client = SignerMiddleware, Wallet>; // 3. Add annotation #[tokio::main] async fn main() -> Result<(), Box> { // 4. Use try_from with RPC endpoint let provider = Provider::::try_from( "{{ networks.moonbase.rpc_url }}" )?; // 5. Use a private key to create a wallet // Do not include the private key in plain text in any production code // This is just for demonstration purposes // Do not include '0x' at the start of the private key let wallet: LocalWallet = "INSERT_YOUR_PRIVATE_KEY" .parse::()? .with_chain_id(Chain::Moonbase); // 6. Wrap the provider and wallet together to create a signer client let client = SignerMiddleware::new(provider.clone(), wallet.clone()); Ok(()) } ``` === "Moonbeam Dev Node" ```rust // 1. Import ethers crate use ethers::providers::{Provider, Http}; // 2. Add client type type Client = SignerMiddleware, Wallet>; // 3. Add annotation #[tokio::main] async fn main() -> Result<(), Box> { // 4. Use try_from with RPC endpoint let provider = Provider::::try_from( "{{ networks.development.rpc_url }}" )?; // 5. Use a private key to create a wallet // Do not include the private key in plain text in any production code // This is just for demonstration purposes // Do not include '0x' at the start of the private key let wallet: LocalWallet = "INSERT_YOUR_PRIVATE_KEY" .parse::()? .with_chain_id(Chain::MoonbeamDev); // 6. Wrap the provider and wallet together to create a signer client let client = SignerMiddleware::new(provider.clone(), wallet.clone()); Ok(()) } ``` ## Send a Transaction {: #send-a-transaction } During this section, you'll be creating a couple of functions, which will be contained in the same `main.rs` file to avoid additional complexity from implementing modules. The first function will be to check the balances of your accounts before trying to send a transaction. The second function will actually send the transaction. To run each of these functions, you will edit the `main` function and run the `main.rs` script. You should already have your provider and client set up in `main.rs` in the way described in the [previous section](#setting-up-the-ethers-provider-and-client). In order to send a transaction, you'll need to add a few more lines of code: 1. Add `use ethers::{utils, prelude::*};` to your imports, which will provide you access to utility functions and the prelude imports all of the necessary data types and traits 2. As you'll be sending a transaction from one address to another, you can specify the sending and receiving addresses in the `main` function. **Note: the `address_from` value should correspond to the private key that is used in the `main` function** ```rust // ... // 1. Add to imports use ethers::{utils, prelude::*}; // ... #[tokio::main] async fn main() -> Result<(), Box> { // ... // 2. Add from and to address let address_from = "YOUR_FROM_ADDRESS".parse::
()? let address_to = "YOUR_TO_ADDRESS".parse::
()? } ``` ### Check Balances Function {: #check-balances-function } Next, you will create the function for getting the sending and receiving accounts' balances by completing the following steps: 1. Create a new asynchronous function named `print_balances` that takes a provider object's reference and the sending and receiving addresses as input 2. Use the `provider` object's `get_balance` function to get the balances of the sending and receiving addresses of the transaction 3. Print the resultant balances for the sending and receiving addresses 4. Call the `print_balances` function in the `main` function ```rust // ... // 1. Create an asynchronous function that takes a provider reference and from and to address as input async fn print_balances(provider: &Provider, address_from: Address, address_to: Address) -> Result<(), Box> { // 2. Use the get_balance function let balance_from = provider.get_balance(address_from, None).await?; let balance_to = provider.get_balance(address_to, None).await?; // 3. Print the resultant balance println!("{} has {}", address_from, balance_from); println!("{} has {}", address_to, balance_to); Ok(()) } #[tokio::main] async fn main() -> Result<(), Box> { // ... // 4. Call print_balances function in main print_balances(&provider).await?; Ok(()) } ``` ### Send Transaction Script {: #send-transaction-script } For this example, you'll be transferring 1 DEV from an origin address (of which you hold the private key) to another address. 1. Create a new asynchronous function named `send_transaction` that takes a client object's reference and the sending and receiving addresses as input 2. Create the transaction object, and include the `to`, `value`, and `from`. When writing the `value` input, use the `ethers::utils::parse_ether` function 3. Use the `client` object to send the transaction 4. Print the transaction after it is confirmed 5. Call the `send_transaction` function in the `main` function ```rust // ... // 1. Define an asynchronous function that takes a client provider and the from and to addresses as input async fn send_transaction(client: &Client, address_from: Address, address_to: Address) -> Result<(), Box> { println!( "Beginning transfer of 1 native currency from {} to {}.", address_from, address_to ); // 2. Create a TransactionRequest object let tx = TransactionRequest::new() .to(address_to) .value(U256::from(utils::parse_ether(1)?)) .from(address_from); // 3. Send the transaction with the client let tx = client.send_transaction(tx, None).await?.await?; // 4. Print out the result println!("Transaction Receipt: {}", serde_json::to_string(&tx)?); Ok(()) } #[tokio::main] async fn main() -> Result<(), Box> { // ... // 5. Call send_transaction function in main send_transaction(&client, address_from, address_to).await?; Ok(()) } ``` ??? code "View the complete script" ```rust use ethers::providers::{Provider, Http}; use ethers::{utils, prelude::*}; type Client = SignerMiddleware, Wallet>; #[tokio::main] async fn main() -> Result<(), Box> { let provider: Provider = Provider::::try_from("https://rpc.api.moonbase.moonbeam.network")?; // Change to correct network // Do not include the private key in plain text in any production code. This is just for demonstration purposes let wallet: LocalWallet = "INSERT_PRIVATE_KEY" .parse::()? .with_chain_id(Chain::Moonbase); // Change to correct network let client = SignerMiddleware::new(provider.clone(), wallet.clone()); let address_from = "INSERT_FROM_ADDRESS".parse::
()?; let address_to = "INSERT_TO_ADDRESS".parse::
()?; send_transaction(&client, &address_from, &address_to).await?; print_balances(&provider, &address_from, &address_to).await?; Ok(()) } // Print the balance of a wallet async fn print_balances(provider: &Provider, address_from: &Address, address_to: &Address) -> Result<(), Box> { let balance_from = provider.get_balance(address_from.clone(), None).await?; let balance_to = provider.get_balance(address_to.clone(), None).await?; println!("{} has {}", address_from, balance_from); println!("{} has {}", address_to, balance_to); Ok(()) } // Sends some native currency async fn send_transaction(client: &Client, address_from: &Address, address_to: &Address) -> Result<(), Box> { println!( "Beginning transfer of 1 native currency {} to {}.", address_from, address_to ); let tx = TransactionRequest::new() .to(address_to.clone()) .value(U256::from(utils::parse_ether(1)?)) .from(address_from.clone()); let tx = client.send_transaction(tx, None).await?.await?; println!("Transaction Receipt: {}", serde_json::to_string(&tx)?); Ok(()) } ``` To run the script, which will send the transaction and then check the balances once the transaction has been sent, you can run the following command: ```bash cargo run ``` If the transaction was successful, in your terminal you'll see the transaction details printed out along with the balance of your address.
cargo run Compiling ethers-examples v0.1.0 (/Users/moonbeam/workspace/ethers-examples) Finished dev [unoptimized + debuginfo] target(s) in 32.76s Running `target/debug/ethers-examples` Beginning transfer of 1 native currency 0x3b93…421e to 0xe773…8dde. Transaction Receipt: {"transactionHash":"0x6f2338c63286f8b27951ddb6748191149d82647b44a00465f1f776624f490ce9","transactionIndex":"0x0","blockHash":"0x8234eb2083e649ab45c7c5fcdf2026d8f47676f7e29305023d1d00cc349ba215","blockNumber":"0x7ac12d","from":"0x3b939fead1557c741ff06492fd0127bd287a421e","to":"0xe773f740828a968c8a9e1e8e05db486937768dde","cumulativeGasUsed":"0x5208","gasUsed":"0x5208","contractAddress":null,"logs":[],"status":"0x1","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","type":"0x0","effectiveGasPrice":"0x7735940"} 0x3b93…421e has 3601703984470865589125 0xe773…8dde has 1000000000000000000
## Deploy a Contract {: #deploy-a-contract } The contract you'll be compiling and deploying in the next couple of sections is a simple incrementer contract, arbitrarily named `Incrementer.sol`. You can get started by creating a file for the contract: ```bash touch Incrementer.sol ``` Next, you can add the Solidity code to the file: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Incrementer { uint256 public number; constructor(uint256 _initialNumber) { number = _initialNumber; } function increment(uint256 _value) public { number = number + _value; } function reset() public { number = 0; } } ``` The `constructor` function, which runs when the contract is deployed, sets the initial value of the number variable stored on-chain (the default is `0`). The `increment` function adds the `_value` provided to the current number, but a transaction needs to be sent, which modifies the stored data. Lastly, the `reset` function resets the stored value to zero. !!! note This contract is a simple example for illustration purposes only and does not handle values wrapping around. During the rest of this section, you'll be creating a couple of functions, which will be contained in the `main.rs` file to avoid additional complexity from implementing modules. The first function will be to compile and deploy the contract. The remaining functions will interact with the deployed contract. You should already have your provider and client set up in `main.rs` in the way described in the [Setting up the Ethers Provider and Client section](#setting-up-the-ethers-provider-and-client). Before getting started with the contract deployment, you'll need to add a few more imports to your `main.rs` file: ```rust use ethers_solc::Solc; use ethers::{prelude::*}; use std::{path::Path, sync::Arc}; ``` The `ethers_solc` import will be used to compile the smart contract. The `prelude` from Ethers imports some necessary data types and traits. Lastly, the `std` imports will enables you to store your smart contracts and wrap the client into an `Arc` type for thread safety. ### Compile and Deploy Contract Script {: #compile-and-deploy-contract-script } This example function will compile and deploy the `Incrementer.sol` smart contract you created in the previous section. The `Incrementer.sol` smart contract should be in the root directory. In the `main.rs` file, you can take the following steps: 1. Create a new asynchronous function named `compile_deploy_contract` that takes a client object's reference as input, and returns an address in the form of `H160` 2. Define a variable named `source` as the path for the directory that hosts all of the smart contracts that should be compiled, which is the root directory 3. Use the `Solc` crate to compile all of the smart contracts in the root directory 4. Get the ABI and bytecode from the compiled result, searching for the `Incrementer.sol` contract 5. Create a contract factory for the smart contract using the ABI, bytecode, and client. The client must be wrapped into an `Arc` type for thread safety 6. Use the factory to deploy. For this example, the value `5` is used as the initial value in the constructor 7. Print out the address after the deployment 8. Return the address 9. Call the `compile_deploy_contract` function in `main` ```rust // ... // 1. Define an asynchronous function that takes a client provider as input and returns H160 async fn compile_deploy_contract(client: &Client) -> Result> { // 2. Define a path as the directory that hosts the smart contracts in the project let source = Path::new(&env!("CARGO_MANIFEST_DIR")); // 3. Compile all of the smart contracts let compiled = Solc::default() .compile_source(source) .expect("Could not compile contracts"); // 4. Get ABI & Bytecode for Incrementer.sol let (abi, bytecode, _runtime_bytecode) = compiled .find("Incrementer") .expect("could not find contract") .into_parts_or_default(); // 5. Create a contract factory which will be used to deploy instances of the contract let factory = ContractFactory::new(abi, bytecode, Arc::new(client.clone())); // 6. Deploy let contract = factory.deploy(U256::from(5))?.send().await?; // 7. Print out the address let addr = contract.address(); println!("Incrementer.sol has been deployed to {:?}", addr); // 8. Return the address Ok(addr) } #[tokio::main] async fn main() -> Result<(), Box> { // ... // 9. Call compile_deploy_contract function in main let addr = compile_deploy_contract(&client).await?; Ok(()) } ``` ### Read Contract Data (Call Methods) {: #read-contract-data } Call methods are the type of interaction that don't modify the contract's storage (change variables), meaning no transaction needs to be sent. They simply read various storage variables of the deployed contract. Rust is typesafe, which is why the ABI for the `Incrementer.sol` contract is required to generate a typesafe Rust struct. For this example, you should create a new file in the root of the Cargo project called `Incrementer_ABI.json`: ```bash touch Incrementer_ABI.json ``` The ABI for `Incrementer.sol` is below, which should be copied and pasted into the `Incrementer_ABI.json` file: ```json [ { "inputs": [ { "internalType": "uint256", "name": "_value", "type": "uint256" } ], "name": "increment", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "number", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "reset", "outputs": [], "stateMutability": "nonpayable", "type": "function" } ] ``` Then you can take the following steps to create a function that reads and returns the `number` method of the `Incrementer.sol` contract: 1. Generate a type-safe interface for the `Incrementer` smart contract with the `abigen` macro 2. Create a new asynchronous function named `read_number` that takes a client object's reference and a contract address reference as input, and returns a U256 3. Create a new instance of the `Incrementer` object generated by the abigen macro with the client and contract address values 4. Call the `number` function in the new `Incrementer` object 5. Print out the resultant value 6. Return the resultant value 7. Call the `read_number` function in `main` ```rust // ... // 1. Generate a type-safe interface for the Incrementer smart contract abigen!( Incrementer, "./Incrementer_ABI.json", event_derives(serde::Deserialize, serde::Serialize) ); // 2. Define an asynchronous function that takes a client provider and address as input and returns a U256 async fn read_number(client: &Client, contract_addr: &H160) -> Result> { // 3. Create contract instance let contract = Incrementer::new(contract_addr.clone(), Arc::new(client.clone())); // 4. Call contract's number function let value = contract.number().call().await?; // 5. Print out number println!("Incrementer's number is {}", value); // 6. Return the number Ok(value) } // ... #[tokio::main] async fn main() -> Result<(), Box> { // ... // 7. Call read_number function in main read_number(&client, &addr).await?; Ok(()) } ``` ??? code "View the complete script" ```rust use ethers::providers::{Provider, Http}; use ethers::{prelude::*}; use ethers_solc::Solc; use std::{path::Path, sync::Arc}; type Client = SignerMiddleware, Wallet>; #[tokio::main] async fn main() -> Result<(), Box> { let provider: Provider = Provider::::try_from("https://rpc.api.moonbase.moonbeam.network")?; // Change to correct network // Do not include the private key in plain text in any production code. This is just for demonstration purposes // Do not include '0x' at the start of the private key let wallet: LocalWallet = "INSERT_PRIVATE_KEY" .parse::()? .with_chain_id(Chain::Moonbase); let client = SignerMiddleware::new(provider.clone(), wallet.clone()); // Deploy contract and read initial incrementer value let addr = compile_deploy_contract(&client).await?; read_number(&client, &addr).await?; // Increment and read the incremented number increment_number(&client, &addr).await?; read_number(&client, &addr).await?; // Reset the incremented number and read it reset(&client, &addr).await?; read_number(&client, &addr).await?; Ok(()) } // Need to install solc for this tutorial: https://github.com/crytic/solc-select async fn compile_deploy_contract(client: &Client) -> Result> { // Incrementer.sol is located in the root directory let source = Path::new(&env!("INSERT_CARGO_MANIFEST_DIR")); // Compile it let compiled = Solc::default() .compile_source(source) .expect("Could not compile contracts"); // Get ABI & Bytecode for Incrementer.sol let (abi, bytecode, _runtime_bytecode) = compiled .find("Incrementer") .expect("could not find contract") .into_parts_or_default(); // Create a contract factory which will be used to deploy instances of the contract let factory = ContractFactory::new(abi, bytecode, Arc::new(client.clone())); // Deploy let contract = factory.deploy(U256::from(5))?.send().await?; let addr = contract.address(); println!("Incrementer.sol has been deployed to {:?}", addr); Ok(addr) } // Generates a type-safe interface for the Incrementer smart contract abigen!( Incrementer, "./Incrementer_ABI.json", event_derives(serde::Deserialize, serde::Serialize) ); async fn read_number(client: &Client, contract_addr: &H160) -> Result> { // Create contract instance let contract = Incrementer::new(contract_addr.clone(), Arc::new(client.clone())); // Call contract's number function let value = contract.number().call().await?; // Print out value println!("Incrementer's number is {}", value); Ok(value) } async fn increment_number(client: &Client, contract_addr: &H160) -> Result<(), Box> { println!("Incrementing number..."); // Create contract instance let contract = Incrementer::new(contract_addr.clone(), Arc::new(client.clone())); // Send contract transaction let tx = contract.increment(U256::from(5)).send().await?.await?; println!("Transaction Receipt: {}", serde_json::to_string(&tx)?); Ok(()) } async fn reset(client: &Client, contract_addr: &H160) -> Result<(), Box> { println!("Resetting number..."); // Create contract instance let contract = Incrementer::new(contract_addr.clone(), Arc::new(client.clone())); // Send contract transaction let tx = contract.reset().send().await?.await?; println!("Transaction Receipt: {}", serde_json::to_string(&tx)?); Ok(()) } ``` To run the script, which will deploy the contract and return the current value stored in the `Incrementer` contract, you can enter the following command into your terminal: ```bash cargo run ``` If successful, you'll see the deployed contract's address and initial value set, which should be `5`, displayed in the terminal.
cargo run Compiling ethers-examples v0.1.0 (/Users/moonbeam/workspace/ethers-examples) Finished dev [unoptimized + debuginfo] target(s) in 1.09s Running `/Users/moonbeam/workspace/ethers-examples/target/debug/ethers-examples` Incrementer.sol has been deployed to 0xeb8a4d5c7cd56c65c9dbd25f793b50a2c917bb5d Incrementer's number is 5
### Interact with Contract (Send Methods) {: #interact-with-contract } Send methods are the type of interaction that modify the contract's storage (change variables), meaning a transaction needs to be signed and sent. In this section, you'll create two functions: one to increment and one to reset the incrementer. This section will also require the `Incrementer_ABI.json` file initialized when [reading from the smart contract](#read-contract-data). Take the following steps to create the function to increment: 1. Ensure that the abigen macro is called for the `Incrementer_ABI.json` somewhere in the `main.rs` file (if it is already in the `main.rs` file, you do not have to have a second one) 2. Create a new asynchronous function named `increment_number` that takes a client object's reference and an address as input 3. Create a new instance of the `Incrementer` object generated by the abigen macro with the client and contract address values 4. Call the `increment` function in the new `Incrementer` object by including a `U256` object as input. In this instance, the value provided is `5` 5. Call the `read_number` function in `main` ```rust // ... // 1. Generate a type-safe interface for the Incrementer smart contract abigen!( Incrementer, "./Incrementer_ABI.json", event_derives(serde::Deserialize, serde::Serialize) ); // 2. Define an asynchronous function that takes a client provider and address as input async fn increment_number(client: &Client, contract_addr: &H160) -> Result<(), Box> { println!("Incrementing number..."); // 3. Create contract instance let contract = Incrementer::new(contract_addr.clone(), Arc::new(client.clone())); // 4. Send contract transaction let tx = contract.increment(U256::from(5)).send().await?.await?; println!("Transaction Receipt: {}", serde_json::to_string(&tx)?); Ok(()) } // ... #[tokio::main] async fn main() -> Result<(), Box> { // ... // 5. Call increment_number function in main increment_number(&client, &addr).await?; Ok(()) } ``` ??? code "View the complete script" ```rust use ethers::providers::{Provider, Http}; use ethers::{prelude::*}; use ethers_solc::Solc; use std::{path::Path, sync::Arc}; type Client = SignerMiddleware, Wallet>; #[tokio::main] async fn main() -> Result<(), Box> { let provider: Provider = Provider::::try_from("https://rpc.api.moonbase.moonbeam.network")?; // Change to correct network // Do not include the private key in plain text in any production code. This is just for demonstration purposes // Do not include '0x' at the start of the private key let wallet: LocalWallet = "INSERT_PRIVATE_KEY" .parse::()? .with_chain_id(Chain::Moonbase); let client = SignerMiddleware::new(provider.clone(), wallet.clone()); // Deploy contract and read initial incrementer value let addr = compile_deploy_contract(&client).await?; read_number(&client, &addr).await?; // Increment and read the incremented number increment_number(&client, &addr).await?; read_number(&client, &addr).await?; // Reset the incremented number and read it reset(&client, &addr).await?; read_number(&client, &addr).await?; Ok(()) } // Need to install solc for this tutorial: https://github.com/crytic/solc-select async fn compile_deploy_contract(client: &Client) -> Result> { // Incrementer.sol is located in the root directory let source = Path::new(&env!("INSERT_CARGO_MANIFEST_DIR")); // Compile it let compiled = Solc::default() .compile_source(source) .expect("Could not compile contracts"); // Get ABI & Bytecode for Incrementer.sol let (abi, bytecode, _runtime_bytecode) = compiled .find("Incrementer") .expect("could not find contract") .into_parts_or_default(); // Create a contract factory which will be used to deploy instances of the contract let factory = ContractFactory::new(abi, bytecode, Arc::new(client.clone())); // Deploy let contract = factory.deploy(U256::from(5))?.send().await?; let addr = contract.address(); println!("Incrementer.sol has been deployed to {:?}", addr); Ok(addr) } // Generates a type-safe interface for the Incrementer smart contract abigen!( Incrementer, "./Incrementer_ABI.json", event_derives(serde::Deserialize, serde::Serialize) ); async fn read_number(client: &Client, contract_addr: &H160) -> Result> { // Create contract instance let contract = Incrementer::new(contract_addr.clone(), Arc::new(client.clone())); // Call contract's number function let value = contract.number().call().await?; // Print out value println!("Incrementer's number is {}", value); Ok(value) } async fn increment_number(client: &Client, contract_addr: &H160) -> Result<(), Box> { println!("Incrementing number..."); // Create contract instance let contract = Incrementer::new(contract_addr.clone(), Arc::new(client.clone())); // Send contract transaction let tx = contract.increment(U256::from(5)).send().await?.await?; println!("Transaction Receipt: {}", serde_json::to_string(&tx)?); Ok(()) } async fn reset(client: &Client, contract_addr: &H160) -> Result<(), Box> { println!("Resetting number..."); // Create contract instance let contract = Incrementer::new(contract_addr.clone(), Arc::new(client.clone())); // Send contract transaction let tx = contract.reset().send().await?.await?; println!("Transaction Receipt: {}", serde_json::to_string(&tx)?); Ok(()) } ``` To run the script, you can enter the following command into your terminal: ```bash cargo run ``` If successful, the transaction receipt will be displayed in the terminal. You can use the `read_number` function in the `main` function to make sure that value is changing as expected. If you're using the `read_number` function after incrementing, you'll also see the incremented number, which should be `10`.
cargo run Compiling ethers-examples v0.1.0 (/Users/moonbeam/workspace/ethers-examples) Finished dev [unoptimized + debuginfo] target(s) in 1.09s Running `/Users/moonbeam/workspace/ethers-examples/target/debug/ethers-examples` Incrementer.sol has been deployed to 0xeb8a4d5c7cd56c65c9dbd25f793b50a2c917bb5d Incrementer's number is 5 Incrementing number... Transaction Receipt: {"transactionHash":"0x6f5c204e74b96b6cf6057512ba142ad727718646d4ebb7abe8bbabada198dafb","transactionIndex":"0x0","blockHash":"0x635a8a234b30c6ee907198ddda3a1478ae52c6adbcc4a67353dd9597ee626950","blockNumber":"0x7ac238","from":"0x3b939fead1557c741ff06492fd0127bd287a421e","to":"0xeb8a4d5c7cd56c65c9dbd25f793b50a2c917bb5d","cumulativeGasUsed":"0x68a6","gasUsed":"0x68a6","contractAddress":null,"logs":[],"status":"0x1","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","type":"0x2","effectiveGasPrice":"0xba43b740"} Incrementer's number is 10
Next you can interact with the `reset` function: 1. Ensure that the abigen macro is called for the `Incrementer_ABI.json` somewhere in the `main.rs` file (if it is already in the `main.rs` file, you do not have to have a second one) 2. Create a new asynchronous function named `reset` that takes a client object's reference and an address as input 3. Create a new instance of the `Incrementer` object generated by the abigen macro with the client and contract address values 4. Call the `reset` function in the new `Incrementer` object 5. Call the `reset` function in `main` ```rust // ... // 1. Generate a type-safe interface for the Incrementer smart contract abigen!( Incrementer, "./Incrementer_ABI.json", event_derives(serde::Deserialize, serde::Serialize) ); // 2. Define an asynchronous function that takes a client provider and address as input async fn reset(client: &Client, contract_addr: &H160) -> Result<(), Box> { println!("Resetting number..."); // 3. Create contract instance let contract = Incrementer::new(contract_addr.clone(), Arc::new(client.clone())); // 4. Send contract transaction let tx = contract.reset().send().await?.await?; println!("Transaction Receipt: {}", serde_json::to_string(&tx)?); Ok(()) } // ... #[tokio::main] async fn main() -> Result<(), Box> { // ... // 5. Call reset function in main reset(&client, &addr).await?; Ok(()) } ``` If successful, the transaction receipt will be displayed in the terminal. You can use the `read_number` function in the `main` function to make sure that value is changing as expected. If you're using the `read_number` function after resetting the number, you should see `0` printed to the terminal.
cargo run Compiling ethers-examples v0.1.0 (/Users/moonbeam/workspace/ethers-examples) Finished dev [unoptimized + debuginfo] target(s) in 1.09s Running `/Users/moonbeam/workspace/ethers-examples/target/debug/ethers-examples` Incrementer.sol has been deployed to 0xeb8a4d5c7cd56c65c9dbd25f793b50a2c917bb5d Incrementer's number is 5 Incrementing number... Transaction Receipt: {"transactionHash":"0x6f5c204e74b96b6cf6057512ba142ad727718646d4ebb7abe8bbabada198dafb","transactionIndex":"0x0","blockHash":"0x635a8a234b30c6ee907198ddda3a1478ae52c6adbcc4a67353dd9597ee626950","blockNumber":"0x7ac238","from":"0x3b939fead1557c741ff06492fd0127bd287a421e","to":"0xeb8a4d5c7cd56c65c9dbd25f793b50a2c917bb5d","cumulativeGasUsed":"0x68a6","gasUsed":"0x68a6","contractAddress":null,"logs":[],"status":"0x1","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","type":"0x2","effectiveGasPrice":"0xba43b740"} Incrementer's number is 10 Resetting number... Transaction Receipt: {"transactionHash":"0xf1010597c6ab3d3cfcd6e8e68bf2eddf4ed38eb93a3052591c88b675ed1e83a4","transactionIndex":"0x0","blockHash":"0x5d4c09abf104cbd88e80487c170d8709aae7475ca84c1f3396f3e35222fbe87f","blockNumber":"0x7ac23b","from":"0x3b939fead1557c741ff06492fd0127bd287a421e","to":"0xeb8a4d5c7cd56c65c9dbd25f793b50a2c917bb5d","cumulativeGasUsed":"0x53c4","gasUsed":"0x53c4","contractAddress":null,"logs":[],"status":"0x1","logsBloom":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","type":"0x2","effectiveGasPrice":"0xba43b740"} Incrementer's number is 0
??? code "View the complete script" ```rust use ethers::providers::{Provider, Http}; use ethers::{prelude::*}; use ethers_solc::Solc; use std::{path::Path, sync::Arc}; type Client = SignerMiddleware, Wallet>; #[tokio::main] async fn main() -> Result<(), Box> { let provider: Provider = Provider::::try_from("https://rpc.api.moonbase.moonbeam.network")?; // Change to correct network // Do not include the private key in plain text in any production code. This is just for demonstration purposes // Do not include '0x' at the start of the private key let wallet: LocalWallet = "INSERT_PRIVATE_KEY" .parse::()? .with_chain_id(Chain::Moonbase); let client = SignerMiddleware::new(provider.clone(), wallet.clone()); // Deploy contract and read initial incrementer value let addr = compile_deploy_contract(&client).await?; read_number(&client, &addr).await?; // Increment and read the incremented number increment_number(&client, &addr).await?; read_number(&client, &addr).await?; // Reset the incremented number and read it reset(&client, &addr).await?; read_number(&client, &addr).await?; Ok(()) } // Need to install solc for this tutorial: https://github.com/crytic/solc-select async fn compile_deploy_contract(client: &Client) -> Result> { // Incrementer.sol is located in the root directory let source = Path::new(&env!("INSERT_CARGO_MANIFEST_DIR")); // Compile it let compiled = Solc::default() .compile_source(source) .expect("Could not compile contracts"); // Get ABI & Bytecode for Incrementer.sol let (abi, bytecode, _runtime_bytecode) = compiled .find("Incrementer") .expect("could not find contract") .into_parts_or_default(); // Create a contract factory which will be used to deploy instances of the contract let factory = ContractFactory::new(abi, bytecode, Arc::new(client.clone())); // Deploy let contract = factory.deploy(U256::from(5))?.send().await?; let addr = contract.address(); println!("Incrementer.sol has been deployed to {:?}", addr); Ok(addr) } // Generates a type-safe interface for the Incrementer smart contract abigen!( Incrementer, "./Incrementer_ABI.json", event_derives(serde::Deserialize, serde::Serialize) ); async fn read_number(client: &Client, contract_addr: &H160) -> Result> { // Create contract instance let contract = Incrementer::new(contract_addr.clone(), Arc::new(client.clone())); // Call contract's number function let value = contract.number().call().await?; // Print out value println!("Incrementer's number is {}", value); Ok(value) } async fn increment_number(client: &Client, contract_addr: &H160) -> Result<(), Box> { println!("Incrementing number..."); // Create contract instance let contract = Incrementer::new(contract_addr.clone(), Arc::new(client.clone())); // Send contract transaction let tx = contract.increment(U256::from(5)).send().await?.await?; println!("Transaction Receipt: {}", serde_json::to_string(&tx)?); Ok(()) } async fn reset(client: &Client, contract_addr: &H160) -> Result<(), Box> { println!("Resetting number..."); // Create contract instance let contract = Incrementer::new(contract_addr.clone(), Arc::new(client.clone())); // Send contract transaction let tx = contract.reset().send().await?.await?; println!("Transaction Receipt: {}", serde_json::to_string(&tx)?); Ok(()) } ```
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/libraries/ --- BEGIN CONTENT --- --- title: Ethereum Libraries description: Learn how to use JavaScript or Python Ethereum libraries such as Ethers.js, Web3.js, or Web3.py to send transactions or deploy contracts on Moonbeam. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/libraries/viem/ --- BEGIN CONTENT --- --- title: How to use viem Ethereum Library description: Check out this tutorial to learn how to use the viem TypeScript interface for Ethereum to send transactions and deploy Solidity smart contracts to Moonbeam. categories: Libraries and SDKs, Ethereum Toolkit --- # viem TypeScript Ethereum Library ## Introduction {: #introduction } [viem](https://viem.sh){target=\_blank} is a modular TypeScript library that allows developers to interact with abstractions over the JSON-RPC API, making it easy to interact with Ethereum nodes. Since Moonbeam has an Ethereum-like API available that is fully compatible with Ethereum-style JSON RPC invocations, developers can leverage this compatibility to interact with Moonbeam nodes. For more information on viem, check out their [documentation site](https://viem.sh/docs/getting-started){target=\_blank}. In this guide, you'll learn how to use viem to send a transaction and deploy a contract on the Moonbase Alpha TestNet. This guide can be adapted for [Moonbeam](/builders/get-started/networks/moonbeam/){target=\_blank}, [Moonriver](/builders/get-started/networks/moonriver/){target=\_blank}, or a [Moonbeam development node](/builders/get-started/networks/moonbeam-dev/){target=\_blank}. ## Checking Prerequisites {: #checking-prerequisites } For the examples in this guide, you will need to have the following: - An account with funds. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} - To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank} !!! note The examples in this guide assume you have a MacOS or Ubuntu 22.04-based environment and will need to be adapted accordingly for Windows. ## Installing viem {: #installing-viem } To get started, you'll need to create a basic TypeScript project. First, create a directory to store all of the files you'll be creating throughout this guide, and initialize the project with the following command: ```bash mkdir viem-examples && cd viem-examples && npm init --y ``` For this guide, you'll need to install the viem library and the Solidity compiler. To install both packages, you can run the following command: === "npm" ```bash npm install typescript ts-node viem solc@0.8.0 ``` === "yarn" ```bash yarn add typescript ts-node viem solc@0.8.0 ``` You can create a TypeScript configuration file by running: ```bash npx tsc --init ``` !!! note This tutorial was created using Node.js v18.18.0. ## Set Up a viem Client (Provider) {: #setting-up-a-viem-provider } Throughout this guide, you'll be creating a bunch of scripts that provide different functionality, such as sending a transaction, deploying a contract, and interacting with a deployed contract. In most of these scripts, you'll need to create a [viem client](https://docs.ethers.org/v6/api/providers/){target=\_blank} to interact with the network. To configure your project for Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. You can create a viem client for reading chain data, like balances or contract data, using the `createPublicClient` function, or you can create a viem client for writing chain data, like sending transactions, using the `createWalletClient` function. ### For Reading Chain Data {: #for-reading-chain-data } To create a client for reading chain data, you can take the following steps: 1. Import the `createPublicClient` and `http` functions from `viem` and the network you want to interact with from `viem/chains`. The chain can be any of the following: `moonbeam`, `moonriver`, or `moonbaseAlpha` 2. Create the `client` using the `createPublicClient` function and pass in the network and the HTTP RPC endpoint === "Moonbeam" ```ts import { createPublicClient, http } from 'viem'; import { moonbeam } from 'viem/chains'; const rpcUrl = '{{ networks.moonbeam.rpc_url }}' const publicClient = createPublicClient({ chain: moonbeam, transport: http(rpcUrl), }); ``` === "Moonriver" ```ts import { createPublicClient, http } from 'viem'; import { moonriver } from 'viem/chains'; const rpcUrl = '{{ networks.moonriver.rpc_url }}' const publicClient = createPublicClient({ chain: moonriver, transport: http(rpcUrl), }); ``` === "Moonbase Alpha" ```ts import { createPublicClient, http } from 'viem'; import { moonbaseAlpha } from 'viem/chains'; const rpcUrl = '{{ networks.moonbase.rpc_url }}' const publicClient = createPublicClient({ chain: moonbaseAlpha, transport: http(rpcUrl), }); ``` === "Moonbeam Dev Node" ```ts import { createPublicClient, http } from 'viem'; import { moonbeamDev } from 'viem/chains'; const rpcUrl = '{{ networks.development.rpc_url }}' const publicClient = createPublicClient({ chain: moonbeamDev, transport: http(rpcUrl), }) ``` ### For Writing Chain Data {: #for-writing-chain-data } To create a client for writing chain data, you can take the following steps: 1. Import the `createWalletClient` and `http` functions from `viem`, the `privateKeyToAccount` function for loading your accounts via their private keys, and the network you want to interact with from `viem/chains`. The chain can be any of the following: `moonbeam`, `moonriver`, or `moonbaseAlpha` 2. Create your account using the `privateKeyToAccount` function 3. Create the `client` using the `createWalletClient` function and pass in the account, network, and the HTTP RPC endpoint !!! remember This is for demo purposes only. Never store your private key in a TypeScript file. === "Moonbeam" ```ts import { createWalletClient, http } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; import { moonbeam } from 'viem/chains'; const account = privateKeyToAccount('INSERT_PRIVATE_KEY'); const rpcUrl = '{{ networks.moonbeam.rpc_url }}' const walletClient = createWalletClient({ account, chain: moonbeam, transport: http(rpcUrl), }); ``` === "Moonriver" ```ts import { createWalletClient, http } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; import { moonriver } from 'viem/chains'; const account = privateKeyToAccount('INSERT_PRIVATE_KEY'); const rpcUrl = '{{ networks.moonriver.rpc_url }}' const walletClient = createWalletClient({ account, chain: moonriver, transport: http(rpcUrl), }); ``` === "Moonbase Alpha" ```ts import { createWalletClient, http } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; import { moonbaseAlpha } from 'viem/chains'; const account = privateKeyToAccount('INSERT_PRIVATE_KEY'); const rpcUrl = '{{ networks.moonbase.rpc_url }}' const walletClient = createWalletClient({ account, chain: moonbaseAlpha, transport: http(rpcUrl), }); ``` === "Moonbeam Dev Node" ```ts import { createWalletClient, http } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; import { moonbeamDev } from 'viem/chains'; const account = privateKeyToAccount('INSERT_PRIVATE_KEY'); const rpcUrl = '{{ networks.development.rpc_url }}' const walletClient = createWalletClient({ account, chain: moonbeamDev, transport: http(rpcUrl), }); ``` !!! note To interact with browser-based wallets, you can use the following code to create an account: ```ts const [account] = await window.ethereum.request({ method: 'eth_requestAccounts', }); const walletClient = createWalletClient({ account, chain: moonbeam, transport: custom(window.ethereum), }); ``` ## Send a Transaction {: #send-transaction } During this section, you'll be creating a couple of scripts. The first one will be to check the balances of your accounts before trying to send a transaction. The second script will actually send the transaction. You can also use the balance script to check the account balances after the transaction has been sent. ### Check Balances Script {: #check-balances-script } You'll only need one file to check the balances of both addresses before and after the transaction is sent. To get started, you can create a `balances.ts` file by running: ```bash touch balances.ts ``` Next, you will create the script for this file and complete the following steps: 1. Update your imports to include the `createPublicClient`, `http`, and `formatEther` functions from `viem` and the network you want to interact with from `viem/chains` 2. [Set up a public viem client](#for-reading-chain-data), which can be used for reading chain data, such as account balances 3. Define the `addressFrom` and `addressTo` variables 4. Create the asynchronous `balances` function that wraps the `publicClient.getBalance` method 5. Use the `publicClient.getBalance` function to fetch the balances for the `addressFrom` and `addressTo` addresses. You can also leverage the `formatEther` function to transform the balance into a more readable number (in GLMR, MOVR, or DEV) 6. Lastly, run the `balances` function ```ts // 1. Imports import { createPublicClient, http, formatEther } from 'viem'; import { moonbaseAlpha } from 'viem/chains'; // 2. Create a public client for reading chain data const rpcUrl = 'https://rpc.api.moonbase.moonbeam.network'; const publicClient = createPublicClient({ chain: moonbaseAlpha, transport: http(rpcUrl), }); // 3. Create address variables const addressFrom = 'INSERT_FROM_ADDRESS'; const addressTo = 'INSERT_TO_ADDRESS'; // 4. Create balances function const balances = async () => { // 5. Fetch balances const balanceFrom = formatEther( await publicClient.getBalance({ address: addressFrom }) ); const balanceTo = formatEther( await publicClient.getBalance({ address: addressTo }) ); console.log(`The balance of ${addressFrom} is: ${balanceFrom} DEV`); console.log(`The balance of ${addressTo} is: ${balanceTo} DEV`); }; // 6. Call the balances function balances(); ``` To run the script and fetch the account balances, you can run the following command: ```bash npx ts-node balances.ts ``` If successful, the balances for the origin and receiving address will be displayed in your terminal in DEV.
npx ts-node balances.ts The balance of 0x3B939FeaD1557C741Ff06492FD0127bd287A421e is: 3601.72 DEV The balance of 0x78F34038c82638E0563b974246D421154C26b004 is: 0 DEV
### Send Transaction Script {: #send-transaction-script } You'll only need one file to execute a transaction between accounts. For this example, you'll be transferring 1 DEV token from an origin address (from which you hold the private key) to another address. To get started, you can create a `transaction.ts` file by running: ```bash touch transaction.ts ``` Next, you will create the script for this file and complete the following steps: 1. Update your imports to include the `createWalletClient`, `http`, and `parseEther` functions from `viem`, the `privateKeyToAccount` function from `viem/accounts`, and the network you want to interact with from `viem/chains` 2. [Set up a viem wallet client](#for-writing-chain-data) for writing chain data, which can be used along with your private key to send transactions. **Note: This is for example purposes only. Never store your private keys in a TypeScript file** 3. [Set up a public viem client](#for-reading-chain-data) for reading chain data, which will be used to wait for the transaction receipt 4. Define the `addressTo` variable 5. Create the asynchronous `send` function, which wraps the transaction object and the `walletClient.sendTransaction` method 6. Use the `walletClient.sendTransaction` function to sign and send the transaction. You'll need to pass in the transaction object, which only requires the recipient's address and the amount to send. Note that `parseEther` can be used, which handles the necessary unit conversions from Ether to Wei, similar to using `parseUnits(value, decimals)`. Use `await` to wait until the transaction is processed and the transaction hash is returned 7. Use the `publicClient.waitForTransactionReceipt` function to wait for the transaction receipt, signaling that the transaction has been completed. This is particularly helpful if you need the transaction receipt or if you're running the `balances.ts` script directly after this one to check if the balances have been updated as expected 8. Lastly, run the `send` function ```ts // 1. Imports import { createPublicClient, createWalletClient, http, parseEther } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; import { moonbaseAlpha } from 'viem/chains'; // 2. Create a wallet client for writing chain data const account = privateKeyToAccount('INSERT_PRIVATE_KEY'); const rpcUrl = 'https://rpc.api.moonbase.moonbeam.network'; const walletClient = createWalletClient({ account, chain: moonbaseAlpha, transport: http(rpcUrl), }); // 3. Create a public client for reading chain data const publicClient = createPublicClient({ chain: moonbaseAlpha, transport: http(rpcUrl), }); // 4. Create to address variable const addressTo = 'INSERT_ADDRESS'; // 5. Create send function const send = async () => { console.log( `Attempting to send transaction from ${account.address} to ${addressTo}` ); // 6. Sign and send tx const hash = await walletClient.sendTransaction({ to: addressTo, value: parseEther('1'), }); // 7. Wait for the transaction receipt await publicClient.waitForTransactionReceipt({ hash, }); console.log(`Transaction successful with hash: ${hash}`); }; // 8. Call the send function send(); ``` To run the script, you can run the following command in your terminal: ```bash npx ts-node transaction.ts ``` If the transaction was successful, in your terminal you'll see the transaction hash has been printed out. !!! note Viem requires that you prepend your private key with `0x`. Many wallets omit this `0x`, so verify you've included it as you replace `INSERT_PRIVATE_KEY`. You can also use the `balances.ts` script to check that the balances for the origin and receiving accounts have changed. The entire workflow would look like this:
npx ts-node balances.ts The balance of 0x3B939FeaD1557C741Ff06492FD0127bd287A421e is: 3601.72 DEV The balance of 0x78F34038c82638E0563b974246D421154C26b004 is: 0 DEV
npx ts-node transaction.ts Attempting to send transaction from 0x3B939FeaD1557C741Ff06492FD0127bd287A421e to 0x78F34038c82638E0563b974246D421154C26b004 Transaction successful with hash: 0xc482d907b2ae4ca1202c6cc5b486694b8439a9853caad9c2cdafec39defa1968 npx ts-node balances.ts The balance of 0x3B939FeaD1557C741Ff06492FD0127bd287A421e is: 3600.72 DEV The balance of 0x78F34038c82638E0563b974246D421154C26b004 is: 1 DEV
## Deploy a Contract {: #deploy-contract } The contract you'll be compiling and deploying in the next couple of sections is a simple incrementer contract, arbitrarily named `Incrementer.sol`. You can get started by creating a file for the contract: ```bash touch Incrementer.sol ``` Next, you can add the Solidity code to the file: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Incrementer { uint256 public number; constructor(uint256 _initialNumber) { number = _initialNumber; } function increment(uint256 _value) public { number = number + _value; } function reset() public { number = 0; } } ``` The `constructor` function, which runs when the contract is deployed, sets the initial value of the number variable stored on-chain (the default is `0`). The `increment` function adds the `_value` provided to the current number, but a transaction needs to be sent, which modifies the stored data. Lastly, the `reset` function resets the stored value to zero. !!! note This contract is a simple example for illustration purposes only and does not handle values wrapping around. ### Compile Contract Script {: #compile-contract-script } In this section, you'll create a script that uses the Solidity compiler to output the bytecode and interface (ABI) for the `Incrementer.sol` contract. To get started, you can create a `compile.ts` file by running: ```bash touch compile.ts ``` Next, you will create the script for this file and complete the following steps: 1. Import the `fs` and `solc` packages 2. Using the `fs.readFileSync` function, you'll read and save the file contents of `Incrementer.sol` to `source` 3. Build the `input` object for the Solidity compiler by specifying the `language`, `sources`, and `settings` to be used 4. Using the `input` object, you can compile the contract using `solc.compile` 5. Extract the compiled contract file and export it to be used in the deployment script ```js // 1. Import packages const fs = require('fs'); const solc = require('solc'); // 2. Get path and load contract const source = fs.readFileSync('Incrementer.sol', 'utf8'); // 3. Create input object const input = { language: 'Solidity', sources: { 'Incrementer.sol': { content: source, }, }, settings: { outputSelection: { '*': { '*': ['*'], }, }, }, }; // 4. Compile the contract const tempFile = JSON.parse(solc.compile(JSON.stringify(input))); const contractFile = tempFile.contracts['Incrementer.sol']['Incrementer']; // 5. Export contract data export default contractFile; ``` ### Deploy Contract Script {: #deploy-contract-script } With the script for compiling the `Incrementer.sol` contract in place, you can then use the results to send a signed transaction that deploys it. To do so, you can create a file for the deployment script called `deploy.ts`: ```bash touch deploy.ts ``` Next, you will create the script for this file and complete the following steps: 1. Update your imports to include the `createPublicClient`, `createWalletClient`, and `http` functions from `viem`, the `privateKeyToAccount` function from `viem/accounts`, the network you want to interact with from `viem/chains`, and the `contractFile` from the `compile.ts` file you created in the [Compile Contract Script](#compile-contract-script) section 2. [Set up a viem wallet client](#for-writing-chain-data) for writing chain data, which will be used along with your private key to deploy the `Incrementer` contract. **Note: This is for example purposes only. Never store your private keys in a TypeScript file** 3. [Set up a public viem client](#for-reading-chain-data) for reading chain data, which will be used to read the transaction receipt for the deployment 4. Load the contract `bytecode` and `abi` for the compiled contract 5. Create the asynchronous `deploy` function that will be used to deploy the contract via the `walletClient.deployContract` method 6. Use the `walletClient.deployContract` function to sign and send the transaction. You'll need to pass in the contract's ABI and bytecode, the account to deploy the transaction from, and the initial value for the incrementer. Use `await` to wait until the transaction is processed and the transaction hash is returned 7. Use the `publicClient.readContract` function to get the transaction receipt for the deployment. Use `await` to wait until the transaction is processed and the contract address is returned 8. Lastly, run the `deploy` function ```ts // 1. Update imports import { createPublicClient, createWalletClient, http } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; import { moonbaseAlpha } from 'viem/chains'; import contractFile from './compile'; // 2. Create a wallet client for writing chain data // The private key must be prepended with `0x` to avoid errors const account = privateKeyToAccount('INSERT_PRIVATE_KEY'); const rpcUrl = 'https://rpc.api.moonbase.moonbeam.network'; const walletClient = createWalletClient({ account, chain: moonbaseAlpha, transport: http(rpcUrl), }); // 3. Create a public client for reading chain data const publicClient = createPublicClient({ chain: moonbaseAlpha, transport: http(rpcUrl), }); // 4. Load contract information const bytecode = contractFile.evm.bytecode.object; const abi = contractFile.abi; const _initialNumber = 5; // 5. Create deploy function const deploy = async () => { console.log(`Attempting to deploy from account: ${account.address}`); // 6. Send tx (initial value set to 5) const contract = await walletClient.deployContract({ abi, account, bytecode, args: [_initialNumber], }); // 7. Get the transaction receipt for the deployment const transaction = await publicClient.waitForTransactionReceipt({ hash: contract, }); console.log(`Contract deployed at address: ${transaction.contractAddress}`); }; // 8. Call the deploy function deploy(); ``` To run the script, you can enter the following command into your terminal: ```bash npx ts-node deploy.ts ``` If successful, the contract's address will be displayed in the terminal.
npx ts-node deploy.ts Attempting to deploy from account: 0x3B939FeaD1557C741Ff06492FD0127bd287A421e Contract deployed at address: 0x4503b1086c6780e888194fd9caebca5f65b210c9
### Read Contract Data (Call Methods) {: #read-contract-data } Call methods are the type of interaction that doesn't modify the contract's storage (change variables), meaning no transaction needs to be sent. They simply read various storage variables of the deployed contract. To get started, you can create a file and name it `get.ts`: ```bash touch get.ts ``` Then you can take the following steps to create the script: 1. Update your imports to include the `createPublicClient` and `http` functions from `viem`, the network you want to interact with from `viem/chains`, and the `contractFile` from the `compile.ts` file you created in the [Compile Contract Script](#compile-contract-script) section 2. [Set up a public viem client](#for-reading-chain-data) for reading chain data, which will be used to read the current number of the `Incrementer` contract 3. Create the `contractAddress` variable using the address of the deployed contract and the `abi` variable using the `contractFile` from the `compile.ts` file 4. Create the asynchronous `get` function 5. Call the contract using the `publicClient.readContract` function, passing in the `abi`, the name of the function, the `contractAddress`, and any arguments (if needed). You can use `await`, which will return the value requested once the request promise resolves 6. Lastly, call the `get` function ```ts // 1. Update imports import { createPublicClient, http } from 'viem'; import { moonbaseAlpha } from 'viem/chains'; import contractFile from './compile'; // 2. Create a public client for reading chain data const rpcUrl = 'https://rpc.api.moonbase.moonbeam.network'; const client = createPublicClient({ chain: moonbaseAlpha, transport: http(rpcUrl), }); // 3. Create contract variables const contractAddress = 'INSERT_CONTRACT_ADDRESS'; const abi = contractFile.abi; // 4. Create get function const get = async () => { console.log(`Making a call to contract at address: ${contractAddress}`); // 5. Call contract const data = await client.readContract({ abi, functionName: 'number', address: contractAddress, args: [], }); console.log(`The current number stored is: ${data}`); }; // 6. Call get function get(); ``` To run the script, you can enter the following command in your terminal: ```bash npx ts-node get.ts ``` If successful, the value will be displayed in the terminal.
npx ts-node get.ts Making a call to contract at address: 0x4503b1086c6780e888194fd9caebca5f65b210c9 The current number stored is: 5
### Interact with Contract (Send Methods) {: #interact-with-contract } Send methods are the type of interactions that modify the contract's storage (change variables), meaning a transaction needs to be signed and sent. In this section, you'll create two scripts: one to increment and one to reset the incrementer. To get started, you can create a file for each script and name them `increment.ts` and `reset.ts`: ```bash touch increment.ts reset.ts ``` Open the `increment.ts` file and take the following steps to create the script: 1. Update your imports to include the `createWalletClient` and `http` functions from `viem`, the network you want to interact with from `viem/chains`, and the `contractFile` from the `compile.ts` file you created in the [Compile Contract Script](#compile-contract-script) section 2. [Set up a viem wallet client](#for-writing-chain-data) for writing chain data, which will be used along with your private key to send a transaction. **Note: This is for example purposes only. Never store your private keys in a TypeScript file** 3. [Set up a public viem client](#for-reading-chain-data) for reading chain data, which will be used to wait for the transaction receipt 4. Create the `contractAddress` variable using the address of the deployed contract, the `abi` variable using the `contractFile` from the `compile.ts` file, and the `_value` to increment the contract by 5. Create the asynchronous `increment` function 6. Call the contract using the `walletClient.writeContract` function, passing in the `abi`, the name of the function, the `contractAddress`, and the `_value`. You can use `await`, which will return the transaction hash once the request promise resolves 7. Use the `publicClient.waitForTransactionReceipt` function to wait for the transaction receipt, signaling that the transaction has been completed. This is particularly helpful if you need the transaction receipt or if you're running the `get.ts` script directly after this one to check that the current number has been updated as expected 8. Lastly, call the `increment` function ```js // 1. Update imports import { createPublicClient, createWalletClient, http } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; import { moonbaseAlpha } from 'viem/chains'; import contractFile from './compile'; // 2. Create a wallet client for writing chain data const account = privateKeyToAccount('INSERT_PRIVATE_KEY'); const rpcUrl = 'https://rpc.api.moonbase.moonbeam.network'; const walletClient = createWalletClient({ account, chain: moonbaseAlpha, transport: http(rpcUrl), }); // 3. Create a public client for reading chain data const publicClient = createPublicClient({ chain: moonbaseAlpha, transport: http(rpcUrl), }); // 4. Create contract variables const contractAddress = 'INSERT_CONTRACT_ADDRESS'; const abi = contractFile.abi; const _value = 3; // 5. Create increment function const increment = async () => { console.log( `Calling the increment by ${_value} function in contract at address: ${contractAddress}` ); // 6. Call contract const hash = await walletClient.writeContract({ abi, functionName: 'increment', address: contractAddress, args: [_value], }); // 7. Wait for the transaction receipt await publicClient.waitForTransactionReceipt({ hash, }); console.log(`Tx successful with hash: ${hash}`); }; // 8. Call increment function increment(); ``` To run the script, you can enter the following command in your terminal: ```bash npx ts-node increment.ts ``` If successful, the transaction hash will be displayed in the terminal. You can use the `get.ts` script alongside the `increment.ts` script to make sure that value is changing as expected.
npx ts-node get.ts Making a call to contract at address: 0x4503b1086c6780e888194fd9caebca5f65b210c9 The current number stored is: 5 npx ts-node increment.ts Calling the increment by 3 function in contract at address: 0x4503b1086c6780e888194fd9caebca5f65b210c9 Tx successful with hash: 0x041c9767e7a96f60f372341647430560569fd6ff64a27b4b9c6241e55dde57e1 npx ts-node get.ts Making a call to contract at address: 0x4503b1086c6780e888194fd9caebca5f65b210c9 The current number stored is: 8
Next, you can open the `reset.ts` file and take the following steps to create the script: 1. Update your imports to include the `createWalletClient` and `http` functions from `viem`, the network you want to interact with from `viem/chains`, and the `contractFile` from the `compile.ts` file you created in the [Compile Contract Script](#compile-contract-script) section 2. [Set up a viem wallet client](#for-writing-chain-data) for writing chain data, which will be used along with your private key to send a transaction. **Note: This is for example purposes only. Never store your private keys in a TypeScript file** 3. [Set up a public viem client](#for-reading-chain-data) for reading chain data, which will be used to wait for the transaction receipt 4. Create the `contractAddress` variable using the address of the deployed contract and the `abi` variable using the `contractFile` from the `compile.ts` file to increment the contract by 5. Create the asynchronous `reset` function 6. Call the contract using the `walletClient.writeContract` function, passing in the `abi`, the name of the function, the `contractAddress`, and an empty array for the arguments. You can use `await`, which will return the transaction hash once the request promise resolves 7. Use the `publicClient.waitForTransactionReceipt` function to wait for the transaction receipt, signaling that the transaction has been completed. This is particularly helpful if you need the transaction receipt or if you're running the `get.ts` script directly after this one to check that the current number has been reset to `0` 8. Lastly, call the `reset` function ```ts // 1. Update imports import { createPublicClient, createWalletClient, http } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; import { moonbaseAlpha } from 'viem/chains'; import contractFile from './compile'; // 2. Create a wallet client for writing chain data const account = privateKeyToAccount('INSERT_PRIVATE_KEY'); const rpcUrl = 'https://rpc.api.moonbase.moonbeam.network'; const walletClient = createWalletClient({ account, chain: moonbaseAlpha, transport: http(rpcUrl), }); // 3. Create a public client for reading chain data const publicClient = createPublicClient({ chain: moonbaseAlpha, transport: http(rpcUrl), }); // 4. Create contract variables const contractAddress = 'INSERT_CONTRACT_ADDRESS'; const abi = contractFile.abi; // 5. Create reset function const reset = async () => { console.log( `Calling the reset function in contract at address: ${contractAddress}` ); // 6. Call contract const hash = await walletClient.writeContract({ abi, functionName: 'reset', address: contractAddress, args: [], }); // 7. Wait for the transaction receipt await publicClient.waitForTransactionReceipt({ hash, }); console.log(`Tx successful with hash: ${hash}`); }; // 8. Call reset function reset(); ``` To run the script, you can enter the following command in your terminal: ```bash npx ts-node reset.ts ``` If successful, the transaction hash will be displayed in the terminal. You can use the `get.ts` script alongside the `reset.ts` script to make sure that value is changing as expected.
npx ts-node get.ts Making a call to contract at address: 0x4503b1086c6780e888194fd9caebca5f65b210c9 The current number stored is: 8 npx ts-node reset.ts Calling the reset function in contract at address: 0x4503b1086c6780e888194fd9caebca5f65b210c9 Tx successful with hash: 0xc1a772131ccf6a03675ff3e88798a6e70a99e145eeb0e98170ff2e3345ee14a7 npx ts-node get.ts Making a call to contract at address: 0x4503b1086c6780e888194fd9caebca5f65b210c9 The current number stored is: 0
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/libraries/web3js/ --- BEGIN CONTENT --- --- title: How to use Web3.js Ethereum Library description: Follow this tutorial to learn how to use the Ethereum Web3 JavaScript Library to deploy Solidity smart contracts to Moonbeam. categories: Libraries and SDKs, Ethereum Toolkit --- # Web3.js JavaScript Library ## Introduction {: #introduction } !!! warning Web3.js has been [sunset](https://blog.chainsafe.io/web3-js-sunset/){target=\_blank}. You can find tutorials on using [Ethers.js](/builders/ethereum/libraries/ethersjs/){target=\_blank} and [viem](/builders/ethereum/libraries/viem/){target=\_blank} on the [Libraries](/builders/ethereum/libraries/){target=\_blank} page. [Web3.js](https://web3js.readthedocs.io){target=\_blank} is a set of libraries that allow developers to interact with Ethereum nodes using HTTP, IPC, or WebSocket protocols with JavaScript. Moonbeam has an Ethereum-like API available that is fully compatible with Ethereum-style JSON-RPC invocations. Therefore, developers can leverage this compatibility and use the Web3.js library to interact with a Moonbeam node as if they were doing so on Ethereum. In this guide, you'll learn how to use the Web3.js library to send a transaction and deploy a contract on Moonbase Alpha. This guide can be adapted for [Moonbeam](/builders/get-started/networks/moonbeam/){target=\_blank}, [Moonriver](/builders/get-started/networks/moonriver/){target=\_blank}, or a [Moonbeam development node](/builders/get-started/networks/moonbeam-dev/){target=\_blank}. ## Checking Prerequisites {: #checking-prerequisites } For the examples in this guide, you will need to have the following: - An account with funds. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} - To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank} !!! note The examples in this guide assume you have a MacOS or Ubuntu 22.04-based environment and will need to be adapted accordingly for Windows. ## Installing Web3.js {: #install-web3js } To get started, you'll need to start a basic JavaScript project. First, create a directory to store all of the files you'll be creating throughout this guide, and initialize the project with the following command: ```bash mkdir web3-examples && cd web3-examples && npm init --y ``` For this guide, you'll need to install the Web3.js library and the Solidity compiler. To install both NPM packages, you can run the following command: === "npm" ```bash npm install web3 solc@0.8.0 ``` === "yarn" ```bash yarn add web3 solc@0.8.0 ``` ## Setup Web3.js with Moonbeam {: #setup-web3-with-moonbeam } You can configure Web3.js to work with any of the Moonbeam networks. To configure your project for Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. The simplest way to get started with each of the networks is as follows: === "Moonbeam" ```js const { Web3 } = require('web3'); // Create Web3 instance const web3 = new Web3('{{ networks.moonbeam.rpc_url }}'); // Insert your RPC URL here ``` === "Moonriver" ```js const { Web3 } = require('web3'); // Create Web3 instance const web3 = new Web3('{{ networks.moonriver.rpc_url }}'); // Insert your RPC URL here ``` === "Moonbase Alpha" ```js const { Web3 } = require('web3'); // Create Web3 instance const web3 = new Web3('{{ networks.moonbase.rpc_url }}'); ``` === "Moonbeam Dev Node" ```js const { Web3 } = require('web3'); // Create Web3 instance const web3 = new Web3('{{ networks.development.rpc_url }}'); ``` Save this code snippet, as you'll need it for the scripts that are used in the following sections. ## Send a Transaction {: #send-a-transaction } During this section, you'll be creating a couple of scripts. The first one will be to check the balances of your accounts before trying to send a transaction. The second script will actually send the transaction. You can also use the balance script to check the account balances after the transaction has been sent. ### Check Balances Script {: #check-balances-script } You'll only need one file to check the balances of both addresses before and after the transaction is sent. To get started, you can create a `balances.js` file by running: ```bash touch balances.js ``` Next, you will create the script for this file and complete the following steps: 1. [Set up the Web3 provider](#setup-web3-with-moonbeam) 2. Define the `addressFrom` and `addressTo` variables 3. Create the asynchronous `balances` function, which wraps the `web3.eth.getBalance` method 4. Use the `web3.eth.getBalance` function to fetch the balances for the `addressFrom` and `addressTo` addresses. You can also leverage the `web3.utils.fromWei` function to transform the balance into a more readable number in DEV 5. Lastly, run the `balances` function ```js // 1. Add the Web3 provider logic // {...} // 2. Create address variables const addressFrom = 'INSERT_FROM_ADDRESS'; const addressTo = 'INSERT_TO_ADDRESS'; // 3. Create balances function const balances = async () => { // 4. Fetch balance info const balanceFrom = web3.utils.fromWei( await web3.eth.getBalance(addressFrom), 'ether' ); const balanceTo = web3.utils.fromWei( await web3.eth.getBalance(addressTo), 'ether' ); console.log(`The balance of ${addressFrom} is: ${balanceFrom} DEV`); console.log(`The balance of ${addressTo} is: ${balanceTo} DEV`); }; // 5. Call balances function balances(); ``` ??? code "View the complete script" ```js const { Web3 } = require('web3'); // 1. Add the Web3 provider logic here: const providerRPC = { development: 'http://localhost:9944', moonbase: 'https://rpc.api.moonbase.moonbeam.network', }; const web3 = new Web3(providerRPC.moonbase); // Change to correct network // 2. Create address variables const addressFrom = 'INSERT_FROM_ADDRESS'; const addressTo = 'INSERT_TO_ADDRESS'; // 3. Create balances function const balances = async () => { // 4. Fetch balance info const balanceFrom = web3.utils.fromWei(await web3.eth.getBalance(addressFrom), 'ether'); const balanceTo = web3.utils.fromWei(await web3.eth.getBalance(addressTo), 'ether'); console.log(`The balance of ${addressFrom} is: ${balanceFrom} DEV`); console.log(`The balance of ${addressTo} is: ${balanceTo} DEV`); }; // 5. Call balances function balances(); ``` To run the script and fetch the account balances, you can run the following command: ```bash node balances.js ``` If successful, the balances for the origin and receiving address will be displayed in your terminal in DEV. ### Send Transaction Script {: #send-transaction-script } You'll only need one file to execute a transaction between accounts. For this example, you'll be transferring 1 DEV token from an origin address (from which you hold the private key) to another address. To get started, you can create a `transaction.js` file by running: ```bash touch transaction.js ``` Next, you will create the script for this file and complete the following steps: 1. [Set up the Web3 provider](#setup-web3-with-moonbeam) 2. Define the `accountFrom`, including the `privateKey`, and the `addressTo` variables. The private key is required to create a wallet instance. **Note: This is for example purposes only. Never store your private keys in a JavaScript file** 3. Create the asynchronous `send` function, which wraps the transaction object, and the sign and send transaction functions 4. Create and sign the transaction using the `web3.eth.accounts.signTransaction` function. Pass in the `gas`, `addressTo`, `value`, `gasPrice`, and `nonce` for the transaction along with the sender's `privateKey` 5. Send the signed transaction using the `web3.eth.sendSignedTransaction` method and pass in the raw transaction. Then use `await` to wait until the transaction is processed and the transaction receipt is returned 6. Lastly, run the `send` function ```js // 1. Add the Web3 provider logic // {...} // 2. Create account variables const accountFrom = { privateKey: 'INSERT_YOUR_PRIVATE_KEY', address: 'INSERT_PUBLIC_ADDRESS_OF_PK', }; const addressTo = 'INSERT_TO_ADDRESS'; // Change addressTo // 3. Create send function const send = async () => { console.log( `Attempting to send transaction from ${accountFrom.address} to ${addressTo}` ); // 4. Sign transaction with PK const createTransaction = await web3.eth.accounts.signTransaction( { gas: 21000, to: addressTo, value: web3.utils.toWei('1', 'ether'), gasPrice: await web3.eth.getGasPrice(), nonce: await web3.eth.getTransactionCount(accountFrom.address), }, accountFrom.privateKey ); // 5. Send transaction and wait for receipt const createReceipt = await web3.eth.sendSignedTransaction( createTransaction.rawTransaction ); console.log( `Transaction successful with hash: ${createReceipt.transactionHash}` ); }; // 6. Call send function send(); ``` ??? code "View the complete script" ```js const { Web3 } = require('web3'); // 1. Add the Web3 provider logic const providerRPC = { development: 'http://localhost:9944', moonbase: 'https://rpc.api.moonbase.moonbeam.network', }; const web3 = new Web3(providerRPC.moonbase); // Change to correct network // 2. Create account variables const accountFrom = { privateKey: 'INSERT_YOUR_PRIVATE_KEY', address: 'INSERT_PUBLIC_ADDRESS_OF_PK', }; const addressTo = 'INSERT_TO_ADDRESS'; // 3. Create send function const send = async () => { console.log( `Attempting to send transaction from ${accountFrom.address} to ${addressTo}` ); // 4. Sign transaction with PK const createTransaction = await web3.eth.accounts.signTransaction( { gas: 21000, to: addressTo, value: web3.utils.toWei('1', 'ether'), gasPrice: await web3.eth.getGasPrice(), nonce: await web3.eth.getTransactionCount(accountFrom.address), }, accountFrom.privateKey ); // 5. Send transaction and wait for receipt const createReceipt = await web3.eth.sendSignedTransaction( createTransaction.rawTransaction ); console.log( `Transaction successful with hash: ${createReceipt.transactionHash}` ); }; // 6. Call send function send(); ``` To run the script, you can run the following command in your terminal: ```bash node transaction.js ``` If the transaction was successful, in your terminal, you'll see the transaction hash has been printed out. You can also use the `balances.js` script to check that the balances for the origin and receiving accounts have changed. The entire workflow would look like this:
node balances.js The balance of 0x3B939FeaD1557C741Ff06492FD0127bd287A421e is: 3603.67979115380310679 DEV The balance of 0xe29A0699e079FeBEe94A02f35C31B026f90F6040 is: 0. DEV node transaction.js Attempting to send transaction from 0x3B939FeaD1557C741Ff06492FD0127bd287A421e to 0xe29A0699e079FeBEe94A02f35C31B026f90F6040 Transaction successful with hash: 0xf1d628ed12c5f40e03e29aa2c23c8c09680ee595c60607c7363a81c0be8ef3cb node balances.js The balance of 0x3B939FeaD1557C741Ff06492FD0127bd287A421e is: 3602.67978852880310679 DEV The balance of 0xe29A0699e079FeBEe94A02f35C31B026f90F6040 is: 1 DEV
### Common Errors When Sending Transactions {: #common-errors } When sending a transaction with Web3.js, it is important that you have all of the required data for the transaction. You'll need to provide the `from` address or the `nonce` of the sender, the `gas` or `gasLimit`, and the `gasPrice`. If you do not specify the `from` address or the `nonce` of the sender, you may receive the following error: ```bash UnableToPopulateNonceError: Invalid value given "UnableToPopulateNonceError". Error: unable to populate nonce, no from address available. ``` To fix this, simply add either the `from` or `nonce` field to the transaction object. If you do not specify the gas correctly, you may receive the following error: ```bash MissingGasError: Invalid value given "gas: 0x5208, gasPrice: undefined, maxPriorityFeePerGas: undefined, maxFeePerGas: undefined". Error: "gas" is missing. ``` To resolve this error, you'll need to make sure that you've provided a `gasPrice` for the transaction. You can use `await web3.eth.getGasPrice()` to programmatically get this value. ## Deploy a Contract {: #deploy-a-contract } The contract you'll be compiling and deploying in the next couple of sections is a simple incrementer contract, arbitrarily named `Incrementer.sol`. You can get started by creating a file for the contract: ```bash touch Incrementer.sol ``` Next, you can add the Solidity code to the file: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Incrementer { uint256 public number; constructor(uint256 _initialNumber) { number = _initialNumber; } function increment(uint256 _value) public { number = number + _value; } function reset() public { number = 0; } } ``` The `constructor` function, which runs when the contract is deployed, sets the initial value of the number variable stored on-chain (the default is `0`). The `increment` function adds the `_value` provided to the current number, but a transaction needs to be sent, which modifies the stored data. Lastly, the `reset` function resets the stored value to zero. !!! note This contract is a simple example for illustration purposes only and does not handle values wrapping around. ### Compile Contract Script {: #compile-contract-script } In this section, you'll create a script that uses the Solidity compiler to output the bytecode and interface (ABI) for the `Incrementer.sol` contract. To get started, you can create a `compile.js` file by running: ```bash touch compile.js ``` Next, you will create the script for this file and complete the following steps: 1. Import the `fs` and `solc` packages 2. Using the `fs.readFileSync` function, you'll read and save the file contents of `Incrementer.sol` to `source` 3. Build the `input` object for the Solidity compiler by specifying the `language`, `sources`, and `settings` to be used 4. Using the `input` object, you can compile the contract using `solc.compile` 5. Extract the compiled contract file and export it to be used in the deployment script ```js // 1. Import packages const fs = require('fs'); const solc = require('solc'); // 2. Get path and load contract const source = fs.readFileSync('Incrementer.sol', 'utf8'); // 3. Create input object const input = { language: 'Solidity', sources: { 'Incrementer.sol': { content: source, }, }, settings: { outputSelection: { '*': { '*': ['*'], }, }, }, }; // 4. Compile the contract const tempFile = JSON.parse(solc.compile(JSON.stringify(input))); const contractFile = tempFile.contracts['Incrementer.sol']['Incrementer']; // 5. Export contract data module.exports = contractFile; ``` ### Deploy Contract Script {: #deploy-contract-script } With the script for compiling the `Incrementer.sol` contract in place, you can then use the results to send a signed transaction that deploys it. To do so, you can create a file for the deployment script called `deploy.js`: ```bash touch deploy.js ``` Next, you will create the script for this file and complete the following steps: 1. Import the contract file from `compile.js` 2. [Set up the Web3 provider](#setup-web3-with-moonbeam) 3. Define the `accountFrom`, including the `privateKey`, and the `addressTo` variables. The private key is required to create a wallet instance. **Note: This is for example purposes only. Never store your private keys in a JavaScript file** 4. Save the `bytecode` and `abi` for the compiled contract 5. Create the asynchronous `deploy` function that will be used to deploy the contract 6. Create the contract instance using the `web3.eth.Contract` function 7. Create the constructor and pass in the `bytecode` and the initial value for the incrementer. For this example, you can set the initial value to `5` 8. Create and sign the transaction using the `web3.eth.accounts.signTransaction` function. Pass in the `data`, `gas`, `gasPrice`, and `nonce` for the transaction along with the sender's `privateKey` 9. Send the signed transaction using the `web3.eth.sendSignedTransaction` method and pass in the raw transaction. Then use `await` to wait until the transaction is processed and the transaction receipt is returned 10. Lastly, run the `deploy` function ```js // 1. Import the contract file const contractFile = require('./compile'); // 2. Add the Web3 provider logic // {...} // 3. Create address variables const accountFrom = { privateKey: 'INSERT_YOUR_PRIVATE_KEY', address: 'INSERT_PUBLIC_ADDRESS_OF_PK', }; // 4. Get the bytecode and ABI const bytecode = contractFile.evm.bytecode.object; const abi = contractFile.abi; // 5. Create deploy function const deploy = async () => { console.log(`Attempting to deploy from account ${accountFrom.address}`); // 6. Create contract instance const incrementer = new web3.eth.Contract(abi); // 7. Create constructor transaction const incrementerTx = incrementer.deploy({ data: bytecode, arguments: [5], }); // 8. Sign transaction with PK const createTransaction = await web3.eth.accounts.signTransaction( { data: incrementerTx.encodeABI(), gas: await incrementerTx.estimateGas(), gasPrice: await web3.eth.getGasPrice(), nonce: await web3.eth.getTransactionCount(accountFrom.address), }, accountFrom.privateKey ); // 9. Send transaction and wait for receipt const createReceipt = await web3.eth.sendSignedTransaction( createTransaction.rawTransaction ); console.log(`Contract deployed at address: ${createReceipt.contractAddress}`); }; // 10. Call deploy function deploy(); ``` ??? code "View the complete script" ```js // 1. Import web3 and the contract file const { Web3 } = require('web3'); const contractFile = require('./compile'); // 2. Add the Web3 provider logic const providerRPC = { development: 'http://localhost:9944', moonbase: 'https://rpc.api.moonbase.moonbeam.network', }; const web3 = new Web3(providerRPC.moonbase); // Change to correct network // 3. Create address variables const accountFrom = { privateKey: 'INSERT_YOUR_PRIVATE_KEY', address: 'INSERT_PUBLIC_ADDRESS_OF_PK', }; // 4. Get the bytecode and API const bytecode = contractFile.evm.bytecode.object; const abi = contractFile.abi; // 5. Create deploy function const deploy = async () => { console.log(`Attempting to deploy from account ${accountFrom.address}`); // 6. Create contract instance const incrementer = new web3.eth.Contract(abi); // 7. Create constructor transaction const incrementerTx = incrementer.deploy({ data: bytecode, arguments: [5], }); // 8. Sign transaction with PK const createTransaction = await web3.eth.accounts.signTransaction( { data: incrementerTx.encodeABI(), gas: await incrementerTx.estimateGas(), gasPrice: await web3.eth.getGasPrice(), nonce: await web3.eth.getTransactionCount(accountFrom.address), }, accountFrom.privateKey ); // 9. Send transaction and wait for receipt const createReceipt = await web3.eth.sendSignedTransaction( createTransaction.rawTransaction ); console.log(`Contract deployed at address: ${createReceipt.contractAddress}`); }; // 10. Call deploy function deploy(); ``` To run the script, you can enter the following command into your terminal: ```bash node deploy.js ``` If successful, the contract's address will be displayed in the terminal.
node deploy.js Attempting to deploy from account 0x3B939FeaD1557C741Ff06492FD0127bd287A421e Contract deployed at address: 0x6dcb33a7f6235e74fd553b50c96f900707142892
### Read Contract Data (Call Methods) {: #read-contract-data } Call methods are the type of interaction that doesn't modify the contract's storage (change variables), meaning no transaction needs to be sent. They simply read various storage variables of the deployed contract. To get started, you can create a file and name it `get.js`: ```bash touch get.js ``` Then you can take the following steps to create the script: 1. Import the `abi` from the `compile.js` file 2. [Set up the Web3 provider](#setup-web3-with-moonbeam) 3. Create the `contractAddress` variable using the address of the deployed contract 4. Create an instance of the contract using the `web3.eth.Contract` function and passing in the `abi` and `contractAddress` 5. Create the asynchronous `get` function 6. Use the contract instance to call one of the contract's methods and pass in any inputs if necessary. For this example, you will call the `number` method which doesn't require any inputs. You can use `await`, which will return the value requested once the request promise resolves 7. Lastly, call the `get` function ```js // 1. Import the contract ABI const { abi } = require('./compile'); // 2. Add the Web3 provider logic // {...} // 3. Create address variables const contractAddress = 'INSERT_CONTRACT_ADDRESS'; // 4. Create contract instance const incrementer = new web3.eth.Contract(abi, contractAddress); // 5. Create get function const get = async () => { console.log(`Making a call to contract at address: ${contractAddress}`); // 6. Call contract const data = await incrementer.methods.number().call(); console.log(`The current number stored is: ${data}`); }; // 7. Call get function get(); ``` ??? code "View the complete script" ```js // 1. Import Web3js and the contract ABI const { Web3 } = require('web3'); const { abi } = require('./compile'); // 2. Add the Web3 provider logic const providerRPC = { development: 'http://localhost:9944', moonbase: 'https://rpc.api.moonbase.moonbeam.network', }; const web3 = new Web3(providerRPC.moonbase); // Change to correct network // 3. Create address variables const contractAddress = 'INSERT_CONTRACT_ADDRESS'; // 4. Create contract instance const incrementer = new web3.eth.Contract(abi, contractAddress); // 5. Create get function const get = async () => { console.log(`Making a call to contract at address: ${contractAddress}`); // 6. Call contract const data = await incrementer.methods.number().call(); console.log(`The current number stored is: ${data}`); }; // 7. Call get function get(); ``` To run the script, you can enter the following command in your terminal: ```bash node get.js ``` If successful, the value will be displayed in the terminal. ### Interact with Contract (Send Methods) {: #interact-with-contract } Send methods are the type of interaction that modifies the contract's storage (change variables), meaning a transaction needs to be signed and sent. In this section, you'll create two scripts: one to increment and one to reset the incrementer. To get started, you can create a file for each script and name them `increment.js` and `reset.js`: ```bash touch increment.js reset.js ``` Open the `increment.js` file and take the following steps to create the script: 1. Import the `abi` from the `compile.js` file 2. [Set up the Web3 provider](#setup-web3-with-moonbeam) 3. Define the `privateKey` for the origin account, the `contractAddress` of the deployed contract, and the `_value` to increment by. The private key is required to create a wallet instance. **Note: This is for example purposes only. Never store your private keys in a JavaScript file** 4. Create an instance of the contract using the `web3.eth.Contract` function and passing in the `abi` and `contractAddress` 5. Use the contract instance to build the increment transaction using the `methods.increment` function and passing in the `_value` as an input 6. Create the asynchronous `increment` function 7. Use the contract instance and the increment transaction you previously created to sign the transaction with the sender's private key. You'll use the `web3.eth.accounts.signTransaction` function and specify the `to` address, `data`, `gas`, `gasPrice`, and `nonce` for the transaction 8. Send the signed transaction using the `web3.eth.sendSignedTransaction` method and pass in the raw transaction. Then use `await` to wait until the transaction is processed and the transaction receipt is returned 9. Lastly, call the `increment` function ```js // 1. Import the contract ABI const { abi } = require('./compile'); // 2. Add the Web3 provider logic // {...} // 3. Create variables const accountFrom = { privateKey: 'INSERT_YOUR_PRIVATE_KEY', address: 'INSERT_PUBLIC_ADDRESS_OF_PK', }; const contractAddress = 'INSERT_CONTRACT_ADDRESS'; const _value = 3; // 4. Create contract instance const incrementer = new web3.eth.Contract(abi, contractAddress); // 5. Build the increment transaction const incrementTx = incrementer.methods.increment(_value); // 6. Create increment function const increment = async () => { console.log( `Calling the increment by ${_value} function in contract at address: ${contractAddress}` ); // 7. Sign transaction with PK const createTransaction = await web3.eth.accounts.signTransaction( { to: contractAddress, data: incrementTx.encodeABI(), gas: await incrementTx.estimateGas(), gasPrice: await web3.eth.getGasPrice(), nonce: await web3.eth.getTransactionCount(accountFrom.address), }, accountFrom.privateKey ); // 8. Send transaction and wait for receipt const createReceipt = await web3.eth.sendSignedTransaction( createTransaction.rawTransaction ); console.log(`Tx successful with hash: ${createReceipt.transactionHash}`); }; // 9. Call increment function increment(); ``` ??? code "View the complete script" ```js // 1. Import Web3js and the contract ABI const { Web3 } = require('web3'); const { abi } = require('./compile'); // 2. Add the Web3 provider logic const providerRPC = { development: 'http://localhost:9944', moonbase: 'https://rpc.api.moonbase.moonbeam.network', }; const web3 = new Web3(providerRPC.moonbase); // Change to correct network // 3. Create variables const accountFrom = { privateKey: 'INSERT_YOUR_PRIVATE_KEY', address: 'INSERT_PUBLIC_ADDRESS_OF_PK', }; const contractAddress = 'INSERT_CONTRACT_ADDRESS'; const _value = 3; // 4. Create contract instance const incrementer = new web3.eth.Contract(abi, contractAddress); // 5. Build increment transaction const incrementTx = incrementer.methods.increment(_value); // 6. Create increment function const increment = async () => { console.log( `Calling the increment by ${_value} function in contract at address: ${contractAddress}` ); // 7. Sign transaction with PK const createTransaction = await web3.eth.accounts.signTransaction( { to: contractAddress, data: incrementTx.encodeABI(), gas: await incrementTx.estimateGas(), gasPrice: await web3.eth.getGasPrice(), nonce: await web3.eth.getTransactionCount(accountFrom.address), }, accountFrom.privateKey ); // 8. Send transaction and wait for receipt const createReceipt = await web3.eth.sendSignedTransaction( createTransaction.rawTransaction ); console.log(`Tx successful with hash: ${createReceipt.transactionHash}`); }; // 9. Call increment function increment(); ``` To run the script, you can enter the following command in your terminal: ```bash node increment.js ``` If successful, the transaction hash will be displayed in the terminal. You can use the `get.js` script alongside the `increment.js` script to make sure that value is changing as expected:
node get.js Making a call to contract at address: 0x6dcb33a7f6235e74fd553b50c96f900707142892 The current number stored is: 5 node increment.js Calling the increment by 3 function in contract at address: 0x6dcb33a7f6235e74fd553b50c96f900707142892 Tx successful with hash: 0xb03d1426376e7efc49d8b6c69aaf91e548578db7fd4a9ba575dbd8030821f6a3 node get.js Making a call to contract at address: 0x6dcb33a7f6235e74fd553b50c96f900707142892 The current number stored is: 8
Next, you can open the `reset.js` file and take the following steps to create the script: 1. Import the `abi` from the `compile.js` file 2. [Set up the Web3 provider](#setup-web3-with-moonbeam) 3. Define the `privateKey` for the origin account and the `contractAddress` of the deployed contract. The private key is required to create a wallet instance. **Note: This is for example purposes only. Never store your private keys in a JavaScript file** 4. Create an instance of the contract using the `web3.eth.Contract` function and passing in the `abi` and `contractAddress` 5. Use the contract instance to build the reset transaction using the `methods.reset` function 6. Create the asynchronous `reset` function 7. Use the contract instance and the reset transaction you previously created to sign the transaction with the sender's private key. You'll use the `web3.eth.accounts.signTransaction` function and specify the `to` address, `data`, `gas`, `gasPrice`, and `nonce` for the transaction 8. Send the signed transaction using the `web3.eth.sendSignedTransaction` method and pass in the raw transaction. Then use `await` to wait until the transaction is processed and the transaction receipt is returned 9. Lastly, call the `reset` function ```js // 1. Import the contract ABI const { abi } = require('./compile'); // 2. Add the Web3 provider logic // {...} // 3. Create variables const accountFrom = { privateKey: 'INSERT_YOUR_PRIVATE_KEY', address: 'INSERT_PUBLIC_ADDRESS_OF_PK', }; const contractAddress = 'INSERT_CONTRACT_ADDRESS'; // 4. Create a contract instance const incrementer = new web3.eth.Contract(abi, contractAddress); // 5. Build reset transaction const resetTx = incrementer.methods.reset(); // 6. Create reset function const reset = async () => { console.log( `Calling the reset function in contract at address: ${contractAddress}` ); // 7. Sign transaction with PK const createTransaction = await web3.eth.accounts.signTransaction( { to: contractAddress, data: resetTx.encodeABI(), gas: await resetTx.estimateGas(), gasPrice: await web3.eth.getGasPrice(), nonce: await web3.eth.getTransactionCount(accountFrom.address), }, accountFrom.privateKey ); // 8. Send transaction and wait for receipt const createReceipt = await web3.eth.sendSignedTransaction( createTransaction.rawTransaction ); console.log(`Tx successful with hash: ${createReceipt.transactionHash}`); }; // 9. Call reset function reset(); ``` ??? code "View the complete script" ```js // 1. Import Web3js and the contract ABI const { Web3 } = require('web3'); const { abi } = require('./compile'); // 2. Add the Web3 provider logic const providerRPC = { development: 'http://localhost:9944', moonbase: 'https://rpc.api.moonbase.moonbeam.network', }; const web3 = new Web3(providerRPC.moonbase); // Change to correct network // 3. Create variables const accountFrom = { privateKey: 'INSERT_YOUR_PRIVATE_KEY', address: 'INSERT_PUBLIC_ADDRESS_OF_PK', }; const contractAddress = 'INSERT_CONTRACT_ADDRESS'; // 4. Create contract instance const incrementer = new web3.eth.Contract(abi, contractAddress); // 5. Build reset transaction const resetTx = incrementer.methods.reset(); // 6. Create reset function const reset = async () => { console.log(`Calling the reset function in contract at address: ${contractAddress}`); // 7. Sign transaction with PK const createTransaction = await web3.eth.accounts.signTransaction( { to: contractAddress, data: resetTx.encodeABI(), gas: await resetTx.estimateGas(), gasPrice: await web3.eth.getGasPrice(), nonce: await web3.eth.getTransactionCount(accountFrom.address), }, accountFrom.privateKey ); // 8. Send transaction and wait for receipt const createReceipt = await web3.eth.sendSignedTransaction(createTransaction.rawTransaction); console.log(`Tx successful with hash: ${createReceipt.transactionHash}`); }; // 9. Call reset function reset(); ``` To run the script, you can enter the following command in your terminal: ```bash node reset.js ``` If successful, the transaction hash will be displayed in the terminal. You can use the `get.js` script alongside the `reset.js` script to make sure that value is changing as expected:
node get.js Making a call to contract at address: 0x6dcb33a7f6235e74fd553b50c96f900707142892 The current number stored is: 8 node reset.js Calling the reset function in contract at address: 0x6dcb33a7f6235e74fd553b50c96f900707142892 Tx successful with hash: 0x557e908ca4da05d5af50983dbc116fbf8049bb2e86b9ec1e9f7d3f516b8a4c55 node get.js Making a call to contract at address: 0x6dcb33a7f6235e74fd553b50c96f900707142892 The current number stored is: 0
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/libraries/web3py/ --- BEGIN CONTENT --- --- title: How to use Web3.py Ethereum Library description: Follow this tutorial to learn how to use the Ethereum Web3 Python Library to to send transactions and deploy Solidity smart contracts to Moonbeam. categories: Libraries and SDKs, Ethereum Toolkit --- # Web3.py Python Library ## Introduction {: #introduction } [Web3.py](https://web3py.readthedocs.io) is a set of libraries that allow developers to interact with Ethereum nodes using HTTP, IPC, or WebSocket protocols with Python. Moonbeam has an Ethereum-like API available that is fully compatible with Ethereum-style JSON-RPC invocations. Therefore, developers can leverage this compatibility and use the Web3.py library to interact with a Moonbeam node as if they were doing so on Ethereum. In this guide, you'll learn how to use the Web3.py library to send a transaction and deploy a contract on Moonbase Alpha. This guide can be adapted for [Moonbeam](/builders/get-started/networks/moonbeam/){target=\_blank}, [Moonriver](/builders/get-started/networks/moonriver/){target=\_blank}, or a [Moonbeam development node](/builders/get-started/networks/moonbeam-dev/){target=\_blank}. ## Checking Prerequisites {: #checking-prerequisites } For the examples in this guide, you will need to have the following: - An account with funds. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} - To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank} !!! note The examples in this guide assume you have a MacOS or Ubuntu 22.04-based environment and will need to be adapted accordingly for Windows. ## Create a Python Project {: #create-a-python-project } To get started, you can create a directory to store all of the files you'll be creating throughout this guide: ```bash mkdir web3-examples && cd web3-examples ``` For this guide, you'll need to install the Web3.py library and the Solidity compiler. To install both packages, you can run the following command: ```bash pip3 install web3 py-solc-x solc-select ``` ## Setup Web3.py with Moonbeam {: #setup-web3-with-moonbeam } Throughout this guide, you'll be creating a bunch of scripts that provide different functionalities, such as sending a transaction, deploying a contract, and interacting with a deployed contract. In most of these scripts, you'll need to create a [Web3.py provider](https://web3py.readthedocs.io/en/stable/providers.html){target=\_blank} to interact with the network. To configure your project for Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. To create a provider, you can take the following steps: 1. Import the `web3` library 2. Create the `web3` provider using the `Web3(Web3.HTTPProvider())` method and providing the endpoint URL === "Moonbeam" ```python # 1. Import web3.py from web3 import Web3 # 2. Create web3.py provider web3 = Web3(Web3.HTTPProvider("{{ networks.moonbeam.rpc_url }}")) # Insert your RPC URL here ``` === "Moonriver" ```python # 1. Import web3.py from web3 import Web3 # 2. Create web3.py provider web3 = Web3(Web3.HTTPProvider("{{ networks.moonriver.rpc_url }}")) # Insert your RPC URL here ``` === "Moonbase Alpha" ```python # 1. Import web3.py from web3 import Web3 # 2. Create web3.py provider web3 = Web3(Web3.HTTPProvider("{{ networks.moonbase.rpc_url }}")) ``` === "Moonbeam Dev Node" ```python # 1. Import web3.py from web3 import Web3 # 2. Create web3.py provider web3 = Web3(Web3.HTTPProvider("{{ networks.development.rpc_url }}")) ``` Save this code snippet, as you'll need it for the scripts that are used in the following sections. ## Send a Transaction {: #send-a-transaction } During this section, you'll be creating a couple of scripts. The first one will be to check the balances of your accounts before trying to send a transaction. The second script will actually send the transaction. You can also use the balance script to check the account balances after the transaction has been sent. ### Check Balances Script {: #check-balances-script } You'll only need one file to check the balances of both addresses before and after the transaction is sent. To get started, you can create a `balances.py` file by running: ```bash touch balances.py ``` Next, you will create the script for this file and complete the following steps: 1. [Set up the Web3 provider](#setup-web3-with-moonbeam) 2. Define the `address_from` and `address_to` variables 3. Get the balance for the accounts using the `web3.eth.get_balance` function and format the results using the `web3.from_wei` ```python from web3 import Web3 # 1. Add the Web3 provider logic here: provider_rpc = { "development": "http://localhost:9944", "moonbase": "https://rpc.api.moonbase.moonbeam.network", } web3 = Web3(Web3.HTTPProvider(provider_rpc["moonbase"])) # Change to correct network # 2. Create address variables address_from = 'INSERT_FROM_ADDRESS' address_to = 'INSERT_TO_ADDRESS' # 3. Fetch balance data balance_from = web3.from_wei( web3.eth.get_balance(Web3.to_checksum_address(address_from)), "ether" ) balance_to = web3.from_wei( web3.eth.get_balance(Web3.to_checksum_address(address_to)), "ether" ) print(f"The balance of { address_from } is: { balance_from } DEV") print(f"The balance of { address_to } is: { balance_to } DEV") ``` To run the script and fetch the account balances, you can run the following command: ```bash python3 balances.py ``` If successful, the balances for the origin and receiving address will be displayed in your terminal in ETH. ### Send Transaction Script {: #send-transaction-script } You'll only need one file for executing a transaction between accounts. For this example, you'll be transferring 1 DEV token from an origin address (from which you hold the private key) to another address. To get started, you can create a `transaction.py` file by running: ```bash touch transaction.py ``` Next, you will create the script for this file and complete the following steps: 1. Add imports, including Web3.py and the `rpc_gas_price_strategy`, which will be used in the following steps to get the gas price used for the transaction 2. [Set up the Web3 provider](#setup-web3-with-moonbeam) 3. Define the `account_from`, including the `private_key`, and the `address_to` variables. The private key is required to sign the transaction. **Note: This is for example purposes only. Never store your private keys in a Python file** 4. Use the [Web3.py Gas Price API](https://web3py.readthedocs.io/en/stable/gas_price.html){target=\_blank} to set a gas price strategy. For this example, you'll use the imported `rpc_gas_price_strategy` 5. Create and sign the transaction using the `web3.eth.account.sign_transaction` function. Pass in the `nonce` `gas`, `gasPrice`, `to`, and `value` for the transaction along with the sender's `private_key`. To get the `nonce` you can use the `web3.eth.get_transaction_count` function and pass in the sender's address. To predetermine the `gasPrice` you'll use the `web3.eth.generate_gas_price` function. For the `value`, you can format the amount to send from an easily readable format to Wei using the `web3.to_wei` function 6. Using the signed transaction, you can then send it using the `web3.eth.send_raw_transaction` function and wait for the transaction receipt by using the `web3.eth.wait_for_transaction_receipt` function ```python # 1. Add imports from web3.gas_strategies.rpc import rpc_gas_price_strategy from web3 import Web3 # 2. Add the Web3 provider logic here: provider_rpc = { "development": "http://localhost:9944", "moonbase": "https://rpc.api.moonbase.moonbeam.network", } web3 = Web3(Web3.HTTPProvider(provider_rpc["moonbase"])) # Change to correct network # 3. Create address variables account_from = { 'private_key': 'INSERT_YOUR_PRIVATE_KEY', 'address': 'INSERT_PUBLIC_ADDRESS_OF_PK', } address_to = 'INSERT_TO_ADDRESS' print( f'Attempting to send transaction from { account_from["address"] } to { address_to }' ) # 4. Set the gas price strategy web3.eth.set_gas_price_strategy(rpc_gas_price_strategy) # 5. Sign tx with PK tx_create = web3.eth.account.sign_transaction( { "nonce": web3.eth.get_transaction_count( Web3.to_checksum_address(account_from["address"]) ), "gasPrice": web3.eth.generate_gas_price(), "gas": 21000, "to": Web3.to_checksum_address(address_to), "value": web3.to_wei("1", "ether"), }, account_from["private_key"], ) # 6. Send tx and wait for receipt tx_hash = web3.eth.send_raw_transaction(tx_create.rawTransaction) tx_receipt = web3.eth.wait_for_transaction_receipt(tx_hash) print(f"Transaction successful with hash: { tx_receipt.transactionHash.hex() }") ``` To run the script, you can run the following command in your terminal: ```bash python3 transaction.py ``` If the transaction was successful, in your terminal you'll see the transaction hash has been printed out. You can also use the `balances.py` script to check that the balances for the origin and receiving accounts have changed. The entire workflow would look like this:
python3 balances.py The balance of 0x3B939FeaD1557C741Ff06492FD0127bd287A421e is: 3563.79 DEV The balance of 0x9Bf5Ae10540a1ab9B363bEA02A9406E6b2efA9af is: 0 DEV python3 transaction.py Attempting to send transaction from 0x3B939FeaD1557C741Ff06492FD0127bd287A421e to 0x9Bf5Ae10540a1ab9B363bEA02A9406E6b2efA9af Transaction successful with hash: 0xac70452510657ed43c27510578d3ce4b3b880d4cca1a24ade1497c6e0ee7f5d6 python3 balances.py The balance of 0x3B939FeaD1557C741Ff06492FD0127bd287A421e is: 3562.79 DEV The balance of 0x9Bf5Ae10540a1ab9B363bEA02A9406E6b2efA9af is: 1 DEV
## Deploy a Contract {: #deploy-a-contract } The contract you'll be compiling and deploying in the next couple of sections is a simple incrementer contract, arbitrarily named `Incrementer.sol`. You can get started by creating a file for the contract: ```bash touch Incrementer.sol ``` Next, you can add the Solidity code to the file: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Incrementer { uint256 public number; constructor(uint256 _initialNumber) { number = _initialNumber; } function increment(uint256 _value) public { number = number + _value; } function reset() public { number = 0; } } ``` The `constructor` function, which runs when the contract is deployed, sets the initial value of the number variable stored on-chain (the default is `0`). The `increment` function adds the `_value` provided to the current number, but a transaction needs to be sent, which modifies the stored data. Lastly, the `reset` function resets the stored value to zero. !!! note This contract is a simple example for illustration purposes only and does not handle values wrapping around. ### Compile Contract Script {: #compile-contract-script } In this section, you'll create a script that uses the Solidity compiler to output the bytecode and interface (ABI) for the `Incrementer.sol` contract. To get started, you can create a `compile.py` file by running: ```bash touch compile.py ``` Next, you will create the script for this file and complete the following steps: 1. Import the `solcx` package 2. **Optional** - If you haven't already installed the Solidity compiler, you can do so with by using the `solcx.install_solc` function 3. Compile the `Incrementer.sol` function using the `solcx.compile_files` function 4. Export the contract's ABI and bytecode ```python # 1. Import solcx import solcx # 2. If you haven't already installed the Solidity compiler, uncomment the following line # solcx.install_solc() # 3. Compile contract temp_file = solcx.compile_files( 'Incrementer.sol', output_values=['abi', 'bin'], # solc_version='0.8.19' ) # 4. Export contract data abi = temp_file['Incrementer.sol:Incrementer']['abi'] bytecode = temp_file['Incrementer.sol:Incrementer']['bin'] ``` !!! note If you see an error stating that `Solc is not installed`, uncomment step 2 described in the code snippet. ### Deploy Contract Script {: #deploy-contract-script } With the script for compiling the `Incrementer.sol` contract in place, you can then use the results to send a signed transaction that deploys it. To do so, you can create a file for the deployment script called `deploy.py`: ```bash touch deploy.py ``` Next, you will create the script for this file and complete the following steps: 1. Add imports, including Web3.py and the ABI and bytecode of the `Incrementer.sol` contract 2. [Set up the Web3 provider](#setup-web3-with-moonbeam) 3. Define the `account_from`, including the `private_key`. The private key is required to sign the transaction. **Note: This is for example purposes only. Never store your private keys in a Python file** 4. Create a contract instance using the `web3.eth.contract` function and passing in the ABI and bytecode of the contract 5. Build a constructor transaction using the contract instance and passing in the value to increment by. For this example, you can use `5`. You'll then use the `build_transaction` function to pass in the transaction information including the `from` address and the `nonce` for the sender. To get the `nonce` you can use the `web3.eth.get_transaction_count` function 6. Sign the transaction using the `web3.eth.account.sign_transaction` function and pass in the constructor transaction and the `private_key` of the sender 7. Using the signed transaction, you can then send it using the `web3.eth.send_raw_transaction` function and wait for the transaction receipt by using the `web3.eth.wait_for_transaction_receipt` function ```python # 1. Add imports from compile import abi, bytecode from web3 import Web3 # 2. Add the Web3 provider logic here: provider_rpc = { "development": "http://localhost:9944", "moonbase": "https://rpc.api.moonbase.moonbeam.network", } web3 = Web3(Web3.HTTPProvider(provider_rpc["moonbase"])) # Change to correct network # 3. Create address variable account_from = { 'private_key': 'INSERT_YOUR_PRIVATE_KEY', 'address': 'INSERT_PUBLIC_ADDRESS_OF_PK', } print(f'Attempting to deploy from account: { account_from["address"] }') # 4. Create contract instance Incrementer = web3.eth.contract(abi=abi, bytecode=bytecode) # 5. Build constructor tx construct_txn = Incrementer.constructor(5).build_transaction( { "from": Web3.to_checksum_address(account_from["address"]), "nonce": web3.eth.get_transaction_count( Web3.to_checksum_address(account_from["address"]) ), } ) # 6. Sign tx with PK tx_create = web3.eth.account.sign_transaction( construct_txn, account_from["private_key"] ) # 7. Send tx and wait for receipt tx_hash = web3.eth.send_raw_transaction(tx_create.rawTransaction) tx_receipt = web3.eth.wait_for_transaction_receipt(tx_hash) print(f"Contract deployed at address: { tx_receipt.contractAddress }") ``` To run the script, you can enter the following command into your terminal: ```bash python3 deploy.py ``` If successful, the contract's address will be displayed in the terminal.
python3 deploy.py Attempting to deploy from account: 0x3B939FeaD1557C741Ff06492FD0127bd287A421e Contract deployed at address: 0xFef3cFb8eE1FE727b3848E551ae5DC8903237B08
### Read Contract Data (Call Methods) {: #read-contract-data } Call methods are the type of interaction that don't modify the contract's storage (change variables), meaning no transaction needs to be sent. They simply read various storage variables of the deployed contract. To get started, you can create a file and name it `get.py`: ```bash touch get.py ``` Then you can take the following steps to create the script: 1. Add imports, including Web3.py and the ABI of the `Incrementer.sol` contract 2. [Set up the Web3 provider](#setup-web3-with-moonbeam) 3. Define the `contract_address` of the deployed contract 4. Create a contract instance using the `web3.eth.contract` function and passing in the ABI and address of the deployed contract 5. Using the contract instance, you can then call the `number` function ```python # 1. Import the ABI from compile import abi from web3 import Web3 # 2. Add the Web3 provider logic here: provider_rpc = { "development": "http://localhost:9944", "moonbase": "https://rpc.api.moonbase.moonbeam.network", } web3 = Web3(Web3.HTTPProvider(provider_rpc["moonbase"])) # Change to correct network # 3. Create address variable contract_address = 'INSERT_CONTRACT_ADDRESS' print(f"Making a call to contract at address: { contract_address }") # 4. Create contract instance Incrementer = web3.eth.contract(address=contract_address, abi=abi) # 5. Call Contract number = Incrementer.functions.number().call() print(f"The current number stored is: { number } ") ``` To run the script, you can enter the following command in your terminal: ```bash python3 get.py ``` If successful, the value will be displayed in the terminal. ### Interact with Contract (Send Methods) {: #interact-with-contract } Send methods are the type of interaction that modify the contract's storage (change variables), meaning a transaction needs to be signed and sent. In this section, you'll create two scripts: one to increment and one to reset the incrementer. To get started, you can create a file for each script and name them `increment.py` and `reset.py`: ```bash touch increment.py reset.py ``` Open the `increment.py` file and take the following steps to create the script: 1. Add imports, including Web3.py and the ABI of the `Incrementer.sol` contract 2. [Set up the Web3 provider](#setup-web3-with-moonbeam) 3. Define the `account_from`, including the `private_key`, the `contract_address` of the deployed contract, and the `value` to increment by. The private key is required to sign the transaction. **Note: This is for example purposes only. Never store your private keys in a Python file** 4. Create a contract instance using the `web3.eth.contract` function and passing in the ABI and address of the deployed contract 5. Build the increment transaction using the contract instance and passing in the value to increment by. You'll then use the `build_transaction` function to pass in the transaction information including the `from` address and the `nonce` for the sender. To get the `nonce` you can use the `web3.eth.get_transaction_count` function 6. Sign the transaction using the `web3.eth.account.sign_transaction` function and pass in the increment transaction and the `private_key` of the sender 7. Using the signed transaction, you can then send it using the `web3.eth.send_raw_transaction` function and wait for the transaction receipt by using the `web3.eth.wait_for_transaction_receipt` function ```python # 1. Add imports from compile import abi from web3 import Web3 # 2. Add the Web3 provider logic here: provider_rpc = { "development": "http://localhost:9944", "moonbase": "https://rpc.api.moonbase.moonbeam.network", } web3 = Web3(Web3.HTTPProvider(provider_rpc["moonbase"])) # Change to correct network # 3. Create variables account_from = { 'private_key': 'INSERT_YOUR_PRIVATE_KEY', 'address': 'INSERT_PUBLIC_ADDRESS_OF_PK', } contract_address = 'INSERT_CONTRACT_ADDRESS' value = 3 print( f"Calling the increment by { value } function in contract at address: { contract_address }" ) # 4. Create contract instance Incrementer = web3.eth.contract(address=contract_address, abi=abi) # 5. Build increment tx increment_tx = Incrementer.functions.increment(value).build_transaction( { "from": Web3.to_checksum_address(account_from["address"]), "nonce": web3.eth.get_transaction_count( Web3.to_checksum_address(account_from["address"]) ), } ) # 6. Sign tx with PK tx_create = web3.eth.account.sign_transaction(increment_tx, account_from["private_key"]) # 7. Send tx and wait for receipt tx_hash = web3.eth.send_raw_transaction(tx_create.rawTransaction) tx_receipt = web3.eth.wait_for_transaction_receipt(tx_hash) print(f"Tx successful with hash: { tx_receipt.transactionHash.hex() }") ``` To run the script, you can enter the following command in your terminal: ```bash python3 increment.py ``` If successful, the transaction hash will be displayed in the terminal. You can use the `get.py` script alongside the `increment.py` script to make sure that value is changing as expected:
python get.py Making a call to contract at address: 0xFef3cFb8eE1FE727b3848E551ae5DC8903237B08 The current number stored is: 5 python increment.py Calling the increment by 3 function in contract at address: 0xFef3cFb8eE1FE727b3848E551ae5DC8903237B08 Tx successful with hash: 0x47757fd97e3ef8db973e335d1f2d19c46b37d0dbd53fea1636ec559ccf119a13 python get.py Making a call to contract at address: 0xFef3cFb8eE1FE727b3848E551ae5DC8903237B08 The current number stored is: 8
Next you can open the `reset.py` file and take the following steps to create the script: 1. Add imports, including Web3.py and the ABI of the `Incrementer.sol` contract 2. [Set up the Web3 provider](#setup-web3-with-moonbeam) 3. Define the `account_from`, including the `private_key`, and the `contract_address` of the deployed contract. The private key is required to sign the transaction. **Note: This is for example purposes only. Never store your private keys in a Python file** 4. Create a contract instance using the `web3.eth.contract` function and passing in the ABI and address of the deployed contract 5. Build the reset transaction using the contract instance. You'll then use the `build_transaction` function to pass in the transaction information including the `from` address and the `nonce` for the sender. To get the `nonce` you can use the `web3.eth.get_transaction_count` function 6. Sign the transaction using the `web3.eth.account.sign_transaction` function and pass in the reset transaction and the `private_key` of the sender 7. Using the signed transaction, you can then send it using the `web3.eth.send_raw_transaction` function and wait for the transaction receipt by using the `web3.eth.wait_for_transaction_receipt` function ```python # 1. Add imports from compile import abi from web3 import Web3 # 2. Add the Web3 provider logic here: provider_rpc = { "development": "http://localhost:9944", "moonbase": "https://rpc.api.moonbase.moonbeam.network", } web3 = Web3(Web3.HTTPProvider(provider_rpc["moonbase"])) # Change to correct network # 3. Create variables account_from = { 'private_key': 'INSERT_YOUR_PRIVATE_KEY', 'address': 'INSERT_PUBLIC_ADDRESS_OF_PK', } contract_address = 'INSERT_CONTRACT_ADDRESS' print(f"Calling the reset function in contract at address: { contract_address }") # 4. Create contract instance Incrementer = web3.eth.contract(address=contract_address, abi=abi) # 5. Build reset tx reset_tx = Incrementer.functions.reset().build_transaction( { "from": Web3.to_checksum_address(account_from["address"]), "nonce": web3.eth.get_transaction_count( Web3.to_checksum_address(account_from["address"]) ), } ) # 6. Sign tx with PK tx_create = web3.eth.account.sign_transaction(reset_tx, account_from["private_key"]) # 7. Send tx and wait for receipt tx_hash = web3.eth.send_raw_transaction(tx_create.rawTransaction) tx_receipt = web3.eth.wait_for_transaction_receipt(tx_hash) print(f"Tx successful with hash: { tx_receipt.transactionHash.hex() }") ``` To run the script, you can enter the following command in your terminal: ```bash python3 reset.py ``` If successful, the transaction hash will be displayed in the terminal. You can use the `get.py` script alongside the `reset.py` script to make sure that value is changing as expected:
python get.py Making a call to contract at address: 0xFef3cFb8eE1FE727b3848E551ae5DC8903237B08 The current number stored is: 8 python reset.py Calling the reset function in contract at address: 0xFef3cFb8eE1FE727b3848E551ae5DC8903237B08 Tx successful with hash: 0x152f07430b524838da848b44d58577db252681fba6fbeaf117b2f9d432e301b2 python get.py Making a call to contract at address: 0xFef3cFb8eE1FE727b3848E551ae5DC8903237B08 The current number stored is: 0
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/account/identity/ --- BEGIN CONTENT --- --- title: Identity Precompile description: Learn all you need to know about the Identity Precompile, such as its address, Solidity interface, and how to interact with it using popular Ethereum libraries. categories: Precompiles, Ethereum Toolkit --- # Identity Precompile on Moonbeam ## Introduction {: #introduction } The Identity Precompile is a Solidity interface that allows you to create, manage, and retrieve information on on-chain identities. Identities are attached to accounts and include personal information, such as your legal name, display name, website, Twitter handle, Riot (now known as Element) name, and more. You can also take advantage of custom fields to include any other relevant information. The Identity Precompile interacts directly with Substrate's [Identity Pallet](/builders/substrate/interfaces/account/identity/){target=\_blank} to provide the functionality needed to create and manage identities. This pallet is coded in Rust and is normally not accessible from the Ethereum side of Moonbeam. However, the Identity Precompile allows you to access this functionality directly from the Solidity interface. The Identity Precompile is located at the following address: === "Moonbeam" ```text {{networks.moonbeam.precompiles.identity }} ``` === "Moonriver" ```text {{networks.moonriver.precompiles.identity }} ``` === "Moonbase Alpha" ```text {{networks.moonbase.precompiles.identity }} ``` !!! note There can be some unintended consequences when using the precompiled contracts on Moonbeam. Please refer to the [Security Considerations](/learn/core-concepts/security/){target=\_blank} page for more information. ## The Identity Precompile Solidity Interface {: #the-solidity-interface } [`Identity.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/identity/Identity.sol){target=\_blank} is a Solidity interface that allows developers to interact with the precompile's methods. ??? code "Identity.sol" ```solidity // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.3; /// @dev The Identity contract's address. address constant IDENTITY_ADDRESS = 0x0000000000000000000000000000000000000818; /// @dev The Identity contract's instance. Identity constant IDENTITY_CONTRACT = Identity(IDENTITY_ADDRESS); /// @author The Moonbeam Team /// @title Pallet Identity Interface /// @title The interface through which solidity contracts will interact with the Identity pallet /// @custom:address 0x0000000000000000000000000000000000000818 interface Identity { /// @dev Associated raw data. struct Data { /// Is `true` if it represents data, else the absence of data is represented by `false`. bool hasData; /// The contained value. bytes value; } /// @dev The super-identity of an alternative "sub" identity. struct SuperOf { /// Is `true` if the struct is valid, `false` otherwise. bool isValid; /// The super account. address account; /// The associated data. Data data; } /// @dev Alternative "sub" identities of an account. struct SubsOf { /// The deposit against this identity. uint256 deposit; /// The sub accounts address[] accounts; } /// @dev Registrar judgements are limited to attestations on these fields. struct IdentityFields { /// Set to `true` if the display field is supported, `false` otherwise. bool display; /// Set to `true` if the legal field is supported, `false` otherwise. bool legal; /// Set to `true` if the web field is supported, `false` otherwise. bool web; /// Set to `true` if the riot field is supported, `false` otherwise. bool riot; /// Set to `true` if the email field is supported, `false` otherwise. bool email; /// Set to `true` if the PGP Fingerprint field is supported, `false` otherwise. bool pgpFingerprint; /// Set to `true` if the image field is supported, `false` otherwise. bool image; /// Set to `true` if the twitter field is supported, `false` otherwise. bool twitter; } /// @dev Registrar info. struct Registrar { /// Is `true` if the struct is valid, `false` otherwise. bool isValid; /// The registrar's index. uint32 index; /// The account address. address account; /// Amount required to be given to the registrar for them to provide judgement. uint256 fee; /// Relevant fields for this registrar. IdentityFields fields; } /// @dev Represents an additional field in identity info. struct Additional { /// The assciated key. Data key; /// The assciated value. Data value; } /// @dev The identity information set for an account. struct IdentityInfo { /// Represents the additional fields for the identity. Additional[] additional; /// Represents the display info for the identity. Data display; /// Represents the legal info for the identity. Data legal; /// Represents the web info for the identity. Data web; /// Represents the riot info for the identity. Data riot; /// Represents the email info for the identity. Data email; /// Set to `true` if `pgpFingerprint` is set, `false` otherwise. bool hasPgpFingerprint; /// Represents a 20-byte the PGP fingerprint info for the identity. bytes pgpFingerprint; /// Represents the image info for the identity. Data image; /// Represents the twitter info for the identity. Data twitter; } /// @dev Judgement provided by a registrar. struct Judgement { /// The default value; no opinion is held. bool isUnknown; /// No judgement is yet in place, but a deposit is reserved as payment for providing one. bool isFeePaid; /// The deposit reserved for providing a judgement. uint256 feePaidDeposit; /// The data appears to be reasonably acceptable in terms of its accuracy. bool isReasonable; /// The target is known directly by the registrar and the registrar can fully attest to it. bool isKnownGood; /// The data was once good but is currently out of date. bool isOutOfDate; /// The data is imprecise or of sufficiently low-quality to be problematic. bool isLowQuality; /// The data is erroneous. This may be indicative of malicious intent. bool isErroneous; } /// @dev Judgement item provided by a registrar. struct JudgementInfo { /// The registrar's index that provided this judgement. uint32 registrarIndex; /// The registrar's provided judgement. Judgement judgement; } /// @dev Registrar info. struct Registration { /// Is `true` if the struct is valid, `false` otherwise. bool isValid; /// The judgments provided on this identity. JudgementInfo[] judgements; /// Amount required to be given to the registrar for them to provide judgement. uint256 deposit; /// The associated identity info. IdentityInfo info; } /// @dev Alternative "sub" identity of an account. struct SubAccount { /// The account address. address account; /// The associated data. Data data; } /// @dev Retrieve identity information for an account. /// @custom:selector f0eb5e54 /// @param who The requested account function identity(address who) external view returns (Registration memory); /// @dev Retrieve super account for an account. /// @custom:selector c18110d6 /// @param who The requested account function superOf(address who) external view returns (SuperOf memory); /// @dev Retrieve sub accounts for an account. /// @custom:selector 3f08986b /// @param who The requested account function subsOf(address who) external view returns (SubsOf memory); /// @dev Retrieve the registrars. /// @custom:selector e88e512e function registrars() external view returns (Registrar[] memory); /// @dev Set identity info for the caller. /// @custom:selector 7e08b4cb /// @param info The identity info function setIdentity(IdentityInfo memory info) external; /// @dev Set sub accounts for the caller. /// @custom:selector 5a5a3591 /// @param subs The sub accounts function setSubs(SubAccount[] memory subs) external; /// @dev Clears identity of the caller. /// @custom:selector 7a6a10c7 function clearIdentity() external; /// @dev Requests registrar judgement on caller's identity. /// @custom:selector d523ceb9 /// @param regIndex The registrar's index /// @param maxFee The maximum fee the caller is willing to pay function requestJudgement(uint32 regIndex, uint256 maxFee) external; /// @dev Cancels the caller's request for judgement from a registrar. /// @custom:selector c79934a5 /// @param regIndex The registrar's index function cancelRequest(uint32 regIndex) external; /// @dev Sets the registrar's fee for providing a judgement. Caller must be the account at the index. /// @custom:selector a541b37d /// @param regIndex The registrar's index /// @param fee The fee the registrar will charge function setFee(uint32 regIndex, uint256 fee) external; /// @dev Sets the registrar's account. Caller must be the account at the index. /// @custom:selector 889bc198 /// @param regIndex The registrar's index /// @param newAccount The new account to set function setAccountId(uint32 regIndex, address newAccount) external; /// @dev Sets the registrar's identity fields. Caller must be the account at the index. /// @custom:selector 05297450 /// @param regIndex The registrar's index /// @param fields The identity fields function setFields(uint32 regIndex, IdentityFields memory fields) external; /// @dev Provides judgement on an accounts identity. /// @custom:selector cd7663a4 /// @param regIndex The registrar's index /// @param target The target account to provide judgment for /// @param judgement The judgement to provide /// @param identity The hash of the identity info function provideJudgement( uint32 regIndex, address target, Judgement memory judgement, bytes32 identity ) external; /// @dev Add a "sub" identity account for the caller. /// @custom:selector 98717196 /// @param sub The sub account /// @param data The associated data function addSub(address sub, Data memory data) external; /// @dev Rename a "sub" identity account of the caller. /// @custom:selector 452df561 /// @param sub The sub account /// @param data The new associated data function renameSub(address sub, Data memory data) external; /// @dev Removes a "sub" identity account of the caller. /// @custom:selector b0a323e0 /// @param sub The sub account function removeSub(address sub) external; /// @dev Removes the sender as a sub-account. /// @custom:selector d5a3c2c4 function quitSub() external; /// @dev An identity was set or reset (which will remove all judgements). /// @custom:selector 3839f7832b2a6263aa1fd5040f37d10fd4f9e9c4a9ef07ec384cb1cef9fb4c0e /// @param who Address of the target account event IdentitySet(address who); /// @dev An identity was cleared, and the given balance returned. /// @custom:selector 3839f7832b2a6263aa1fd5040f37d10fd4f9e9c4a9ef07ec384cb1cef9fb4c0e /// @param who Address of the target account event IdentityCleared(address who); /// @dev A judgement was asked from a registrar. /// @custom:selector 3839f7832b2a6263aa1fd5040f37d10fd4f9e9c4a9ef07ec384cb1cef9fb4c0e /// @param who Address of the requesting account /// @param registrarIndex The registrar's index event JudgementRequested(address who, uint32 registrarIndex); /// @dev A judgement request was retracted. /// @custom:selector 3839f7832b2a6263aa1fd5040f37d10fd4f9e9c4a9ef07ec384cb1cef9fb4c0e /// @param who Address of the target account. /// @param registrarIndex The registrar's index event JudgementUnrequested(address who, uint32 registrarIndex); /// @dev A judgement was given by a registrar. /// @custom:selector 3839f7832b2a6263aa1fd5040f37d10fd4f9e9c4a9ef07ec384cb1cef9fb4c0e /// @param target Address of the target account /// @param registrarIndex The registrar's index event JudgementGiven(address target, uint32 registrarIndex); /// @dev A sub-identity was added to an identity and the deposit paid. /// @custom:selector 3839f7832b2a6263aa1fd5040f37d10fd4f9e9c4a9ef07ec384cb1cef9fb4c0e /// @param sub Address of the sub account /// @param main Address of the main account event SubIdentityAdded(address sub, address main); /// @dev A sub-identity was removed from an identity and the deposit freed. /// @custom:selector 3839f7832b2a6263aa1fd5040f37d10fd4f9e9c4a9ef07ec384cb1cef9fb4c0e /// @param sub Address of the sub account /// @param main Address of the main account event SubIdentityRemoved(address sub, address main); /// @dev A sub-identity was cleared and the given deposit repatriated from the main identity account to the sub-identity account /// @custom:selector 3839f7832b2a6263aa1fd5040f37d10fd4f9e9c4a9ef07ec384cb1cef9fb4c0e /// @param sub Address of the sub account event SubIdentityRevoked(address sub); } ``` The Identity Precompile contains some functions that can be called by anyone and some judgment-related functions that can only be called by a registrar. The functions that can be called by anyone are as follows: ??? function "**identity**(*address* who) - returns registration information for a given account" === "Parameters" - `who` - address of the account to query the identity information for ??? function "**superOf**(*address* who) - retrieves the super account for a sub-account. If the given account is not a sub-account, the address returned is `0x0000000000000000000000000000000000000000`" === "Parameters" - `who` - address of the account to query the super-account for ??? function "**subsOf**(*address* who) - returns the sub-accounts for a given account. If the given account doesn't have any sub-accounts, an empty array is returned (`[]`)" === "Parameters" - `who` - address of the account to query the sub-accounts for ??? function "**registrars**() - returns the list of registrars" === "Parameters" None. ??? function "**setIdentity**(*IdentityInfo memory* info) - sets the identity for the caller" === "Parameters" - `info` - IdentityInfo memory struct containing the identity information to be set ??? function "**setSubs**(*SubAccount[] memory* subs) - sets the sub-accounts for the caller" === "Parameters" - `subs` - SubAccount[] memory array containing the sub-accounts to be set ??? function "**clearIdentity**() - clears the identity for the caller" === "Parameters" None. ??? function "**requestJudgement**(*uint32* regIndex, *uint256* maxFee) - requests judgment from a given registrar along with the maximum fee the caller is willing to pay" === "Parameters" - `regIndex` - uint32 index of the registrar to request judgment from - `maxFee` - uint256 maximum fee the caller is willing to pay for the judgment ??? function "**cancelRequest**(*uint32* regIndex) - cancels the caller's request for judgment from a given registrar" === "Parameters" - `regIndex` - uint32 index of the registrar to cancel the judgment request from ??? function "**addSub**(*address* sub, *Data memory* data) - adds a sub-identity account for the caller" === "Parameters" - `sub` - address of the sub-account to add - `data` - Data memory struct containing the sub-account information ??? function "**renameSub**(*address* sub, *Data memory* data) - renames a sub-identity account for the caller" === "Parameters" - `sub` - address of the sub-account to rename - `data` - Data memory struct containing the new sub-account information ??? function "**removeSub**(*address* sub) - removes a sub identity account for the caller" === "Parameters" - `sub` - address of the sub-account to remove ??? function "**quitSub**(*address* sub) - removes the caller as a sub-identity account" === "Parameters" - `sub` - address of the sub-account to quit The judgment-related functions that must be called by a registrar and the caller must be the registrar account that corresponds to the `regIndex` are: ??? function "**setFee**(*uint32* regIndex, *uint256* fee) - sets the fee for a registrar" === "Parameters" - `regIndex` - uint32 index of the registrar setting the fee - `fee` - uint256 new fee amount to be set for the registrar ??? function "**setAccountId**(*uint32* regIndex, *address* newAccount) - sets a new account for a registrar" === "Parameters" - `regIndex` - uint32 index of the registrar being updated - `newAccount` - address of the new account to be set for the registrar ??? function "**setFields**(*uint32* regIndex, *IdentityFields memory* fields) - sets the registrar's identity" === "Parameters" - `regIndex` - uint32 index of the registrar setting their identity fields - `fields` - IdentityFields memory struct containing the identity fields to be set ??? function "**provideJudgement**(*uint32* regIndex, *address* target, *Judgement memory* judgement, *bytes32* identity) - provides judgment on an account's identity" === "Parameters" - `regIndex` - uint32 index of the registrar providing the judgment - `target` - address of the account receiving the judgment - `judgement` - Judgement memory struct containing the judgment details - `identity` - bytes32 hash of the identity information being judged ## Interact with the Solidity Interface {: #interact-with-interface } The following sections will cover how to interact with the Identity Precompile using [Ethereum libraries](/builders/ethereum/libraries/){target=\_blank}, such as [Ethers.js](/builders/ethereum/libraries/ethersjs/){target=\_blank}, [Web3.js](/builders/ethereum/libraries/web3js/){target=\_blank}, and [Web3.py](/builders/ethereum/libraries/web3py/){target=\_blank}. The examples in this guide will be on Moonbase Alpha. To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. ### Using Ethereum Libraries {: #use-ethereum-libraries } To interact with the Identity Precompile's Solidity interface with an Ethereum library, you'll need the Identity Precompile's ABI. ??? code "Identity Precompile ABI" ```js [ { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "address", "name": "who", "type": "address" } ], "name": "IdentityCleared", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "address", "name": "who", "type": "address" } ], "name": "IdentitySet", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "address", "name": "target", "type": "address" }, { "indexed": false, "internalType": "uint32", "name": "registrarIndex", "type": "uint32" } ], "name": "JudgementGiven", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "address", "name": "who", "type": "address" }, { "indexed": false, "internalType": "uint32", "name": "registrarIndex", "type": "uint32" } ], "name": "JudgementRequested", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "address", "name": "who", "type": "address" }, { "indexed": false, "internalType": "uint32", "name": "registrarIndex", "type": "uint32" } ], "name": "JudgementUnrequested", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "address", "name": "sub", "type": "address" }, { "indexed": false, "internalType": "address", "name": "main", "type": "address" } ], "name": "SubIdentityAdded", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "address", "name": "sub", "type": "address" }, { "indexed": false, "internalType": "address", "name": "main", "type": "address" } ], "name": "SubIdentityRemoved", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "address", "name": "sub", "type": "address" } ], "name": "SubIdentityRevoked", "type": "event" }, { "inputs": [ { "internalType": "address", "name": "sub", "type": "address" }, { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "data", "type": "tuple" } ], "name": "addSub", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "uint32", "name": "regIndex", "type": "uint32" } ], "name": "cancelRequest", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "clearIdentity", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "who", "type": "address" } ], "name": "identity", "outputs": [ { "components": [ { "internalType": "bool", "name": "isValid", "type": "bool" }, { "components": [ { "internalType": "uint32", "name": "registrarIndex", "type": "uint32" }, { "components": [ { "internalType": "bool", "name": "isUnknown", "type": "bool" }, { "internalType": "bool", "name": "isFeePaid", "type": "bool" }, { "internalType": "uint256", "name": "feePaidDeposit", "type": "uint256" }, { "internalType": "bool", "name": "isReasonable", "type": "bool" }, { "internalType": "bool", "name": "isKnownGood", "type": "bool" }, { "internalType": "bool", "name": "isOutOfDate", "type": "bool" }, { "internalType": "bool", "name": "isLowQuality", "type": "bool" }, { "internalType": "bool", "name": "isErroneous", "type": "bool" } ], "internalType": "struct Identity.Judgement", "name": "judgement", "type": "tuple" } ], "internalType": "struct Identity.JudgementInfo[]", "name": "judgements", "type": "tuple[]" }, { "internalType": "uint256", "name": "deposit", "type": "uint256" }, { "components": [ { "components": [ { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "key", "type": "tuple" }, { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "value", "type": "tuple" } ], "internalType": "struct Identity.Additional[]", "name": "additional", "type": "tuple[]" }, { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "display", "type": "tuple" }, { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "legal", "type": "tuple" }, { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "web", "type": "tuple" }, { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "riot", "type": "tuple" }, { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "email", "type": "tuple" }, { "internalType": "bool", "name": "hasPgpFingerprint", "type": "bool" }, { "internalType": "bytes", "name": "pgpFingerprint", "type": "bytes" }, { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "image", "type": "tuple" }, { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "twitter", "type": "tuple" } ], "internalType": "struct Identity.IdentityInfo", "name": "info", "type": "tuple" } ], "internalType": "struct Identity.Registration", "name": "", "type": "tuple" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "uint32", "name": "regIndex", "type": "uint32" }, { "internalType": "address", "name": "target", "type": "address" }, { "components": [ { "internalType": "bool", "name": "isUnknown", "type": "bool" }, { "internalType": "bool", "name": "isFeePaid", "type": "bool" }, { "internalType": "uint256", "name": "feePaidDeposit", "type": "uint256" }, { "internalType": "bool", "name": "isReasonable", "type": "bool" }, { "internalType": "bool", "name": "isKnownGood", "type": "bool" }, { "internalType": "bool", "name": "isOutOfDate", "type": "bool" }, { "internalType": "bool", "name": "isLowQuality", "type": "bool" }, { "internalType": "bool", "name": "isErroneous", "type": "bool" } ], "internalType": "struct Identity.Judgement", "name": "judgement", "type": "tuple" }, { "internalType": "bytes32", "name": "identity", "type": "bytes32" } ], "name": "provideJudgement", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "quitSub", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "registrars", "outputs": [ { "components": [ { "internalType": "bool", "name": "isValid", "type": "bool" }, { "internalType": "uint32", "name": "index", "type": "uint32" }, { "internalType": "address", "name": "account", "type": "address" }, { "internalType": "uint256", "name": "fee", "type": "uint256" }, { "components": [ { "internalType": "bool", "name": "display", "type": "bool" }, { "internalType": "bool", "name": "legal", "type": "bool" }, { "internalType": "bool", "name": "web", "type": "bool" }, { "internalType": "bool", "name": "riot", "type": "bool" }, { "internalType": "bool", "name": "email", "type": "bool" }, { "internalType": "bool", "name": "pgpFingerprint", "type": "bool" }, { "internalType": "bool", "name": "image", "type": "bool" }, { "internalType": "bool", "name": "twitter", "type": "bool" } ], "internalType": "struct Identity.IdentityFields", "name": "fields", "type": "tuple" } ], "internalType": "struct Identity.Registrar[]", "name": "", "type": "tuple[]" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "sub", "type": "address" } ], "name": "removeSub", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "sub", "type": "address" }, { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "data", "type": "tuple" } ], "name": "renameSub", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "uint32", "name": "regIndex", "type": "uint32" }, { "internalType": "uint256", "name": "maxFee", "type": "uint256" } ], "name": "requestJudgement", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "uint32", "name": "regIndex", "type": "uint32" }, { "internalType": "address", "name": "newAccount", "type": "address" } ], "name": "setAccountId", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "uint32", "name": "regIndex", "type": "uint32" }, { "internalType": "uint256", "name": "fee", "type": "uint256" } ], "name": "setFee", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "uint32", "name": "regIndex", "type": "uint32" }, { "components": [ { "internalType": "bool", "name": "display", "type": "bool" }, { "internalType": "bool", "name": "legal", "type": "bool" }, { "internalType": "bool", "name": "web", "type": "bool" }, { "internalType": "bool", "name": "riot", "type": "bool" }, { "internalType": "bool", "name": "email", "type": "bool" }, { "internalType": "bool", "name": "pgpFingerprint", "type": "bool" }, { "internalType": "bool", "name": "image", "type": "bool" }, { "internalType": "bool", "name": "twitter", "type": "bool" } ], "internalType": "struct Identity.IdentityFields", "name": "fields", "type": "tuple" } ], "name": "setFields", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "components": [ { "components": [ { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "key", "type": "tuple" }, { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "value", "type": "tuple" } ], "internalType": "struct Identity.Additional[]", "name": "additional", "type": "tuple[]" }, { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "display", "type": "tuple" }, { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "legal", "type": "tuple" }, { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "web", "type": "tuple" }, { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "riot", "type": "tuple" }, { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "email", "type": "tuple" }, { "internalType": "bool", "name": "hasPgpFingerprint", "type": "bool" }, { "internalType": "bytes", "name": "pgpFingerprint", "type": "bytes" }, { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "image", "type": "tuple" }, { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "twitter", "type": "tuple" } ], "internalType": "struct Identity.IdentityInfo", "name": "info", "type": "tuple" } ], "name": "setIdentity", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "components": [ { "internalType": "address", "name": "account", "type": "address" }, { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "data", "type": "tuple" } ], "internalType": "struct Identity.SubAccount[]", "name": "subs", "type": "tuple[]" } ], "name": "setSubs", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "who", "type": "address" } ], "name": "subsOf", "outputs": [ { "components": [ { "internalType": "uint256", "name": "deposit", "type": "uint256" }, { "internalType": "address[]", "name": "accounts", "type": "address[]" } ], "internalType": "struct Identity.SubsOf", "name": "", "type": "tuple" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "who", "type": "address" } ], "name": "superOf", "outputs": [ { "components": [ { "internalType": "bool", "name": "isValid", "type": "bool" }, { "internalType": "address", "name": "account", "type": "address" }, { "components": [ { "internalType": "bool", "name": "hasData", "type": "bool" }, { "internalType": "bytes", "name": "value", "type": "bytes" } ], "internalType": "struct Identity.Data", "name": "data", "type": "tuple" } ], "internalType": "struct Identity.SuperOf", "name": "", "type": "tuple" } ], "stateMutability": "view", "type": "function" } ] ``` Once you have the ABI, you can interact with the precompile using the Ethereum library of your choice. Generally speaking, you'll take the following steps: 1. Create a provider 2. Create a contract instance of the Identity Precompile 3. Interact with the Identity Precompile's functions In the examples below, you'll learn how to assemble the data required to set an identity, how to set an identity, and how to retrieve the identity information once it's been set. !!! remember The following snippets are for demo purposes only. Never store your private keys in a JavaScript or Python file. === "Ethers.js" ```js import { ethers } from 'ethers'; // Import Ethers library import ABI from './identityPrecompileABI.js'; // Import Identity Precompile ABI const privateKey = 'INSERT_PRIVATE_KEY'; const identityPrecompileAddress = '0x0000000000000000000000000000000000000818'; // Create Ethers provider and signer const provider = new ethers.JsonRpcProvider( 'https://rpc.api.moonbase.moonbeam.network' ); const signer = new ethers.Wallet(privateKey, provider); // Create interface for the Identity Precompile const identityPrecompile = new ethers.Contract( identityPrecompileAddress, ABI, signer ); // Interact with the Precompile Registry const setIdentity = async () => { // Assemble identity info const identityInfo = { additional: [], display: { hasData: true, value: '0x416c696365', // Alice in hex }, legal: { hasData: false, value: '0x', }, web: { hasData: false, value: '0x', }, riot: { hasData: false, value: '0x', }, email: { hasData: false, value: '0x', }, hasPgpFingerprint: false, pgpFingerprint: '0x', image: { hasData: false, value: '0x', }, twitter: { hasData: false, value: '0x', }, }; // Set the identity const submitIdentity = await identityPrecompile.setIdentity(identityInfo); console.log(`Identity set. Transaction hash: ${submitIdentity.hash}`); // Retrieve the identity const identity = await identityPrecompile.identity(signer.address); console.log(`Identity is valid: ${identity[0]}`); console.log(`Judgements provided for this identity: ${identity[1]}`); console.log(`Deposit paid for this identity: ${identity[2]}`); console.log(`Identity information: ${identity[3]}`); console.log(`Display name: ${ethers.toUtf8String(identity[3][1][1])}`); }; setIdentity(); ``` === "Web3.js" ```js import { Web3 } from 'web3'; import ABI from './identityPrecompileABI.js'; // Import Identity Precompile ABI const from = { privateKey: 'INSERT_PRIVATE_KEY', address: 'INSERT_ADDRESS', }; const identityPrecompileAddress = '0x0000000000000000000000000000000000000818'; // Create provider const web3 = new Web3('https://rpc.api.moonbase.moonbeam.network'); // Create interface for the Identity Precompile const identityPrecompile = new web3.eth.Contract( ABI, identityPrecompileAddress, { from: from.address } ); // Interact with the Precompile Registry const setIdentity = async () => { // Assemble identity info const identityInfo = { additional: [], display: { hasData: true, value: '0x416c696365', // Alice in hex }, legal: { hasData: false, value: '0x', }, web: { hasData: false, value: '0x', }, riot: { hasData: false, value: '0x', }, email: { hasData: false, value: '0x', }, hasPgpFingerprint: false, pgpFingerprint: '0x', image: { hasData: false, value: '0x', }, twitter: { hasData: false, value: '0x', }, }; // Set the identity const submitIdentity = await identityPrecompile.methods.setIdentity( identityInfo ); const sendTransaction = await web3.eth.accounts.signTransaction( { to: identityPrecompileAddress, data: submitIdentity.encodeABI(), gas: await submitIdentity.estimateGas(), gasPrice: await web3.eth.getGasPrice(), nonce: await web3.eth.getTransactionCount(from.address), }, from.privateKey ); // Sign and send the transaction to set the identity const createReceipt = await web3.eth.sendSignedTransaction( sendTransaction.rawTransaction ); console.log( `Identity set. Transaction hash: ${createReceipt.transactionHash}` ); // Retrieve the identity const identity = await identityPrecompile.methods.identity(address).call(); console.log(`Identity is valid: ${identity[0]}`); console.log(`Judgements provided for this identity: ${identity[1]}`); console.log(`Deposit paid for this identity: ${identity[2]}`); console.log(`Identity information: ${identity[3]}`); console.log(`Display name: ${web3.utils.hexToUtf8(identity[3][1][1])}`); }; setIdentity(); ``` === "Web3.py" ```py from web3 import Web3 # Paste or import the Identity Precompile ABI abi = "INSERT_IDENTITY_PRECOMPILE_ABI" account_from = { "private_key": "INSERT_PRIVATE_KEY", "address": "INSERT_ADDRESS", } identity_precompile_address = "0x0000000000000000000000000000000000000818" # Create provider web3 = Web3(Web3.HTTPProvider("https://rpc.api.moonbase.moonbeam.network")) # Create interface for the Precompile Registry identity_precompile = web3.eth.contract(address=identity_precompile_address, abi=abi) def set_identity(): # Assemble identity info identity_info = { "additional": [], "display": { "hasData": True, "value": "0x416c696365", # Alice in hex }, "legal": { "hasData": False, "value": "0x", }, "web": { "hasData": False, "value": "0x", }, "riot": { "hasData": False, "value": "0x", }, "email": { "hasData": False, "value": "0x", }, "hasPgpFingerprint": False, "pgpFingerprint": "0x", "image": { "hasData": False, "value": "0x", }, "twitter": { "hasData": False, "value": "0x", }, } # Set the identity submit_identity = identity_precompile.functions.setIdentity( identity_info ).build_transaction( { "from": Web3.to_checksum_address(account_from["address"]), "nonce": web3.eth.get_transaction_count( Web3.to_checksum_address(account_from["address"]) ), } ) # Sign and send the transaction to set the identity tx_create = web3.eth.account.sign_transaction( submit_identity, account_from["private_key"] ) tx_hash = web3.eth.send_raw_transaction(tx_create.rawTransaction) tx_receipt = web3.eth.wait_for_transaction_receipt(tx_hash) print(f"Identity set. Transaction hash: { tx_receipt.transactionHash.hex() }") # Retrieve the identity identity = identity_precompile.functions.identity(account_from["address"]).call() print(f"Identity is valid: { identity[0] }") print(f"Judgements provided for this identity: { identity[1] }") print(f"Deposit paid for this identity: { identity[2] }") print(f"Identity information: { identity[3] }") print(f"Display name: { web3.to_text(identity[3][1][1]) }") set_identity() ``` --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/account/ --- BEGIN CONTENT --- --- title: Account-Related Precompiled Contracts description: Efficiently manage accounts on Moonbeam with precompiled contracts designed for creating and managing proxy accounts and on-chain identities. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/account/proxy/ --- BEGIN CONTENT --- --- title: Interacting with the Proxy Precompile description: How to use the Moonbeam proxy Solidity precompile interface to add and remove proxy accounts from Substrate's Proxy Pallet. keywords: solidity, ethereum, proxy, moonbeam, precompiled, contracts, substrate categories: Precompiles, Ethereum Toolkit --- # Interacting with the Proxy Precompile ## Introduction {: #introduction } The Proxy Precompile on Moonbeam allows accounts to set proxy accounts that can perform specific limited actions on their behalf, such as governance, staking, or balance transfers. If a user wanted to provide a second user access to a limited number of actions on their behalf, traditionally the only method to do so would be by providing the first account's private key to the second. However, Moonbeam has included the [Substrate Proxy Pallet](/builders/substrate/interfaces/account/proxy/){target=\_blank}, which enables proxy accounts. Proxy accounts ought to be used due to the additional layer of security that they provide, where many accounts can perform actions for a main account. This is best if, for example, a user wants to keep their wallet safe in cold storage but still wants to access parts of the wallet's functionality like governance or staking. **The Proxy Precompile can only be called from an Externally Owned Account (EOA) or by the [Batch Precompile](/builders/ethereum/precompiles/ux/batch/){target=\_blank}.** To learn more about proxy accounts and how to set them up for your own purposes without use of the Proxy Precompile, view the [Setting up a Proxy Account](/tokens/manage/proxy-accounts/){target=\_blank} page. The Proxy Precompile is located at the following address: === "Moonbeam" ```text {{networks.moonbeam.precompiles.proxy}} ``` === "Moonriver" ```text {{networks.moonriver.precompiles.proxy}} ``` === "Moonbase Alpha" ```text {{networks.moonbase.precompiles.proxy}} ``` !!! note There can be some unintended consequences when using the precompiled contracts on Moonbeam. Please refer to the [Security Considerations](/learn/core-concepts/security/){target=\_blank} page for more information. ## The Proxy Solidity Interface {: #the-proxy-solidity-interface } [`Proxy.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/proxy/Proxy.sol){target=\_blank} is an interface through which Solidity contracts can interact with the Proxy Pallet. You do not have to be familiar with the Substrate API since you can interact with it using the Ethereum interface you're familiar with. The interface includes the following functions: ??? function "**addProxy**(*address* delegate, *ProxyType* proxyType, *uint32* delay) - registers a proxy account for the sender after a specified number of `delay` blocks (generally zero). Will fail if a proxy for the caller already exists" === "Parameters" - `delegate` - address of the account to be registered as a proxy - `proxyType` - ProxyType enumeration specifying the type of proxy to be registered - `delay` - uint32 number of blocks before the proxy registration becomes active ??? function "**removeProxy**(*address* delegate, *ProxyType* proxyType, *uint32* delay) - removes a registered proxy for the sender" === "Parameters" - `delegate` - address of the proxy account to be removed - `proxyType` - ProxyType enumeration of the proxy type to be removed - `delay` - uint32 delay value of the proxy to be removed ??? function "**removeProxies**() - removes all of the proxy accounts delegated to the sender" === "Parameters" None. ??? function "**isProxy**(*address* real, *address* delegate, *ProxyType* proxyType, *uint32* delay) - returns a boolean, `true` if the delegate address is a proxy of type `proxyType`, for address `real`, with the specified `delay`" === "Parameters" - `real` - address of the account that might be represented by the proxy - `delegate` - address of the potential proxy account - `proxyType` - ProxyType enumeration of the proxy type to check - `delay` - uint32 delay value to check The `proxyType` parameter is defined by the following `ProxyType` enum, where the values start at `0` with the most permissive proxy type and are represented as `uint8` values: ```solidity enum ProxyType { Any, NonTransfer, Governance, Staking, CancelProxy, Balances, AuthorMapping, IdentityJudgement } ``` ## Proxy Types {: #proxy-types } There are multiple types of proxy roles that can be delegated to accounts, where are represented in `Proxy.sol` through the `ProxyType` enum. The following list includes all of the possible proxies and the type of transactions they can make on behalf of the primary account: - **Any** — the any proxy will allow the proxy account to make any type of transaction that the `Governance`, `Staking`, `Balances`, and `AuthorMapping` proxy types can perform. Note that balance transfers are only allowed to EOAs, not contracts or Precompiles - **NonTransfer** — the non-transfer proxy will allow the proxy account to make any type of transaction through the `Governance`, `Staking` and `AuthorMapping` Precompiles, where the `msg.value` is checked to be zero - **Governance** - the governance proxy will allow the proxy account to make any type of governance related transaction (includes both democracy or council pallets) - **Staking** - the staking proxy will allow the proxy account to make staking related transactions through the `Staking` Precompile, including calls to the `AuthorMapping` Precompile - **CancelProxy** - the cancel proxy will allow the proxy account to reject and remove delayed proxy announcements (of the primary account). Currently, this is not an action supported by the Proxy Precompile - **Balances** - the balances proxy will allow the proxy account to only make balance transfers to EOAs - **AuthorMapping** - this type of proxy account is used by collators to migrate services from one server to another - **IdentityJudgement** - the identity judgement proxy will allow the proxy account to judge and certify the personal information associated with accounts on Polkadot. Currently, this is not an action supported by the Proxy Precompile ## Interact with the Solidity Interface {: #interact-with-the-solidity-interface } The following section will cover how to interact with the Proxy Precompile from Remix. Please note that **the Proxy Precompile can only be called from an EOA or by the [Batch Precompile](/builders/ethereum/precompiles/ux/batch/){target=\_blank}**. ### Checking Prerequisites {: #checking-prerequisites } The below example is demonstrated on Moonbase Alpha, however, similar steps can be taken for Moonbeam and Moonriver. You should: - Have MetaMask installed and [connected to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank} - Have an account with some DEV tokens. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} - Have a second account that you control to use as a proxy account (funding optional) ### Remix Set Up {: #remix-set-up } To get started, get a copy of [`Proxy.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/proxy/Proxy.sol){target=\_blank} and take the following steps: 1. Click on the **File explorer** tab 2. Copy and paste the file contents into a [Remix file](https://remix.ethereum.org){target=\_blank} named `Proxy.sol` ![Copying and Pasting the Proxy Interface into Remix](/images/builders/ethereum/precompiles/account/proxy/proxy-1.webp) ### Compile the Contract {: #compile-the-contract } 1. Click on the **Compile** tab, second from top 2. Then to compile the interface, click on **Compile Proxy.sol** ![Compiling Proxy.sol](/images/builders/ethereum/precompiles/account/proxy/proxy-2.webp) ### Access the Contract {: #access-the-contract } 1. Click on the **Deploy and Run** tab, directly below the **Compile** tab in Remix. Note: you are not deploying a contract here, instead you are accessing a precompiled contract that is already deployed 2. Make sure **Injected Provider - Metamask** is selected in the **ENVIRONMENT** drop down 3. Ensure **Proxy.sol** is selected in the **CONTRACT** dropdown. Since this is a precompiled contract there is no need to deploy, instead you are going to provide the address of the Precompile in the **At Address** field 4. Provide the address of the Proxy Precompile for Moonbase Alpha: `{{networks.moonbase.precompiles.proxy}}` and click **At Address** 5. The Proxy Precompile will appear in the list of **Deployed Contracts** ![Provide the address](/images/builders/ethereum/precompiles/account/proxy/proxy-3.webp) ### Add a Proxy {: #add-proxy } You can add a proxy for your account via the Proxy Precompile if your account doesn't already have a proxy. In this example, you will add a [balances](#:~:text=Balances) proxy to an account by taking the following steps: 1. Expand the Proxy Precompile contract to see the available functions 2. Find the **addProxy** function and press the button to expand the section 3. Insert your second account's address as the **delegate**, `5` as **proxyType**, and `0` as **delay** 4. Press **transact** and confirm the transaction in MetaMask !!! note When constructing the transaction in Remix, the **proxyType** is represented as a `uint8`, instead of the expected enum `ProxyType`. In Solidity, enums are compiled as `uint8`, so when you pass in `5` for **proxyType**, you indicate the sixth element in the `ProxyType` enum, which is the balances proxy. ![Call the addProxy function](/images/builders/ethereum/precompiles/account/proxy/proxy-4.webp) ### Check a Proxy's Existence {: #check-proxy } You can determine whether or not an account is a proxy account for a primary account. In this example, you will insert the parameters of the [previously added proxy](#add-proxy) to determine if the proxy account was successfully added: 1. Find the **isProxy** function and press the button to expand the section 2. Insert your primary account's address as **real**, your second account's address as **delegate**, `5` as **proxyType**, and `0` as **delay** 3. Press **call** If everything went correctly, the output should be `true`. ![Call the isProxy function](/images/builders/ethereum/precompiles/account/proxy/proxy-5.webp) ### Remove a Proxy {: #remove-proxy } You can remove a proxy from your account via the Proxy Precompile. In this example, you will remove the balances proxy [previously added](#add-proxy) to your delegate account by taking the following steps: 1. Expand the Proxy Precompile contract to see the available functions 2. Find the **removeProxy** function and press the button to expand the section 3. Insert your second account's address as the **delegate**, `5` as **proxyType**, `0` and as **delay** 4. Press **transact** and confirm the transaction in MetaMask After the transaction is confirmed, if you repeat the steps to [check for a proxy's existence](#check-proxy), the result should be `false`. ![Call the removeProxy function](/images/builders/ethereum/precompiles/account/proxy/proxy-6.webp) And that's it! You've completed your introduction to the Proxy Precompile. Additional information on setting up proxies is available on the [Setting up a Proxy Account](/tokens/manage/proxy-accounts/){target=\_blank} page and the [Proxy Accounts](https://wiki.polkadot.network/learn/learn-proxies/){target=\_blank} page on Polkadot's documentation. Feel free to reach out on [Discord](https://discord.com/invite/PfpUATX){target=\_blank} if you have any questions about any aspect of the Proxy Precompile. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/features/governance/collective/ --- BEGIN CONTENT --- --- title: Collective Precompile Contract description: Learn how to use the Moonbeam Collective Precompile to perform democracy functions through any of the collectives on Moonbeam, such as the Treasury Council. keywords: solidity, ethereum, collective, proposal, council technical, committee, moonbeam, precompiled, contracts categories: Precompiles, Ethereum Toolkit --- # Interacting with the Collective Precompile ## Introduction {: #introduction } The Collective Precompile enables a user to directly interact with [Substrate's collective pallet](https://paritytech.github.io/substrate/master/pallet_collective/index.html){target=\_blank} directly from a Solidity interface. A collective is a group of members that are responsible for specific democracy-related actions such as proposing, voting on, executing, and closing motions. Each can execute different actions with different origins. Consequently, collectives can be created with very specific scopes. There are currently two collectives: the Treasury Council collective and the OpenGov Technical Committee collective. As such, there is a precompile for each collective. For more information on the OpenGov Technical Committee please refer to the [Governance on Moonbeam](/learn/features/governance/){target=\_blank} page, and for more information on the Treasury Council, please refer to the [Treasury on Moonbeam](/learn/features/treasury/){target=\_blank} page. This guide will show you how to propose, vote on, and close a proposal using the Collective Precompile. The Collective Precompiles are located at the following addresses: === "Moonbeam" | Collective | Address | |:---------------------------:|:--------------------------------------------------------------------:| | Treasury Council | {{networks.moonbeam.precompiles.collective_treasury }} | | OpenGov Technical Committee | {{networks.moonbeam.precompiles.collective_opengov_tech_committee }} | === "Moonriver" | Collective | Address | |:---------------------------:|:---------------------------------------------------------------------:| | Treasury Council | {{networks.moonriver.precompiles.collective_treasury }} | | OpenGov Technical Committee | {{networks.moonriver.precompiles.collective_opengov_tech_committee }} | === "Moonbase Alpha" | Collective | Address | |:---------------------------:|:--------------------------------------------------------------------:| | Treasury Council | {{networks.moonbase.precompiles.collective_treasury }} | | OpenGov Technical Committee | {{networks.moonbase.precompiles.collective_opengov_tech_committee }} | !!! note There can be some unintended consequences when using the precompiled contracts on Moonbeam. Please refer to the [Security Considerations](/learn/core-concepts/security/){target=\_blank} page for more information. ## The Collective Solidity Interface {: #the-call-permit-interface } [`Collective.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} is a Solidity interface that allows developers to interact with the precompile's five methods. The interface includes the following functions: ??? function "**execute**(*bytes memory* proposal) - executes a proposal as a single member of the collective. The sender must be a member of the collective. This will *not* revert if the Substrate proposal is dispatched but fails" === "Parameters" - `proposal` - bytes memory containing the [SCALE encoded](https://docs.polkadot.com/polkadot-protocol/basics/data-encoding/){target=\_blank} Substrate call that proposes an action ??? function "**propose**(*uint32* threshold, *bytes memory* proposal) - adds a new proposal to be voted on. The sender must be a member of the collective. If the threshold is less than two then the proposal will be dispatched and executed directly, with the proposer as dispatcher. If the threshold is met, the index of the new proposal is returned" === "Parameters" - `threshold` - uint32 amount of members required to dispatch the proposal - `proposal` - bytes memory containing the [SCALE encoded](https://docs.polkadot.com/polkadot-protocol/basics/data-encoding/){target=\_blank} Substrate call that proposes an action ??? function "**vote**(*bytes32* proposalHash, *uint32* proposalIndex, *bool* approve) - votes on a proposal. The sender must be a member of the collective" === "Parameters" - `proposalHash` - bytes32 hash of the proposal - `proposalIndex` - uint32 index of the proposal - `approve` - bool indicating the vote to approve the proposal or not ??? function "**close**(*bytes32* proposalHash, *uint32* proposalIndex, *uint64* proposalWeightBound, *uint32* lengthBound) - closes a proposal. Can be called by anyone once there are enough votes. Returns a boolean indicating whether the proposal was executed or removed" === "Parameters" - `proposalHash` - bytes32 hash of the proposal - `proposalIndex` - uint32 index of the proposal - `proposalWeightBound` - uint64 maximum amount of Substrate weight the proposal can use. If the proposal call uses more, the call will revert - `lengthBound` - uint32 value higher or equal to the length of the SCALE encoded proposal in bytes ??? function "**proposalHash**(*bytes memory* proposal) - computes the hash of a proposal" === "Parameters" - `proposal` - bytes memory containing the [SCALE encoded](https://docs.polkadot.com/polkadot-protocol/basics/data-encoding/){target=\_blank} Substrate call that proposes an action The interface includes the following events: - **Executed**(*bytes32* proposalHash) - emitted when a proposal is executed - **Proposed**(*address indexed* who, *uint32* indexed proposalIndex, *bytes32 indexed* proposalHash, *uint32* threshold) - emitted when a proposal has successfully been proposed and can be executed or voted on - **Voted**(*address indexed* who, *bytes32 indexed proposalHash, *bool* voted) - emitted when a proposal is voted on - **Closed**(*bytes32 indexed* proposalHash) - emitted when a proposal has been closed ## Interacting with the Solidity Interface {: #interacting-with-the-solidity-interface } The example in this section will show you how to submit a Treasury proposal using the Treasury Council Collective Precompile. As such, the proposal will be subject to meeting the voting requirements of the Treasury Council. The threshold for accepting a Treasury proposal is at least three-fifths of the Treasury Council. On the other hand, the threshold for rejecting a proposal is at least one-half of the Treasury Council. Please keep in mind that in order to propose and vote on the proposal, you must be a member of the Treasury Council. If you are not a member of the Treasury Council on Moonbeam, Moonriver, or Moonbase Alpha, you can test out the features of the Collective Precompile using a [Moonbeam development node](/builders/get-started/networks/moonbeam-dev/){target=\_blank}. The Moonbeam development node comes with [ten pre-funded accounts](/builders/get-started/networks/moonbeam-dev/#pre-funded-development-accounts){target=\_blank}, of which Baltathar, Charleth, and Dorothy are automatically set as members of the Treasury Council collective. You can use any of these three accounts to follow along with the rest of the guide. ### Checking Prerequisites {: #checking-prerequisites } The example in this guide will be shown on a Moonbeam development node, however, it can be adapted for any of the Moonbeam-based networks. To get started, you will need to have the following: - Have MetaMask installed and [connected to one of the Moonbeam-based networks](/tokens/connect/metamask/){target=\_blank} - Have an account with funds. If using a Moonbeam development node, the development accounts are pre-funded. For Moonbeam, Moonriver, or Moonbase Alpha, you'll need to fund your account. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} If you're using a Moonbeam development node and the development accounts, you'll also need to do the following: - Set your development node to seal blocks on a time interval such as every 6 seconds (6000 milliseconds) using the `--sealing 6000` flag - [Connect Polkadot.js Apps to your local Moonbeam development node](/builders/get-started/networks/moonbeam-dev/#connecting-polkadot-js-apps-to-a-local-moonbeam-node){target=\_blank} - Import Baltathar's, Charleth's, and/or Dorothy's accounts into [Polkadot.js Apps](/tokens/connect/polkadotjs/#creating-or-importing-an-h160-account){target=\_blank} and [MetaMask](/tokens/connect/metamask/#import-accounts){target=\_blank} ### Remix Set Up {: #remix-set-up } 1. Get a copy of [`Collective.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} 2. Copy and paste the file contents into a [Remix file](https://remix.ethereum.org){target=\_blank} named `Collective.sol` ![Copying and Pasting the Collective Interface into Remix](/images/builders/ethereum/precompiles/features/governance/collective/collective-1.webp) ### Compile the Contract {: #compile-the-contract } 1. Click on the **Compile** tab, second from top 2. Then to compile the interface, click on **Compile Collective.sol** ![Compiling Collective.sol](/images/builders/ethereum/precompiles/features/governance/collective/collective-2.webp) ### Access the Contract {: #access-the-contract } 1. Click on the **Deploy and Run** tab, directly below the **Compile** tab in Remix. Note: You are not deploying a contract here; instead you are accessing a precompiled contract that is already deployed 2. Make sure **Injected Provider - Metamask** is selected in the **ENVIRONMENT** drop down 3. Ensure **Collective - Collective.sol** is selected in the **CONTRACT** dropdown. Since this is a precompiled contract there is no need to deploy, instead you are going to provide the address of the precompile in the **At Address** Field 4. Provide the address of the Collective Precompile,`{{networks.moonbase.precompiles.collective_treasury}}`, and click **At Address** 5. The Collective Precompile will appear in the list of **Deployed Contracts** ![Access the precompile contract](/images/builders/ethereum/precompiles/features/governance/collective/collective-3.webp) ### Create a Proposal {: #create-a-proposal } In order to submit a proposal to be voted on by the Treasury Council collective, you must first create a Treasury proposal. If a Treasury proposal that you want to vote on already exists and you have the proposal index, you can skip ahead to the next section. To submit a Treasury proposal, you can do so via the [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/treasury){target=\_blank} Treasury page. For this example, you can create a simple proposal to send Alith 10 DEV tokens that can be used to host a community event. To get started, click on **Submit proposal**, and fill out the following information: 1. From the **submit with account** dropdown, select the account you want to submit the proposal with. The bond for the proposal will be taken from this account 2. Select the **beneficiary**, which can be **Alith** for this example 3. Enter `10` for the **value** 4. Click on **Submit proposal** and then sign and submit the proposal ![Submit a treasury proposal](/images/builders/ethereum/precompiles/features/governance/collective/collective-4.webp) You should see the proposal appear in the **proposals** section. If this is the first proposal created, it will have a proposal index of `0`, which will be needed in the next section. To view all of the proposals, you can navigate to the **Developer** tab, select **Chain State**, and take the following steps: 1. From the **selected state query** dropdown, choose **treasury** 2. Select the **proposals** extrinsic 3. Toggle the **include option** slider off 4. Click **+** to submit the query 5. The results will appear below with the proposal index and the proposal details ![View all treasury proposals](/images/builders/ethereum/precompiles/features/governance/collective/collective-5.webp) Now that you have the proposal and the proposal index, you'll be able to approve the proposal in the following section using the Collective Precompile. ### Propose the Proposal {: #propose-the-proposal } In order to propose a proposal using the Collective Precompile, so that the corresponding collective can vote on it, you will need to obtain the encoded call data of the call, to be executed by proposal. You can get the encoded call data from Polkadot.js Apps. For this example, you need to propose the **approveProposal** extrinsic of the treasury pallet. To do so, navigate to the **Developer** tab, select **Extrinsics**, and take the following steps: 1. Select an account (any account is fine because you're not submitting any transaction here) 2. Select the **treasury** pallet 3. Choose the **approveProposal** extrinsic 4. Enter the proposal index that the collective will vote on to approve 5. Copy the **encoded call data** for the proposal ![Get encoded proposal](/images/builders/ethereum/precompiles/features/governance/collective/collective-6.webp) For this example, the extrinsic encoded call data for the proposal in this example is `0x110200`. With the encoded proposal, you can head back to Remix and expand the **COLLECTIVE** precompile contract under the **Deployed Contracts** section. Make sure you're connected to your account that is a member of the Treasury Council, and take the following steps to propose the approval: 1. Expand the **propose** function 2. Enter the **threshold**. Keep in mind that for Treasury proposals to be approved, at least three-fifths of the Treasury Council is needed to vote in approval. As such, you can set the threshold to `2` for this example 3. For the **proposal** field, you can paste the encoded proposal you retrieved from Polkadot.js Apps 4. Click **transact** 5. MetaMask will pop up and you can confirm the transaction ![Propose the approval](/images/builders/ethereum/precompiles/features/governance/collective/collective-7.webp) ### Vote on a Proposal {: #vote-on-a-proposal } To vote on a proposal, you'll need to get the proposal hash by passing in the encoded proposal into the **proposalHash** function. ![Get the proposal hash](/images/builders/ethereum/precompiles/features/governance/collective/collective-8.webp) Once you have the proposal hash, make sure you're connected to your account that is a member of the Treasury Council, and take the following steps to vote on a proposal: 1. Expand the **vote** function in Remix 2. Enter the **proposalHash** 3. Enter the **proposalIndex** 4. Enter `true` for the **approve** field 5. Click **transact** 6. MetaMask will pop up and you can confirm the transaction ![Vote on the proposal](/images/builders/ethereum/precompiles/features/governance/collective/collective-9.webp) With the threshold set to `2`, you'll need to switch accounts in MetaMask to another member of the Treasury Council collective and repeat the steps above to vote and meet the threshold. Once the threshold has been met, you can then close the proposal, which will automatically execute it, and if approved, the proposal enters a queue to be placed into a spend period where the proposed amount will be distributed to the beneficiary. In this case, once the proposal is placed into a spend period, 10 DEV tokens will be distributed to Alith. ## Close a Proposal {: #close-a-proposal } If a proposal has enough votes, anyone can close a proposal. You do not need to be a member of the Treasury Council in order to close a proposal. To close a proposal, you can take the following steps: 1. Expand the **close** function 2. Enter the **proposalHash** 3. Enter the **proposalIndex** 4. Enter the **proposalWeightBound**, which for this example can be `1000000000` 5. Enter the **lengthBound**, which can be a value equal to or greater than the length of the encoded call data for the proposal. For this example the encoded call data is `0x110200`, and as such, you can set this value to `8` 6. Click on **transact** 7. MetaMask will pop up and you can confirm the transaction ![Close the proposal](/images/builders/ethereum/precompiles/features/governance/collective/collective-10.webp) You can verify the proposal has been approved using Polkadot.js Apps. From the **Developer** tab, select **Chain State**, and take the following steps: 1. Select the **treasury** pallet 2. Select the **approvals** extrinsic 3. Click **+** to submit the query 4. The proposal will appear in the list of approvals ![Review the treasury approvals](/images/builders/ethereum/precompiles/features/governance/collective/collective-11.webp) Once the proposal is in a spend period, the funds will get distributed to the beneficiary, and the original bond will be returned to the proposer. If the Treasury runs out of funds, the approved proposals will remain in storage until the following spend period when the Treasury has enough funds again. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/features/governance/conviction-voting/ --- BEGIN CONTENT --- --- title: Conviction Voting Precompile Contract description: Learn how to vote on referenda, set up voting delegations, and more, directly through a Solidity interface with the Conviction Voting Precompile on Moonbeam. categories: Precompiles, Ethereum Toolkit --- # Interacting with the Conviction Voting Precompile ## Introduction {: #introduction } As a Polkadot parachain and decentralized network, Moonbeam features native on-chain governance that enables stakeholders to participate in the direction of the network. With the introduction of OpenGov, also referred to as Governance v2, the Conviction Voting Pallet allows token holders to make, delegate, and manage Conviction-weighted votes on referenda. To learn more about Moonbeam's governance system, such as an overview of related terminology, principles, mechanics, and more, please refer to the [Governance on Moonbeam](/learn/features/governance/){target=\_blank} page. The Conviction Voting Precompile interacts directly with Substrate's Conviction Voting Pallet. This pallet is coded in Rust and is normally not accessible from the Ethereum API side of Moonbeam. However, the Conviction Voting Precompile allows you to access governance-related functions of the Substrate Conviction Voting Pallet directly from a Solidity interface. Additionally, this enables a vastly improved end-user experience. For example, token holders can vote on referenda or delegate a vote directly from MetaMask, rather than importing an account in Polkadot.js Apps and navigating a complex UI. The Conviction Voting Precompile is located at the following address: === "Moonbeam" ```text {{ networks.moonbeam.precompiles.conviction_voting }} ``` === "Moonriver" ```text {{ networks.moonriver.precompiles.conviction_voting }} ``` === "Moonbase Alpha" ```text {{ networks.moonbase.precompiles.conviction_voting }} ``` !!! note There can be some unintended consequences when using the precompiled contracts on Moonbeam. Please refer to the [Security Considerations](/learn/core-concepts/security/){target=\_blank} page for more information. ## The Conviction Voting Solidity Interface {: #the-conviction-voting-solidity-interface } [`ConvictionVoting.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/conviction-voting/ConvictionVoting.sol){target=\_blank} is a Solidity interface that allows developers to interact with the precompile's methods. The interfaces includes a `Conviction` enum that defines the [Conviction multiplier](/learn/features/governance/#conviction-multiplier-v2){target=\_blank} types. The enum has the following variables: - **None** - 0.1x votes, unlocked - **Locked1x** - 1x votes, locked for an Enactment Period following a successful vote - **Locked2x** - 2x votes, locked for 2x Enactment Period following a successful vote - **Locked3x** - 4x votes, locked for 4x Enactments Period following a successful vote - **Locked4x** - 8x votes, locked for 8x Enactments Period following a successful vote - **Locked5x** - 16x votes, locked for 16x Enactments Period following a successful vote - **Locked6x** - 32x votes, locked for 32x Enactments Period following a successful vote The interface includes the following functions: ??? function "**votingFor**(*address* who, *uint16* trackId) - returns the votes for a given account and Track" === "Parameters" - `who` - address of the account to query the votes for - `trackId` - uint16 Track ID where the requested changes need to occur ??? function "**classLocksFor**(*address* who) - returns the class locks for a given account" === "Parameters" - `who` - address of the account to query the class locks for ??? function "**voteYes**(*uint32* pollIndex, *uint256* voteAmount, *Conviction* conviction) - votes a Conviction-weighted "Aye" on a poll (referendum)" === "Parameters" - `pollIndex` - uint32 index of the poll (referendum) - `voteAmount` - uint256 balance to be locked for the vote - `conviction` - Conviction represents a value from the aforementioned `Conviction` enum ??? function "**voteNo**(*uint32* pollIndex, *uint256* voteAmount, *Conviction* conviction) - votes a Conviction-weighted "Nay" on a poll (referendum)" === "Parameters" - `pollIndex` - uint32 index of the poll (referendum) - `voteAmount` - uint256 balance to be locked for the vote - `conviction` - Conviction represents a value from the aforementioned `Conviction` enum ??? function "**voteSplit**(*uint32* pollIndex, *uint256* aye, *uint256* nay) - votes a split vote, with a given amount locked for "Aye" and a given amount locked for "Nay", on a poll (referendum)" === "Parameters" - `pollIndex` - uint32 index of the poll (referendum) - `aye` - uint256 balance to be locked for the "Aye" vote - `nay` - uint256 balance to be locked for the "Nay" vote ??? function "**voteSplitAbstain**(*uint32* pollIndex, *uint256* aye, *uint256* nay) - votes a split abstained vote, with a given amount locked for "Aye", a given amount locked for "Nay", and a given amount locked for an abstain vote (support), on a poll (referendum)" === "Parameters" - `pollIndex` - uint32 index of the poll (referendum) - `aye` - uint256 balance to be locked for the "Aye" vote - `nay` - uint256 balance to be locked for the "Nay" vote ??? function "**removeVote**(*uint32* pollIndex) - [removes a vote](/builders/substrate/interfaces/features/governance/conviction-voting/#extrinsics){target=\_blank} in a poll (referendum)" === "Parameters" - `pollIndex` - uint32 index of the poll (referendum) ??? function "**removeVoteForTrack**(*uint32* pollIndex, *uint16* trackId) - [removes a vote](/builders/substrate/interfaces/features/governance/conviction-voting/#extrinsics){target=\_blank} from a specific track in a poll (referendum)" === "Parameters" - `pollIndex` - uint32 index of the poll (referendum) - `trackId` - uint16 Track ID where the requested changes need to occur ??? function "**removeOtherVote**(*address* target, *uint16* trackId, *uint32* pollIndex) - [removes a vote](/builders/substrate/interfaces/features/governance/conviction-voting/#extrinsics){target=\_blank} in a poll (referendum) for another voter" === "Parameters" - `target` - address that has a vote or tokens to be removed or unlocked - `trackId` - uint16 Track ID where the requested changes need to occur - `pollIndex` - uint32 index of the poll (referendum) ??? function "**delegate**(*uint16* trackId, *address* representative, *Conviction* conviction, *uint256* amount) - delegates another account as a representative to place a Conviction-weighted vote on the behalf of the sending account for a specific Track" === "Parameters" - `trackId` - uint16 Track ID where the requested changes need to occur - `representative` - address of the account to be delegated as representative - `conviction` - Conviction represents a value from the aforementioned `Conviction` enum - `amount` - uint256 balance to be delegated ??? function "**undelegate**(*uint16* trackId) - removes the caller's vote delegations for a specific Track" === "Parameters" - `trackId` - uint16 Track ID where the requested changes need to occur ??? function "**unlock**(*uint16* trackId, *address* target) - unlocks the locked tokens of a specific account for a specific Track" === "Parameters" - `trackId` - uint16 Track ID where the requested changes need to occur - `target` - address that has a vote or tokens to be removed or unlocked The interface also includes the following events: - **Voted**(*uint32 indexed* pollIndex, *address* voter, *bool* aye, *uint256* voteAmount, *uint8* conviction) - emitted when an account makes a vote - **VoteSplit**(*uint32 indexed* pollIndex, *address* voter, *uin256* aye, *uint256* nay) - emitted when an account makes a split vote - **VoteSplitAbstained**(*uint32 indexed* pollIndex, *address* voter, *uin256* aye, *uint256* nay, *uint256* nay) - emitted when an account makes a split abstained vote - **VoteRemoved**(*uint32 indexed* pollIndex, *address* voter) - emitted when an account's (`voter`) vote has been removed from an ongoing poll (referendum) - **VoteRemovedForTrack**(*uint32 indexed* pollIndex, *uint16* trackId, *address* voter) - emitted when an account's (`voter`) vote has been removed from an ongoing poll (referendum) for a specific Track - **VoteRemovedOther**(*uint32 indexed* pollIndex, *address* caller, *address* target, *uint16* trackId) - emitted when an account (`caller`) removed a vote for another account (`target`) - **Delegated**(*uint16 indexed* trackId, *address* from, *address* to, *uint256* delegatedAmount, *uint8* conviction) - emitted when an account (`from`) delegates a Conviction-weighted vote of a given amount to another account (`to`) - **Undelegated**(*uint16 indexed* trackId, *address* caller) - emitted when an account's (`caller`) delegations are removed for a specific Track - **Unlocked**(*uint16 indexed* trackId, *address* caller) - emitted when an account's (`caller`) locked tokens are unlocked for a specific Track ## Interact with the Solidity Interface {: #interact-with-the-solidity-interface } ### Checking Prerequisites {: #checking-prerequisites } The below example is demonstrated on Moonbase Alpha, however, similar steps can be taken for Moonriver. To follow the steps in this guide, you'll need to have the following: - MetaMask installed and [connected to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank} - An account with some DEV tokens. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} ### Remix Set Up {: #remix-set-up } 1. Click on the **File explorer** tab 2. Paste a copy of [`ConvictionVoting.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/conviction-voting/ConvictionVoting.sol){target=\_blank} into a [Remix file](https://remix.ethereum.org){target=\_blank} named `ConvictionVoting.sol` ![Copy and paste the referenda Solidity interface into Remix.](/images/builders/ethereum/precompiles/features/governance/conviction-voting/conviction-voting-1.webp) ### Compile the Contract {: #compile-the-contract } 1. Click on the **Compile** tab, second from top 2. Then to compile the interface, click on **Compile ConvictionVoting.sol** ![Compile the ConvictionVoting.sol interface using Remix.](/images/builders/ethereum/precompiles/features/governance/conviction-voting/conviction-voting-2.webp) ### Access the Contract {: #access-the-contract } 1. Click on the **Deploy and Run** tab, directly below the **Compile** tab in Remix. Note: you are not deploying a contract here, instead you are accessing a precompiled contract that is already deployed 2. Make sure **Injected Provider - Metamask** is selected in the **ENVIRONMENT** drop down 3. Ensure **ConvictionVoting.sol** is selected in the **CONTRACT** dropdown. Since this is a precompiled contract there is no need to deploy, instead you are going to provide the address of the precompile in the **At Address** field 4. Provide the address of the Conviction Voting Precompile for Moonbase Alpha: `{{ networks.moonbase.precompiles.conviction_voting }}` and click **At Address** 5. The Conviction Voting Precompile will appear in the list of **Deployed Contracts** ![Access the ConvictionVoting.sol interface by provide the precompile's address.](/images/builders/ethereum/precompiles/features/governance/conviction-voting/conviction-voting-3.webp) ### Vote on a Referendum {: #vote-on-a-referendum } You can lock tokens and vote on a referendum at anytime during the Lead-in Period or the Decide Period. In order for a referendum to pass, it needs to garner minimum Approval and Support, which vary by track. For more information on each of the relative periods and the Approval and Support requirements by Track, please refer to the [OpenGov section of the governance overview page](/learn/features/governance/#opengov){target=\_blank}. First, you'll need to get the index of the referendum you wish to vote on. To get the index of a referendum, head to [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network%2Fpublic-ws#/referenda){target=\_blank} and take the following steps: 1. From the **Governance** tab dropdown, select **Referenda** 2. Look for the referenda you want to vote on. You can view more details about a specific referendum by clicking on the triangle icon. If there is no triangle icon, this means that only a proposal hash, and no preimage has been submitted for the proposal 3. Take note of the referendum index ![View the list of referenda on Polkadot.js Apps.](/images/builders/ethereum/precompiles/features/governance/conviction-voting/conviction-voting-4.webp) Now, you're ready to return to Remix to vote on the referendum via the Conviction Voting Precompile. There are two methods you can use to vote on a referendum: `voteYes` or `voteNo`. As you probably have already figured out, if you're in agreement with the proposal, you'll use `voteYes` and if in disagreement, you'll use `voteNo`. You'll specify the amount of tokens you want to lock with your vote and the Conviction, using index of the Conviction you want to vote with in the [aforementioned `Conviction` enum](#the-conviction-voting-solidity-interface). For example, if you wanted to lock your tokens for the duration of two Enactment Periods following a successful vote, you would enter `2` for the `Locked2x` Conviction. For more information on Convictions, you can check out the [Conviction Multiplier section of the Governance v2 documentation](/learn/features/governance/#conviction-multiplier-v2){target=\_blank}. To submit your vote, you can take the following steps: 1. Expand the Conviction Voting Precompile contract to see the available functions if it is not already open 2. Find the **voteYes** or **voteNo** function, however you want to vote, and press the button to expand the section 3. Enter the index of the referendum to vote on 4. Enter the number of tokens to lock in Wei. Avoid entering your full balance here because you need to pay for transaction fees 5. Enter the Conviction you want to vote with 6. Press **transact** and confirm the transaction in MetaMask ![Vote on the proposal using the voteYes function of the Conviction Voting Precompile.](/images/builders/ethereum/precompiles/features/governance/conviction-voting/conviction-voting-5.webp) Once the referendum has closed, you can use the Conviction Voting precompile to remove your vote and unlock your tokens. ### Delegate a Vote {: #delegate-a-vote } In addition to voting on a referendum yourself, you can delegate a Conviction-weighted vote to someone who is more knowledgeable on a particular topic to vote on your behalf, a process known as Vote Delegation. You can even delegate a different account for each of the Tracks. To get started, you can take the following steps: 1. Find the **delegate** function and press the button to expand the section 2. Enter the Track ID of the Track that you want the delegation to be used on. Track IDs can be found in the [Referenda page of Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network%2Fpublic-ws#/referenda){target=\_blank} 3. Enter the delegate account that will have the power to vote on your behalf 4. Enter the number of tokens they can vote with in Wei. Avoid entering your full balance here because you need to pay for transaction fees 5. Enter the Conviction they can vote with 6. Press **transact** and confirm the transaction in MetaMask ![Delegate a vote using the delegate function of the Conviction Voting Precompile.](/images/builders/ethereum/precompiles/features/governance/conviction-voting/conviction-voting-6.webp) Now the delegate account can vote on your behalf! If you no longer want a delegate vote to exist, you can remove it using the `undelegate` function of the Conviction Voting Precompile. And that's it! You've completed your introduction to the Conviction Voting Precompile. There are a few more functions that are documented in [`ConvictionVoting.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/conviction-voting/ConvictionVoting.sol){target=\_blank} — feel free to reach out on [Discord](https://discord.com/invite/PfpUATX){target=\_blank} if you have any questions about those functions or any other aspect of the Conviction Voting Precompile. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/features/governance/ --- BEGIN CONTENT --- --- title: Solidity Precompiles description: Facilitate decentralized decision-making with Moonbeam's governance precompiles for creating and submitting proposals and voting on referenda. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/features/governance/preimage/ --- BEGIN CONTENT --- --- title: Preimage Precompile Contract description: Learn how to take the first necessary step to submit a proposal on-chain by submitting a preimage that contains the action to be carried out in the proposal. categories: Precompiles, Ethereum Toolkit --- # Interacting with the Preimage Precompile ## Introduction {: #introduction } As a Polkadot parachain and decentralized network, Moonbeam features native on-chain governance that enables stakeholders to participate in the direction of the network. With the introduction of OpenGov, also referred to as Governance v2, the Preimage Pallet allows token holders to take the first step towards creating a proposal by submitting the preimage, which is the action to be carried out in the proposal, on-chain. The hash of the preimage is required to submit the proposal. To learn more about Moonbeam's governance system, such as an overview of related terminology, the roadmap of a proposal, and more, please refer to the [Governance on Moonbeam](/learn/features/governance/){target=\_blank} page. The Preimage Precompile interacts directly with Substrate's Preimage Pallet. This pallet is coded in Rust and is normally not accessible from the Ethereum side of Moonbeam. However, the Preimage Precompile allows you to access functions needed to create and manage preimages, all of which are part of the Substrate Preimage Pallet, directly from a Solidity interface. The Preimage Precompile is located at the following address: === "Moonbeam" ```text {{ networks.moonbeam.precompiles.preimage }} ``` === "Moonriver" ```text {{ networks.moonriver.precompiles.preimage }} ``` === "Moonbase Alpha" ```text {{ networks.moonbase.precompiles.preimage }} ``` !!! note There can be some unintended consequences when using the precompiled contracts on Moonbeam. Please refer to the [Security Considerations](/learn/core-concepts/security/){target=\_blank} page for more information. ## The Preimage Solidity Interface {: #the-preimage-solidity-interface } [`Preimage.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/preimage/Preimage.sol){target=\_blank} is a Solidity interface that allows developers to interact with the precompile's two methods: ??? function "**notePreimage**(*bytes memory* encodedPropsal) - registers a preimage on-chain for an upcoming proposal. This doesn't require the proposal to be in the dispatch queue but does require a deposit which is returned once enacted. Uses the [`notePreimage`](/builders/substrate/interfaces/features/governance/preimage/#:~:text=notePreimage(encodedProposal)){target=\_blank} method of the preimage pallet" === "Parameters" - `encodedProposal` - bytes memory containing the encoded proposal to be registered. Returns the preimage hash ??? function "**unnotePreimage**(*bytes32* hash) - clears an unrequested preimage from storage. Uses the [`unnotePreimage`](/builders/substrate/interfaces/features/governance/preimage/#:~:text=unnotePreimage(hash)){target=\_blank} method of the preimage pallet" === "Parameters" - `hash` - bytes32 hash of the preimage to be removed from storage The interface also includes the following events: - **PreimageNoted**(*bytes32* hash) - emitted when a preimage was registered on-chain - **PreimageUnnoted**(*bytes32* hash) - emitted when a preimage was un-registered on-chain ## Interact with the Solidity Interface {: #interact-with-the-solidity-interface } ### Checking Prerequisites {: #checking-prerequisites } The below example is demonstrated on Moonbase Alpha, however, similar steps can be taken for Moonriver. To follow the steps in this guide, you'll need to have the following: - MetaMask installed and [connected to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank} - An account with some DEV tokens. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} ### Remix Set Up {: #remix-set-up } 1. Click on the **File explorer** tab 2. Paste a copy of [`Preimage.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/preimage/Preimage.sol){target=\_blank} into a [Remix file](https://remix.ethereum.org){target=\_blank} named `Preimage.sol` ![Copy and paste the referenda Solidity interface into Remix.](/images/builders/ethereum/precompiles/features/governance/preimage/preimage-1.webp) ### Compile the Contract {: #compile-the-contract } 1. Click on the **Compile** tab, second from top 2. Then to compile the interface, click on **Compile Preimage.sol** ![Compile the Preimage.sol interface using Remix.](/images/builders/ethereum/precompiles/features/governance/preimage/preimage-2.webp) ### Access the Contract {: #access-the-contract } 1. Click on the **Deploy and Run** tab, directly below the **Compile** tab in Remix. Note: you are not deploying a contract here, instead you are accessing a precompiled contract that is already deployed 2. Make sure **Injected Provider - Metamask** is selected in the **ENVIRONMENT** drop down 3. Ensure **Preimage.sol** is selected in the **CONTRACT** dropdown. Since this is a precompiled contract there is no need to deploy, instead you are going to provide the address of the precompile in the **At Address** field 4. Provide the address of the Preimage Precompile for Moonbase Alpha: `{{ networks.moonbase.precompiles.preimage }}` and click **At Address** 5. The Preimage Precompile will appear in the list of **Deployed Contracts** ![Access the Preimage.sol interface by providing the precompile's address.](/images/builders/ethereum/precompiles/features/governance/preimage/preimage-3.webp) ### Submit a Preimage of a Proposal {: #submit-a-preimage } In order to submit a proposal, you'll first need to submit a preimage of that proposal, which essentially defines the proposed action on-chain. You can submit the preimage using the `notePreimage` function of the Preimage Precompile. The `notePreimage` function accepts the encoded proposal, so the first step you'll need to take is to get the encoded proposal, which can easily be done using Polkadot.js Apps. In this section, you'll get the preimage hash and the encoded proposal data for a proposal. To get the preimage hash, you'll first need to navigate to the **Preimage** page of [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network%2Fpublic-ws#){target=\_blank}: 1. Navigate to the [**Governance** tab](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network%2Fpublic-ws#/democracy){target=\_blank} 2. Select **Preimages** from the dropdown 3. From the **Preimages** page, click on **+ Add preimage** ![Add a new preimage](/images/builders/ethereum/precompiles/features/governance/preimage/preimage-4.webp) Then take the following steps: 1. Select an account (any account is fine because you're not submitting any transaction here) 2. Choose the pallet you want to interact with and the dispatchable function (or action) to propose. The action you choose will determine the fields that need to fill in the following steps. In this example, it is the **system** pallet and the **remark** function 3. Enter the text of the remark, ensuring it is unique. Duplicate proposals such as "Hello World!" will not be accepted 4. Click the **Submit preimage** button but don't sign or confirm the transaction on the next page ![Get the proposal hash](/images/builders/ethereum/precompiles/features/governance/preimage/preimage-5.webp) On the next screen, take the following steps: 1. Press the triangle icon to reveal the encoded proposal in bytes 2. Copy the **bytes** (encoded proposal) — you'll need them when calling the `notePreimage` function ![Get the encoded proposal](/images/builders/ethereum/precompiles/features/governance/preimage/preimage-6.webp) !!! note You should NOT sign and submit the transaction here. You will submit this information via the `notePreimage` function in the next step. Now you can take the **bytes** of the encoded proposal that you got from [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network%2Fpublic-ws#/democracy){target=\_blank} and submit it via the `notePreimage` function of the Preimage Precompile. To submit the preimage via the `notePreimage` function, take the following steps: 1. Expand the Preimage Precompile contract to see the available functions 2. Find the **notePreimage** function and press the button to expand the section 3. Provide the **bytes** of the encoded proposal that you noted in the prior section. Note, the encoded proposal is not the same as the preimage hash. Ensure you are entering the correct value into this field 4. Press **transact** and confirm the transaction in MetaMask ![Submit the preimage using the notePreimage function of the Preimage Precompile.](/images/builders/ethereum/precompiles/features/governance/preimage/preimage-7.webp) Now that you've submitted the preimage for your proposal your proposal can be submitted! Head over to the [Referenda Precompile documentation](/builders/ethereum/precompiles/features/governance/referenda/){target=\_blank} to learn how to submit your proposal. If you wish to remove a preimage, you can follow the same steps noted above except use the `unnotePreimage` function and pass in the preimage hash instead of the encoded proposal. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/features/governance/referenda/ --- BEGIN CONTENT --- --- title: Referenda Precompile Contract description: Learn how to view and submit proposals on-chain to be put forth for referenda, directly through a Solidity interface with the Referenda Precompile on Moonbeam. categories: Precompiles, Ethereum Toolkit --- # Interacting with the Referenda Precompile ## Introduction {: #introduction } As a Polkadot parachain and decentralized network, Moonbeam features native on-chain governance that enables stakeholders to participate in the direction of the network. With the introduction of OpenGov, also referred to as Governance v2, the Referenda Pallet allows token holders to get information on existing referenda, submit a proposal to be put forth for referenda, and manage actions related to the Decision Deposit, which is required for a referenda to be decided on. To learn more about Moonbeam's governance system, such as an overview of related terminology, principles, mechanics, and more, please refer to the [Governance on Moonbeam](/learn/features/governance/){target=\_blank} page. The Referenda Precompile interacts directly with Substrate's [Referenda Pallet](/builders/substrate/interfaces/features/governance/referenda/){target=\_blank}. This pallet is coded in Rust and is normally not accessible from the Ethereum side of Moonbeam. However, the Referenda Precompile allows you to access functions needed to view referenda, submit referenda, and manage the required Decision Deposit, all of which are part of the Substrate Referenda Pallet, directly from a Solidity interface. The Referenda Precompile is located at the following address: === "Moonbeam" ```text {{ networks.moonbeam.precompiles.referenda }} ``` === "Moonriver" ```text {{ networks.moonriver.precompiles.referenda }} ``` === "Moonbase Alpha" ```text {{ networks.moonbase.precompiles.referenda }} ``` !!! note There can be some unintended consequences when using the precompiled contracts on Moonbeam. Please refer to the [Security Considerations](/learn/core-concepts/security/){target=\_blank} page for more information. ## The Referenda Solidity Interface {: #the-referenda-solidity-interface } [`Referenda.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/referenda/Referenda.sol){target=\_blank} is a Solidity interface that allows developers to interact with the precompile's methods. The methods are as follows: ??? function "**referendumCount**() - a read-only function that returns the total referendum count" === "Parameters" None. === "Returns" - `uint256` total count of referenda ??? function "**submissionDeposit**() - a read-only function that returns the Submission Deposit required for each referendum" === "Parameters" None. === "Returns" - `uint256` amount of the required Submission Deposit ??? function "**decidingCount**(*uint16* trackId) - a read-only function that returns the total count of deciding referenda for a given Track" === "Parameters" - `trackId` - uint16 Track ID to query the deciding count for === "Returns" - `uint256` count of deciding referenda for the specified Track ??? function "**trackIds**() - a read-only function that returns a list of the Track IDs for all Tracks (and Origins)" === "Parameters" None. === "Returns" - `uint16[]` array of Track IDs ??? function "**trackInfo**(*uint16* trackId) - a read-only function that returns the following governance parameters configured for a given Track ID" === "Parameters" - `trackId` - uint16 Track ID to query the parameters for === "Returns" - `string` name - the name of the Track - `uint256` maxDeciding - the maximum number of referenda that can be decided on at once - `uint256` decisionDeposit - the amount of the Decision Deposit - `uint256` preparePeriod - the duration of the Prepare Period - `uint256` decisionPeriod - the duration of the Decide Period - `uint256` confirmPeriod - the duration of the Confirm Period - `uint256` minEnactmentPeriod - the minimum amount of time the Enactment Period must be - `bytes` minApproval - the minimum "Aye" votes as a percentage of overall Conviction-weighted votes needed for an approval - `bytes` minSupport - minimum number of "Aye" votes, not taking into consideration Conviction-weighted votes, needed as a percent of the total supply needed for an approval ??? function "**referendumStatus**(*uint32* referendumIndex) - a read-only function that returns the status for a given referendum" === "Parameters" - `referendumIndex` - uint32 index of the referendum to query the status for === "Returns" ReferendumStatus enum: ```solidity enum ReferendumStatus { Ongoing, Approved, Rejected, Cancelled, TimedOut, Killed } ``` ??? function "**ongoingReferendumInfo**(*uint32* referendumIndex) - a read-only function that returns information pertaining to an ongoing referendum" === "Parameters" - `referendumIndex` - uint32 index of the ongoing referendum to query === "Returns" - `uint16` trackId - the Track of this referendum - `bytes` origin - the Origin for this referendum - `bytes` proposal - the hash of the proposal up for referendum - `bool` enactmentType - `true` if the proposal is scheduled to be dispatched *at* enactment time and `false` if *after* enactment time - `uint256` enactmentTime - the time the proposal should be scheduled for enactment - `uint256` submissionTime - the time of submission - `address` submissionDepositor - the address of the depositor for the Submission Deposit - `uint256` submissionDeposit - the amount of the Submission Deposit - `address` decisionDepositor - the address of the depositor for the Decision Deposit - `uint256` decisionDeposit - the amount of the Decision Deposit - `uint256` decidingSince - when this referendum entered the Decide Period - `uint256` decidingConfirmingEnd - when this referendum is scheduled to leave the Confirm Period - `uint256` ayes - the number of "Aye" votes, expressed in terms of post-conviction lock-vote - `uint32` support - percent of "Aye" votes, expressed pre-conviction, over total votes in the class - `uint32` approval - percent of "Aye" votes over "Aye" and "Nay" votes - `bool` inQueue - `true` if this referendum has been placed in the queue for being decided - `uint256` alarmTime - the next scheduled wake-up - `bytes` taskAddress - scheduler task address if scheduled ??? function "**closedReferendumInfo**(*uint32* referendumIndex) - a read-only function that returns information pertaining to a closed referendum" === "Parameters" - `referendumIndex` - uint32 index of the closed referendum to query === "Returns" - `uint256` end - when the referendum ended - `address` submissionDepositor - the address of the depositor for the Submission Deposit - `uint256` submissionDeposit - the amount of the Submission Deposit - `address` decisionDepositor - the address of the depositor for the Decision Deposit - `uint256` decisionDeposit - the amount of the Decision Deposit ??? function "**killedReferendumBlock**(*uint32* referendumIndex) - a read-only function that returns the block a given referendum was killed" === "Parameters" - `referendumIndex` - uint32 index of the killed referendum to query === "Returns" - `uint256` block number at which the referendum was killed ??? function "**submitAt**(*uint16* trackId, *bytes32* proposalHash, *uint32* proposalLen, *uint32* block) - submits a referendum given a Track ID corresponding to the origin from which the proposal is to be dispatched. Returns the referendum index of the submitted referendum" === "Parameters" - `trackId` - uint16 Track ID corresponding to the origin from which the proposal is to be dispatched - `proposalHash` - bytes32 preimage hash of the proposed runtime call - `proposalLen` - uint32 length of the proposal - `block` - uint32 block number *at* which this will be executed === "Returns" - `uint32` index of the submitted referendum ??? function "**submitAfter**(*uint16* trackId, *bytes32* proposalHash, *uint32* proposalLen, *uint32* block) - submits a referendum given a Track ID corresponding to the origin from which the proposal is to be dispatched. Returns the referendum index of the submitted referendum" === "Parameters" - `trackId` - uint16 Track ID corresponding to the origin from which the proposal is to be dispatched - `proposalHash` - bytes32 preimage hash of the proposed runtime call - `proposalLen` - uint32 length of the proposal - `block` - uint32 block number *after* which this will be executed === "Returns" - `uint32` index of the submitted referendum ??? function "**placeDecisionDeposit**(*uint32* index) - posts the Decision Deposit for a referendum given the index of the going referendum" === "Parameters" - `index` - uint32 index of the ongoing referendum to place the Decision Deposit for === "Returns" None. ??? function "**refundDecisionDeposit**(*uint32* index) - refunds the Decision Deposit for a closed referendum back to the depositor" === "Parameters" - `index` - uint32 index of the closed referendum in which the Decision Deposit is still locked === "Returns" None. ??? function "**refundSubmissionDeposit**(*uint32* index) - refunds the Submission Deposit for a closed referendum back to the depositor" === "Parameters" - `index` - uint32 index of the closed referendum to refund the Submission Deposit for === "Returns" None. The interface also includes the following events: - **SubmittedAt**(*uint16 indexed* trackId, *uint32* referendumIndex, *bytes32* hash) - emitted when a referenda has been submitted *at* a given block - **SubmittedAfter**(*uint16 indexed* trackId, *uint32* referendumIndex, *bytes32* hash) - emitted when a referenda has been submitted *after* a given block - **DecisionDepositPlaced**(*uint32* index, *address* caller, *uint256* depositedAmount) - emitted when a Decision Deposit for a referendum has been placed - **DecisionDepositRefunded**(*uint32* index, *address* caller, *uint256* refundedAmount) - emitted when a Decision Deposit for a closed referendum has been refunded - **SubmissionDepositRefunded**(*uint32* index, *address* caller, *uint256* refundedAmount) - emitted when a Submission Deposit for a valid referendum has been refunded ## Interact with the Solidity Interface {: #interact-with-the-solidity-interface } ### Checking Prerequisites {: #checking-prerequisites } The below example is demonstrated on Moonbase Alpha, however, similar steps can be taken for Moonriver. To follow the steps in this guide, you'll need to have the following: - MetaMask installed and [connected to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank} - An account with some DEV tokens. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} ### Remix Set Up {: #remix-set-up } 1. Click on the **File explorer** tab 2. Paste a copy of [`Referenda.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/referenda/Referenda.sol){target=\_blank} into a [Remix file](https://remix.ethereum.org){target=\_blank} named `Referenda.sol` ![Copy and paste the Referenda Solidity interface into Remix.](/images/builders/ethereum/precompiles/features/governance/referenda/referenda-1.webp) ### Compile the Contract {: #compile-the-contract } 1. Click on the **Compile** tab, second from top 2. Then to compile the interface, click on **Compile Referenda.sol** ![Compile the Referenda.sol interface using Remix.](/images/builders/ethereum/precompiles/features/governance/referenda/referenda-2.webp) ### Access the Contract {: #access-the-contract } 1. Click on the **Deploy and Run** tab, directly below the **Compile** tab in Remix. Note: you are not deploying a contract here, instead you are accessing a precompiled contract that is already deployed 2. Make sure **Injected Provider - Metamask** is selected in the **ENVIRONMENT** drop down 3. Ensure **Referenda.sol** is selected in the **CONTRACT** dropdown. Since this is a precompiled contract there is no need to deploy, instead you are going to provide the address of the precompile in the **At Address** field 4. Provide the address of the Referenda Precompile for Moonbase Alpha: `{{ networks.moonbase.precompiles.referenda }}` and click **At Address** 5. The Referenda Precompile will appear in the list of **Deployed Contracts** ![Access the Referenda.sol interface by provide the precompile's address.](/images/builders/ethereum/precompiles/features/governance/referenda/referenda-3.webp) ### Submit a Proposal {: #submit-a-proposal } In order to submit a proposal, you should have already submitted the preimage hash for the proposal. If you have not done so, please follow the steps outlined in the [Preimage Precompile](/builders/ethereum/precompiles/features/governance/preimage/){target=\_blank} documentation. There are two methods that can be used to submit a proposal: `submitAt` and `submitAfter`. The `submitAt` function submits a proposal to be executed *at* a given block and the `submitAfter` function submits a proposal to be executed *after* a specific block. For this example, `submitAt` will be used, but the same steps can be applied if you want to use `submitAfter` instead. To submit the proposal, you'll need to determine which Track your proposal belongs to and the Track ID of that Track. For help with these requirements, you can refer to the [OpenGov section of the governance overview page](/learn/features/governance/#opengov){target=\_blank}. You'll also need to make sure you have the preimage hash and the length of the preimage handy, both of which you should have received from following the steps in the [Preimage Precompile](/builders/ethereum/precompiles/features/governance/preimage/){target=\_blank} documentation. If you're unsure, you can find your preimage from the [Preimage page of Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/preimages){target=\_blank} and copy the preimage hash. To get the length of the preimage, you can then query the `preimage` pallet using the `preimageFor` method from the [Polkadot.js Apps Chain State page](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/chainstate){target=\_blank}. Once you have the Track ID, preimage hash, and preimage length, you can go ahead and submit the proposal using the Referenda Precompile. From Remix, you can take the following steps: 1. Expand the Referenda Precompile contract to see the available functions 2. Find the **submitAt** function and press the button to expand the section 3. Enter the track ID that your proposal will be processed through 4. Enter the preimage hash. You should have received this from following the steps in the [Preimage Precompile](/builders/ethereum/precompiles/features/governance/preimage/){target=\_blank} documentation 5. Enter the length of the preimage 6. Enter the block you want the proposal to be executed at 7. Press **transact** and confirm the transaction in MetaMask ![Submit the proposal using the submitAt function of the Referenda Precompile.](/images/builders/ethereum/precompiles/features/governance/referenda/referenda-4.webp) After your transaction has been confirmed you'll be able to see the proposal listed on the **Referenda** page of [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network%2Fpublic-ws#/referenda){target=\_blank}. You can also check out your proposal on [Polkassembly](https://moonbase.polkassembly.io/opengov){target=\_blank}, which sorts proposals by the Track they belong to. ### Submit Decision Deposit {: #submit-decision-deposit } Now that you've submitted your proposal, the next step is to submit the Decision Deposit. The Decision Deposit is the minimum deposit amount required for a referendum to progress to the decision phase at the end of the Lead-in Period. For more information on the Decision Deposit, please refer to the [OpenGov section of the governance overview page](/learn/features/governance/#opengov){target=\_blank}. You can submit the Decision Deposit using the `placeDecisionDeposit` function of the Referenda Precompile. You'll just need to have the index of the referendum and enough funds to do so. The Decision Deposit varies by Track, to find the minimum amount required you can take a look at the [General Parameters by Track table on the governance overview page](/learn/features/governance/#general-parameters-by-track){target=\_blank}. To submit the deposit, you can take the following steps: 1. Find the **placeDecisionDeposit** function and press the button to expand the section 2. Enter the index of the referendum 3. Press **transact** and confirm the transaction in MetaMask ![Place the Decision Deposit for a Referenda using the placeDecisionDeposit function of the Referenda Precompile.](/images/builders/ethereum/precompiles/features/governance/referenda/referenda-5.webp) Now that the Decision Deposit has been placed, the referendum is one step closer to moving to the Decide Period. There will also need to be enough Capacity in the designated Track and the duration of the Prepare Period must pass for it to move to the Decide Period. To vote on referenda, you can follow the steps outlined in the [Conviction Voting Precompile](/builders/ethereum/precompiles/features/governance/conviction-voting/){target=\_blank} documentation. ### Refund Decision Deposit {: #refund-decision-deposit } Once a referendum has either been approved or rejected, the Decision Deposit can be refunded. This holds true as long as the referendum wasn't cancelled due to the proposal being malicious. If the proposal is deemed malicious and killed via the Root Track or the Emergency Killer Track, the Decision Deposit will be slashed. To refund the Decision Deposit, you can use the `refundDecisionDeposit` function of the Referenda Precompile. To do so, you can take the following steps: 1. Find the **refundDecisionDeposit** function and press the button to expand the section 2. Enter the index of the referendum 3. Press **transact** and confirm the transaction in MetaMask ![Refund the Decision Deposit for a Referenda using the refundDecisionDeposit function of the Referenda Precompile.](/images/builders/ethereum/precompiles/features/governance/referenda/referenda-6.webp) And that's it! You've completed your introduction to the Referenda Precompile. There are a few more functions that are documented in [`Referenda.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/referenda/Referenda.sol){target=\_blank} — feel free to reach out on [Discord](https://discord.com/invite/PfpUATX){target=\_blank} if you have any questions about those functions or any other aspect of the Referenda Precompile. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/features/ --- BEGIN CONTENT --- --- title: Precompiles For Key Moonbeam Features description: Access essential network features on Moonbeam through precompiled contracts for governance, staking, and secure randomness generation. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/features/randomness/ --- BEGIN CONTENT --- --- title: Randomness Precompile description: Learn about the sources of VRF randomness on Moonbeam and how to use the randomness precompile and consumer interface to generate on-chain randomness. keywords: solidity, ethereum, randomness, VRF, moonbeam, precompiled, contracts categories: Precompiles, Ethereum Toolkit --- # Interacting with the Randomness Precompile ## Introduction {: #introduction } Moonbeam utilizes verifiable random functions (VRF) to generate randomness that can be verified on-chain. A VRF is a cryptographic function that takes some input and produces random values, along with a proof of authenticity that these random values were generated by the submitter. The proof can be verified by anyone to ensure the random values generated were calculated correctly. There are two available sources of randomness that provide random inputs based on block producers' VRF keys and past randomness results: [local VRF](/learn/features/randomness/#local-vrf) and [BABE epoch randomness](/learn/features/randomness/#babe-epoch-randomness). Local VRF is determined directly within Moonbeam using the collator of the block's VRF key and the last block's VRF output. On the other hand, [BABE](https://docs.polkadot.com/polkadot-protocol/architecture/polkadot-chain/pos-consensus/#block-production-babe){target=\_blank} epoch randomness is based on all the VRF produced by the relay chain validators during a complete [epoch](https://wiki.polkadot.network/general/glossary/#epoch){target=\_blank}. For more information on the two sources of randomness, how the request and fulfillment process works, and security considerations, please refer to the [Randomness on Moonbeam](/learn/features/randomness/){target=\_blank} page. Moonbeam provides a randomness precompile, which is a Solidity interface that enables smart contract developers to generate randomness via local VRF or BABE epoch randomness using the Ethereum API. Moonbeam also provides a randomness consumer Solidity contract that your contract must inherit from in order to consume fulfilled randomness requests. This guide will show you how to use the randomness precompile and randomness consumer contract to create a lottery where the winners will randomly be selected. You'll also learn how to interact with the randomness precompile directly to perform actions such as purging an expired randomness request. The randomness precompile is located at the following address: === "Moonbeam" ```text {{ networks.moonbeam.precompiles.randomness }} ``` === "Moonriver" ```text {{ networks.moonriver.precompiles.randomness }} ``` === "Moonbase Alpha" ```text {{ networks.moonbase.precompiles.randomness }} ``` !!! note There can be some unintended consequences when using the precompiled contracts on Moonbeam. Please refer to the [Security Considerations](/learn/core-concepts/security/){target=\_blank} page for more information. ## The Randomness Solidity Interface {: #the-randomness-interface } [Randomness.sol](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/randomness/Randomness.sol){target=\_blank} is a Solidity interface that allows developers to interact with the precompile's methods. ??? code "Randomness.sol" ```solidity // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.3; /// @dev The Randomness contract's address. address constant RANDOMNESS_ADDRESS = 0x0000000000000000000000000000000000000809; /// @dev The Randomness contract's instance. Randomness constant RANDOMNESS_CONTRACT = Randomness(RANDOMNESS_ADDRESS); /// @dev Maximum number of random words being requested uint32 constant MAX_RANDOM_WORDS = 100; /// @dev Minimum number of blocks before a request can be fulfilled for Local VRF Request uint32 constant MIN_VRF_BLOCKS_DELAY = 2; /// @dev Maximum number of blocks before a request can be fulfilled for Local VRF Request uint32 constant MAX_VRF_BLOCKS_DELAY = 2000; /// @dev The deposit amount needed to request random words. There is 1 deposit per request uint256 constant REQUEST_DEPOSIT_AMOUNT = 1000000000000000000; /// @author The Moonbeam Team /// @title Pallet Randomness Interface /// @dev The interface through which solidity contracts will interact with Randomness /// @custom:address 0x0000000000000000000000000000000000000809 interface Randomness { /// @notice Event emitted when the request has been successfully executed event FulFillmentSucceeded(); /// @notice Event emitted when the request has failed to execute fulfillment event FulFillmentFailed(); /// @notice The status of the request /// @param DoesNotExist The request doesn't exist /// @param Pending The request cannot be fulfilled yet /// @param Ready The request is ready to be fulfilled /// @param Expired The request has expired enum RequestStatus { DoesNotExist, Pending, Ready, Expired } /// @notice The type of randomness source /// @param LocalVRF Randomness VRF using the parachain material as seed /// @param RelayBabeEpoch Randomness VRF using relay material from previous epoch enum RandomnessSource { LocalVRF, RelayBabeEpoch } /// @notice The request details /// @param id The id of the request (is always < 2**64) /// @param refundAddress The address receiving the left-over fees after the fulfillment /// @param contractAddress The address of the contract being called back during fulfillment /// @param fee The amount to set aside to pay for the fulfillment /// @param gasLimit The gas limit to use for the fulfillment /// @param salt A string being mixed with the randomness seed to obtain different random words. This should be as unique as possible; using the same salt will lead to same randomness result. /// @param numWords The number of random words requested (from 1 to MAX_RANDOM_WORDS) /// @param randomnessSource The type of randomness source used to generate the random words /// @param fulfillmentBlock The parachain block number at which the request can be fulfilled (for LocalVRF only) /// @param fulfillmentEpochIndex The relay epoch index at which the request can be fulfilled (for RelayBabeEpoch) /// @param expirationBlock The parachain block number at which the request expires (for LocalVRF only) /// @param expirationEpochIndex The relay epoch index at which the request expires (for RelayBabeEpoch) /// @param status The current status of the request struct Request { uint256 id; address refundAddress; address contractAddress; uint256 fee; uint256 gasLimit; bytes32 salt; uint32 numWords; RandomnessSource randomnessSource; uint32 fulfillmentBlock; uint64 fulfillmentEpochIndex; uint32 expirationBlock; uint64 expirationEpochIndex; RequestStatus status; } /// Return the current relay epoch index /// @dev An epoch represents real time and not a block number /// @dev Currently, time between epoch changes cannot be longer than: /// @dev - Kusama/Westend/Rococo: 600 relay blocks (1 hour) /// @dev - Polkadot: 2400 relay blocks (4 hours) /// @custom:selector 81797566 function relayEpochIndex() external view returns (uint64); /// Return the deposit required to perform a request /// @dev Each request will need a deposit. /// @custom:selector fb7cfdd7 function requiredDeposit() external view returns (uint256); /// @notice Returns the request status /// @param requestId The id of the request to check (must be < 2**64) /// @return status Status of the request /// @custom:selector d8a4676f function getRequestStatus(uint256 requestId) external view returns (RequestStatus status); /// @notice Returns the request or revert /// @param requestId The id of the request to check (must be < 2**64) /// @return request The request /// @custom:selector c58343ef function getRequest(uint256 requestId) external view returns (Request memory request); /// @notice Request random words generated from the parachain VRF /// @dev This is using pseudo-random VRF executed by the collator at the fulfillment /// @dev Warning: /// @dev The collator in charge of producing the block at fulfillment can decide to skip /// @dev producing the block in order to have a different random word generated by the next /// @dev collator, at the cost of a block reward. It is therefore economically viable to use /// @dev this randomness source only if the financial reward at stake is lower than the block /// @dev reward. /// @dev In order to reduce the risk of a collator being able to predict the random words /// @dev when the request is performed, it is possible to increase the delay to multiple blocks /// @dev The higher the delay is, the less likely the collator will be able to know which /// @dev collator will be in charge of fulfilling the request. /// @dev Fulfillment is manual and can be executed by anyone (for free) after the given delay /// @param refundAddress The address receiving the left-over fees after the fulfillment /// @param fee The amount to set aside to pay for the fulfillment /// @param gasLimit The gas limit to use for the fulfillment /// @param salt A string being mixed with the randomness seed to obtain different random words /// @param numWords The number of random words requested (from 1 to MAX_RANDOM_WORDS) /// @param delay The number of blocks until the request can be fulfilled (between MIN_DELAY_BLOCKS and MAX_DELAY_BLOCKS) /// @return requestId The id of the request requestLocalVRFRandomWords /// @custom:selector 9478430c function requestLocalVRFRandomWords( address refundAddress, uint256 fee, uint64 gasLimit, bytes32 salt, uint8 numWords, uint64 delay ) external returns (uint256); /// @notice Request random words generated from the relaychain Babe consensus /// @dev The random words are generated from the hash of the all the VRF provided by the /// @dev relaychain validator during 1 epoch. /// @dev It requires a delay of at least 1 epoch after the current epoch to be unpredictable /// @dev at the time the request is performed. /// @dev Warning: /// @dev The validator (on the relaychain) of the last block of an epoch can decide to skip /// @dev producing the block in order to choose the previous generated epoch random number /// @dev at the cost of a relaychain block rewards. It is therefore economically viable to use /// @dev this randomness source only if the financial reward at stake is lower than the relaychain /// @dev block reward. /// @dev (see https://crates.parity.io/pallet_babe/struct.RandomnessFromOneEpochAgo.html) /// @dev Fulfillment is manual and can be executed by anyone (for free) at /// @dev the beginning of the 2nd relay epoch following the current one /// @param refundAddress The address receiving the left-over fees after the fulfillment /// @param fee Amount to set aside to pay for the fulfillment. Those fees are taken from the contract /// @param gasLimit Gas limit for the fulfillment /// @param salt Salt to be mixed with raw randomness to get output /// @param numWords Number of random words to be returned (limited to MAX_RANDOM_WORDS) /// @return requestId The id of the request /// @custom:selector 33c14a63 function requestRelayBabeEpochRandomWords( address refundAddress, uint256 fee, uint64 gasLimit, bytes32 salt, uint8 numWords ) external returns (uint256); /// @dev fulFill the request which will call the contract method "fulfillRandomWords" /// @dev Fees of the caller are refunded if the request is fulfillable /// @param requestId Request to be fulfilled (must be < 2**64) /// @custom:selector 9a91eb0d function fulfillRequest(uint256 requestId) external; /// @param requestId Request receiving the additional fees (must be < 2**64) /// @param feeIncrease Amount to increase /// @custom:selector d0408a7f function increaseRequestFee(uint256 requestId, uint256 feeIncrease) external; /// @param requestId Request to be purged (must be < 2**64) /// @custom:selector 1d26cbab function purgeExpiredRequest(uint256 requestId) external; } ``` The interface includes functions, constants, events, and enums, as covered in the following sections. ### Functions {: #functions } The interface includes the following functions: ??? function "**relayEpochIndex**() - returns the current relay epoch index, where an epoch represents real time and not a block number" === "Parameters" None. === "Returns" - `uint256` current relay epoch index ??? function "**requiredDeposit**() - returns the deposit required to perform a randomness request" === "Parameters" None. === "Returns" - `uint256` required deposit amount ??? function "**getRequestStatus**(*uint256* requestId) - returns the request status of a given randomness request" === "Parameters" - `requestId` - uint256 ID of the randomness request === "Returns" - `uint8` status code of the request ??? function "**getRequest**(*uint256* requestId) - returns the request details of a given randomness request" === "Parameters" - `requestId` - uint256 ID of the randomness request === "Returns" - `bool` whether the request is ready or not - `bool` whether the request is expired or not - `uint256` deposit amount - `uint256` fee amount ??? function "**requestLocalVRFRandomWords**(*address* refundAddress, *uint256* fee, *uint64* gasLimit, *bytes32* salt, *uint8* numWords, *uint64* delay) - request random words generated from the parachain VRF" === "Parameters" - `refundAddress` - address receiving the left-over fees after the fulfillment - `fee` - uint256 amount to set aside to pay for the fulfillment - `gasLimit` - uint64 gas limit to use for the fulfillment - `salt` - bytes32 string that is mixed with the randomness seed to obtain different random words - `numWords` - uint8 number of random words requested, up to the maximum number of random words - `delay` - uint64 number of blocks that must pass before the request can be fulfilled. This value will need to be between the minimum and maximum number of blocks before a local VRF request can be fulfilled === "Returns" - `uint256` ID of the created request ??? function "**requestRelayBabeEpochRandomWords**(*address* refundAddress, *uint256* fee, *uint64* gasLimit, *bytes32* salt, *uint8* numWords) - request random words generated from the relay chain BABE consensus" === "Parameters" - `refundAddress` - address receiving the left-over fees after the fulfillment - `fee` - uint256 amount to set aside to pay for the fulfillment - `gasLimit` - uint64 gas limit to use for the fulfillment - `salt` - bytes32 string that is mixed with the randomness seed to obtain different random words - `numWords` - uint8 number of random words requested, up to the maximum number of random words === "Returns" - `uint256` ID of the created request ??? function "**fulfillRequest**(*uint256* requestId) - fulfill the request which will call the consumer contract method [`fulfillRandomWords`](#:~:text=rawFulfillRandomWords(uint256 requestId, uint256[] memory randomWords)). Fees of the caller are refunded if the request is fulfillable" === "Parameters" - `requestId` - uint256 ID of the randomness request === "Returns" None. ??? function "**increaseRequestFee**(*uint256* requestId, *uint256* feeIncrease) - increases the fee associated with a given randomness request. This is needed if the gas price increases significantly before the request is fulfilled" === "Parameters" - `requestId` - uint256 ID of the randomness request - `feeIncrease` - uint256 amount to increase fees by === "Returns" None. ??? function "**purgeExpiredRequest**(*uint256* requestId) - removes a given expired request from storage and transfers the request fees to the caller and the deposit back to the original requester" === "Parameters" - `requestId` - uint256 ID of the randomness request === "Returns" None. ### Constants {: #constants } The interface includes the following constants: - **maxRandomWords** - the maximum number of random words being requested - **minBlockDelay** - the minimum number of blocks before a request can be fulfilled for local VRF requests - **maxBlockDelay** - the maximum number of blocks before a request can be fulfilled for local VRF requests - **deposit** - the deposit amount needed to request random words. There is one deposit per request === "Moonbeam" | Variable | Value | |:----------------------:|:---------------------------------------------------------------:| | MAX_RANDOM_WORDS | {{ networks.moonbeam.randomness.max_random_words }} words | | MIN_VRF_BLOCKS_DELAY | {{ networks.moonbeam.randomness.min_vrf_blocks_delay }} blocks | | MAX_VRF_BLOCKS_DELAY | {{ networks.moonbeam.randomness.max_vrf_blocks_delay }} blocks | | REQUEST_DEPOSIT_AMOUNT | {{ networks.moonbeam.randomness.req_deposit_amount.glmr }} GLMR | === "Moonriver" | Variable | Value | |:----------------------:|:----------------------------------------------------------------:| | MAX_RANDOM_WORDS | {{ networks.moonriver.randomness.max_random_words }} words | | MIN_VRF_BLOCKS_DELAY | {{ networks.moonriver.randomness.min_vrf_blocks_delay }} blocks | | MAX_VRF_BLOCKS_DELAY | {{ networks.moonriver.randomness.max_vrf_blocks_delay }} blocks | | REQUEST_DEPOSIT_AMOUNT | {{ networks.moonriver.randomness.req_deposit_amount.movr }} MOVR | === "Moonbase Alpha" | Variable | Value | |:----------------------:|:--------------------------------------------------------------:| | MAX_RANDOM_WORDS | {{ networks.moonbase.randomness.max_random_words }} words | | MIN_VRF_BLOCKS_DELAY | {{ networks.moonbase.randomness.min_vrf_blocks_delay }} blocks | | MAX_VRF_BLOCKS_DELAY | {{ networks.moonbase.randomness.max_vrf_blocks_delay }} blocks | | REQUEST_DEPOSIT_AMOUNT | {{ networks.moonbase.randomness.req_deposit_amount.dev }} DEV | ### Events {: #events } The interface includes the following events: - **FulfillmentSucceeded**() - emitted when the request has been successfully executed - **FulfillmentFailed**() - emitted when the request has failed to execute fulfillment ### Enums {: #enums } The interface includes the following enums: - **RequestStatus** - the status of the request, which can be `DoesNotExist` (0), `Pending` (1), `Ready` (2), or `Expired` (3) - **RandomnessSource** - the type of the randomness source, which can be `LocalVRF` (0) or `RelayBabeEpoch` (1) ## The Randomness Consumer Solidity Interface {: #randomness-consumer-solidity-interface } The [`RandomnessConsumer.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/4e2a5785424be6faa01cd14e90155d9d2ec734ee/precompiles/randomness/RandomnessConsumer.sol){target=\_blank} Solidity interface makes it easy for smart contracts to interact with the randomness precompile. Using the randomness consumer ensures the fulfillment comes from the randomness precompile. ??? code "RandomnessConsumer.sol" ```solidity // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.3; /// @dev The Randomness contract's address. address constant RANDOMNESS_ADDRESS = 0x0000000000000000000000000000000000000809; /// @dev The Randomness contract's instance. Randomness constant RANDOMNESS_CONTRACT = Randomness(RANDOMNESS_ADDRESS); /// @dev Maximum number of random words being requested uint32 constant MAX_RANDOM_WORDS = 100; /// @dev Minimum number of blocks before a request can be fulfilled for Local VRF Request uint32 constant MIN_VRF_BLOCKS_DELAY = 2; /// @dev Maximum number of blocks before a request can be fulfilled for Local VRF Request uint32 constant MAX_VRF_BLOCKS_DELAY = 2000; /// @dev The deposit amount needed to request random words. There is 1 deposit per request uint256 constant REQUEST_DEPOSIT_AMOUNT = 1000000000000000000; /// @author The Moonbeam Team /// @title Pallet Randomness Interface /// @dev The interface through which solidity contracts will interact with Randomness /// @custom:address 0x0000000000000000000000000000000000000809 interface Randomness { /// @notice Event emitted when the request has been successfully executed event FulFillmentSucceeded(); /// @notice Event emitted when the request has failed to execute fulfillment event FulFillmentFailed(); /// @notice The status of the request /// @param DoesNotExist The request doesn't exist /// @param Pending The request cannot be fulfilled yet /// @param Ready The request is ready to be fulfilled /// @param Expired The request has expired enum RequestStatus { DoesNotExist, Pending, Ready, Expired } /// @notice The type of randomness source /// @param LocalVRF Randomness VRF using the parachain material as seed /// @param RelayBabeEpoch Randomness VRF using relay material from previous epoch enum RandomnessSource { LocalVRF, RelayBabeEpoch } /// @notice The request details /// @param id The id of the request (is always < 2**64) /// @param refundAddress The address receiving the left-over fees after the fulfillment /// @param contractAddress The address of the contract being called back during fulfillment /// @param fee The amount to set aside to pay for the fulfillment /// @param gasLimit The gas limit to use for the fulfillment /// @param salt A string being mixed with the randomness seed to obtain different random words. This should be as unique as possible; using the same salt will lead to same randomness result. /// @param numWords The number of random words requested (from 1 to MAX_RANDOM_WORDS) /// @param randomnessSource The type of randomness source used to generate the random words /// @param fulfillmentBlock The parachain block number at which the request can be fulfilled (for LocalVRF only) /// @param fulfillmentEpochIndex The relay epoch index at which the request can be fulfilled (for RelayBabeEpoch) /// @param expirationBlock The parachain block number at which the request expires (for LocalVRF only) /// @param expirationEpochIndex The relay epoch index at which the request expires (for RelayBabeEpoch) /// @param status The current status of the request struct Request { uint256 id; address refundAddress; address contractAddress; uint256 fee; uint256 gasLimit; bytes32 salt; uint32 numWords; RandomnessSource randomnessSource; uint32 fulfillmentBlock; uint64 fulfillmentEpochIndex; uint32 expirationBlock; uint64 expirationEpochIndex; RequestStatus status; } /// Return the current relay epoch index /// @dev An epoch represents real time and not a block number /// @dev Currently, time between epoch changes cannot be longer than: /// @dev - Kusama/Westend/Rococo: 600 relay blocks (1 hour) /// @dev - Polkadot: 2400 relay blocks (4 hours) /// @custom:selector 81797566 function relayEpochIndex() external view returns (uint64); /// Return the deposit required to perform a request /// @dev Each request will need a deposit. /// @custom:selector fb7cfdd7 function requiredDeposit() external view returns (uint256); /// @notice Returns the request status /// @param requestId The id of the request to check (must be < 2**64) /// @return status Status of the request /// @custom:selector d8a4676f function getRequestStatus(uint256 requestId) external view returns (RequestStatus status); /// @notice Returns the request or revert /// @param requestId The id of the request to check (must be < 2**64) /// @return request The request /// @custom:selector c58343ef function getRequest(uint256 requestId) external view returns (Request memory request); /// @notice Request random words generated from the parachain VRF /// @dev This is using pseudo-random VRF executed by the collator at the fulfillment /// @dev Warning: /// @dev The collator in charge of producing the block at fulfillment can decide to skip /// @dev producing the block in order to have a different random word generated by the next /// @dev collator, at the cost of a block reward. It is therefore economically viable to use /// @dev this randomness source only if the financial reward at stake is lower than the block /// @dev reward. /// @dev In order to reduce the risk of a collator being able to predict the random words /// @dev when the request is performed, it is possible to increase the delay to multiple blocks /// @dev The higher the delay is, the less likely the collator will be able to know which /// @dev collator will be in charge of fulfilling the request. /// @dev Fulfillment is manual and can be executed by anyone (for free) after the given delay /// @param refundAddress The address receiving the left-over fees after the fulfillment /// @param fee The amount to set aside to pay for the fulfillment /// @param gasLimit The gas limit to use for the fulfillment /// @param salt A string being mixed with the randomness seed to obtain different random words /// @param numWords The number of random words requested (from 1 to MAX_RANDOM_WORDS) /// @param delay The number of blocks until the request can be fulfilled (between MIN_DELAY_BLOCKS and MAX_DELAY_BLOCKS) /// @return requestId The id of the request requestLocalVRFRandomWords /// @custom:selector 9478430c function requestLocalVRFRandomWords( address refundAddress, uint256 fee, uint64 gasLimit, bytes32 salt, uint8 numWords, uint64 delay ) external returns (uint256); /// @notice Request random words generated from the relaychain Babe consensus /// @dev The random words are generated from the hash of the all the VRF provided by the /// @dev relaychain validator during 1 epoch. /// @dev It requires a delay of at least 1 epoch after the current epoch to be unpredictable /// @dev at the time the request is performed. /// @dev Warning: /// @dev The validator (on the relaychain) of the last block of an epoch can decide to skip /// @dev producing the block in order to choose the previous generated epoch random number /// @dev at the cost of a relaychain block rewards. It is therefore economically viable to use /// @dev this randomness source only if the financial reward at stake is lower than the relaychain /// @dev block reward. /// @dev (see https://crates.parity.io/pallet_babe/struct.RandomnessFromOneEpochAgo.html) /// @dev Fulfillment is manual and can be executed by anyone (for free) at /// @dev the beginning of the 2nd relay epoch following the current one /// @param refundAddress The address receiving the left-over fees after the fulfillment /// @param fee Amount to set aside to pay for the fulfillment. Those fees are taken from the contract /// @param gasLimit Gas limit for the fulfillment /// @param salt Salt to be mixed with raw randomness to get output /// @param numWords Number of random words to be returned (limited to MAX_RANDOM_WORDS) /// @return requestId The id of the request /// @custom:selector 33c14a63 function requestRelayBabeEpochRandomWords( address refundAddress, uint256 fee, uint64 gasLimit, bytes32 salt, uint8 numWords ) external returns (uint256); /// @dev fulFill the request which will call the contract method "fulfillRandomWords" /// @dev Fees of the caller are refunded if the request is fulfillable /// @param requestId Request to be fulfilled (must be < 2**64) /// @custom:selector 9a91eb0d function fulfillRequest(uint256 requestId) external; /// @param requestId Request receiving the additional fees (must be < 2**64) /// @param feeIncrease Amount to increase /// @custom:selector d0408a7f function increaseRequestFee(uint256 requestId, uint256 feeIncrease) external; /// @param requestId Request to be purged (must be < 2**64) /// @custom:selector 1d26cbab function purgeExpiredRequest(uint256 requestId) external; } ``` The consumer interface includes the following functions: - **fulfillRandomWords**(*uint256* requestId, *uint256[] memory* randomWords) - handles the VRF response for a given request. This method is triggered by a call to `rawFulfillRandomWords` - **rawFulfillRandomWords**(*uint256* requestId, *uint256[] memory* randomWords) - executed when the [`fulfillRequest` function](#:~:text=fulfillRequest(uint256 requestId)) of the randomness precompile is called. The origin of the call is validated, ensuring the randomness precompile is the origin, and then the `fulfillRandomWords` method is called ## Request & Fulfill Process {: #request-and-fulfill-process } To consume randomness, you must have a contract that does the following: - Imports the `Randomness.sol` precompile and `RandomnessConsumer.sol` interface - Inherits from the `RandomnessConsumer.sol` interface - Requests randomness through the precompile's [`requestLocalVRFRandomWords` method](#:~:text=requestLocalVRFRandomWords) or [`requestRelayBabeEpochRandomWords` method](#:~:text=requestRelayBabeEpochRandomWords), depending on the source of randomness you want to use - Requests fulfillment through the precompile's [`fulfillRequest` method](#:~:text=fulfillRequest) - Consumes randomness through a `fulfillRandomWords` method with the same [signature as the `fulfillRandomWords` method](#:~:text=fulfillRandomWords(uint256 requestId, uint256[] memory randomWords)) of the `RandomnessConsumer.sol` contract When randomness is requested through the precompile's `requestLocalVRFRandomWords` or `requestRelayBabeEpochRandomWords` method, a fee is set aside to pay for the fulfillment of the request. When using local VRF, to increase unpredictability, a specified delay period (in blocks) must pass before the request can be fulfilled. At the very least, the delay period must be greater than one block. For BABE epoch randomness, you do not need to specify a delay but can fulfill the request at the beginning of the 2nd epoch following the current one. After the delay, fulfillment of the request can be manually executed by anyone through the `fulfillRequest` method using the fee that was initially set aside for the request. When fulfilling the randomness request via the precompile's `fulfillRequest` method, the [`rawFulfillRandomWords`](#:~:text=rawFulfillRandomWords(uint256 requestId, uint256[] memory randomWords)) function in the `RandomnessConsumer.sol` contract will be called, which will verify that the sender is the randomness precompile. From there, [`fulfillRandomWords`](#:~:text=fulfillRandomWords(uint256 requestId, uint256[] memory randomWords)) is called and the requested number of random words are computed using the current block's randomness result and a given salt and returned. If the fulfillment was successful, the [`FulfillmentSucceeded` event](#:~:text=FulfillmentSucceeded) will be emitted; otherwise the [`FulfillmentFailed` event](#:~:text=FulfillmentFailed) will be emitted. For fulfilled requests, the cost of execution will be refunded from the request fee to the caller of `fulfillRequest`. Then any excess fees and the request deposit are transferred to the specified refund address. Your contract's `fulfillRandomWords` callback is responsible for handling the fulfillment. For example, in a lottery contract, the callback would use the random words to choose a winner and payout the winnings. If a request expires it can be purged through the precompile's [`purgeExpiredRequest` function](/builders/ethereum/precompiles/features/randomness/#:~:text=purgeExpiredRequest){target=\_blank}. When this function is called the request fee is paid out to the caller and the deposit will be returned to the original requester. The happy path for a randomness request is shown in the following diagram: ![Randomness request happy path diagram](/images/learn/features/randomness/randomness-1.webp) ## Generate a Random Number using the Randomness Precompile {: #interact-with-the-solidity-interfaces } In the following sections of this tutorial, you'll learn how to create a smart contract that generates a random number using the Randomness Precompile and the Randomness Consumer. If you want to just explore some of the functions of the Randomness Precompile, you can skip ahead to the [Use Remix to Interact Directly with the Randomness Precompile](#interact-directly) section. ### Checking Prerequisites {: #checking-prerequisites } For this guide, you will need to have the following: - [MetaMask installed and connected to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank} - An account funded with DEV tokens. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} ### Create a Random Number Generator Contract {: #create-random-generator-contract } The contract that will be created in this section includes the functions that you'll need at a bare minimum to request randomness and consume the results from fulfilling randomness requests. **This contract is for educational purposes only and is not meant for production use.** The contract will include the following functions: - A constructor that accepts the deposit required to request randomness - A function that submits randomness requests. For this example, the source of randomness will be local VRF, but you can easily modify the contract to use BABE epoch randomness - A function that fulfills the request by calling the `fulfillRequest` function of the Randomness Precompile. This function will be `payable` as the fulfillment fee will need to be submitted at the time of the randomness request - A function that consumes the fulfillment results. This function's signature must match the [signature of the `fulfillRandomWords` method](#:~:text=fulfillRandomWords(uint256 requestId, uint256[] memory randomWords)) of the Randomness Consumer contract Without further ado, the contract is as follows: ```solidity // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; import "https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/randomness/Randomness.sol"; import {RandomnessConsumer} from "https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/randomness/RandomnessConsumer.sol"; contract RandomNumber is RandomnessConsumer { // The Randomness Precompile Interface Randomness public randomness = Randomness(0x0000000000000000000000000000000000000809); // Variables required for randomness requests uint256 public requiredDeposit = randomness.requiredDeposit(); uint64 public FULFILLMENT_GAS_LIMIT = 100000; // The fee can be set to any value as long as it is enough to cover // the fulfillment costs. Any leftover fees will be refunded to the // refund address specified in the requestRandomness function below. // 150 Gwei should be sufficient for all networks. // For Moonbase Alpha and Moonriver, you can specify 5 Gwei uint256 public MIN_FEE = FULFILLMENT_GAS_LIMIT * 150 gwei; uint32 public VRF_BLOCKS_DELAY = MIN_VRF_BLOCKS_DELAY; bytes32 public SALT_PREFIX = "INSERT_ANY_STRING_FOR_SALT"; // Storage variables for the current request uint256 public requestId; uint256[] public random; constructor() payable RandomnessConsumer() { // Because this contract can only perform 1 random request at a time, // We only need to have 1 required deposit require(msg.value >= requiredDeposit); } function requestRandomness() public payable { // Make sure that the value sent is enough require(msg.value >= MIN_FEE); // Request local VRF randomness requestId = randomness.requestLocalVRFRandomWords( msg.sender, // Refund address msg.value, // Fulfillment fee FULFILLMENT_GAS_LIMIT, // Gas limit for the fulfillment SALT_PREFIX ^ bytes32(requestId++), // A salt to generate unique results 1, // Number of random words VRF_BLOCKS_DELAY // Delay before request can be fulfilled ); } function fulfillRequest() public { randomness.fulfillRequest(requestId); } function fulfillRandomWords( uint256, // requestId uint256[] memory randomWords ) internal override { // Save the randomness results random = randomWords; } } ``` As you can see, there are also some constants in the contract that can be edited as you see fit, especially the `SALT_PREFIX` which can be used to produce unique results. In the following sections, you'll use Remix to deploy and interact with the contract. ### Remix Set Up {: #remix-set-up} To add the contract to Remix and follow along with this section of the tutorial, you will need to create a new file named `RandomnessNumber.sol` in Remix and paste the `RandomNumber` contract into the file. ![Add the random number generator contract to Remix.](/images/builders/ethereum/precompiles/features/randomness/randomness-2.webp) ### Compile & Deploy the Random Number Generator Contract {: #compile-deploy-random-number } To compile the `RandomNumber.sol` contract in Remix, you'll need to take the following steps: 1. Click on the **Compile** tab, second from top 2. Click on the **Compile RandomNumber.sol** button If the contract was compiled successfully, you will see a green checkmark next to the **Compile** tab. ![Compile the random number generator contract in Remix.](/images/builders/ethereum/precompiles/features/randomness/randomness-3.webp) Now you can go ahead and deploy the contract by taking these steps: 1. Click on the **Deploy and Run** tab directly below the **Compile** tab 2. Make sure **Injected Provider - Metamask** is selected in the **ENVIRONMENT** dropdown. Once you select **Injected Provider - Metamask**, you might be prompted by MetaMask to connect your account to Remix 3. Make sure the correct account is displayed under **ACCOUNT** 4. Enter the deposit amount in the **VALUE** field, which is `{{ networks.moonbase.randomness.req_deposit_amount.wei }}` in Wei (`{{ networks.moonbase.randomness.req_deposit_amount.dev }}` Ether) 5. Ensure **RandomNumber - RandomNumber.sol** is selected in the **CONTRACT** dropdown 6. Click **Deploy** 7. Confirm the MetaMask transaction that appears by clicking **Confirm** ![Deploy the random number generator contract in Remix.](/images/builders/ethereum/precompiles/features/randomness/randomness-4.webp) The **RANDOMNUMBER** contract will appear in the list of **Deployed Contracts**. ### Submit a Request to Generate a Random Number {: #request-randomness } To request randomness, you're going to use the `requestRandomness` function of the contract, which will require you to submit a deposit as defined in the Randomness Precompile. You can submit the randomness request and pay the deposit by taking these steps: 1. Enter an amount in the **VALUE** field for the fulfillment fee, it must be equal to or greater than the minimum fee specified in the `RandomNumber` contract, which is `15000000` Gwei. 2. Expand the **RANDOMNUMBER** contract 3. Click on the **requestRandomness** button 4. Confrm the transaction in MetaMask ![Request a random number using the random number generator contract in Remix.](/images/builders/ethereum/precompiles/features/randomness/randomness-5.webp) Once you submit the transaction, the `requestId` will be updated with the ID of the request. You can use the `requestId` call of the Random Number contract to get the request ID and the `getRequestStatus` function of the Randomness Precompile to check the status of this request ID. ### Fulfill the Request and Save the Random Number {: #fulfill-request-save-number } After submitting the randomness request, you'll need to wait for the duration of the delay before you can fulfill the request. For the `RandomNumber.sol` contract, the delay was set to the minimum block delay defined in the Randomness Precompile, which is {{ networks.moonbase.randomness.min_vrf_blocks_delay }} blocks. You must also fulfill the request before it is too late. For local VRF, the request expires after {{ networks.moonbase.randomness.block_expiration }} blocks and for BABE epoch randomness, the request expires after {{ networks.moonbase.randomness.epoch_expiration }} epochs. Assuming you've waited for the minimum blocks (or epochs if you're using BABE epoch randomness) to pass and the request hasn't expired, you can fulfill the request by taking the following steps: 1. Click on the **fulfillRequest** button 2. Confirming the transaction in MetaMask ![Fulfill the randomness request using the random number generator contract in Remix.](/images/builders/ethereum/precompiles/features/randomness/randomness-6.webp) Once the request has been fulfilled, you can check the random number that was generated: 1. Expand the **random** function 2. Since the contract only requested one random word, you can get the random number by accessing the `0` index of the `random` array 3. Click **call** 4. The random number will appear below the **call** button ![Retrieve the random number that was generated by the random number contract in Remix.](/images/builders/ethereum/precompiles/features/randomness/randomness-7.webp) Upon successful fulfillment, the excess fees and deposit will be sent to the address specified as the refund address. If the request happened to expire before it could be fulfilled, you can interact with the Randomness Precompile directly to purge the request and unlock the deposit and fees. Please refer to the following section for instructions on how to do this. ## Use Remix to Interact Directly with the Randomness Precompile {: #interact-directly } In addition to interacting with the randomness precompile via a smart contract, you can also interact with it directly in Remix to perform operations such as creating a randomness request, checking on the status of a request, and purging expired requests. Remember, you need to have a contract that inherits from the consumer contract in order to fulfill requests, as such if you fulfill a request using the precompile directly there will be no way to consume the results. ### Remix Set Up {: #remix-set-up } To add the interfaces to Remix and follow along with this section of the tutorial, you will need to: 1. Get a copy of [`Randomness.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/randomness/Randomness.sol){target=\_blank} 2. Paste the file contents into a Remix file named **Randomness.sol** ![Add precompile to Remix](/images/builders/ethereum/precompiles/features/randomness/randomness-8.webp) ### Compile & Access the Randomness Precompile {: #compile-randomness } Next, you will need to compile the `Randomness.sol` file in Remix. To get started, make sure you have the **Randomness.sol** file open and take the following steps: 1. Click on the **Compile** tab, second from top 2. To compile the contract, click on **Compile Randomness.sol** If the contract was compiled successfully, you will see a green checkmark next to the **Compile** tab. Instead of deploying the randomness precompile, you will access the interface given the address of the precompiled contract: 1. Click on the **Deploy and Run** tab directly below the **Compile** tab in Remix. Please note the precompiled contract is already deployed 2. Make sure **Injected Provider - Metamask** is selected in the **ENVIRONMENT** dropdown. Once selected, you might be prompted by MetaMask to connect your account to Remix 3. Make sure the correct account is displayed under **ACCOUNT** 4. Ensure **Randomness - Randomness.sol** is selected in the **CONTRACT** dropdown. Since this is a precompiled contract, there is no need to deploy any code. Instead we are going to provide the address of the precompile in the **At Address** Field 5. Provide the address of the batch precompile: `{{ networks.moonbase.precompiles.randomness }}` and click **At Address** ![Access the address](/images/builders/ethereum/precompiles/features/randomness/randomness-9.webp) The **RANDOMNESS** precompile will appear in the list of **Deployed Contracts**. You will use this to fulfill the randomness request made from the lottery contract later on in this tutorial. ### Get Request Status & Purge Expired Request {: #get-request-status-and-purge } Anyone can purge expired requests. You do not need to be the one who requested the randomness to be able to purge it. When you purge an expired request, the request fees will be transferred to you, and the deposit for the request will be returned to the original requester. To purge a request, first you have to make sure that the request has expired. To do so, you can verify the status of a request using the `getRequestStatus` function of the precompile. The number that is returned from this call corresponds to the index of the value in the [`RequestStatus`](#enums) enum. As a result, you'll want to verify the number returned is `3` for `Expired`. Once you've verified that the request is expired, you can call the `purgeExpiredRequest` function to purge the request. To verify and purge a request, you can take the following steps: 1. Expand the **RANDOMNESS** contract 2. Enter the request ID of the request you want to verify has expired and click on **getRequestStatus** 3. The response will appear just underneath the function. Verify that you received a `3` 4. Expand the **purgeExpiredRequest** function and enter the request ID 5. Click on **transact** 6. MetaMask will pop-up and you can confirm the transaction ![Purge an exired request](/images/builders/ethereum/precompiles/features/randomness/randomness-10.webp) Once the transaction goes through, you can verify the request has been purged by calling the **getRequestStatus** function again with the same request ID. You should receive a status of `0`, or `DoesNotExist`. You can also expect the amount of the request fees to be transferred to your account. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/features/staking/ --- BEGIN CONTENT --- --- title: Staking Precompile Contract description: Unlock the potential of staking with a specialized precompiled contract designed to streamline and optimize participation in Moonbeam. keywords: solidity, ethereum, staking, moonbeam, precompiled, contracts categories: Precompiles, Ethereum Toolkit --- # Interacting with the Staking Precompile ## Introduction {: #introduction } Moonbeam uses a Delegated Proof of Stake system through the [Parachain Staking](/builders/substrate/interfaces/features/staking/){target=\_blank} Pallet, allowing token holders (delegators) to express exactly which collator candidates they would like to support and with what quantity of stake. The design of the Parachain Staking Pallet is such that it enforces shared risk/reward on chain between delegators and candidates. For general information on staking, such as general terminology, staking variables, and more, please refer to the [Staking on Moonbeam](/learn/features/staking/){target=\_blank} page. The staking module is coded in Rust and it is part of a pallet that is normally not accessible from the Ethereum side of Moonbeam. However, a staking precompile allows developers to access the staking features using the Ethereum API in a precompiled contract located at address: === "Moonbeam" ```text {{networks.moonbeam.precompiles.staking}} ``` === "Moonriver" ```text {{networks.moonriver.precompiles.staking}} ``` === "Moonbase Alpha" ```text {{networks.moonbase.precompiles.staking}} ``` This guide will cover the available methods in the staking precompile interface. In addition, it will show you how to interact with the Parachain Staking Pallet through the staking precompile and the Ethereum API. The examples in this guide are done on Moonbase Alpha, but they can be adapted for Moonbeam or Moonriver. !!! note There can be some unintended consequences when using the precompiled contracts on Moonbeam. Please refer to the [Security Considerations](/learn/core-concepts/security/){target=\_blank} page for more information. ## Exit Delays {: #exit-delays } Some of the Parachain Staking Pallet extrinsics include exit delays that you must wait before the request can be executed. The exit delays to note are as follows: === "Moonbeam" | Variable | Value | |:-----------------------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------:| | Decrease candidate bond | {{ networks.moonbeam.collator_timings.can_bond_less.rounds }} rounds ({{ networks.moonbeam.collator_timings.can_bond_less.hours }} hours) | | Decrease delegator bond | {{ networks.moonbeam.delegator_timings.del_bond_less.rounds }} rounds ({{ networks.moonbeam.delegator_timings.del_bond_less.hours }} hours) | | Revoke delegation | {{ networks.moonbeam.delegator_timings.revoke_delegations.rounds }} rounds ({{ networks.moonbeam.delegator_timings.revoke_delegations.hours }} hours) | | Leave candidates | {{ networks.moonbeam.collator_timings.leave_candidates.rounds }} rounds ({{ networks.moonbeam.collator_timings.leave_candidates.hours }} hours) | | Leave delegators | {{ networks.moonbeam.delegator_timings.leave_delegators.rounds }} rounds ({{ networks.moonbeam.delegator_timings.leave_delegators.hours }} hours) | === "Moonriver" | Variable | Value | |:-----------------------:|:-------------------------------------------------------------------------------------------------------------------------------------------------------:| | Decrease candidate bond | {{ networks.moonriver.collator_timings.can_bond_less.rounds }} rounds ({{ networks.moonriver.collator_timings.can_bond_less.hours }} hours) | | Decrease delegator bond | {{ networks.moonriver.delegator_timings.del_bond_less.rounds }} rounds ({{ networks.moonriver.delegator_timings.del_bond_less.hours }} hours) | | Revoke delegation | {{ networks.moonriver.delegator_timings.revoke_delegations.rounds }} rounds ({{ networks.moonriver.delegator_timings.revoke_delegations.hours }} hours) | | Leave candidates | {{ networks.moonriver.collator_timings.leave_candidates.rounds }} rounds ({{ networks.moonriver.collator_timings.leave_candidates.hours }} hours) | | Leave delegators | {{ networks.moonriver.delegator_timings.leave_delegators.rounds }} rounds ({{ networks.moonriver.delegator_timings.leave_delegators.hours }} hours) | === "Moonbase Alpha" | Variable | Value | |:-----------------------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------:| | Decrease candidate bond | {{ networks.moonbase.collator_timings.can_bond_less.rounds }} rounds ({{ networks.moonbase.collator_timings.can_bond_less.hours }} hours) | | Decrease delegator bond | {{ networks.moonbase.delegator_timings.del_bond_less.rounds }} rounds ({{ networks.moonbase.delegator_timings.del_bond_less.hours }} hours) | | Revoke delegation | {{ networks.moonbase.delegator_timings.revoke_delegations.rounds }} rounds ({{ networks.moonbase.delegator_timings.revoke_delegations.hours }} hours) | | Leave candidates | {{ networks.moonbase.collator_timings.leave_candidates.rounds }} rounds ({{ networks.moonbase.collator_timings.leave_candidates.hours }} hours) | | Leave delegators | {{ networks.moonbase.delegator_timings.leave_delegators.rounds }} rounds ({{ networks.moonbase.delegator_timings.leave_delegators.hours }} hours) | ## Parachain Staking Solidity Interface {: #the-parachain-staking-solidity-interface } [`StakingInterface.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/parachain-staking/StakingInterface.sol){target=\_blank} is an interface through which Solidity contracts can interact with parachain-staking. The beauty is that Solidity developers don’t have to learn the Substrate API. Instead, they can interact with staking functions using the Ethereum interface they are familiar with. The Solidity interface includes the following functions: ??? function "**isDelegator**(*address* delegator) - read-only function that checks whether the specified address is currently a staking delegator. Uses the [`delegatorState`](/builders/substrate/interfaces/features/staking/#:~:text=delegatorState(AccountId20)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `delegator` - address to check if they are currently a delegator === "Returns" - `bool` whether the address is currently a delegator ??? function "**isCandidate**(*address* candidate) - read-only function that checks whether the specified address is currently a collator candidate. Uses the [`candidateState`](/builders/substrate/interfaces/features/staking/#:~:text=candidateState(AccountId20)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `candidate` - address to check if they are currently a collator candidate === "Returns" - `bool` whether the address is currently a candidate ??? function "**isSelectedCandidate**(*address* candidate) - read-only function that checks whether the specified address is currently part of the active collator set. Uses the [`selectedCandidates`](/builders/substrate/interfaces/features/staking/#:~:text=selectedCandidates()){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `candidate` - address to check if they are currently an active collator === "Returns" - `bool` whether the address is currently an active collator ??? function "**points**(*uint256* round) - read-only function that gets the total points awarded to all collators in a given round. Uses the [`points`](/builders/substrate/interfaces/features/staking/#:~:text=points(u32)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `round` - uint256 round number to query points for === "Returns" - `uint256` total points awarded in the specified round ??? function "**awardedPoints**(*uint32* round, *address* candidate) - read-only function that returns the total points awarded in a given round to a given collator. If `0` is returned, it could be because no blocks were produced or the storage for that round has been removed. Uses the [`points`](/builders/substrate/interfaces/features/staking/#:~:text=awardedPts(u32, AccountId20)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `round` - uint32 round number to query - `candidate` - address of the collator to query points for === "Returns" - `uint256` points awarded to the collator in the specified round ??? function "**delegationAmount**(*address* delegator, *address* candidate) - read-only function that returns the amount delegated by a given delegator in support of a given candidate. Uses the [`delegatorState`](/builders/substrate/interfaces/features/staking/#:~:text=delegatorState(AccountId20)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `delegator` - address of the delegator - `candidate` - address of the candidate === "Returns" - `uint256` amount delegated ??? function "**isInTopDelegations**(*address* delegator, *address* candidate) - read-only function that returns a boolean indicating whether the given delegator is in the top delegations for the given candidate. Uses the [`topDelegations`](/builders/substrate/interfaces/features/staking/#:~:text=topDelegations(AccountId20)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `delegator` - address of the delegator to check - `candidate` - address of the candidate === "Returns" - `bool` whether the delegator is in the top delegations ??? function "**minDelegation**() - read-only function that gets the minimum delegation amount. Uses the [`minDelegation`](/builders/substrate/interfaces/features/staking/#:~:text=minDelegation()){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" None. === "Returns" - `uint256` minimum delegation amount ??? function "**candidateCount**() - read-only function that gets the current amount of collator candidates. Uses the [`candidatePool`](/builders/substrate/interfaces/features/staking/#:~:text=candidatePool()){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" None. === "Returns" - `uint256` current number of collator candidates ??? function "**round**() - read-only function that returns the current round number. Uses the [`round`](/builders/substrate/interfaces/features/staking/#:~:text=round()){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" None. === "Returns" - `uint256` current round number ??? function "**candidateDelegationCount**(*address* candidate) - read-only function that returns the number of delegations for the specified collator candidate address. Uses the [`candidateInfo`](/builders/substrate/interfaces/features/staking/#:~:text=candidateInfo(AccountId20)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `candidate` - address of the collator candidate to query === "Returns" - `uint256` number of delegations for the candidate ??? function "**candidateAutoCompoundingDelegationCount**(*address* candidate) - a read-only function that returns the number of auto-compounding delegations for the specified candidate. Uses the [`autoCompoundingDelegations`](/builders/substrate/interfaces/features/staking/#:~:text=autoCompoundingDelegations(AccountId20)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `candidate` - address of the candidate to query === "Returns" - `uint256` number of auto-compounding delegations ??? function "**delegatorDelegationCount**(*address* delegator) - read-only function that returns the number of delegations for the specified delegator address. Uses the [`delegatorState`](/builders/substrate/interfaces/features/staking/#:~:text=delegatorState(AccountId20)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `delegator` - address of the delegator to query === "Returns" - `uint256` number of delegations for the delegator ??? function "**selectedCandidates**() - read-only function that gets the selected candidates for the current round. Uses the [`selectedCandidates`](/builders/substrate/interfaces/features/staking/#:~:text=selectedCandidates()){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" None. === "Returns" - `address[]` array of selected candidate addresses ??? function "**delegationRequestIsPending**(*address* delegator, *address* candidate) - returns a boolean to indicate whether there is a pending delegation request made by a given delegator for a given candidate" === "Parameters" - `delegator` - address of the delegator - `candidate` - address of the candidate === "Returns" - `bool` whether there is a pending delegation request ??? function "**candidateExitIsPending**(*address* candidate) - returns a boolean to indicate whether a pending exit exists for a specific candidate. Uses the [`candidateInfo`](/builders/substrate/interfaces/features/staking/#:~:text=candidateInfo(AccountId20)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `candidate` - address of the candidate to check === "Returns" - `bool` whether there is a pending exit request ??? function "**candidateRequestIsPending**(*address* candidate) - returns a boolean to indicate whether there is a pending bond less request made by a given candidate. Uses the [`candidateInfo`](/builders/substrate/interfaces/features/staking/#:~:text=candidateInfo(AccountId20)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `candidate` - address of the candidate to check === "Returns" - `bool` whether there is a pending bond less request ??? function "**delegationAutoCompound**(*address* delegator, *address* candidate) - returns the auto-compound percentage for a delegation given the delegator and candidate" === "Parameters" - `delegator` - address of the delegator - `candidate` - address of the candidate === "Returns" - `uint256` auto-compound percentage ??? function "**getDelegatorTotalStaked**(*address* delegator) - read-only function that returns the total staked amount of a given delegator, regardless of the candidate. Uses the [`delegatorState`](/builders/substrate/interfaces/features/staking/#:~:text=delegatorState(AccountId20)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `delegator` - address of the delegator to query === "Returns" - `uint256` total staked amount ??? function "**getCandidateTotalCounted**(*address* candidate) - read-only function that returns the total amount staked for a given candidate. Uses the [`candidateInfo`](/builders/substrate/interfaces/features/staking/#:~:text=candidateInfo(AccountId20)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `candidate` - address of the candidate to query === "Returns" - `uint256` total amount staked for the candidate ??? function "**joinCandidates**(*uint256* amount, *uint256* candidateCount) - allows the account to join the set of collator candidates with the specified bond amount and the current candidate count. Uses the [`joinCandidates`](/builders/substrate/interfaces/features/staking/#:~:text=joinCandidates(bond, candidateCount)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `amount` - uint256 bond amount to stake as a candidate - `candidateCount` - uint256 current number of candidates in the pool === "Returns" None. ??? function "**scheduleLeaveCandidates**(*uint256* candidateCount) - schedules a request for a candidate to remove themselves from the candidate pool. Scheduling the request does not automatically execute it. There is an [exit delay](#exit-delays) that must be waited before you can execute the request via the `executeLeaveCandidates` extrinsic. Uses the [`scheduleLeaveCandidates`](/builders/substrate/interfaces/features/staking/#:~:text=scheduleLeaveCandidates(candidateCount)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `candidateCount` - uint256 current number of candidates in the pool === "Returns" None. ??? function "**executeLeaveCandidates**(*address* candidate, *uint256* candidateDelegationCount) - executes the due request to leave the set of collator candidates. Uses the [`executeLeaveCandidates`](/builders/substrate/interfaces/features/staking/#:~:text=executeLeaveCandidates(candidate, candidateDelegationCount)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `candidate` - address of the candidate leaving the pool - `candidateDelegationCount` - uint256 number of delegations for the candidate === "Returns" None. ??? function "**cancelLeaveCandidates**(*uint256* candidateCount) - allows a candidate to cancel a pending scheduled request to leave the candidate pool. Given the current number of candidates in the pool. Uses the [`cancelLeaveCandidates`](/builders/substrate/interfaces/features/staking/#:~:text=cancelLeaveCandidates(candidateCount)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `candidateCount` - uint256 current number of candidates in the pool === "Returns" None. ??? function "**goOffline**() - temporarily leave the set of collator candidates without unbonding. Uses the [`goOffline`](/builders/substrate/interfaces/features/staking/#:~:text=goOffline()){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" None. === "Returns" None. ??? function "**goOnline**() - rejoin the set of collator candidates after previously calling `goOffline()`. Uses the [`goOnline`](/builders/substrate/interfaces/features/staking/#:~:text=goOnline()){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" None. === "Returns" None. ??? function "**candidateBondMore**(*uint256* more) - collator candidate increases bond by the specified amount. Uses the [`candidateBondMore`](/builders/substrate/interfaces/features/staking/#:~:text=candidateBondMore(more)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `more` - uint256 amount to increase the bond by === "Returns" None. ??? function "**scheduleCandidateBondLess**(*uint256* less) - schedules a request to decrease a candidates bond by the specified amount. Scheduling the request does not automatically execute it. There is an [exit delay](#exit-delays) that must be waited before you can execute the request via the `execute_candidate_bond_request` extrinsic. Uses the [`scheduleCandidateBondLess`](/builders/substrate/interfaces/features/staking/#:~:text=scheduleCandidateBondLess(less)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `less` - uint256 amount to decrease the bond by === "Returns" None. ??? function "**executeCandidateBondLess**(*address* candidate) - executes any due requests to decrease a specified candidate's bond amount. Uses the [`executeCandidateBondLess`](/builders/substrate/interfaces/features/staking/#:~:text=executeCandidateBondLess(candidate)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `candidate` - address of the candidate to execute the bond decrease for === "Returns" None. ??? function "**cancelCandidateBondLess**() - allows a candidate to cancel a pending scheduled request to decrease a candidates bond. Uses the [`cancelCandidateBondLess`](/builders/substrate/interfaces/features/staking/#:~:text=cancelCandidateBondLess()){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" None. === "Returns" None. ??? function "**delegateWithAutoCompound**(*address* candidate, *uint256* amount, *uint8* autoCompound, *uint256* candidateDelegationCount, *uint256* candidateAutoCompoundingDelegationCount, *uint256* delegatorDelegationCount) - makes a delegation in support of a collator candidate and automatically sets the percent of rewards to auto-compound given an integer (no decimals) for `autoCompound` between 0-100. Uses the [`delegateWithAutoCompound`](/builders/substrate/interfaces/features/staking/#:~:text=delegateWithAutoCompound){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `candidate` - address of the candidate to delegate to - `amount` - uint256 amount to delegate - `autoCompound` - uint8 percentage of rewards to auto-compound (0-100) - `candidateDelegationCount` - uint256 current number of delegations for the candidate - `candidateAutoCompoundingDelegationCount` - uint256 current number of auto-compounding delegations for the candidate - `delegatorDelegationCount` - uint256 current number of delegations from the delegator === "Returns" None. ??? function "**scheduleRevokeDelegation**(*address* candidate) - schedules a request to revoke a delegation given the address of a candidate. Scheduling the request does not automatically execute it. There is an [exit delay](#exit-delays) that must be waited before you can execute the request via the `executeDelegationRequest` extrinsic. Uses the [`scheduleRevokeDelegation`](/builders/substrate/interfaces/features/staking/#:~:text=scheduleRevokeDelegation(collator)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `candidate` - address of the candidate to revoke delegation from === "Returns" None. ??? function "**delegatorBondMore**(*address* candidate, *uint256* more) - delegator increases bond to a collator by the specified amount. Uses the [`delegatorBondMore`](/builders/substrate/interfaces/features/staking/#:~:text=delegatorBondMore(candidate, more)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `candidate` - address of the candidate to increase delegation for - `more` - uint256 amount to increase the delegation by === "Returns" None. ??? function "**scheduleDelegatorBondLess**(*address* candidate, *uint256* less) - schedules a request for a delegator to bond less with respect to a specific candidate. Scheduling the request does not automatically execute it. There is an [exit delay](#exit-delays) that must be waited before you can execute the request via the `executeDelegationRequest` extrinsic. Uses the [`scheduleDelegatorBondLess`](/builders/substrate/interfaces/features/staking/#:~:text=scheduleDelegatorBondLess(candidate, less)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `candidate` - address of the candidate to decrease delegation for - `less` - uint256 amount to decrease the delegation by === "Returns" None. ??? function "**executeDelegationRequest**(*address* delegator, *address* candidate) - executes any due delegation requests provided the address of a delegator and a candidate. Uses the [`executeDelegationRequest`](/builders/substrate/interfaces/features/staking/#:~:text=executeDelegationRequest(delegator, candidate)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `delegator` - address of the delegator - `candidate` - address of the candidate === "Returns" None. ??? function "**cancelDelegationRequest**(*address* candidate) - cancels any pending delegation requests provided the address of a candidate. Uses the [`cancelDelegationRequest`](/builders/substrate/interfaces/features/staking/#:~:text=cancelDelegationRequest(candidate)){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `candidate` - address of the candidate to cancel the delegation request for === "Returns" None. ??? function "**setAutoCompound**(*address* candidate, *uint8* value, *uint256* candidateAutoCompoundingDelegationCount, *uint256* delegatorDelegationCount) - sets an auto-compound value for an existing delegation given an integer (no decimals) for the `value` between 0-100. Uses the [`setAutoCompound`](/builders/substrate/interfaces/features/staking/#:~:text=setAutoCompound){target=\_blank} method of the Parachain Staking Pallet" === "Parameters" - `candidate` - address of the candidate - `value` - uint8 percentage to auto-compound (0-100) - `candidateAutoCompoundingDelegationCount` - uint256 current number of auto-compounding delegations for the candidate - `delegatorDelegationCount` - uint256 current number of delegations from the delegator === "Returns" None. ## Interact with the Solidity Interface {: #interact-with-solidity-interface } ### Checking Prerequisites {: #checking-prerequisites } The below example is demonstrated on Moonbase Alpha, however, similar steps can be taken for Moonbeam and Moonriver. - Have MetaMask installed and [connected to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank} - Have an account with at least `{{networks.moonbase.staking.min_del_stake}}` token. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} !!! note The example below requires more than `{{networks.moonbase.staking.min_del_stake}}` token due to the minimum delegation amount plus gas fees. If you need more than the faucet dispenses, please contact us on Discord and we will be happy to help you. ### Remix Set Up {: #remix-set-up } 1. Click on the **File explorer** tab 2. Get a copy of [`StakingInterface.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/parachain-staking/StakingInterface.sol){target=\_blank} and paste the file contents into a Remix file named `StakingInterface.sol` ![Copying and Pasting the Staking Interface into Remix](/images/builders/ethereum/precompiles/features/staking/staking-1.webp) ### Compile the Contract {: #compile-the-contract } 1. Click on the **Compile** tab, second from top 2. Then to compile the interface, click on **Compile StakingInterface.sol** ![Compiling StakingInterface.sol](/images/builders/ethereum/precompiles/features/staking/staking-2.webp) ### Access the Contract {: #access-the-contract } 1. Click on the **Deploy and Run** tab, directly below the **Compile** tab in Remix. Note: you are not deploying a contract here, instead you are accessing a precompiled contract that is already deployed 2. Make sure **Injected Provider - Metamask** is selected in the **ENVIRONMENT** drop down 3. Ensure **ParachainStaking - StakingInterface.sol** is selected in the **CONTRACT** dropdown. Since this is a precompiled contract there is no need to deploy, instead you are going to provide the address of the precompile in the **At Address** field 4. Provide the address of the staking precompile for Moonbase Alpha: `{{networks.moonbase.precompiles.staking}}` and click **At Address** 5. The Parachain Staking precompile will appear in the list of **Deployed Contracts** ![Provide the address](/images/builders/ethereum/precompiles/features/staking/staking-3.webp) ### Delegate a Collator with Auto-Compounding {: #delegate-a-collator } For this example, you are going to be delegating a collator and setting up the percentage of rewards to auto-compound on Moonbase Alpha. Delegators are token holders who stake tokens, vouching for specific candidates. Any user that holds a minimum amount of {{networks.moonbase.staking.min_del_stake}} token in their free balance can become a delegator. When delegating a candidate, you can simultaneously set up auto-compounding. You'll be able to specify a percentage of your rewards that will automatically be applied to your total delegation. You don't have to set up auto-compounding right away, you can always do it at a later time. You can do your own research and select the candidate you desire. For this guide, the following candidate address will be used: `{{ networks.moonbase.staking.candidates.address1 }}`. In order to delegate a candidate, you'll need to determine the candidate's current delegation count, their auto-compounding delegation count, and your own delegation count. The candidate delegation count is the number of delegations backing a specific candidate. To obtain the candidate delegator count, you can call a function that the staking precompile provides. Expand the **PARACHAINSTAKING** contract found under the **Deployed Contracts** list, then: 1. Find and expand the **candidateDelegationCount** function 2. Enter the candidate address (`{{ networks.moonbase.staking.candidates.address1 }}`) 3. Click **call** 4. After the call is complete, the results will be displayed ![Call collator delegation count](/images/builders/ethereum/precompiles/features/staking/staking-4.webp) The auto-compounding delegation count is the amount of delegations that have auto-compounding configured. To determine the number of delegations that have auto-compounding set up, you can 1. Find and expand the **candidateAutoCompoundingDelegationCount** function 2. Enter the candidate address (`{{ networks.moonbase.staking.candidates.address1 }}`) 3. Click **call** 4. After the call is complete, the results will be displayed ![Get candidate auto-compounding delegation count](/images/builders/ethereum/precompiles/features/staking/staking-5.webp) The last item you'll need to retrieve is your delegation count. If you don't know your existing number of delegations, you can easily get them by following these steps: 1. Find and expand the **delegatorDelegationCount** function 2. Enter your address 3. Click **call** 4. After the call is complete, the results will be displayed ![Call delegator delegation count](/images/builders/ethereum/precompiles/features/staking/staking-6.webp) Now that you have obtained the [candidate delegator count](#:~:text=To obtain the candidate delegator count), the [auto-compounding delegation count](#:~:text=To determine the number of delegations that have auto-compounding set up), and your [number of existing delegations](#:~:text=If you don't know your existing number of delegations), you have all of the information you need to delegate a candidate and set up auto-compounding. To get started: 1. Find and expand the **delegateWithAutoCompound** function 2. Enter the candidate address you would like to delegate. For this example you can use `{{ networks.moonbase.staking.candidates.address1 }}` 3. Provide the amount to delegate in Wei. There is a minimum of `{{networks.moonbase.staking.min_del_stake}}` token to delegate, so the lowest amount in Wei is `{{networks.moonbase.staking.min_del_stake_wei}}` 4. Enter an integer (no decimals) between 0-100 to represent the percentage of rewards to auto-compound 5. Enter the delegation count for the candidate 6. Enter the auto-compounding delegation count for the candidate 7. Enter your delegation count 8. Press **transact** 9. MetaMask will pop up, you can review the details and confirm the transaction ![Delegate a Collator](/images/builders/ethereum/precompiles/features/staking/staking-7.webp) If you want to delegate without setting up auto-compounding, you can follow the previous steps, but instead of using **delegateWithAutoCompound**, you can use the **delegate** extrinsic. ### Verify Delegation {: #verify-delegation } To verify your delegation was successful, you can check the chain state in Polkadot.js Apps. First, add your MetaMask address to the [address book in Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/addresses){target=\_blank}. Navigate to **Accounts** and then **Address Book**, click on **Add contact**, and enter the following information: 1. Add your MetaMask address 2. Provide a nickname for the account 3. Click **Save** ![Add to Address Book](/images/builders/ethereum/precompiles/features/staking/staking-8.webp) To verify your delegation was successful, head to [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/chainstate){target=\_blank} and navigate to **Developer** and then **Chain State** 1. Select the **parachainStaking** pallet 2. Select the **delegatorState** query 3. Enter your address 4. Optionally, you can enable the **include option** slider if you want to provide a specific blockhash to query 5. Click the **+** button to return the results and verify your delegation !!! note You do not have to enter anything in the **blockhash to query at** field if you are looking for an overview of your delegations. ![Verify delegation](/images/builders/ethereum/precompiles/features/staking/staking-9.webp) ### Confirm Auto-Compounding Percentage {: #confirm-auto-compounding } You can confirm the percentage of rewards you've set to auto-compound in Remix using the `delegationAutoCompound` function of the Solidity interface: 1. Find and expand the **delegationAutoCompound** function 2. Enter your account you used to delegate with 3. Enter the candidate you've delegated 4. Click **call** 5. The response will appear below the **call** button ![Verify auto-compound percentage](/images/builders/ethereum/precompiles/features/staking/staking-10.webp) ### Set or Change the Auto-Compounding Percentage {: #set-or-change-auto-compounding } If you initially set up your delegation without auto-compounding or if you want to update the percentage on an existing delegation with auto-compounding set up, you can use the `setAutoCompound` function of the Solidity interface. You'll need to get the number of delegations with auto-compounding set up for the candidate you want to set or update auto-compounding for. You'll also need to retrieve your own delegation count. You can follow the instructions in the [Delegate a Collator with Auto-Compounding](#delegate-a-collator) section to get both of these items. Once you have the necessary information, you can take the following steps in Remix: 1. Find and expand the **setAutoCompound** function 2. Enter the candidate's account you want to set or update auto-compounding for 3. Enter a number 0-100 to represent the percentage of rewards you want to auto-compound 4. Enter the auto-compounding delegation count for the candidate 5. Enter your delegation count 6. Press **transact** 7. MetaMask will pop up, you can review the details and confirm the transaction ![Set or update auto-compound percentage](/images/builders/ethereum/precompiles/features/staking/staking-11.webp) ### Revoke a Delegation {: #revoke-a-delegation } As of [runtime version 1001](https://moonbeam.network/news/moonriver-technical-update-staking-changes-as-part-of-runtime-upgrade-1001){target=\_blank}, there have been significant changes to the way users can interact with various staking features. Including the way staking exits are handled. Exits now require you to schedule a request to exit or revoke a delegation, wait a delay period, and then execute the request. To revoke a delegation for a specific candidate and receive your tokens back, you can use the `scheduleRevokeDelegation` extrinsic. Scheduling a request does not automatically revoke your delegation, you must wait an [exit delay](#exit-delays), and then execute the request by using the `executeDelegationRequest` method. To revoke a delegation and receive your tokens back, head back over to Remix, then: 1. Find and expand the **scheduleRevokeDelegation** function 2. Enter the candidate address you would like to revoke the delegation for 3. Click **transact** 4. MetaMask will pop up, you can review the transaction details, and click **Confirm** ![Revoke delegation](/images/builders/ethereum/precompiles/features/staking/staking-12.webp) Once the transaction is confirmed, you must wait the duration of the exit delay before you can execute and revoke the delegation request. If you try to revoke it before the exit delay is up, your extrinsic will fail. After the exit delay has passed, you can go back to Remix and follow these steps to execute the due request: 1. Find and expand the **executeDelegationRequest** function 2. Enter the address of the delegator you would like to revoke the delegation for 3. Enter the candidate address you would like to revoke the delegation from 4. Click **transact** 5. MetaMask will pop up, you can review the transaction details, and click **Confirm** After the call is complete, the results will be displayed and the delegation will be revoked for the given delegator and from the specified candidate. You can also check your delegator state again on Polkadot.js Apps to confirm. If for any reason you need to cancel a pending scheduled request to revoke a delegation, you can do so by following these steps in Remix: 1. Find and expand the **cancelDelegationRequest** function 2. Enter the candidate address you would like to cancel the pending request for 3. Click **transact** 4. MetaMask will pop up, you can review the transaction details, and click **Confirm** You can check your delegator state again on Polkadot.js Apps to confirm that your delegation is still intact. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/ --- BEGIN CONTENT --- --- title: Solidity Precompiles description: Discover the precompiled contracts on Moonbeam, your gateway to effortless interaction with Substrate modules and features using the Ethereum API. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/interoperability/gmp/ --- BEGIN CONTENT --- --- title: GMP Precompile description: Learn about the GMP precompile on Moonbeam and how to use it with the Moonbeam Routed Liquidity program provided by bridges like Wormhole. keywords: solidity, ethereum, GMP, wormhole, moonbeam, bridge, connected, contracts, MRL categories: Precompiles, Ethereum Toolkit --- # Interacting with the GMP Precompile ## Introduction {: #introduction } Moonbeam Routed Liquidity (MRL) refers to Moonbeam’s use case as the port parachain for liquidity from origin chains into other Polkadot parachains. This is possible because of general message passing (GMP), where messages with arbitrary data and tokens can be sent across non-parachain blockchains through [chain-agnostic GMP protocols](/builders/interoperability/protocols/){target=\_blank}. These GMP protocols can combine with [Polkadot's XCM messaging system](/builders/interoperability/xcm/overview/){target=\_blank} to allow for seamless liquidity routing. The GMP precompile acts as an interface for Moonbeam Routed Liquidity, acting as a middleman between token-bearing messages from GMP protocols and parachains connected to Moonbeam via [XCMP](/builders/interoperability/xcm/overview/#xcm-transport-protocols){target=\_blank}. Currently, the GMP Precompile only supports the relaying of liquidity through the [Wormhole GMP protocol](/builders/interoperability/protocols/wormhole/){target=\_blank}. The GMP Precompile is located at the following address: === "Moonbeam" ```text {{networks.moonbeam.precompiles.gmp}} ``` === "Moonriver" ```text {{networks.moonriver.precompiles.gmp}} ``` === "Moonbase Alpha" ```text {{networks.moonbase.precompiles.gmp}} ``` In practice, it is unlikely that a developer will have to directly interact with the precompile. GMP protocols' relayers interact with the precompile to complete cross-chain actions, so the origin chain that the cross-chain action originates is where the developer has the responsibility to ensure that the GMP precompile is used *eventually*. ## The GMP Solidity Interface {: #the-gmp-solidity-interface } [`Gmp.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/gmp/Gmp.sol){target=\_blank} is a Solidity interface that allows developers to interact with the precompile. ??? code "Gmp.sol" ```solidity // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.3; /// @dev The Gmp contract's address. address constant GMP_ADDRESS = 0x0000000000000000000000000000000000000816; /// @dev The Gmp contract's instance. Gmp constant GMP_CONTRACT = Gmp(GMP_ADDRESS); /// @author The Moonbeam Team /// @title Gmp precompile /// @dev Provides an endpoint to Gmp protocols which can automatically forward to XCM /// @custom:address 0x0000000000000000000000000000000000000816 interface Gmp { // TODO: Here we would specify the endpoints for each GMP protocol on a case by case basis. // These endpoints are basically the hand offs for each protocol -- where they delegate to // the target contract. // // This design should allow users to interact with this precompile with no changes to the // underlying GMP protocols by simply specifying the correct precompile as the target. /// Receive a wormhole VAA and process it /// /// @custom:selector f53774ab function wormholeTransferERC20(bytes memory vaa) external; } ``` The GMP precompile has one method: - **wormholeTransferERC20**(*bytes memory* vaa) - receives a Wormhole bridge transfer [verified action approval (VAA)](https://wormhole.com/docs/protocol/infrastructure/vaas/){target=\_blank}, mints tokens via the Wormhole token bridge, and forwards the liquidity to the custom payload’s [multilocation](/builders/interoperability/xcm/core-concepts/multilocations/){target=\_blank}. The payload is expected to be a precompile-specific SCALE encoded object, as explained in this guide's [Building the Payload for Wormhole](#building-the-payload-for-wormhole) section VAAs are payload-containing packages generated after origin-chain transactions and are discovered by Wormhole [Guardians](https://wormhole.com/docs/protocol/infrastructure/guardians/){target=\_blank}. The most common instance in which a user will have to interact with the precompile is during a recovery, where a relayer doesn’t complete an MRL transaction. For example, a user must search for the VAA that comes with their origin chain transaction and manually invoke the `wormholeTransferERC20` function. ## Building the Payload for Wormhole {: #building-the-payload-for-wormhole } Currently, the GMP precompile only supports sending liquidity with Wormhole, through Moonbeam, and into other parachains. The GMP precompile does not assist with a route from parachains back to Moonbeam and subsequently, Wormhole-connected chains. To send liquidity from a Wormhole-connected origin chain like Ethereum, users must invoke the [`transferTokensWithPayload` method](https://wormhole.com/docs/protocol/infrastructure/vaas/#token--message){target=\_blank} on the [origin-chain's deployment](https://wormhole.com/docs/protocol/infrastructure/core-contracts/#token-bridge){target=\_blank} of the [WormholeTokenBridge smart contract](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/interfaces/ITokenBridge.sol){target=\_blank}. This function requires a bytes payload, which must be formatted as a SCALE encoded multilocation object wrapped within [another precompile-specific versioned type](https://github.com/moonbeam-foundation/moonbeam/blob/{{ networks.moonbase.spec_version }}/precompiles/gmp/src/types.rs#L25-L48){target=\_blank}. You may be unfamiliar with SCALE encoding and multilocations if you are unfamiliar with the Polkadot ecosystem. [SCALE encoding](https://docs.polkadot.com/polkadot-protocol/basics/data-encoding/){target=\_blank} is a compact form of encoding that Polkadot uses. The [`MultiLocation` type](https://wiki.polkadot.network/learn/learn-xcvm/){target=\_blank} is used to define a relative point in Polkadot, such as a specific account on a specific parachain (Polkadot blockchain). Moonbeam’s GMP protocol requires a multilocation to represent the destination for liquidity routing, which most likely means an account on another parachain. Whatever it is, this destination must be expressed as relative to Moonbeam. !!! remember Multilocations being relative is important, because a parachain team may erroneously give you a multilocation relative to their own chain, which can be different. Providing an incorrect multilocation can result in **loss of funds**! Each parachain will have its specific methods of interpreting a multilocation, and should confirm with the project that the multilocation that you formed is correct. However, you will most likely be forming a multilocation with an account. Multiple types of accounts can be included in a multilocation, which you must know beforehand when constructing your multilocation. The two most common are: - **AccountKey20** — an account ID that is 20-bytes in length, including Ethereum-compatible account IDs such as those on Moonbeam - **AccountId32** — an account ID that is 32-bytes in length, standard in Polkadot and its parachains The following multilocation templates target accounts on other parachains with Moonbeam as the relative origin. To use them, replace `INSERT_PARACHAIN_ID` with the parachain ID of the network you wish to send funds to and replace `INSERT_ADDRESS` with the address of the account you want to send funds to on that parachain. === "AccountId32" ```js { V4: { parents: 1, interior: { X2: [ { Parachain: 'INSERT_PARACHAIN_ID' }, { AccountId32: { id: 'INSERT_ADDRESS', }, }, ], }, }, }; ``` === "AccountKey20" ```js { V4: { parents: 1, interior: { X2: [ { Parachain: 'INSERT_PARACHAIN_ID' }, { AccountKey20: { key: 'INSERT_ADDRESS', }, }, ], }, } }; ``` It can be challenging to correctly SCALE encode the entire payload without the right tools, mainly due to the [custom types expected by the precompile](https://github.com/moonbeam-foundation/moonbeam/blob/{{ networks.moonbase.spec_version }}/precompiles/gmp/src/types.rs#L25-L48){target=\_blank}. Fortunately, the Polkadot.js API can assist with this. The versioned user action expected by the precompile accepts two versions: V1 and V2. V1 accepts the `XcmRoutingUserAction` type, which attempts to route the transferred assets to the destination defined by the multilocation. V2 accepts the `XcmRoutingUserActionWithFee` type, which also attempts to route the transferred assets to the destination and allows a fee to be paid. Relayers can use V2 to specify a fee on Moonbeam to relay the transaction to the given destination. The following script shows how to create a `Uint8Array` that can be used as a payload for the GMP precompile: === "V1" ```typescript import { ApiPromise, WsProvider } from '@polkadot/api'; enum MRLTypes { // Runtime defined MultiLocation. Allows for XCM versions 2, 3, and 4 XcmVersionedLocation = 'XcmVersionedLocation', // MRL payload (V1) that only defines the destination MultiLocation XcmRoutingUserAction = 'XcmRoutingUserAction', // Wrapper object for the MRL payload VersionedUserAction = 'VersionedUserAction', } // Parachain IDs of each parachain enum Parachain { MoonbaseBeta = 888, // Insert additional parachain IDs } // List of parachains that use ethereum (20) accounts const ETHEREUM_ACCOUNT_PARACHAINS = [Parachain.MoonbaseBeta]; // A function that creates a SCALE encoded payload to use with transferTokensWithPayload async function createMRLPayload( parachainId: Parachain, account: string ): Promise { // Create a multilocation object based on the target parachain's account type const isEthereumStyle = ETHEREUM_ACCOUNT_PARACHAINS.includes(parachainId); const multilocation = { V4: { parents: 1, interior: { X2: [ { Parachain: parachainId }, isEthereumStyle ? { AccountKey20: { key: account } } : { AccountId32: { id: account } }, ], }, }, }; // Creates an API for Moonbeam that defines MRL's special types const wsProvider = new WsProvider('wss://wss.api.moonbase.moonbeam.network'); const api = await ApiPromise.create({ provider: wsProvider, types: { [MRLTypes.XcmRoutingUserAction]: { destination: MRLTypes.XcmVersionedLocation, }, [MRLTypes.VersionedUserAction]: { _enum: { V1: MRLTypes.XcmRoutingUserAction }, }, }, }); // Format multilocation object as a Polkadot.js type const versionedLocation = api.createType( MRLTypes.XcmVersionedLocation, multilocation ); const userAction = api.createType(MRLTypes.XcmRoutingUserAction, { destination: versionedLocation, }); // Wrap and format the MultiLocation object into the precompile's input type const versionedUserAction = api.createType(MRLTypes.VersionedUserAction, { V1: userAction, }); // Disconnect the API api.disconnect(); // SCALE encode resultant precompile formatted objects return versionedUserAction.toU8a(); } ``` === "V2" ```typescript import { ApiPromise, WsProvider } from '@polkadot/api'; import { u256 } from '@polkadot/types'; enum MRLTypes { // Runtime defined MultiLocation. Allows for XCM versions 2 and 3 XcmVersionedLocation = 'XcmVersionedLocation', // MRL payload (V2) that defines the destination MultiLocation and a // fee for the relayer XcmRoutingUserActionWithFee = 'XcmRoutingUserActionWithFee', // Wrapper object for the MRL payload VersionedUserAction = 'VersionedUserAction', } // Parachain IDs of each parachain enum Parachain { MoonbaseBeta = 888, // Insert additional parachain IDs } // List of parachains that use ethereum (20) accounts const ETHEREUM_ACCOUNT_PARACHAINS = [Parachain.MoonbaseBeta]; // A function that creates a SCALE encoded payload to use with // transferTokensWithPayload async function createMRLPayload( parachainId: Parachain, account: string, fee: u256 ): Promise { // Create a multilocation object based on the target parachain's account // type const isEthereumStyle = ETHEREUM_ACCOUNT_PARACHAINS.includes(parachainId); const multilocation = { V4: { parents: 1, interior: { X2: [ { Parachain: parachainId }, isEthereumStyle ? { AccountKey20: { key: account } } : { AccountId32: { id: account } }, ], }, }, }; // Creates an API for Moonbeam that defines MRL's special types const wsProvider = new WsProvider('wss://wss.api.moonbase.moonbeam.network'); const api = await ApiPromise.create({ provider: wsProvider, types: { [MRLTypes.XcmRoutingUserActionWithFee]: { destination: MRLTypes.XcmVersionedLocation, fee: 'U256', }, [MRLTypes.VersionedUserAction]: { _enum: { V2: MRLTypes.XcmRoutingUserActionWithFee }, }, }, }); // Format multilocation object as a Polkadot.js type const versionedLocation = api.createType( MRLTypes.XcmVersionedLocation, multilocation ); const userAction = api.createType(MRLTypes.XcmRoutingUserActionWithFee, { destination: versionedLocation, fee, }); // Wrap and format the MultiLocation object into the precompile's input type const versionedUserAction = api.createType(MRLTypes.VersionedUserAction, { V2: userAction, }); // Disconnect the API api.disconnect(); // SCALE encode resultant precompile formatted objects return versionedUserAction.toU8a(); } ``` ## Restrictions {: #restrictions } The GMP precompile is currently in its early stages. There are many restrictions, and it only supports a “happy path” into parachains. Here are some restrictions that you should be aware of: - There is currently no fee mechanism. Relayers that run the forwarding of liquidity on Moonbeam to a parachain will be subsidizing transactions. This may change in the future - The precompile does not check to ensure that the destination chain supports the token that is being sent to it. **Incorrect multilocations may result in loss of funds** - Errors in constructing a multilocation will result in reverts, which will trap tokens and result in a loss of funds - There is currently no recommended path backward, from parachains to other chains like Ethereum. There is additional protocol-level work that must be done before a one-click method can be realized - Due to a restriction with the ERC-20 XC-assets, the only way to send tokens from a parachain back through Moonbeam is to have xcGLMR on the origin parachain and use it as a fee asset when sending tokens back --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/interoperability/ --- BEGIN CONTENT --- --- title: Interoperability Precompiles description: Unlock cross-chain capabilities with Moonbeam's precompiled contracts designed for interoperability, including GMP and XCM protocols. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/overview/ --- BEGIN CONTENT --- --- title: Solidity Precompiles description: An overview of the available Solidity precompiles on Moonbeam. Precompiles enable you to interact with Substrate features using the Ethereum API. categories: Reference, Basics --- # Overview of the Precompiled Contracts on Moonbeam ## Overview {: #introduction } On Moonbeam, a precompiled contract is native Substrate code that has an Ethereum-style address and can be called using the Ethereum API, like any other smart contract. The precompiles allow you to call the Substrate runtime directly which is not normally accessible from the Ethereum side of Moonbeam. The Substrate code responsible for implementing precompiles can be found in the [EVM pallet](/learn/platform/technology/#evm-pallet){target=\_blank}. The EVM pallet includes the [standard precompiles found on Ethereum and some additional precompiles that are not specific to Ethereum](https://github.com/polkadot-evm/frontier/tree/master/frame/evm/precompile){target=\_blank}. It also provides the ability to create and execute custom precompiles through the generic [`Precompiles` trait](https://polkadot-evm.github.io/frontier/rustdocs/pallet_evm/trait.Precompile.html){target=\_blank}. There are several custom Moonbeam-specific precompiles that have been created, all of which can be found in the [Moonbeam codebase](https://github.com/moonbeam-foundation/moonbeam/tree/master/precompiles){target=\_blank}. It is important to highlight that the precompiles from this list with the `CallableByContract` check are not callable inside the contract constructor. The Ethereum precompiled contracts contain complex functionality that is computationally intensive, such as hashing and encryption. The custom precompiled contracts on Moonbeam provide access to Substrate-based functionality such as staking, governance, XCM-related functions, and more. The Moonbeam-specific precompiles can be interacted with through familiar and easy-to-use Solidity interfaces using the Ethereum API, which are ultimately used to interact with the underlying Substrate interface. This flow is depicted in the following diagram: ![Precompiled Contracts Diagram](/images/builders/ethereum/precompiles/overview/overview-1.webp) !!! note There can be some unintended consequences when using the precompiled contracts on Moonbeam. Please refer to the [Security Considerations](/learn/core-concepts/security/){target=\_blank} page for more information. ## Precompiled Contract Addresses {: #precompiled-contract-addresses } The precompiled contracts are categorized by address and based on the origin network. If you were to convert the precompiled addresses to decimal format, and break them into categories by numeric value, the categories are as follows: - **0-1023** - [Ethereum MainNet precompiles](#ethereum-mainnet-precompiles) - **1024-2047** - precompiles that are [not in Ethereum and not Moonbeam specific](#non-moonbeam-specific-nor-ethereum-precomiles) - **2048-4095** - [Moonbeam specific precompiles](#moonbeam-specific-precompiles) ### Ethereum MainNet Precompiles {: #ethereum-mainnet-precompiles } === "Moonbeam" | Contract | Address | |:---------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------:| | [ECRECOVER](/builders/ethereum/precompiles/utility/eth-mainnet/#verify-signatures-with-ecrecover){target=\_blank} | 0x0000000000000000000000000000000000000001 | | [SHA256](/builders/ethereum/precompiles/utility/eth-mainnet/#hashing-with-sha256){target=\_blank} | 0x0000000000000000000000000000000000000002 | | [RIPEMD160](/builders/ethereum/precompiles/utility/eth-mainnet/#hashing-with-ripemd-160){target=\_blank} | 0x0000000000000000000000000000000000000003 | | [Identity](/builders/ethereum/precompiles/utility/eth-mainnet/#the-identity-function){target=\_blank} | 0x0000000000000000000000000000000000000004 | | [Modular Exponentiation](/builders/ethereum/precompiles/utility/eth-mainnet/#modular-exponentiation){target=\_blank} | 0x0000000000000000000000000000000000000005 | | [BN128Add](/builders/ethereum/precompiles/utility/eth-mainnet/#bn128add){target=\_blank} | 0x0000000000000000000000000000000000000006 | | [BN128Mul](/builders/ethereum/precompiles/utility/eth-mainnet/#bn128mul){target=\_blank} | 0x0000000000000000000000000000000000000007 | | [BN128Pairing](/builders/ethereum/precompiles/utility/eth-mainnet/#bn128pairing){target=\_blank} | 0x0000000000000000000000000000000000000008 | | [Blake2](https://polkadot-evm.github.io/frontier/rustdocs/pallet_evm_precompile_blake2/struct.Blake2F.html){target=\_blank} | 0x0000000000000000000000000000000000000009 | | [P256Verify](https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md){target=\_blank} | 0x0000000000000000000000000000000000000100 | === "Moonriver" | Contract | Address | |:---------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------:| | [ECRECOVER](/builders/ethereum/precompiles/utility/eth-mainnet/#verify-signatures-with-ecrecover){target=\_blank} | 0x0000000000000000000000000000000000000001 | | [SHA256](/builders/ethereum/precompiles/utility/eth-mainnet/#hashing-with-sha256){target=\_blank} | 0x0000000000000000000000000000000000000002 | | [RIPEMD160](/builders/ethereum/precompiles/utility/eth-mainnet/#hashing-with-ripemd-160){target=\_blank} | 0x0000000000000000000000000000000000000003 | | [Identity](/builders/ethereum/precompiles/utility/eth-mainnet/#the-identity-function){target=\_blank} | 0x0000000000000000000000000000000000000004 | | [Modular Exponentiation](/builders/ethereum/precompiles/utility/eth-mainnet/#modular-exponentiation){target=\_blank} | 0x0000000000000000000000000000000000000005 | | [BN128Add](/builders/ethereum/precompiles/utility/eth-mainnet/#bn128add){target=\_blank} | 0x0000000000000000000000000000000000000006 | | [BN128Mul](/builders/ethereum/precompiles/utility/eth-mainnet/#bn128mul){target=\_blank} | 0x0000000000000000000000000000000000000007 | | [BN128Pairing](/builders/ethereum/precompiles/utility/eth-mainnet/#bn128pairing){target=\_blank} | 0x0000000000000000000000000000000000000008 | | [Blake2](https://polkadot-evm.github.io/frontier/rustdocs/pallet_evm_precompile_blake2/struct.Blake2F.html){target=\_blank} | 0x0000000000000000000000000000000000000009 | | [P256Verify](https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md){target=\_blank} | 0x0000000000000000000000000000000000000100 | === "Moonbase Alpha" | Contract | Address | |:---------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------:| | [ECRECOVER](/builders/ethereum/precompiles/utility/eth-mainnet/#verify-signatures-with-ecrecover){target=\_blank} | 0x0000000000000000000000000000000000000001 | | [SHA256](/builders/ethereum/precompiles/utility/eth-mainnet/#hashing-with-sha256){target=\_blank} | 0x0000000000000000000000000000000000000002 | | [RIPEMD160](/builders/ethereum/precompiles/utility/eth-mainnet/#hashing-with-ripemd-160){target=\_blank} | 0x0000000000000000000000000000000000000003 | | [Identity](/builders/ethereum/precompiles/utility/eth-mainnet/#the-identity-function){target=\_blank} | 0x0000000000000000000000000000000000000004 | | [Modular Exponentiation](/builders/ethereum/precompiles/utility/eth-mainnet/#modular-exponentiation){target=\_blank} | 0x0000000000000000000000000000000000000005 | | [BN128Add](/builders/ethereum/precompiles/utility/eth-mainnet/#bn128add){target=\_blank} | 0x0000000000000000000000000000000000000006 | | [BN128Mul](/builders/ethereum/precompiles/utility/eth-mainnet/#bn128mul){target=\_blank} | 0x0000000000000000000000000000000000000007 | | [BN128Pairing](/builders/ethereum/precompiles/utility/eth-mainnet/#bn128pairing){target=\_blank} | 0x0000000000000000000000000000000000000008 | | [Blake2](https://polkadot-evm.github.io/frontier/rustdocs/pallet_evm_precompile_blake2/struct.Blake2F.html){target=\_blank} | 0x0000000000000000000000000000000000000009 | | [P256Verify](https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md){target=\_blank} | 0x0000000000000000000000000000000000000100 | ### Non-Moonbeam Specific nor Ethereum Precompiles {: #non-moonbeam-specific-nor-ethereum-precompiles } === "Moonbeam" | Contract | Address | |:--------------------------------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------:| | [SHA3FIPS256](/builders/ethereum/precompiles/utility/eth-mainnet/#hashing-with-sha3fips256){target=\_blank} | 0x0000000000000000000000000000000000000400 | | Dispatch [Removed] | 0x0000000000000000000000000000000000000401 | | [ECRecoverPublicKey](https://polkadot-evm.github.io/frontier/rustdocs/pallet_evm_precompile_simple/struct.ECRecoverPublicKey.html){target=\_blank} | 0x0000000000000000000000000000000000000402 | === "Moonriver" | Contract | Address | |:--------------------------------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------:| | [SHA3FIPS256](/builders/ethereum/precompiles/utility/eth-mainnet/#hashing-with-sha3fips256){target=\_blank} | 0x0000000000000000000000000000000000000400 | | Dispatch [Removed] | 0x0000000000000000000000000000000000000401 | | [ECRecoverPublicKey](https://polkadot-evm.github.io/frontier/rustdocs/pallet_evm_precompile_simple/struct.ECRecoverPublicKey.html){target=\_blank} | 0x0000000000000000000000000000000000000402 | === "Moonbase Alpha" | Contract | Address | |:-------------------------------------------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------:| | [SHA3FIPS256](/builders/ethereum/precompiles/utility/eth-mainnet/#hashing-with-sha3fips256){target=\_blank} | 0x0000000000000000000000000000000000000400 | | Dispatch [Removed] | 0x0000000000000000000000000000000000000401 | | [ECRecoverPublicKey](https://polkadot-evm.github.io/frontier/rustdocs/pallet_evm_precompile_simple/struct.ECRecoverPublicKey.html){target=\_blank} | 0x0000000000000000000000000000000000000402 | ### Moonbeam Specific Precompiles {: #moonbeam-specific-precompiles } === "Moonbeam" | Contract | Address | |:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------:| | [Parachain Staking](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/parachain-staking/StakingInterface.sol){target=\_blank} | {{networks.moonbeam.precompiles.staking}} | | [Crowdloan Rewards](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/crowdloan-rewards/CrowdloanInterface.sol){target=\_blank} | {{networks.moonbeam.precompiles.crowdloan}} | | [ERC-20 Interface](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/balances-erc20/ERC20.sol){target=\_blank} | {{networks.moonbeam.precompiles.erc20}} | | Democracy [Removed] | {{networks.moonbeam.precompiles.democracy}} | | [X-Tokens](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xtokens/Xtokens.sol){target=\_blank} | {{networks.moonbeam.precompiles.xtokens}} | | [Relay Encoder](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/relay-encoder/RelayEncoder.sol){target=\_blank} | {{networks.moonbeam.precompiles.relay_encoder}} | | [XCM Transactor V1](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-transactor/src/v1/XcmTransactorV1.sol){target=\_blank} | {{networks.moonbeam.precompiles.xcm_transactor_v1}} | | [Author Mapping](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/author-mapping/AuthorMappingInterface.sol){target=\_blank} | {{networks.moonbeam.precompiles.author_mapping}} | | [Batch](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/batch/Batch.sol){target=\_blank} | {{networks.moonbeam.precompiles.batch}} | | [Randomness](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/randomness/Randomness.sol){target=\_blank} | {{networks.moonbeam.precompiles.randomness}} | | [Call Permit](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/call-permit/CallPermit.sol){target=\_blank} | {{networks.moonbeam.precompiles.call_permit}} | | [Proxy](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/proxy/Proxy.sol){target=\_blank} | {{networks.moonbeam.precompiles.proxy}} | | [XCM Utilities](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-utils/XcmUtils.sol){target=\_blank} | {{networks.moonbeam.precompiles.xcm_utils}} | | [XCM Transactor V2](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-transactor/src/v2/XcmTransactorV2.sol){target=\_blank} | {{networks.moonbeam.precompiles.xcm_transactor_v2}} | | [Council Collective [Removed]](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonbeam.precompiles.collective_council}} | | [Technical Committee Collective [Removed]](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonbeam.precompiles.collective_tech_committee}} | | [Treasury Council Collective](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonbeam.precompiles.collective_treasury}} | | [Referenda](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/referenda/Referenda.sol){target=\_blank} | {{networks.moonbeam.precompiles.referenda}} | | [Conviction Voting](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/conviction-voting/ConvictionVoting.sol){target=\_blank} | {{networks.moonbeam.precompiles.conviction_voting}} | | [Preimage](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/preimage/Preimage.sol){target=\_blank} | {{networks.moonbeam.precompiles.preimage}} | | [OpenGov Tech Committee](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonbeam.precompiles.collective_opengov_tech_committee}} | | [Precompile Registry](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/precompile-registry/PrecompileRegistry.sol){target=\_blank} | {{networks.moonbeam.precompiles.registry}} | | [GMP](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/gmp/Gmp.sol){target=\_blank} | {{networks.moonbeam.precompiles.gmp}} | | [XCM Transactor V3](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-transactor/src/v3/XcmTransactorV3.sol){target=\_blank} | {{networks.moonbeam.precompiles.xcm_transactor_v3}} | | [XCM interface](https://github.com/Moonsong-Labs/moonkit/blob/main/precompiles/pallet-xcm/XcmInterface.sol){target=\_blank} | {{networks.moonbeam.precompiles.xcm_interface}} | | [Identity](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/identity/Identity.sol){target=\_blank} | {{networks.moonbeam.precompiles.identity}} | === "Moonriver" | Contract | Address | |:-------------------------------------------------------------------------------------------------------------------------------------------------------------:|:--------------------------------------------------------------------:| | [Parachain Staking](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/parachain-staking/StakingInterface.sol){target=\_blank} | {{networks.moonriver.precompiles.staking}} | | [Crowdloan Rewards](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/crowdloan-rewards/CrowdloanInterface.sol){target=\_blank} | {{networks.moonriver.precompiles.crowdloan}} | | [ERC-20 Interface](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/balances-erc20/ERC20.sol){target=\_blank} | {{networks.moonriver.precompiles.erc20}} | | Democracy [Disabled] | {{networks.moonriver.precompiles.democracy}} | | [X-Tokens](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xtokens/Xtokens.sol){target=\_blank} | {{networks.moonriver.precompiles.xtokens}} | | [Relay Encoder](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/relay-encoder/RelayEncoder.sol){target=\_blank} | {{networks.moonriver.precompiles.relay_encoder}} | | [XCM Transactor V1](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-transactor/src/v1/XcmTransactorV1.sol){target=\_blank} | {{networks.moonriver.precompiles.xcm_transactor_v1}} | | [Author Mapping](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/author-mapping/AuthorMappingInterface.sol){target=\_blank} | {{networks.moonriver.precompiles.author_mapping}} | | [Batch](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/batch/Batch.sol){target=\_blank} | {{networks.moonriver.precompiles.batch}} | | [Randomness](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/randomness/Randomness.sol){target=\_blank} | {{networks.moonriver.precompiles.randomness}} | | [Call Permit](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/call-permit/CallPermit.sol){target=\_blank} | {{networks.moonriver.precompiles.call_permit}} | | [Proxy](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/proxy/Proxy.sol){target=\_blank} | {{networks.moonriver.precompiles.proxy}} | | [XCM Utilities](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-utils/XcmUtils.sol){target=\_blank} | {{networks.moonriver.precompiles.xcm_utils}} | | [XCM Transactor V2](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-transactor/src/v2/XcmTransactorV2.sol){target=\_blank} | {{networks.moonriver.precompiles.xcm_transactor_v2}} | | [Council Collective [Removed]](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonriver.precompiles.collective_council}} | | [Technical Committee Collective [Removed]](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonriver.precompiles.collective_tech_committee}} | | [Treasury Council Collective](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonriver.precompiles.collective_treasury}} | | [Referenda](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/referenda/Referenda.sol){target=\_blank} | {{networks.moonriver.precompiles.referenda}} | | [Conviction Voting](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/conviction-voting/ConvictionVoting.sol){target=\_blank} | {{networks.moonriver.precompiles.conviction_voting}} | | [Preimage](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/preimage/Preimage.sol){target=\_blank} | {{networks.moonriver.precompiles.preimage}} | | [OpenGov Tech Committee](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonriver.precompiles.collective_opengov_tech_committee}} | | [Precompile Registry](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/precompile-registry/PrecompileRegistry.sol){target=\_blank} | {{networks.moonriver.precompiles.registry}} | | [GMP](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/gmp/Gmp.sol){target=\_blank} | {{networks.moonriver.precompiles.gmp}} | | [XCM Transactor V3](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-transactor/src/v3/XcmTransactorV3.sol){target=\_blank} | {{networks.moonriver.precompiles.xcm_transactor_v3}} | | [XCM interface](https://github.com/Moonsong-Labs/moonkit/blob/main/precompiles/pallet-xcm/XcmInterface.sol){target=\_blank} | {{networks.moonriver.precompiles.xcm_interface}} | | [Identity](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/identity/Identity.sol){target=\_blank} | {{networks.moonriver.precompiles.identity}} | === "Moonbase Alpha" | Contract | Address | |:--------------------------------------------------------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------:| | [Parachain Staking](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/parachain-staking/StakingInterface.sol){target=\_blank} | {{networks.moonbase.precompiles.staking}} | | [Crowdloan Rewards](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/crowdloan-rewards/CrowdloanInterface.sol){target=\_blank} | {{networks.moonbase.precompiles.crowdloan}} | | [ERC-20 Interface](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/balances-erc20/ERC20.sol){target=\_blank} | {{networks.moonbase.precompiles.erc20}} | | Democracy [Removed] | {{networks.moonbase.precompiles.democracy}} | | [X-Tokens](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xtokens/Xtokens.sol){target=\_blank} | {{networks.moonbase.precompiles.xtokens}} | | [Relay Encoder](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/relay-encoder/RelayEncoder.sol){target=\_blank} | {{networks.moonbase.precompiles.relay_encoder}} | | [XCM Transactor V1](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-transactor/src/v1/XcmTransactorV1.sol){target=\_blank} | {{networks.moonbase.precompiles.xcm_transactor_v1}} | | [Author Mapping](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/author-mapping/AuthorMappingInterface.sol){target=\_blank} | {{networks.moonbase.precompiles.author_mapping}} | | [Batch](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/batch/Batch.sol){target=\_blank} | {{networks.moonbase.precompiles.batch}} | | [Randomness](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/randomness/Randomness.sol){target=\_blank} | {{networks.moonbase.precompiles.randomness}} | | [Call Permit](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/call-permit/CallPermit.sol){target=\_blank} | {{networks.moonbase.precompiles.call_permit}} | | [Proxy](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/proxy/Proxy.sol){target=\_blank} | {{networks.moonbase.precompiles.proxy}} | | [XCM Utilities](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-utils/XcmUtils.sol){target=\_blank} | {{networks.moonbase.precompiles.xcm_utils}} | | [XCM Transactor V2](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-transactor/src/v2/XcmTransactorV2.sol){target=\_blank} | {{networks.moonbase.precompiles.xcm_transactor_v2}} | | [Council Collective [Removed]](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonbase.precompiles.collective_council}} | | [Technical Committee Collective [Removed]](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonbase.precompiles.collective_tech_committee}} | | [Treasury Council Collective](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonbase.precompiles.collective_treasury}} | | [Referenda](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/referenda/Referenda.sol){target=\_blank} | {{networks.moonbase.precompiles.referenda}} | | [Conviction Voting](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/conviction-voting/ConvictionVoting.sol){target=\_blank} | {{networks.moonbase.precompiles.conviction_voting}} | | [Preimage](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/preimage/Preimage.sol){target=\_blank} | {{networks.moonbase.precompiles.preimage}} | | [OpenGov Tech Committee](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/collective/Collective.sol){target=\_blank} | {{networks.moonbase.precompiles.collective_opengov_tech_committee}} | | [Precompile Registry](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/precompile-registry/PrecompileRegistry.sol){target=\_blank} | {{networks.moonbase.precompiles.registry}} | | [GMP](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/gmp/Gmp.sol){target=\_blank} | {{networks.moonbase.precompiles.gmp}} | | [XCM Transactor V3](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-transactor/src/v3/XcmTransactorV3.sol){target=\_blank} | {{networks.moonbase.precompiles.xcm_transactor_v3}} | | [XCM Interface](https://github.com/Moonsong-Labs/moonkit/blob/main/precompiles/pallet-xcm/XcmInterface.sol){target=\_blank} | {{networks.moonbeam.precompiles.xcm_interface}} | | [Identity](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/identity/Identity.sol){target=\_blank} | {{networks.moonbase.precompiles.identity}} | --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/utility/eth-mainnet/ --- BEGIN CONTENT --- --- title: Ethereum MainNet Precompiles description: Learn how to use the standard precompiled contracts available on Ethereum such as ECRECOVER, SHA256, and more on Moonbeam. keywords: ethereum, moonbeam, ecrecover, sha256, ripemd-160, Bn128Add, Bn128Mul, Bn128Pairing categories: Precompiles, Ethereum Toolkit --- # Ethereum MainNet Precompiled Contracts ## Introduction {: #introduction } Precompiled contracts in Ethereum are contracts that include complex cryptographic computations, but do not require the overhead of the EVM. These precompiles can be used within the EVM to handle specific common operations such as hashing and signature schemes. The following precompiles are currently included: ecrecover, sha256, ripemd-160, Bn128Add, Bn128Mul, Bn128Pairing, the identity function, and modular exponentiation. These precompiles are natively available on Ethereum and, to maintain Ethereum compatibility, they are also available on Moonbeam. In this guide, you will learn how to use and/or verify these precompiles. ## Checking Prerequisites {: #checking-prerequisites } You need to install Node.js (for this example, you can use v16.x) and the npm package manager. You can download directly from [Node.js](https://nodejs.org/en/download/package-manager){target=\_blank} or in your terminal: === "Ubuntu" ```bash curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash - sudo apt install -y nodejs ``` === "MacOS" ```bash # You can use homebrew (https://docs.brew.sh/Installation) brew install node # Or you can use nvm (https://github.com/nvm-sh/nvm) nvm install node ``` You can verify that everything is installed correctly by querying the version for each package: ```bash node -v ``` ```bash npm -v ``` As of writing this guide, the versions used were 15.2.1 and 7.0.8, respectively. You will also need to install the [Web3](https://web3js.readthedocs.io/en/latest){target=\_blank} package by executing: ```bash npm install --save web3 ``` To verify the installed version of Web3, you can use the `ls` command: ```bash npm ls web3 ``` As of writing this guide, the version used was 1.3.0. You will be also using [Remix](/builders/ethereum/dev-env/remix/){target=\_blank}, connecting it to the Moonbase Alpha TestNet via [MetaMask](/tokens/connect/metamask/){target=\_blank}. To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. ## Verify Signatures with ECRECOVER {: #verify-signatures-with-ecrecover } The main function of this precompile is to verify the signature of a message. In general terms, you feed `ecrecover` the transaction's signature values and it returns an address. The signature is verified if the address returned is the same as the public address that sent the transaction. The following will be a small example to showcase how to leverage this precompiled function. You'll need to retrieve the transaction's signature values (`v`, `r`, `s`). Therefore, you'll sign and retrieve the signed message where these values are: ```js const { Web3 } = require('web3'); // Provider const web3 = new Web3('https://rpc.api.moonbase.moonbeam.network'); // Address and Private Key const address = '0x6Be02d1d3665660d22FF9624b7BE0551ee1Ac91b'; const pk1 = '99B3C12287537E38C90A9219D4CB074A89A16E9CDB20BF85728EBD97C343E342'; const msg = web3.utils.sha3('supercalifragilisticexpialidocious'); async function signMessage(pk) { try { // Sign and get Signed Message const smsg = await web3.eth.accounts.sign(msg, pk); console.log(smsg); } catch (error) { console.error(error); } } signMessage(pk1); ``` This code will return the following object in the terminal: ```text { message: '0xc2ae6711c7a897c75140343cde1cbdba96ebbd756f5914fde5c12fadf002ec97', messageHash: '0xc51dac836bc7841a01c4b631fa620904fc8724d7f9f1d3c420f0e02adf229d50', v: '0x1b', r: '0x44287513919034a471a7dc2b2ed121f95984ae23b20f9637ba8dff471b6719ef', s: '0x7d7dc30309a3baffbfd9342b97d0e804092c0aeb5821319aa732bc09146eafb4', signature: '0x44287513919034a471a7dc2b2ed121f95984ae23b20f9637ba8dff471b6719ef7d7dc30309a3baffbfd9342b97d0e804092c0aeb5821319aa732bc09146eafb41b' } ``` With the necessary values, you can go to [Remix](/builders/ethereum/dev-env/remix/){target=\_blank} to test the precompiled contract. Note that this can also be verified with the Web3.js library, but in this case, you can go to Remix to be sure that it is using the precompiled contract on the blockchain. The Solidity code you can use to verify the signature is the following: ```solidity pragma solidity ^0.7.0; contract ECRECOVER { address addressTest = 0x12Cb274aAD8251C875c0bf6872b67d9983E53fDd; bytes32 msgHash = 0xc51dac836bc7841a01c4b631fa620904fc8724d7f9f1d3c420f0e02adf229d50; uint8 v = 0x1b; bytes32 r = 0x44287513919034a471a7dc2b2ed121f95984ae23b20f9637ba8dff471b6719ef; bytes32 s = 0x7d7dc30309a3baffbfd9342b97d0e804092c0aeb5821319aa732bc09146eafb4; function verify() public view returns (bool) { // Use ECRECOVER to verify address return (ecrecover(msgHash, v, r, s) == (addressTest)); } } ``` Using the [Remix compiler and deployment](/builders/ethereum/dev-env/remix/){target=\_blank} and with [MetaMask pointing to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank}, you can deploy the contract and call the `verify()` method that returns **true** if the address returned by `ecrecover` is equal to the address used to sign the message (related to the private key and needs to be manually set in the contract). ## Hashing with SHA256 {: #hashing-with-sha256 } This hashing function returns the SHA256 hash from the given data. To test this precompile, you can use this [SHA256 Hash Calculator tool](https://md5calc.com/hash/sha256){target=\_blank} to calculate the SHA256 hash of any string you want. In this case, you'll do so with `Hello World!`. You can head directly to Remix and deploy the following code, where the calculated hash is set for the `expectedHash` variable: ```solidity pragma solidity ^0.7.0; contract Hash256 { bytes32 public expectedHash = 0x7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069; function calculateHash() internal pure returns (bytes32) { string memory word = "Hello World!"; bytes32 hash = sha256(bytes(word)); return hash; } function checkHash() public view returns (bool) { return (calculateHash() == expectedHash); } } ``` Once the contract is deployed, you can call the `checkHash()` method that returns **true** if the hash returned by `calculateHash()` is equal to the hash provided. ## Hashing with RIPEMD160 {: #hashing-with-ripemd-160 } This hashing function returns a RIPEMD160 hash from the given data. To test this precompile, you can use this [RIPEMD160 Hash Calculator tool](https://md5calc.com/hash/ripemd160){target=\_blank} to calculate the RIPEMD160 hash of any string. In this case, you'll do so again with `Hello World!`. You'll reuse the same code as before, but use the `ripemd160` function. Note that it returns a `bytes20` type variable: ```solidity pragma solidity ^0.7.0; contract HashRipmd160 { bytes20 public expectedHash = hex"8476ee4631b9b30ac2754b0ee0c47e161d3f724c"; function calculateHash() internal pure returns (bytes20) { string memory word = "Hello World!"; bytes20 hash = ripemd160(bytes(word)); return hash; } function checkHash() public view returns (bool) { return (calculateHash() == expectedHash); } } ``` With the contract deployed, you can call the `checkHash()` method that returns **true** if the hash returned by `calculateHash()` is equal to the hash provided. ## BN128Add {: #bn128add } The BN128Add precompile implements a native elliptic curve point addition. It returns an elliptic curve point representing `(ax, ay) + (bx, by)` such that `(ax, ay)` and `(bx, by)` are valid points on the curve BN256. Currently there is no BN128Add support in Solidity, so it needs to be called with inline assembly. The following sample code can be used to call this precompile. ```solidity pragma solidity >=0.4.21; contract Precompiles { function callBn256Add( bytes32 ax, bytes32 ay, bytes32 bx, bytes32 by ) public returns (bytes32[2] memory result) { bytes32[4] memory input; input[0] = ax; input[1] = ay; input[2] = bx; input[3] = by; assembly { let success := call(gas, 0x06, 0, input, 0x80, result, 0x40) switch success case 0 { revert(0, 0) } } } } ``` Using the [Remix compiler and deployment](/builders/ethereum/dev-env/remix/){target=\_blank} and with [MetaMask pointing to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank}, you can deploy the contract and call the `callBn256Add(bytes32 ax, bytes32 ay, bytes32 bx, bytes32 by)` method to return the result of the operation. ## BN128Mul {: #bn128mul } The BN128Mul precompile implements a native elliptic curve multiplication with a scalar value. It returns an elliptic curve point representing `scalar * (x, y)` such that `(x, y)` is a valid curve point on the curve BN256. Currently there is no BN128Mul support in Solidity, so it needs to be called with inline assembly. The following sample code can be used to call this precompile. ```solidity pragma solidity >=0.4.21; contract Precompiles { function callBn256ScalarMul( bytes32 x, bytes32 y, bytes32 scalar ) public returns (bytes32[2] memory result) { bytes32[3] memory input; input[0] = x; input[1] = y; input[2] = scalar; assembly { let success := call(gas, 0x07, 0, input, 0x60, result, 0x40) switch success case 0 { revert(0, 0) } } } } ``` Using the [Remix compiler and deployment](/builders/ethereum/dev-env/remix/){target=\_blank} and with [MetaMask pointing to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank}, you can deploy the contract and call the `callBn256ScalarMul(bytes32 x, bytes32 y, bytes32 scalar)` method to return the result of the operation. ## BN128Pairing {: #bn128pairing } The BN128Pairing precompile implements elliptic curve pairing operation to perform zkSNARK verification. For more information, check out the [EIP-197 standard](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-197.md){target=\_blank}. Currently there is no BN128Pairing support in Solidity, so it needs to be called with inline assembly. The following sample code can be used to call this precompile. ```solidity pragma solidity >=0.4.21; contract Precompiles { function callBn256Pairing( bytes memory input ) public returns (bytes32 result) { // input is a serialized bytes stream of (a1, b1, a2, b2, ..., ak, bk) from (G_1 x G_2)^k uint256 len = input.length; require(len % 192 == 0); assembly { let memPtr := mload(0x40) let success := call( gas(), 0x08, 0, add(input, 0x20), len, memPtr, 0x20 ) switch success case 0 { revert(0, 0) } default { result := mload(memPtr) } } } } ``` Using the [Remix compiler and deployment](/builders/ethereum/dev-env/remix/){target=\_blank} and with [MetaMask pointing to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank}, you can deploy the contract and call the `function callBn256Pairing(bytes memory input)` method to return the result of the operation. ## The Identity Function {: #the-identity-function } Also known as datacopy, this function serves as a cheaper way to copy data in memory. Currently there is no Identity Function support in Solidity, so it needs to be called with inline assembly. The following sample code (adapted to Solidity), can be used to call this precompiled contract: ```solidity pragma solidity ^0.7.0; contract Identity { bytes public memoryStored; function callDatacopy(bytes memory data) public returns (bytes memory) { bytes memory result = new bytes(data.length); assembly { let len := mload(data) if iszero( call( gas(), 0x04, 0, add(data, 0x20), len, add(result, 0x20), len ) ) { invalid() } } memoryStored = result; return result; } } ``` You can use this [Web3 Type Converter tool](https://web3-type-converter.onbrn.com){target=\_blank} to get bytes from any string, as this is the input of the `callDataCopy()` method. With the contract deployed, you can call the `callDataCopy()` method and verify if `memoryStored` matches the bytes that you pass in as an input of the function. ## Modular Exponentiation {: #modular-exponentiation } This precompile calculates the remainder when an integer `b` (base) is raised to the `e`-th power (the exponent), and is divided by a positive integer `m` (the modulus). The Solidity compiler does not support it, so it needs to be called with inline assembly. The following code was simplified to show the functionality of this precompile: ```solidity pragma solidity ^0.7.0; contract ModularCheck { uint public checkResult; // Function to Verify ModExp Result function verify(uint _base, uint _exp, uint _modulus) public { checkResult = modExp(_base, _exp, _modulus); } function modExp( uint256 _b, uint256 _e, uint256 _m ) public returns (uint256 result) { assembly { // Free memory pointer let pointer := mload(0x40) // Define length of base, exponent and modulus. 0x20 == 32 bytes mstore(pointer, 0x20) mstore(add(pointer, 0x20), 0x20) mstore(add(pointer, 0x40), 0x20) // Define variables base, exponent and modulus mstore(add(pointer, 0x60), _b) mstore(add(pointer, 0x80), _e) mstore(add(pointer, 0xa0), _m) // Store the result let value := mload(0xc0) // Call the precompiled contract 0x05 = bigModExp if iszero(call(not(0), 0x05, 0, pointer, 0xc0, value, 0x20)) { revert(0, 0) } result := mload(value) } } } ``` You can try this in [Remix](/builders/ethereum/dev-env/remix/){target=\_blank}. Use the function `verify()`, passing the base, exponent, and modulus. The function will store the value in the `checkResult` variable. ## P256 Verify {: #p256-verify } The P256Verify Precompile adds support for [RIP-7212](https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md){target=\_blank}, signature verification for Secp256r1 elliptic curve. This precompile adds a WASM implementation of the signature verification and is intended to be replaced by a native runtime function call once available. ```solidity // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.3; contract P256Verify { function verify( bytes32 msg_hash, bytes32[2] memory signature, bytes32[2] memory public_key ) public view returns (bool) { bool output; bytes memory args = abi.encodePacked( msg_hash, signature[0], signature[1], public_key[0], public_key[1] ); bool success; assembly { success := staticcall(not(0), 0x100, add(args, 32), mload(args), output, 0x20) } require(success, "p256verify precompile call failed"); return output; } } ``` The file below contains two different test cases: one with a valid signature test and a second with an invalid signature test. ??? code "p256verifywithtests.sol" ```solidity // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.3; contract P256Verify { function verify( bytes32 msg_hash, bytes32[2] memory signature, bytes32[2] memory public_key ) public view returns (bool) { bool output; bytes memory args = abi.encodePacked( msg_hash, signature[0], signature[1], public_key[0], public_key[1] ); bool success; assembly { success := staticcall(not(0), 0x100, add(args, 32), mload(args), output, 0x20) } require(success, "p256verify precompile call failed"); return output; } function test() public { bytes32[2] memory msg_hashes; bytes32[2][2] memory signatures; bytes32[2][2] memory public_keys; bool[2] memory expected_result; // Case 1 (valid) msg_hashes[0] = hex"b5a77e7a90aa14e0bf5f337f06f597148676424fae26e175c6e5621c34351955"; signatures[0][0] = hex"289f319789da424845c9eac935245fcddd805950e2f02506d09be7e411199556"; signatures[0][1] = hex"d262144475b1fa46ad85250728c600c53dfd10f8b3f4adf140e27241aec3c2da"; public_keys[0][0] = hex"3a81046703fccf468b48b145f939efdbb96c3786db712b3113bb2488ef286cdc"; public_keys[0][1] = hex"ef8afe82d200a5bb36b5462166e8ce77f2d831a52ef2135b2af188110beaefb1"; expected_result[0] = true; // Case 2 (invalid) msg_hashes[1] = hex"d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b"; signatures[1][0] = hex"6162630000000000000000000000000000000000000000000000000000000000"; signatures[1][1] = hex"6162630000000000000000000000000000000000000000000000000000000000"; public_keys[1][0] = hex"6162630000000000000000000000000000000000000000000000000000000000"; public_keys[1][1] = hex"6162630000000000000000000000000000000000000000000000000000000000"; expected_result[0] = false; for (uint256 i = 0; i < expected_result.length; i++) { bool result = verify(msg_hashes[i], signatures[i], public_keys[i]); if (expected_result[i]) { require(result, "Expected success"); } else { require(!result, "Expected failure"); } } } } ``` Using the [Remix compiler and deployment](/builders/ethereum/dev-env/remix/){target=\_blank} and with [MetaMask pointing to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank}, you can deploy the contract and call the `verify` method with the following parameters: === "Valid Signature" | Parameter | Value | |--------------|------------------------------------------------------------------------------------------------------------------------------------------------| | `msg_hash` | `0xb5a77e7a90aa14e0bf5f337f06f597148676424fae26e175c6e5621c34351955` | | `signature` | `["0x289f319789da424845c9eac935245fcddd805950e2f02506d09be7e411199556", "0xd262144475b1fa46ad85250728c600c53dfd10f8b3f4adf140e27241aec3c2da"]` | | `public_key` | `["0x3a81046703fccf468b48b145f939efdbb96c3786db712b3113bb2488ef286cdc", "0xef8afe82d200a5bb36b5462166e8ce77f2d831a52ef2135b2af188110beaefb1"]` | | Expected Result | `true` | === "Invalid Signature" | Parameter | Value | |-----------------|------------------------------------------------------------------------------------------------------------------------------------------------| | `msg_hash` | `0xd182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b` | | `signature` | `["0x6162630000000000000000000000000000000000000000000000000000000000", "0x6162630000000000000000000000000000000000000000000000000000000000"]` | | `public_key` | `["0x6162630000000000000000000000000000000000000000000000000000000000", "0x6162630000000000000000000000000000000000000000000000000000000000"]` | | Expected Result | `false` | You'll receive two booleans in response; the first one indicates whether the signature was valid, and the second indicates whether the call to the P256Verify precompile was successful. The second boolean should always return true; the first is the one to check to see if the signature is valid. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/utility/ --- BEGIN CONTENT --- --- title: Utility Precompiles description: Utilize a range of utility functions with precompiles, including Ethereum MainNet hashing algorithms and additional Moonbeam-specific functions. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/utility/non-specific/ --- BEGIN CONTENT --- --- title: Non-Network Specific Precompiles description: Learn how to use precompiled contracts, which are not specific to Ethereum or Moonbeam, yet are supported for use in your application. keywords: ethereum, moonbeam, ECRecoverPublicKey, sha3FIPS256 categories: Precompiles, Ethereum Toolkit --- # Non-Network Specific Precompiled Smart Contracts ## Introduction {: #introduction } A precompiled contract, or precompile, is a set of programmed functionalities hard-coded into the blockchain client. Precompiles perform computationally heavy tasks, such as cryptographic processes like hashing. Moving these functionalities to the blockchain client serves the dual purpose of making the computation more efficient than using a traditional smart contract and ensuring everyone has access to the complete and accurate set of processes and algorithms required to operate correctly. Precompile functionality is bundled and shared under a smart contract address, which allows interactions similar to those of a traditional smart contract. Some precompiled contracts are not specific to Ethereum or Moonbeam, but are supported for use in your Moonbeam application. The nonspecific precompiles currently included in this category are the `ECRecoverPublicKey` and `SHA3FIPS256` precompiles. In the next section, you will learn more about the functionalities included in these precompiles. ## Retrieve a Public Key with ECRecoverPublicKey {: verifying-signatures-ecrecoverpublickey } The primary function of the `ECRecoverPublicKey` precompile is to recover the public key used to create a digital signature from a given message hash and signature. This precompile is similar to [ECRecover](/builders/ethereum/precompiles/utility/eth-mainnet/#verify-signatures-with-ecrecover/){target=\_blank}, with the exception of returning the public key of the account that signed the message rather than the account address. In the following sections, you will learn how to use the `ECRecoverPublicKey` precompile. ### Checking Prerequisites {: #checking-prerequisites } You need to install Node.js (for this example, you can use v16.x) and the npm package manager. You can download directly from [Node.js](https://nodejs.org/en/download/package-manager){target=\_blank} or in your terminal: === "Ubuntu" ```bash curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash - sudo apt install -y nodejs ``` === "MacOS" ```bash # You can use homebrew (https://docs.brew.sh/Installation) brew install node # Or you can use nvm (https://github.com/nvm-sh/nvm) nvm install node ``` You can verify that everything is installed correctly by querying the version for each package: ```bash node -v ``` ```bash npm -v ``` The versions used in this example are v20.15.0 (Node.js) and 10.7.0 (npm). You will also need to install the [Web3](https://web3js.readthedocs.io/en/latest){target=\_blank} package by executing: ```bash npm install --save web3 ``` To verify the installed version of Web3, you can use the `ls` command: ```bash npm ls web3 ``` This example uses version 4.11.1. You will also use [Remix](/builders/ethereum/dev-env/remix/){target=\_blank}, connecting it to the Moonbase Alpha TestNet via [MetaMask](/tokens/connect/metamask/){target=\_blank}. To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. ### Retrieve Transaction Signature Values To use the `ECRecoverPublicKey` precompile, you must first sign a message to create and retrieve the message hash and transaction signature values (`v`, `r`, `s`) to pass as arguments in the contract call. Always use security best practices when handling private keys. Create a new file called `signMessage.js` in your project directory: ```bash touch signMessage.js ``` Open `signMessage.js` in your code editor and add the following script to initialize Web3 with Moonbase Alpha TestNet, sign and hash the message, and return the signature values: ```js title="signMessage.js" const { Web3 } = require('web3'); const web3 = new Web3('https://rpc.api.moonbase.moonbeam.network'); // Address and private key const address = 'INSERT_RECEIVER_ADDRESS'; const pk1 = 'INSERT_SENDER_PRIVATE_KEY'; const msg = web3.utils.sha3('supercooltestmessage'); async function signMessage(pk) { try { // Sign and get signed message const smsg = await web3.eth.accounts.sign(msg, pk); console.log(smsg); } catch (error) { console.error(error); } } signMessage(pk1); ``` Return to your terminal command line to run the script with this command: ```bash node signMessage.js ``` This code will return the following object in the terminal:
node signMessage.js { message: '0x5836e21a51f25aad199e2e0feb5ca19673ed56b3811285f5124d7a8171d75851', messageHash: '0xa69b720d0293b9e8f4e471afb80f9d410b825abe5ce524e7d5755fd2a00bf9de', v: '0x1b', r: '0xb7d4783ee3b34d6fbc419d5b7bc67002c511322c5c71b49a7d78a8b7e9c5b30a', s: '0x4e5939eaef3917b1cb09af9e632cc9a727b64191b7ee40a6ae34f6fdde60a371', signature: '0xb7d4783ee3b34d6fbc419d5b7bc67002c511322c5c71b49a7d78a8b7e9c5b30a4e5939eaef3917b1cb09af9e632cc9a727b64191b7ee40a6ae34f6fdde60a3711b' }
Save these values as you will need them in the next section. ### Test ECRecoverPublicKey Contract You can now visit [Remix](https://remix.ethereum.org/){target=\_blank} to test the precompiled contract. Note that you could also use the Web3.js library, but in this case, you can go to Remix to ensure it is using the precompiled contract on the blockchain. The Solidity code you can use to retrieve the public key is the following: ```solidity title="RecoverPublicKey.sol" // SPDX-License-Identifier: MIT pragma solidity >=0.8.2 <0.9.0; contract RecoverPublicKey { function recoverPublicKey( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) public view returns (bytes memory) { address precompileAddress = 0x0000000000000000000000000000000000000402; (bool success, bytes memory publicKey) = precompileAddress.staticcall( abi.encodeWithSignature( "ECRecoverPublicKey(bytes32,uint8,bytes32,bytes32)", hash, v, r, s ) ); require(success, "ECRecoverPublicKey failed"); return publicKey; } } ``` Using the [Remix compiler and deployment](/builders/ethereum/dev-env/remix/){target=\_blank} and with [MetaMask pointing to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank}, you can deploy the contract and call the `recoverPublicKey()` method which returns the public key for the account that signed the message. You can now use this public key value for other cryptographic functions and verifications. ![Returned Public Key on Remix](/images/builders/ethereum/precompiles/utility/nonspecific/nonspecific-1.webp) ## Create a Hash with SHA3FIPS256 {: #create-a-hash-with-sha3fips256 } SHA3-256 is part of the SHA-3 family of cryptographic hashes codified in [FIPS202](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf){target=\_blank} that produces an output 256 bits in length. Although the name is similar to SHA256, the SHA-3 family is built with an entirely different algorithm and accordingly produces a different hash output than SHA256 for the same input. You can verify this yourself using this [SHA3-256 Hash Calculator tool](https://md5calc.com/hash/sha3-256){target=\_blank}. After calculating the SHA3-256 output, change the algorithm in the drop-down selector to SHA256 and take note of the resulting output. Currently there is no SHA3-256 support in Solidity, so it needs to be called with inline assembly. The following sample code can be used to call this precompile. ```solidity pragma solidity ^0.7.0; contract Precompiles { function sha3fips(bytes memory data) public view returns (bytes32) { bytes32[1] memory h; assembly { if iszero( staticcall(not(0), 0x400, add(data, 32), mload(data), h, 32) ) { invalid() } } return h[0]; } } ``` Using [Remix](/builders/ethereum/dev-env/remix/){target=\_blank} with [MetaMask pointing to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank}, you can deploy the contract and call the `sha3fips(bytes memory data)` method to return the encoded string of the data parameter.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/utility/registry/ --- BEGIN CONTENT --- --- title: Precompile Registry description: Learn how to access and interact with the Precompile Registry on Moonbeam, which can be used to check if a given address is a precompile and if it is supported. categories: Precompiles, Ethereum Toolkit --- # Precompile Registry on Moonbeam ## Introduction {: #introduction } The Precompile Registry serves as a single source of truth for the available [precompiles on Moonbeam](/builders/ethereum/precompiles/overview/){target=\_blank}. The Precompile Registry can be used to determine if an address corresponds to a precompile and whether or not a precompile is active or deprecated. This is particularly useful when there are upstream changes within the Substrate and Polkadot ecosystems that result in backward-incompatible changes to precompiles. Developers can design an exit strategy to ensure their dApp recovers gracefully in these scenarios. The Precompile Registry also serves an additional purpose, as it allows any user to set "dummy code" (`0x60006000fd`) for precompiles, which makes precompiles callable from Solidity. This is necessary as precompiles on Moonbeam, by default, don't have bytecode. The "dummy code" can bypass checks in Solidity that ensure contract bytecode exists and is non-empty. The Registry Precompile is located at the following address: === "Moonbeam" ```text {{networks.moonbeam.precompiles.registry }} ``` === "Moonriver" ```text {{networks.moonriver.precompiles.registry }} ``` === "Moonbase Alpha" ```text {{networks.moonbase.precompiles.registry }} ``` !!! note There can be some unintended consequences when using the precompiled contracts on Moonbeam. Please refer to the [Security Considerations](/learn/core-concepts/security/){target=\_blank} page for more information. ## The Precompile Registry Solidity Interface {: #the-solidity-interface } [`PrecompileRegistry.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/precompile-registry/PrecompileRegistry.sol){target=\_blank} is a Solidity interface that allows developers to interact with the precompile's methods. ??? code "PrecompileRegistry.sol" ```solidity // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.3; /// @dev The Precompile Registry contract's address. address constant PRECOMPILE_REGISTRY_ADDRESS = 0x0000000000000000000000000000000000000815; /// @dev The Precompile Registry contract's instance. PrecompileRegistry constant PRECOMPILE_REGISTRY_CONTRACT = PrecompileRegistry(PRECOMPILE_REGISTRY_ADDRESS); /// @author The Moonbeam Team /// @title Precompile Registry /// @dev Interface to the set of available precompiles. interface PrecompileRegistry { /// @dev Query if the given address is a precompile. Note that deactivated precompiles /// are still considered precompiles and will return `true`. /// @param a: Address to query /// @return output Is this address a precompile? /// @custom:selector 446b450e function isPrecompile(address a) external view returns (bool); /// @dev Query if the given address is an active precompile. Will return false if the /// address is not a precompile or if this precompile is deactivated. /// @param a: Address to query /// @return output Is this address an active precompile? /// @custom:selector 6f5e23cf function isActivePrecompile(address a) external view returns (bool); /// @dev Update the account code of a precompile address. /// As precompiles are implemented inside the Runtime, they don't have a bytecode, and /// their account code is empty by default. However in Solidity calling a function of a /// contract often automatically adds a check that the contract bytecode is non-empty. /// For that reason a dummy code (0x60006000fd) can be inserted at the precompile address /// to pass that check. This function allows any user to insert that code to precompile address /// if they need it. /// @param a: Address of the precompile. /// @custom:selector 48ceb1b4 function updateAccountCode(address a) external; } ``` The interface includes the following functions: ??? function "**isPrecompile**(*address* a) - returns a boolean indicating whether a given address is a precompile or not. Returns `true` for active and deprecated precompiles" === "Parameters" - `a` - address to check if it is a precompile === "Returns" - `bool` whether the address is a precompile (active or deprecated) ??? function "**isActivePrecompile**(*address* a) - returns a boolean indicating whether a given address is an active precompile or not. Returns `false` if a precompile has been deprecated" === "Parameters" - `a` - address to check if it is an active precompile === "Returns" - `bool` whether the address is an active precompile ??? function "**updateAccountCode**(*address* a) - updates a given precompile's bytecode with dummy code (`0x60006000fd`) given the address of the precompile. Precompiles, by default, don't have bytecode associated with them. This function can be used to add dummy bytecode to bypass requirements in Solidity that check if a contract's bytecode is not empty before its functions can be called" === "Parameters" - `a` - address of the precompile to update with dummy bytecode === "Returns" None. ## Interact with the Precompile Registry Solidity Interface {: #interact-with-precompile-registry-interface } The following sections will cover how to interact with the Registry Precompile from [Remix](/builders/ethereum/dev-env/remix/){target=\_blank} and [Ethereum libraries](/builders/ethereum/libraries/){target=\_blank}, such as [Ethers.js](/builders/ethereum/libraries/ethersjs/){target=\_blank}, [Web3.js](/builders/ethereum/libraries/web3js/){target=\_blank}, and [Web3.py](/builders/ethereum/libraries/web3py/){target=\_blank}. The examples in this guide will be on Moonbase Alpha. To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. ### Use Remix to Interact with the Precompile Registry {: #use-remix } To quickly get started with [Remix](/builders/ethereum/dev-env/remix/){target=\_blank}, the [Precompile Registry contract has been loaded from GitHub](https://remix.ethereum.org/#url=https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/precompile-registry/PrecompileRegistry.sol){target=\_blank}. You can also create a new file in Remix and manually paste in the contents of the [`PrecompileRegistry.sol`](#the-solidity-interface) contract. ![Add the Precompile Registry Interface to Remix](/images/builders/ethereum/precompiles/utility/registry/registry-1.webp) Then you can take the following steps to compile, deploy, and interact with the Precompile Registry: 1. From the **Compile** tab, click on **Compile PrecompileRegistry.sol** to compile the contract. A green checkmark will appear upon successfully compiling the contract ![Compile the Precompile Registry contract](/images/builders/ethereum/precompiles/utility/registry/registry-2.webp) 2. From the **Deploy and run transactions** tab, you can load the Precompile Registry using its address: 1. Make sure **Injected Provider - Metamask** is selected in the **ENVIRONMENT** drop down and you've connected MetaMask to Moonbase Alpha 2. Ensure **PrecompileRegistry** is selected in the **CONTRACT** dropdown. Since this is a precompiled contract there is no need to deploy, instead you are going to provide the address of the Precompile in the **At Address** field 3. Provide the address of the Precompile Registry for Moonbase Alpha: `{{ networks.moonbase.precompiles.registry }}` and click **At Address** 4. The Precompile Registry will appear in the list of **Deployed Contracts** ![Access the Precompile Registry contract](/images/builders/ethereum/precompiles/utility/registry/registry-3.webp) 3. You can interact with any of the precompile's methods. Under **Deployed Contracts**, expand the Precompile Registry to view the list of methods. For example, you can use the **isPrecompile** function to check if an address is a precompile ![Interact with the Precompile Registry contract](/images/builders/ethereum/precompiles/utility/registry/registry-4.webp) ### Use Ethereum Libraries to Interact with the Precompile Registry {: #use-ethereum-libraries } To interact with the Precompile Registry's Solidity interface with an Ethereum library, you'll need the Precompile Registry's ABI. ??? code "Precompile Registry ABI" ```js [ { "inputs": [ { "internalType": "address", "name": "a", "type": "address" } ], "name": "isActivePrecompile", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "a", "type": "address" } ], "name": "isPrecompile", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "a", "type": "address" } ], "name": "updateAccountCode", "outputs": [], "stateMutability": "nonpayable", "type": "function" } ] ``` Once you have the ABI, you can interact with the Registry using the Ethereum library of your choice. Generally speaking, you'll take the following steps: 1. Create a provider 2. Create a contract instance of the Precompile Registry 3. Interact with the Precompile Registry's functions !!! remember The following snippets are for demo purposes only. Never store your private keys in a JavaScript or Python file. === "Ethers.js" ```js import { ethers } from 'ethers'; // Import Ethers library import ABI from './precompileRegistryABI.js'; // Import Precompile Registry ABI const privateKey = 'INSERT_PRIVATE_KEY'; // Create Ethers provider and signer const provider = new ethers.JsonRpcProvider( 'https://rpc.api.moonbase.moonbeam.network' ); const signer = new ethers.Wallet(privateKey, provider); // Create interface for the Precompile Registry const precompileRegistry = new ethers.Contract( '0x0000000000000000000000000000000000000815', ABI, signer ); // Interact with the Precompile Registry const isActivePrecompile = async () => { const proxyPrecompile = '0x000000000000000000000000000000000000080b'; // Check if the Proxy Precompile is a precompile const isPrecompile = await precompileRegistry.isPrecompile(proxyPrecompile); // Should return 'Address is a precompile: true' console.log(`Address is a precompile: ${isPrecompile}`); // Check if the Proxy Precompile is an active precompile const isActivePrecompile = await precompileRegistry.isActivePrecompile( proxyPrecompile ); // Should return 'Address is an active precompile: true' console.log(`Address is an active precompile: ${isActivePrecompile}`); }; isActivePrecompile(); ``` === "Web3.js" ```js import { Web3 } from 'web3'; import ABI from './precompileRegistryABI.js'; // Import Precompile Registry ABI const privateKey = 'INSERT_PRIVATE_KEY'; // Create provider const web3 = new Web3('https://rpc.api.moonbase.moonbeam.network'); // Create interface for the Precompile Registry const precompileRegistry = new web3.eth.Contract( ABI, '0x0000000000000000000000000000000000000815', { from: web3.eth.accounts.privateKeyToAccount(privateKey).address } ); // Interact with the Precompile Registry const isActivePrecompile = async () => { const proxyPrecompile = '0x000000000000000000000000000000000000080b'; // Check if the Proxy Precompile is a precompile const isPrecompile = await precompileRegistry.methods.isPrecompile( proxyPrecompile ).call(); // Should return 'Address is a precompile: true' console.log(`Address is a precompile: ${isPrecompile}`); // Check if the Proxy Precompile is an active precompile const isActivePrecompile = await precompileRegistry.methods.isActivePrecompile(proxyPrecompile).call(); // Should return 'Address is an active precompile: true' console.log(`Address is a precompile: ${isActivePrecompile}`); }; isActivePrecompile(); ``` === "Web3.py" ```py from web3 import Web3 abi = "INSERT_PRECOMPILE_REGISTRY_ABI" # Paste or import the Precompile Registry ABI private_key = "INSERT_PRIVATE_KEY" # Create provider web3 = Web3(Web3.HTTPProvider("https://rpc.api.moonbase.moonbeam.network")) # Create interface for the Precompile Registry precompile_registry = web3.eth.contract( address="0x0000000000000000000000000000000000000815", abi=abi ) # Interact with the Precompile Registry def is_active_precompile(): proxy_precompile = "0x000000000000000000000000000000000000080b" # Check if the Proxy Precompile is a precompile is_precompile = precompile_registry.functions.isPrecompile(proxy_precompile).call() # Should return 'Address is a precompile: true' print("Address is a precompile: ", is_precompile) # Check if the Proxy Precompile is an active precompile is_active_precompile = precompile_registry.functions.isActivePrecompile( proxy_precompile ).call() # Should return 'Address is an active precompile: true' print("Address is an active precompile: ", is_active_precompile) is_active_precompile() ``` --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/utility/relay-data-verifier/ --- BEGIN CONTENT --- --- title: Relay Data Verifier Precompile Contract description: Learn how to verify data availability and authenticity on the relay chain via a Solidity interface with Moonbeam's Relay Data Verifier Precompile contract. keywords: solidity, ethereum, verify, proof, relay chain, transaction, moonbeam, precompiled, contracts categories: Precompiles, Ethereum Toolkit --- # Interacting with the Relay Data Verifier Precompile ## Introduction {: #introduction } Polkadot relies on state proofs to guarantee data integrity at a particular time. A state proof is a concise, cryptographic data structure representing a specific subset of transactions or state data within a trie. It consists of a set of hashes that form a path from the target data to the root hash stored in the block header. A client can independently reconstruct the root hash and compare it with the original stored in the block header by providing a state proof. If the reconstructed root hash matches the original, it confirms the target data's authenticity, validity, and inclusion within the blockchain. Polkadot's unique architecture and parachain block validation process means blockchains like Moonbeam have the relay chain storage root hash in their state. Consequently, Moonbeam can provide a mechanism to verify a relay chain state by checking the proof against the stored storage root hash. Moonbeam's [relay data verifier precompiled](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/relay-data-verifier/RelayDataVerifier.sol){target=\_blank} contract provides an easy way for smart contracts to programmatically build functions that rely on verifying relay chain state in contract calls. Consequently, no oracles are needed to feed relay chain data to Moonbeam. This functionality is readily available at the following contract addresses: === "Moonbeam" ```text {{networks.moonbeam.precompiles.relay_data_verifier }} ``` === "Moonriver" ```text {{networks.moonriver.precompiles.relay_data_verifier }} ``` === "Moonbase Alpha" ```text {{networks.moonbase.precompiles.relay_data_verifier }} ``` !!! note There can be some unintended consequences when using the precompiled contracts on Moonbeam. Please refer to the [Security Considerations](/learn/core-concepts/security/){target=\_blank} page for more information. ## The Relay Data Verifier Solidity Interface {: #the-relay-data-verifier-solidity-interface } [`RelayDataVerifier.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/relay-data-verifier/RelayDataVerifier.sol){target=\_blank} is a Solidity interface that allows developers to interact with the precompile's methods. ??? code "RelayDataVerifier.sol" ```solidity // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.3; /// @dev The RelayDataVerifier contract's address. address constant RELAY_DATA_VERIFIER_ADDRESS = 0x0000000000000000000000000000000000000819; /// @dev The RelayDataVerifier contract's instance. RelayDataVerifier constant RELAY_DATA_VERIFIER_CONTRACT = RelayDataVerifier( RELAY_DATA_VERIFIER_ADDRESS ); /// @author The Moonbeam Team /// @title Relay Proof Verifier Interface /// @dev The interface that Solidity contracts use to interact with the Relay Proof Verifier /// precompile. /// A typical workflow to verify relay chain data is the following: /// 1. Moonbeam RPC Call: Call `latestRelayBlockNumber` function to get the latest relay /// block number tracked by the chain in `pallet-storage-root`. /// 2. Relay RPC Call: Call `chain_getBlockHash(blockNumber)` RPC method to get the relay block hash /// for the block number obtained in step 1. /// 3. Relay RPC Call: Call `state_getReadProof(keys, at)` RPC method where `at` /// is the relay block hash obtained in step 2 to get the 'ReadProof` of the entries. /// 4. Moonbeam RPC Call: Submit an ethereum transaction (directly or through a SC) to call the /// `verifyEntry` or `verifyEntries` function to verify the data against the relay block /// number. The call data contain the relay block number obtained in step 1, and the read /// proof generated in step 3, along with the key/s to verify. /// @custom:address 0x0000000000000000000000000000000000000819 interface RelayDataVerifier { /// @dev ReadProof struct returned by the `state_getReadProof` RPC method. struct ReadProof { // The block hash against which the proof is generated bytes32 at; /// The storage proof bytes[] proof; } /// @dev Verifies a storage entry in the Relay Chain using a relay block number and a storage /// proof. This function takes a relay block number, a storage proof, and the key of the storage /// entry to verify. It returns the value associated with the key if the verification is /// successful. /// @custom:selector 27001faa /// @param relayBlockNumber The relay block number against which the entry is being verified. /// @param readProof The storage proof used to verify the entry. /// @param key The key of the storage entry to verify. /// @return value The value associated with the key, returned as a bytes array. function verifyEntry( uint32 relayBlockNumber, ReadProof calldata readProof, bytes calldata key ) external returns (bytes memory value); /// @dev Verifies a set of entries in the Relay Chain and returns the corresponding values. /// This function takes a relay block number, a storage proof, and an array of keys for the /// storage entries to verify. It returns an array of values associated with the keys, in the /// same order as the keys. /// @custom:selector 2da33a45 /// @param relayBlockNumber The relay block number for which the data is being verified. /// @param readProof The storage proof used to verify the data. /// @param keys The keys of the storage entries to verify. /// @return values The values associated with the keys, returned in the same order as the keys. function verifyEntries( uint32 relayBlockNumber, ReadProof calldata readProof, bytes[] calldata keys ) external returns (bytes[] memory values); /// @dev Returns the latest relay block number that has a storage root stored on-chain. /// @custom:selector aed36869 /// @return relayBlockNumber the lastest relay block number function latestRelayBlockNumber() external view returns (uint32 relayBlockNumber); } ``` The interface includes the following functions: ???+ function "**latestRelayBlockNumber**() — retrieves the most recent relay chain block that has its storage root stored on the blockchain itself" === "Parameters" None === "Returns" The latest relay block number that has a storage root stored on-chain. ??? function "**verifyEntry**(_uint32_ relayBlockNumber, _ReadProof_ calldata readProof, _bytes_ callData key) — verifies a storage entry in the relay chain using a relay block number, a storage proof, and the storage key. It returns the value associated with the key if the verification is successful" === "Parameters" - `relayBlockNumber` - the relay block number for which the data is being verified. The latest relay block number can be obtained from the `latestRelayBlockNumber()` function - `readProof` - a struct defined in the precompile contract, containing the storage proof used to verify the data. The `ReadProof` struct is defined as: ``` struct ReadProof { // The block hash against which the proof is generated bytes32 at; /// The storage proof bytes[] proof; } ``` - `key` - the storage key for the generated proof === "Returns" When performing a [static call](https://docs.ethers.org/v6/api/contract/#BaseContractMethod-staticCall){target=\_blank} on the `verifyEntry` function, you can view the returned value associated with the key in hexadecimal format. ```js '0x01000000040000000100000000000000f88ce384dca20000000000000000000000370589030a0000000000000000000000203d88792d0000000000000000000000000000000000000000000000000080' ``` ??? function "**verifyEntries**(_uint32_ relayBlockNumber, _ReadProof_ calldata readProof, _bytes[]_ callData keys) — verifies a set of entries in the relay chain and returns the corresponding values. This function takes a relay block number, a storage proof, and an array of storage keys to verify. It returns an array of values associated with the keys, in the same order as the keys" === "Parameters" - `relayBlockNumber` - the relay block number for which the data is being verified. The latest relay block number can be obtained from the `latestRelayBlockNumber()` function - `readProof` - a struct defined in the precompile contract, containing the storage proof used to verify the data. The `ReadProof` struct is defined as: ``` struct ReadProof { // The block hash against which the proof is generated bytes32 at; /// The storage proof bytes[] proof; } ``` - `keys` - the storage keys for the generated proof === "Returns" When performing a [static call](https://docs.ethers.org/v6/api/contract/#BaseContractMethod-staticCall){target=\_blank} on the `verifyEntries` function, you can view an array containing the corresponding values mapped to their respective keys, represented in hexadecimal format. ```js ['0x01000000040000000100000000000000f88ce384dca20000000000000000000000370589030a0000000000000000000000203d88792d0000000000000000000000000000000000000000000000000080'] ``` ## Interact with the Solidity Interface {: #interact-with-the-solidity-interface } A typical workflow to verify relay chain data involves the following steps: 1. **Moonbeam RPC call** - call the `latestRelayBlockNumber` function to get the latest relay block number tracked by the chain in the `pallet-storage-root` 2. **Relay RPC call** - call the `chain_getBlockHash(blockNumber)` RPC method to get the relay block hash for the block number obtained in step one 3. **Relay RPC call** - call the `state_getReadProof(keys, at)` RPC method to retrieve the storage proof, where `at` is the relay block hash obtained in step two, and `keys` is an array of strings which contains the keys for target storage items. For `@polkadot/api`, it can be obtained via `api.query.module.key()` function 4. **Moonbeam RPC call** - submit an Ethereum transaction to call the `verifyEntry` or `verifyEntries` function to verify the data against the relay block number. The call data should contain the relay block number obtained in step one, the read proof generated in step three, and the key(s) to verify The following sections will cover how to interact with the Relay Data Verifier Precompile using Ethereum libraries, such as Ethers.js, Web3.js, and Web3.py. The examples in this guide will be on Moonbase Alpha. ### Checking Prerequisites {: #checking-prerequisites } To follow along with this tutorial, you will need to have: - Create or have an account on Moonbase Alpha to test out the different features in the precompile - The account will need to be funded with `DEV` tokens. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} ### Using Ethereum Libraries {: #using-ethereum-libraries } To interact with the Solidity interface using an Ethereum library, you'll need the precompile's ABI (Application Binary Interface). The ABI for the Relay Chain Data Verifier Precompile is as follows: ??? code "Relay Data Verifier Precompile ABI" ```js [ { inputs: [], name: 'latestRelayBlockNumber', outputs: [ { internalType: 'uint32', name: 'relayBlockNumber', type: 'uint32', }, ], stateMutability: 'view', type: 'function', }, { inputs: [ { internalType: 'uint32', name: 'relayBlockNumber', type: 'uint32', }, { components: [ { internalType: 'bytes32', name: 'at', type: 'bytes32', }, { internalType: 'bytes[]', name: 'proof', type: 'bytes[]', }, ], internalType: 'struct RelayDataVerifier.ReadProof', name: 'readProof', type: 'tuple', }, { internalType: 'bytes[]', name: 'keys', type: 'bytes[]', }, ], name: 'verifyEntries', outputs: [ { internalType: 'bytes[]', name: 'values', type: 'bytes[]', }, ], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ { internalType: 'uint32', name: 'relayBlockNumber', type: 'uint32', }, { components: [ { internalType: 'bytes32', name: 'at', type: 'bytes32', }, { internalType: 'bytes[]', name: 'proof', type: 'bytes[]', }, ], internalType: 'struct RelayDataVerifier.ReadProof', name: 'readProof', type: 'tuple', }, { internalType: 'bytes', name: 'key', type: 'bytes', }, ], name: 'verifyEntry', outputs: [ { internalType: 'bytes', name: 'value', type: 'bytes', }, ], stateMutability: 'nonpayable', type: 'function', }, ]; ``` Once you have the ABI, you can interact with the precompile using the Ethereum library of your choice, such as [Ethers.js](/builders/ethereum/libraries/ethersjs/){target=\_blank}, [Web3.js](/builders/ethereum/libraries/web3js/){target=\_blank}, or [Web3.py](/builders/ethereum/libraries/web3py/){target=\_blank}. The general steps are as follows: 1. Create a provider 2. Create a contract instance of the precompile 3. Interact with the precompile's functions The provided code example demonstrates how to use the Ethers.js library to interact with the Moonbase Alpha network and its relay chain, verifying a data entry using the `verifyEntry` function. !!! note The code snippets presented in the following sections are not meant for production environments. Please make sure you adapt it for each use case. === "Ethers.js" ```js // For reading local ABI file import * as fs from 'fs'; // Import Ethers library, to interact with Moonbeam networks import { ethers } from 'ethers'; // Import Polkadot library, to interact with relay chain import { ApiPromise, WsProvider } from '@polkadot/api'; const abi = JSON.parse(fs.readFileSync('./RelayChainDataVerifierABI.json')); const privateKey = 'INSERT_PRIVATE_KEY'; const precompileAddress = '0x0000000000000000000000000000000000000819'; const moonbeamURL = 'https://rpc.api.moonbase.moonbeam.network'; const relayURL = 'wss://relay.api.moonbase.moonbeam.network'; // Create Ethers provider and signer const provider = new ethers.JsonRpcProvider(moonbeamURL); const signer = new ethers.Wallet(privateKey, provider); const precompileContract = new ethers.Contract(precompileAddress, abi, signer); async function run() { // Create provider for relay chain const wsProvider = new WsProvider(relayURL); const api = await ApiPromise.create({ provider: wsProvider }); // Get the storage key for a random account on relay chain const key = api.query.system.account.key( '5CBATpb3yvEM4mhX9Dw3tyuqiWKhq9YBG6ugSbodRUSbodoU' ); // Find the latest available relay chain block number from Moonbeam const blockNum = await precompileContract.latestRelayBlockNumber(); // Get the block hash and storage proof from relay chain const blockHash = await api.rpc.chain.getBlockHash(blockNum); const proof = await api.rpc.state.getReadProof([key], blockHash); // This tx will be rejected if the verification failed const receipt = await precompileContract.verifyEntry(blockNum, proof, key); await receipt.wait(); console.log(receipt.hash); } await run(); ``` === "Web3.js" ```js // For reading local ABI file import * as fs from 'fs'; // Import web3js library, to interact with Moonbeam networks import { Web3 } from 'web3'; // Import Polkadot library, to interact with relay chain import { ApiPromise, WsProvider } from '@polkadot/api'; const abi = JSON.parse(fs.readFileSync('./RelayChainDataVerifierABI.json')); const privateKey = 'INSERT_PRIVATE_KEY'; const precompileAddress = '0x0000000000000000000000000000000000000819'; const moonbeamURL = 'https://rpc.api.moonbase.moonbeam.network'; const relayURL = 'wss://relay.api.moonbase.moonbeam.network'; // Create Web3js provider and signer const web3 = new Web3(moonbeamURL); const precompileContract = new web3.eth.Contract(abi, precompileAddress); const account = web3.eth.accounts.privateKeyToAccount(privateKey); async function run() { // Create provider for relay chain const wsProvider = new WsProvider(relayURL); const api = await ApiPromise.create({ provider: wsProvider }); // Get the storage key for a random account on relay chain const key = api.query.system.account.key( '5CBATpb3yvEM4mhX9Dw3tyuqiWKhq9YBG6ugSbodRUSbodoU' ); // Find the latest available relay chain block number from Moonbeam const blockNum = await precompileContract.methods .latestRelayBlockNumber() .call(); // Get the block hash and storage proof from relay chain const blockHash = await api.rpc.chain.getBlockHash(blockNum); const proof = await api.rpc.state.getReadProof([key], blockHash); const callObject = { to: precompileAddress, data: precompileContract.methods .verifyEntry(blockNum, proof, key) .encodeABI(), gas: await precompileContract.methods .verifyEntry(blockNum, proof, key) .estimateGas(), gasPrice: await web3.eth.getGasPrice(), nonce: await web3.eth.getTransactionCount(account.address), }; // This tx will be rejected if the verification failed const tx = await web3.eth.accounts.signTransaction( callObject, account.privateKey ); const receipt = await web3.eth.sendSignedTransaction(tx.rawTransaction); console.log(receipt.transactionHash); } await run(); ``` === "Web3.py" ```py # Import packages from eth_account import Account from substrateinterface import SubstrateInterface from web3 import Web3 # Initialize variables abi = INSERT_ABI privateKey = "INSERT_PRIVATE_KEY" precompileAddress = "0x0000000000000000000000000000000000000819" moonbeamURL = "https://rpc.api.moonbase.moonbeam.network" relayURL = "wss://relay.api.moonbase.moonbeam.network" # Create provider for Moonbeam network web3 = Web3(Web3.HTTPProvider(moonbeamURL)) account = Account.from_key(privateKey) precompileContract = web3.eth.contract(address=precompileAddress, abi=abi) # Create provider for relay chain substrate = SubstrateInterface(url=relayURL) # Get storage key key = substrate.generate_storage_hash( storage_module="System", storage_function="Account", params=["5CBATpb3yvEM4mhX9Dw3tyuqiWKhq9YBG6ugSbodRUSbodoU"], ) # Find the latest available relay chain block number from Moonbeam blockNum = precompileContract.functions.latestRelayBlockNumber().call() # Get the block hash from relay chain blockHash = substrate.get_block_hash(blockNum) # Get the storage proof from relay chain response = substrate.rpc_request("state_getReadProof", [[key], blockHash]) proof = response["result"] # Call smart contract tx = precompileContract.functions.verifyEntry(blockNum, proof, key).build_transaction( { "from": Web3.to_checksum_address(account.address), "nonce": web3.eth.get_transaction_count( Web3.to_checksum_address(account.address) ), } ) tx_create = web3.eth.account.sign_transaction(tx, privateKey) tx_hash = web3.eth.send_raw_transaction(tx_create.rawTransaction) tx_receipt = web3.eth.wait_for_transaction_receipt(tx_hash) ``` --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/ux/batch/ --- BEGIN CONTENT --- --- title: Batch Precompile Contract description: Learn how to transact multiple transfers and contract interactions at once via a Solidity interface with Moonbeam's Batch Precompile contract. keywords: solidity, ethereum, batch, transaction, moonbeam, precompiled, contracts categories: Precompiles, Ethereum Toolkit --- # Interacting with the Batch Precompile ## Introduction {: #introduction } The batch precompiled contract on Moonbeam allows developers to combine multiple EVM calls into one. Currently, having users interact with multiple contracts would require multiple transaction confirmations in the user's wallet. An example would be approving a smart contract's access to a token, then transferring it. With the batch precompile, developers can enhance user experience with batched transactions as it minimizes the number of transactions a user is required to confirm to one. Additionally, gas fees can be reduced since batching avoids multiple base gas fees (the initial 21000 units of gas spent to begin a transaction). The precompile interacts directly with [Substrate's EVM pallet](/learn/platform/technology/#evm-pallet){target=\_blank}. The caller of the batch function will have their address act as the `msg.sender` for all subtransactions, but unlike [delegate calls](https://docs.soliditylang.org/en/v0.8.15/introduction-to-smart-contracts.html#delegatecall-callcode-and-libraries){target=\_blank}, the target contract will still affect its own storage. It is effectively the same as if the user signed multiple transactions, but with only one confirmation. The precompile is located at the following address: === "Moonbeam" ```text {{networks.moonbeam.precompiles.batch }} ``` === "Moonriver" ```text {{networks.moonriver.precompiles.batch }} ``` === "Moonbase Alpha" ```text {{networks.moonbase.precompiles.batch }} ``` !!! note There can be some unintended consequences when using the precompiled contracts on Moonbeam. Please refer to the [Security Considerations](/learn/core-concepts/security/){target=\_blank} page for more information. ## The Batch Solidity Interface {: #the-batch-interface } [`Batch.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/batch/Batch.sol){target=\_blank} is a Solidity interface that allows developers to interact with the precompile's three methods. The interface includes the following functions: ??? function "**batchSome**(*address[]* to, *uint256[]* value, *bytes[]* callData, *uint64[]* gasLimit) - performs multiple calls, where the same index of each array combine into the information required for a single subcall. If a subcall reverts, following subcalls will still be attempted" === "Parameters" - `to` - address[] array of addresses to direct subtransactions to, where each entry is a subtransaction - `value` - uint256[] array of native currency values to send in the subtransactions, where the index corresponds to the subtransaction of the same index in the to array. If this array is shorter than the to array, all the following subtransactions will default to a value of 0 - `callData` - bytes[] array of call data to include in the subtransactions, where the index corresponds to the subtransaction of the same index in the to array. If this array is shorter than the to array, all of the following subtransactions will include no call data - `gasLimit` - uint64[] array of gas limits in the subtransactions, where the index corresponds to the subtransaction of the same index in the to array. Values of 0 are interpreted as unlimited and will have all remaining gas of the batch transaction forwarded. If this array is shorter than the to array, all of the following subtransactions will have all remaining gas forwarded ??? function "**batchSomeUntilFailure**(*address[]* to, *uint256[]* value, *bytes[]* callData, *uint64[]* gasLimit) - performs multiple calls, where the same index of each array combine into the information required for a single subcall. If a subcall reverts, no following subcalls will be executed" === "Parameters" - `to` - address[] array of addresses to direct subtransactions to, where each entry is a subtransaction - `value` - uint256[] array of native currency values to send in the subtransactions, where the index corresponds to the subtransaction of the same index in the to array. If this array is shorter than the to array, all the following subtransactions will default to a value of 0 - `callData` - bytes[] array of call data to include in the subtransactions, where the index corresponds to the subtransaction of the same index in the to array. If this array is shorter than the to array, all of the following subtransactions will include no call data - `gasLimit` - uint64[] array of gas limits in the subtransactions, where the index corresponds to the subtransaction of the same index in the to array. Values of 0 are interpreted as unlimited and will have all remaining gas of the batch transaction forwarded. If this array is shorter than the to array, all of the following subtransactions will have all remaining gas forwarded ??? function "**batchAll**(*address[]* to, *uint256[]* value, *bytes[]* callData, *uint64[]* gasLimit) - performs multiple calls atomically, where the same index of each array combine into the information required for a single subcall. If a subcall reverts, all subcalls will revert" === "Parameters" - `to` - address[] array of addresses to direct subtransactions to, where each entry is a subtransaction - `value` - uint256[] array of native currency values to send in the subtransactions, where the index corresponds to the subtransaction of the same index in the to array. If this array is shorter than the to array, all the following subtransactions will default to a value of 0 - `callData` - bytes[] array of call data to include in the subtransactions, where the index corresponds to the subtransaction of the same index in the to array. If this array is shorter than the to array, all of the following subtransactions will include no call data - `gasLimit` - uint64[] array of gas limits in the subtransactions, where the index corresponds to the subtransaction of the same index in the to array. Values of 0 are interpreted as unlimited and will have all remaining gas of the batch transaction forwarded. If this array is shorter than the to array, all of the following subtransactions will have all remaining gas forwarded The interface also includes the following required events: - **SubcallSucceeded**(*uint256* index) - emitted when subcall of the given index succeeds - **SubcallFailed**(*uint256* index) - emitted when a subcall of the given index fails ## Interact with the Solidity Interface {: #interact-with-the-solidity-interface } ### Checking Prerequisites {: #checking-prerequisites } To follow along with this tutorial, you will need to have: - [MetaMask installed and connected to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank} - Create or have two accounts on Moonbase Alpha to test out the different features in the batch precompile - At least one of the accounts will need to be funded with `DEV` tokens. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} ### Example Contract {: #example-contract} The contract `SimpleContract.sol` will be used as an example of batching contract interactions, but in practice, any contract can be interacted with. ```solidity // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; contract SimpleContract { mapping(uint256 => string) public messages; function setMessage(uint256 id, string calldata message) external { messages[id] = message; } } ``` ### Remix Set Up {: #remix-set-up } You can interact with the batch precompile using [Remix](https://remix.ethereum.org){target=\_blank}. You'll need a copy of [`Batch.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/batch/Batch.sol){target=\_blank} and [`SimpleContract.sol`](#example-contract). To add the precompile to Remix and follow along with the tutorial, you will need to: 1. Click on the **File explorer** tab 2. Paste the `Batch.sol` contract into a Remix file named **Batch.sol** 3. Paste the `SimpleContract.sol` contract into a Remix file named **SimpleContract.sol** ### Compile the Contract {: #compile-the-contract } Next, you will need to compile both files in Remix: 1. Make sure that you have the **Batch.sol** file open 2. Click on the **Compile** tab, second from top 3. To compile the contract, click on **Compile Batch.sol** ![Compiling Batch.sol](/images/builders/ethereum/precompiles/ux/batch/batch-1.webp) If the interface was compiled successfully, you will see a green checkmark next to the **Compile** tab. ### Access the Precompile {: #access-the-precompile } Instead of deploying the batch precompile, you will access the interface given the address of the precompiled contract: 1. Click on the **Deploy and Run** tab directly below the **Compile** tab in Remix. Please note the precompiled contract is already deployed 2. Make sure **Injected Provider - Metamask** is selected in the **ENVIRONMENT** dropdown. Once you select **Injected Provider - Metamask**, you might be prompted by MetaMask to connect your account to Remix 3. Make sure the correct account is displayed under **ACCOUNT** 4. Ensure **Batch - Batch.sol** is selected in the **CONTRACT** dropdown. Since this is a precompiled contract, there is no need to deploy any code. Instead we are going to provide the address of the precompile in the **At Address** field 5. Provide the address of the batch precompile: `{{networks.moonbase.precompiles.batch}}` and click **At Address** ![Access the address](/images/builders/ethereum/precompiles/ux/batch/batch-2.webp) The **BATCH** precompile will appear in the list of **Deployed Contracts**. ### Deploy Example Contract {: #deploy-example-contract } On the other hand, `SimpleContract.sol` will be deployed as a new contract. Before starting this section, repeat the [compilation step](#compile-the-contract) with the `SimpleContract.sol` file. 1. Click on the **Deploy and Run** tab directly below the **Compile** tab in Remix 2. Make sure **Injected Provider - Metamask** is selected in the **ENVIRONMENT** dropdown. Once you select **Injected Provider - Metamask**, you might be prompted by MetaMask to connect your account to Remix 3. Make sure the correct account is displayed under **ACCOUNT** 4. Ensure **SimpleContract - SimpleContract.sol** is selected in the **CONTRACT** dropdown 5. Click **Deploy** 6. Confirm the MetaMask transaction that appears by clicking **Confirm** ![Deploy SimpleContract](/images/builders/ethereum/precompiles/ux/batch/batch-3.webp) The **SIMPLECONTRACT** contract will appear in the list of **Deployed Contracts**. ### Send Native Currency via Precompile {: #send-native-currency-via-precompile } Sending native currency with the batch precompile is more involved than pressing a few buttons in Remix or MetaMask. For this example, you will be using the **batchAll** function to send native currency atomically. Transactions have a value field to specify the amount of native currency being sent with it. In Remix, this is represented by the **VALUE** input in the **DEPLOY & RUN TRANSACTIONS** tab. However, for the batch precompile, this data is provided within the **value** array input of the batch functions. Try transferring native currency to two wallets of your choice via the batch precompile on Moonbase Alpha: 1. Make sure that you have at least 0.5 DEV in your connected wallet 2. Expand the batch contract under **Deployed Contracts** 3. Expand the **batchAll** function 4. For the **to** input, insert your addresses in the following format: `["INSERT_ADDRESS_1", "INSERT_ADDRESS_2"]`, where the first address corresponds to the first wallet of your choice and the second address corresponds to the second wallet of your choice 5. For the **value** input, insert the amount you wish to transfer in Wei for each address. For example, `["100000000000000000", "200000000000000000"]` will transfer 0.1 DEV to the first address and 0.2 DEV to the second address 6. For both of the remaining **callData** and **gasLimit** inputs, insert `[]`. Call data and gas limit are not a concern for transferring native currency 7. Press **transact** 8. Press **Confirm** in the MetaMask extension to confirm the transaction ![Send Batch Transfer](/images/builders/ethereum/precompiles/ux/batch/batch-4.webp) Once the transaction is complete, be sure to check both of the accounts' balances, either in MetaMask or in a [block explorer](/builders/get-started/explorers/){target=\_blank}. Congratulations! You've now sent a batched transfer via the batch precompile. !!! note Typically if you wanted to send the native currency to or through a contract, you would have to set the value within the overall transaction object and interact with a payable function. However, since the batch precompile interacts directly with Substrate code, this is not a typical Ethereum transaction and is thus not necessary. ### Find a Contract Interaction's Call Data {: #find-a-contract-interactions-call-data } Visual interfaces like [Remix](/builders/ethereum/dev-env/remix/){target=\_blank} and handy libraries like [Ethers.js](/builders/ethereum/libraries/ethersjs/){target=\_blank} hide the way that Ethereum transactions interact with Solidity smart contracts. The name and input types of a function are hashed into a [function selector](https://docs.soliditylang.org/en/latest/abi-spec.html#function-selector-and-argument-encoding){target=\_blank} and the input data is encoded. These two pieces are then combined and sent as the transaction's call data. To send a subtransaction within a batch transaction, the sender needs to know its call data beforehand. Try finding a transaction's call data using Remix: 1. Expand the `SimpleContract.sol` contract under **Deployed Contracts** 2. Expand the **setMessage** function 3. Enter the input of the function. For this example, **id** will be `1` and **message** will be `"moonbeam"` 4. Instead of sending the transaction, click the copy button next to the **transact** button to copy the call data ![Transaction Call Data](/images/builders/ethereum/precompiles/ux/batch/batch-5.webp) Now you have the transaction's call data! Considering the example values of `1` and `"moonbeam"`, we can keep an eye out for their encoded values in the call data: ```text 0x648345c8 // function selector 0000000000000000000000000000000000000000000000000000000000000001 // 1 id 0000000000000000000000000000000000000000000000000000000000000040 // 64 string offset 0000000000000000000000000000000000000000000000000000000000000008 // 8 length in bytes 6d6f6f6e6265616d000000000000000000000000000000000000000000000000 // "moonbeam" in bytes ``` The call data can be broken into five lines, where: - The first line is the function selector - The second line is equal to 1, which is the **id** that was provided - What's left has to do with the **message** input. These last three lines are tricky, since strings are a [dynamic type](https://docs.soliditylang.org/en/v0.8.15/abi-spec.html#use-of-dynamic-types){target=\_blank} with a dynamic length. The third line refers to an offset to define where the string's data starts. The fourth line refers to the string's length, in this case 8 because "moonbeam" is 8 bytes long . Finally, the fifth line is "moonbeam" in hexadecimal format (8 ASCII characters are 16 hexadecimal characters) left aligned and with zeros for padding ### Function Interaction via Precompile {: #function-interaction-via-precompile } This section's example will be using the **batchAll** function that will ensure the transactions are resolved atomically. Keep in mind that there are also two other batch functions that can either continue subtransactions despite errors or halt subsequent subtransactions but not revert previous ones. Interacting with a function is very similar to [sending a native currency](#send-native-currency-via-precompile), since they are both transactions. However, call data is required to properly provide input to functions and a sender may desire to limit the amount of gas spent in each subtransaction. The `callData` and `gasLimit` fields are more relevant for subtransactions that interact with contracts. For each function in the batch interface, the `callData` input is an array where each index corresponds to the call data for each recipient of the subtransaction, that is, each `to` input. If the size of the `callData` array is less than the `to` array, the remaining subtransactions will have no call data (functions with no inputs). The `gasLimit` input is an array that corresponds to the amount of gas that each can spend for each subtransaction. If its value at an index is 0 or the index is the size of the array or greater (and smaller than the `to` array's size), all of the remaining gas from the previous subtransaction is forwarded. To use the precompile to send an atomic batch transaction, take the following steps: 1. Copy the `SimpleContract.sol` contract's address with the copy button on the right side of its header. Be sure to also have the [call data from the previous section](#find-a-contract-interactions-call-data) 2. Expand the batch contract under **Deployed Contracts** 3. Expand the **batchAll** function 4. For the **to** input, insert the address of the `SimpleContract.sol` contract that you previously copied in the following format: `["INSERT_SIMPLE_CONTRACT_ADDRESS"]` 5. For the value input, since `SimpleContract.sol` does not require any native currency to be paid to it, insert `["0"]` for 0 Wei 6. For the **callData** input, insert your call data from the previous section in the following format: `["INSERT_CALL_DATA"]` 7. For the **gasLimit** input, insert `[]`. You can put in a gas limit value, but it is optional 8. Press **transact** 9. Press **Confirm** in the MetaMask extension to confirm the transaction ![Batch Function Interaction](/images/builders/ethereum/precompiles/ux/batch/batch-6.webp) If you used the same call data as the tutorial, check to make sure that the transaction has been successful: 1. Expand the `SimpleContract.sol` contract under **Deployed Contracts** 2. To the right of the **messages** button, insert `1` 3. Press the blue **messages** button ![SimpleContract Confirmation](/images/builders/ethereum/precompiles/ux/batch/batch-7.webp) The phrase **"moonbeam"** should appear underneath it. Congratulations! You have interacted with a function with the batch precompile. ### Combining Subtransactions {: combining-subtransactions } So far, transferring native currency and interacting with functions have been separate, but they can be intertwined. The following four strings can be combined as inputs for a batch transaction. They will transact 1 DEV to the public Gerald (`0x6Be02d1d3665660d22FF9624b7BE0551ee1Ac91b`) account, and interact with a predeployed `SimpleContract.sol` contract twice. Here is a break-down: There are three subtransactions, so there are three addresses in the `to` input array. The first is the public Gerald account, the next two are a predeployed `SimpleContract.sol` contract. You can replace the last two with your own instance of `SimpleContract.sol` if you wish. Or, replace only one: you can interact with multiple contracts in a single message. ```text [ "0x6Be02d1d3665660d22FF9624b7BE0551ee1Ac91b", "0xd14b70a55F6cBAc06d4FA49b99be0370D0e1BD39", "0xd14b70a55F6cBAc06d4FA49b99be0370D0e1BD39" ] ``` There will also be three values for the `value` array. The first address in the `to` input array has to do with sending 1 DEV, so 1 DEV in Wei is within the array. The following two values are 0 because the function that their subtransactions are interacting with do not accept or require native currency. ```text ["1000000000000000000", "0", "0"] ``` You will need three values for the `callData` array. Since transferring native currency does not require call data, the string is simply blank. The second and third values in the array correspond to invocations of **setMessage** that set messages to ids 5 and 6. ```text [ "0x", "0x648345c8000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000009796f752061726520610000000000000000000000000000000000000000000000", "0x648345c800000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000e61206d6f6f6e6265616d2070726f000000000000000000000000000000000000" ] ``` The final input is for `gas_input`. This array will be left empty to forward all remaining gas to each subtransaction. ```text [] ``` Try sending a batched transaction with these inputs in Remix the same way [you batched a function call](#function-interaction-via-precompile). And that's it! You've successfully interacted with the ERC-20 precompile using MetaMask and Remix! ## Ethereum Development Libraries {: #ethereum-development-libraries } If you have followed the [Ethers.js tutorial](/builders/ethereum/libraries/ethersjs/){target=\_blank} on Moonbeam, you may find it difficult to find the call data for a function. The answer is hidden within Ether's `Interface` object, where the [encodeFunctionData](https://docs.ethers.org/v6/api/abi/#Interface-encodeFunctionData){target=\_blank} function allows you to input your function name and inputs to receive the resultant call data. [Web3.js](/builders/ethereum/libraries/web3js/){target=\_blank} has a similar function, [encodeFunctionCall](https://web3js.readthedocs.io/en/v1.2.11/web3-eth-abi.html#encodefunctioncall){target=\_blank}. !!! note The code snippets presented in the following sections are not meant for production environments. Please make sure you adapt it for each use-case. === "Ethers.js" ```js // Import the contract ABI const { abi } = require('./INSERT_ABI_PATH'); // Use ABI to create an interface const yourContractInterface = new ethers.Interface(abi); // Find call data for the setMessage function const callData = yourContractInterface.encodeFunctionData( 'INSERT_FUNCTION_NAME', [ 'INSERT_INPUT_1', 'INSERT_INPUT_2', // ... ] ); ``` === "Web3.js" ```js // Import the contract ABI const { abi } = require('./INSERT_ABI_PATH'); // Find call data for the setMessage function const callData = web3.eth.abi.encodeFunctionCall(abi, [ 'INSERT_INPUT_1', 'INSERT_INPUT_2', // ... ]); ``` === "Web3.py" ```py # Import the ABI and bytecode from compile import abi, bytecode # Create contract instance your_contract = web3.eth.contract(abi=abi, bytecode=bytecode) # Encode the contract call call_data = your_contract.encodeABI( fn_name="INSERT_FUNCTION_NAME", args=["INSERT_INPUT_1", "INSERT_INPUT_2", ...] ) ``` Afterwards, you should be all set to interact with the batch precompile as one typically would with a contract in [Ethers](/builders/ethereum/libraries/ethersjs/){target=\_blank}. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/ux/call-permit/ --- BEGIN CONTENT --- --- title: Call Permit Precompile Contract description: Learn how to use the Call Permit Precompile contract on Moonbeam to sign a permit for any EVM call that can be dispatched by anyone or any smart contract. keywords: solidity, ethereum, call permit, permit, gasless transaction, moonbeam, precompiled, contracts categories: Precompiles, Ethereum Toolkit --- # Interacting with the Call Permit Precompile ## Introduction {: #introduction } The Call Permit Precompile on Moonbeam allows a user to sign a permit, an [EIP-712](https://eips.ethereum.org/EIPS/eip-712){target=\_blank} signed message, for any EVM call and it can be dispatched by anyone or any smart contract. It is similar to the [ERC-20 Permit Solidity Interface](/builders/interoperability/xcm/xc20/interact/#the-erc20-permit-interface){target=\_blank}, except it applies to any EVM call instead of approvals only. When the call permit is dispatched, it is done so on behalf of the user who signed the permit and the user or contract that dispatches the permit is responsible for paying transaction fees. As such, the precompile can be used to perform gas-less transactions. For example, Alice signs a call permit and Bob dispatches it and performs the call on behalf of Alice. Bob pays for the transaction fees and as such, Alice doesn't need to have any of the native currency to pay for the transaction, unless the call includes a transfer. The Call Permit Precompile is located at the following address: === "Moonbeam" ```text {{networks.moonbeam.precompiles.call_permit }} ``` === "Moonriver" ```text {{networks.moonriver.precompiles.call_permit }} ``` === "Moonbase Alpha" ```text {{networks.moonbase.precompiles.call_permit }} ``` !!! note There can be some unintended consequences when using the precompiled contracts on Moonbeam. Please refer to the [Security Considerations](/learn/core-concepts/security/){target=\_blank} page for more information. ## The Call Permit Solidity Interface {: #the-call-permit-interface } [`CallPermit.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/call-permit/CallPermit.sol){target=\_blank} is a Solidity interface that allows developers to interact with the precompile's three methods. The interface includes the following functions: ??? function "**dispatch**(*address* from, *address* to, *uint256* value, *bytes* data, *uint64[]* gaslimit, *uint256* deadline, *uint8* v, *bytes32* r, *bytes32* s) - dispatches a call on the behalf of another user with a EIP-712 permit. This function can be called by anyone or any smart contract. The transaction will revert if the permit is not valid or if the dispatched call reverts or errors (such as out of gas). If successful, the nonce of the signer is increased to prevent this permit to be replayed" === "Parameters" - `from` - address of the signer of the permit. The call will be dispatched on behalf of this address - `to` - address the call is made to - `value` - uint256 value being transferred from the `from` account - `data` - bytes containing the call data, or action to be executed - `gasLimit` - uint64[] gas limit the dispatched call requires. Providing an argument for this parameter prevents the dispatcher from manipulating the gas limit - `deadline` - uint256 time in UNIX seconds after which the permit will no longer be valid. In JavaScript, you can get the current time in UNIX seconds by running `console.log(Date.now())` in a JavaScript script or a browser console - `v` - uint8 recovery ID of the signature. The last one byte of the concatenated signature - `r` - bytes32 first 32 bytes of the concatenated signature - `s` - bytes32 second 32 bytes of the concatenated signature ??? function "**nonces**(*address* owner) - returns the current nonce for given owner" === "Parameters" - `owner` - address of the account to query the nonce for ??? function "**DOMAIN_SEPARATOR**() - returns the EIP-712 domain separator which is used to avoid replay attacks. It follows the [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612#specification){target=\_blank} implementation" === "Parameters" None. The domain separator is defined in the [EIP-712 standard](https://eips.ethereum.org/EIPS/eip-712){target=\_blank} and is calculated as: ```text keccak256(PERMIT_DOMAIN, name, version, chain_id, address) ``` The parameters of the hash can be broken down as follows: - **PERMIT_DOMAIN** - is the `keccak256` of `EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)` - **name** - is the name of the signing domain and must be `'Call Permit Precompile'` exactly - **version** - is the version of the signing domain. For this case **version** is set to `1` - **chainId** - is the chain ID of the network - **verifyingContract** - is the address of the contract that will verify the signature. In this case, the Call Permit Precompile address When `dispatch` is called, the permit needs to be verified before the call is dispatched. The first step is to [compute the domain separator](https://github.com/moonbeam-foundation/moonbeam/blob/ae705bb2e9652204ace66c598a00dcd92445eb81/precompiles/call-permit/src/lib.rs#L138){target=\_blank}. The calculation can be seen in [Moonbeam's implementation](https://github.com/moonbeam-foundation/moonbeam/blob/ae705bb2e9652204ace66c598a00dcd92445eb81/precompiles/call-permit/src/lib.rs#L112-L126){target=\_blank} or you can check out a practical example in [OpenZeppelin's EIP712 contract](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/4a9cc8b4918ef3736229a5cc5a310bdc17bf759f/contracts/utils/cryptography/draft-EIP712.sol#L70-L84){target=\_blank}. From there, a [hash of the signature and the given arguments](https://github.com/moonbeam-foundation/moonbeam/blob/ae705bb2e9652204ace66c598a00dcd92445eb81/precompiles/call-permit/src/lib.rs#L140-L151){target=\_blank} is generated which guarantees that the signature can only be used for the call permit. It uses a given nonce to ensure the signature is not subject to a replay attack. It is similar to [OpenZeppelin's `ERC20Permit` contract](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/4a9cc8b4918ef3736229a5cc5a310bdc17bf759f/contracts/token/ERC20/extensions/draft-ERC20Permit.sol#L52){target=\_blank}, except the `PERMIT_TYPEHASH` is for a call permit, and the arguments match that of the [dispatch function](#:~:text=The interface includes the following functions) plus the nonce. The domain separator and the hash struct can be used to build the [final hash](https://github.com/moonbeam-foundation/moonbeam/blob/ae705bb2e9652204ace66c598a00dcd92445eb81/precompiles/call-permit/src/lib.rs#L153-L157){target=\_blank} of the fully encoded message. A practical example is shown in [OpenZeppelin's EIP712 contract](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/4a9cc8b4918ef3736229a5cc5a310bdc17bf759f/contracts/utils/cryptography/draft-EIP712.sol#L101){target=\_blank}. With the final hash and the v, r, and s values, the signature can be [verified and recovered](https://github.com/moonbeam-foundation/moonbeam/blob/ae705bb2e9652204ace66c598a00dcd92445eb81/precompiles/call-permit/src/lib.rs#L211-L223){target=\_blank}. If successfully verified, the nonce will increase by one and the call will be dispatched. ## Setup the Contracts {: #setup-the-example-contract } For this example, you'll learn how to sign a call permit that updates a message in a simple example contract, [`SetMessage.sol`](#example-contract). Before you can generate the call permit signature, you'll need to deploy the contract and define the `dispatch` function arguments for the call permit. Once you've setup the example contract, then you can setup the Call Permit Precompile contract. ### Checking Prerequisites {: #checking-prerequisites } To follow along with this tutorial, you will need to have: - [MetaMask installed and connected to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank} - Create or have two accounts on Moonbase Alpha to test out the different features in the Call Permit Precompile - At least one of the accounts will need to be funded with `DEV` tokens. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} ### Example Contract {: #example-contract } The `SetMessage.sol` contract will be used as an example of using a call permit, but in practice, any contract can be interacted with. ```solidity // SPDX-License-Identifier: GPL-3.0 pragma solidity 0.8.7; contract SetMessage { string storedMessage; function set(string calldata x) public { storedMessage = x; } function get() public view returns (string memory) { return storedMessage; } } ``` ### Remix Set Up {: #remix-set-up } You can use [Remix](https://remix.ethereum.org){target=\_blank} to compile the example contract and deploy it. You'll need a copy of [`SetMessage.sol`](#example-contract){target=\_blank} and [`CallPermit.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/call-permit/CallPermit.sol){target=\_blank}. To add the contracts to Remix, you can take the following steps: 1. Click on the **File explorer** tab 2. Paste the `SetMessage.sol` contract into a Remix file named `SetMessage.sol` 3. Paste the `CallPermit.sol` contract into a Remix file named `CallPermit.sol` ![Copying and pasting the example contract into Remix](/images/builders/ethereum/precompiles/ux/call-permit/call-1-new.webp) ### Compile & Deploy the Example Contract {: #compile-deploy-example-contract } First you'll need to compile the example contract: 1. Click on the **Compile** tab, second from top 2. Then to compile the interface, click on **Compile SetMessage.sol** ![Compiling SetMessage.sol](/images/builders/ethereum/precompiles/ux/call-permit/call-2.webp) Then you can deploy it: 1. Click on the **Deploy and Run** tab, directly below the **Compile** tab in Remix. Note: you are not deploying a contract here, instead you are accessing a precompiled contract that is already deployed 2. Make sure **Injected Provider - Metamask** is selected in the **ENVIRONMENT** drop down 3. Ensure **SetMessage.sol** is selected in the **CONTRACT** dropdown 4. Click **Deploy** 4. MetaMask will pop up and you'll need to **Confirm** the transaction ![Provide the address](/images/builders/ethereum/precompiles/ux/call-permit/call-3.webp) The contract will appear under the list of **Deployed Contracts** on the left side panel. Copy the contract address as you will need to use it to generate the call permit signature in the next section. ### Compile & Access the Call Permit Precompile {: #compile-access-call-permit } First you'll need to compile the Call Permit Precompile contract: 1. Click on the **Compile** tab, second from top 2. Then to compile the interface, click on **Compile CallPermit.sol** ![Compiling SetMessage.sol](/images/builders/ethereum/precompiles/ux/call-permit/call-4.webp) Then instead of deploying the contract, you'll just need to access it given the address of the precompile: 1. Click on the **Deploy and Run** tab, directly below the **Compile** tab in Remix. Note: you are not deploying a contract here, instead you are accessing a precompiled contract that is already deployed 2. Make sure **Injected Provider - Metamask** is selected in the **ENVIRONMENT** drop down 3. Ensure **CallPermit.sol** is selected in the **CONTRACT** dropdown. Since this is a precompiled contract there is no need to deploy, instead you are going to provide the address of the precompile in the **At Address** field 4. Provide the address of the Call Permit Precompile for Moonbase Alpha: `{{networks.moonbase.precompiles.call_permit}}` and click **At Address** 5. The Call Permit Precompile will appear in the list of **Deployed Contracts** ![Provide the address](/images/builders/ethereum/precompiles/ux/call-permit/call-5.webp) ## Generate Call Permit Signature {: #generate-call-permit-signature} In order to interact with the Call Permit Precompile, you have to have or generate a signature to dispatch the call permit with. There are several ways you can generate the signature, this guide will show you two different ways to generate it: in the browser using the [MetaMask extension](https://chromewebstore.google.com/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn){target=\_blank} and [JSFiddle](https://jsfiddle.net){target=\_blank} and using MetaMask's [`@metamask/eth-sig-util` npm package](https://www.npmjs.com/package/@metamask/eth-sig-util){target=\_blank}. Regardless of which method you choose to generate the signature, the following steps will be taken: 1. The `message` will be created and includes some of the data that is needed to create the call permit. It includes the arguments that will be passed into the `dispatch` function and the nonce of the signer 2. A JSON structure of the data the user needs to sign will be assembled for the call permit and include all of the types for the `dispatch` arguments and the nonce. This will result in the `CallPermit` type and will be saved as the `primaryType` 3. The domain separator will be created using `"Call Permit Precompile"` exactly for the name, the version of your DApp or platform, the chain ID of the network the signature is to be used on, and the address of the contract that will verify the signature 4. All of the assembled data, the `types`, `domain`, `primaryType` and `message`, will be signed using MetaMask (either in the browser or through the MetaMask's JavaScript signing library) 5. The signature will be returned and you can use [Ethers.js](https://docs.ethers.org/v6){target=\_blank} [`Signature.from` method](https://docs.ethers.org/v6/api/crypto/#Signature_from){target=\_blank} to return the `v`, `r`, and `s` values of the signature ### The Call Permit Arguments {: #call-permit-arguments } As seen in the [Call Permit Interface](#the-call-permit-interface) section, the `dispatch` function takes the following parameters: `from`, `to`, `value`, `data`, `gasLimit`, `deadline`, `v`, `r`, and `s`. In order to get the signature arguments (`v`, `r`, and `s`), you'll need to sign a message containing the arguments for the remainder of the aforementioned parameters, plus the nonce of the signer. - `from` - the address of the account you want to sign the call permit with - `to` - the contract address for the `SetMessage.sol` contract - `value` - can be `0` for this example as you'll just be setting a message instead of transferring any funds - `data` - you can send any message you would like, you'll just need the hex representation of the message you want to set using the `SetMessage.sol` contract. This will contain the function selector of the `set` function and the string of the message. For this example, you can send `hello world`. To do so, you can use this hex representation: ```text 0x4ed3885e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000 ``` - `gasLimit` - `100000` will be enough to send the dispatched call - `deadline` - you can get the current time in UNIX seconds by running `console.log(Date.now())` in a JavaScript script or a browser console. Once you have the current time, you can add additional time in seconds to represent when the call permit will expire The nonce of the signer will also be needed. If this is your first time signing a call permit the nonce will be `0`. You can also check the nonce in Remix: 1. Expand the call permit contract 2. Next to the **nonces** function, enter the address of the signer and click on **nonces** 3. The result will be returned directly under the function ![Get the nonce](/images/builders/ethereum/precompiles/ux/call-permit/call-6.webp) ### Use the Browser {: #use-the-browser } To get started, you can open [JSFiddle](https://jsfiddle.net){target=\_blank} or another JavaScript playground in the browser. First, you'll need to add [Ethers.js](/builders/ethereum/libraries/ethersjs/){target=\_blank} as it will be used to get the `v`, `r`, and `s` values of the signature: 1. Click on **Resources** 2. Start to type in `ethers` and the dropdown should populate matching libraries. Choose **ethers** 3. Click on the **+** button The CDN for Ethers.js will appear in the list of libraries under **Resources**. ![Add Ethers to JSFiddle](/images/builders/ethereum/precompiles/ux/call-permit/call-7.webp) In the **Javascript** code box, copy and paste the following JavaScript snippet, making sure to replace the `to` variables (and any other variables as you see fit): ```js const main = async () => { await window.ethereum.enable(); const accounts = await window.ethereum.request({ method: 'eth_requestAccounts', }); const from = accounts[0]; const to = 'INSERT_TO_ADDRESS'; const value = 0; const data = '0x4ed3885e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000'; const gaslimit = 100000; const nonce = 'INSERT_SIGNERS_NONCE'; const deadline = 'INSERT_DEADLINE'; const createPermitMessageData = function () { const message = { from: from, to: to, value: value, data: data, gaslimit: gaslimit, nonce: nonce, deadline: deadline, }; const typedData = JSON.stringify({ types: { EIP712Domain: [ { name: 'name', type: 'string', }, { name: 'version', type: 'string', }, { name: 'chainId', type: 'uint256', }, { name: 'verifyingContract', type: 'address', }, ], CallPermit: [ { name: 'from', type: 'address', }, { name: 'to', type: 'address', }, { name: 'value', type: 'uint256', }, { name: 'data', type: 'bytes', }, { name: 'gaslimit', type: 'uint64', }, { name: 'nonce', type: 'uint256', }, { name: 'deadline', type: 'uint256', }, ], }, primaryType: 'CallPermit', domain: { name: 'Call Permit Precompile', version: '1', chainId: 1287, verifyingContract: '0x000000000000000000000000000000000000080a', }, message: message, }); return { typedData, message, }; }; const method = 'eth_signTypedData_v4'; const messageData = createPermitMessageData(); const params = [from, messageData.typedData]; web3.currentProvider.sendAsync( { method, params, from, }, function (err, result) { if (err) return console.dir(err); if (result.error) { alert(result.error.message); return console.error('ERROR', result); } console.log('Signature:' + JSON.stringify(result.result)); const ethersSignature = ethers.Signature.from(result.result); const formattedSignature = { r: ethersSignature.r, s: ethersSignature.s, v: ethersSignature.v, }; console.log(formattedSignature); } ); }; main(); ``` To run the code, click **Run** at the top of the page (or you can also use `control` and `s`). MetaMask should pop up and prompt you to connect an account. Make sure to choose the account you want to sign the message with. Then go ahead and sign the message. ![Sign the message with MetaMask](/images/builders/ethereum/precompiles/ux/call-permit/call-8.webp) Once you've signed the message, go back to JSFiddle and if the console isn't already open, go ahead and open it to see the signature values include the `v`, `r`, and `s`, values. Copy these values as you'll need them when interacting with the Call Permit Precompile in the following sections. ![Signature values in the JSFiddle console](/images/builders/ethereum/precompiles/ux/call-permit/call-9.webp) ### Use MetaMask's JS Signing Library {: #use-metamasks-signing-library } To generate the call permit signature using JavaScript and MetaMask's [`@metamask/eth-sig-util` npm package](https://www.npmjs.com/package/@metamask/eth-sig-util){target=\_blank}, you'll first need to create a project locally. You can do so with the following commands: ```bash mkdir call-permit-example && cd call-permit-example && touch getSignature.js npm init -y ``` You should now have a file where you can create the script to get the signature along with a `package.json` file. Open the `package.json` file, and below the `"dependencies"` section, add: ```json "type": "module" ``` Next, you can install the MetaMask signing library and [Ethers.js](https://docs.ethers.org/v6){target=\_blank}: ```bash npm i @metamask/eth-sig-util ethers ``` !!! note Never reveal your private keys as they give direct access to your funds. The following steps are for demonstration purposes only. In the `getSignature.js` file, you can copy the following code snippet: ```js import { ethers } from 'ethers'; import { signTypedData, SignTypedDataVersion } from '@metamask/eth-sig-util'; const from = 'INSERT_FROM_ADDRESS'; const to = 'INSERT_TO_ADDRESS'; const value = 0; const data = '0x4ed3885e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000'; const gaslimit = 100000; const nonce = 'INSERT_SIGNERS_NONCE'; const deadline = 'INSERT_DEADLINE'; const createPermitMessageData = () => { const message = { from: from, to: to, value: value, data: data, gaslimit: gaslimit, nonce: nonce, deadline: deadline, }; const typedData = { types: { EIP712Domain: [ { name: 'name', type: 'string' }, { name: 'version', type: 'string' }, { name: 'chainId', type: 'uint256' }, { name: 'verifyingContract', type: 'address' }, ], CallPermit: [ { name: 'from', type: 'address' }, { name: 'to', type: 'address' }, { name: 'value', type: 'uint256' }, { name: 'data', type: 'bytes' }, { name: 'gaslimit', type: 'uint64' }, { name: 'nonce', type: 'uint256' }, { name: 'deadline', type: 'uint256' }, ], }, primaryType: 'CallPermit', domain: { name: 'Call Permit Precompile', version: '1', chainId: 1287, verifyingContract: '0x000000000000000000000000000000000000080a', }, message: message, }; return { typedData, message, }; }; const messageData = createPermitMessageData(); // For demo purposes only. Never store your private key in a JavaScript/TypeScript file const signature = signTypedData({ privateKey: Buffer.from('INSERT_FROM_ACCOUNT_PRIVATE_KEY', 'hex'), data: messageData.typedData, version: SignTypedDataVersion.V4, }); console.log(`Transaction successful with hash: ${signature}`); const ethersSignature = ethers.Signature.from(signature); const formattedSignature = { r: ethersSignature.r, s: ethersSignature.s, v: ethersSignature.v, }; console.log(formattedSignature); ``` To run the script, use the following command: ```bash node getSignature.js ``` In the console, you should see the concatenated signature along with the values for the signature including the `v`, `r`, and `s` values. Copy these values as you'll need them when interacting with the Call Permit Precompile in the following sections. ![Signature values in the console](/images/builders/ethereum/precompiles/ux/call-permit/call-10.webp) ## Interact with the Solidity Interface {: #interact-with-the-solidity-interface } Now that you have generated the call permit signature you will be able to test out calling the `dispatch` function of the Call Permit Precompile. ### Dispatch a Call {: #dispatch-a-call } When you send the `dispatch` function, you'll need the same arguments as you used to sign the call permit. To get started, go back to the **Deploy and Run** tab in Remix and under the **Deployed Contracts** section expand the call permit contract. Make sure that you're connected to the account that you want to consume the call permit and pay the transaction fees with. Then take the following steps: 1. For the **from** field, enter the account address you used to sign the call permit with 2. Copy and paste the contract address of `SetMessage.sol` 3. Enter `0` for the **value** field 4. Enter the hex representation of the function selector for the `set` function and the string you want to set as the message for the `SetMessage.sol` contract. For this example, `hello world` can be used: ```text 0x4ed3885e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000 ``` 5. Enter `100000` for the **gasLimit** field 6. Enter the `deadline` you used when signing the call permit 7. Copy the `v` value you should have retrieved while generating the call permit signature and paste it into the **v** field 8. Copy the `r` value you should have retrieved while generating the call permit signature and paste it into the **r** field 9. Copy the `s` value you should have retrieved while generating the call permit signature and paste it into the **s** field 10. Click **transact** to send the transaction 11. MetaMask should pop-up and you can confirm the transaction ![Dispatch the call permit](/images/builders/ethereum/precompiles/ux/call-permit/call-11.webp) Once the transaction goes through, you can verify that the message was updated to `hello world`. To do so, you can: 1. Expand the `SetMessage.sol` contract 2. Click on **get** 3. The result will appear below the function, and it should show `hello world` ![Verify the dispatch was executed as intended](/images/builders/ethereum/precompiles/ux/call-permit/call-12.webp) Congratulations! You've successfully generated a call permit signature and used it to dispatch a call on behalf of the call permit signer. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/ux/erc20/ --- BEGIN CONTENT --- --- title: Native Token ERC-20 Precompile description: Learn how to access and interact with an ERC-20 representation of the native token on Moonbeam through the precompiled ERC-20 Interface. keywords: solidity, ethereum, native, token, moonbeam, precompiled, contracts categories: Precompiles, Ethereum Toolkit --- # Native Token ERC-20 Precompile ## Introduction {: #introduction } The native token ERC-20 precompiled contract on Moonbeam allows developers to interact with the native protocol token through an ERC-20 interface. Although GLMR and MOVR are not ERC-20 tokens, now you can interact with them as if they were native ERC-20s! One of the main benefits of this precompile is that it removes the necessity of having a wrapped representation of the protocol token as an ERC-20 smart contract, such as WETH on Ethereum. Furthermore, it prevents having multiple wrapped representations of the same protocol token. Consequently, DApps that need to interact with the protocol token via an ERC-20 interface can do so without needing a separate smart contract. Under the hood, the [ERC-20 precompile](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/balances-erc20/src/lib.rs){target=\_blank} executes specific Substrate actions related to the Substrate balances pallet, which is coded in Rust. The balances pallet provides functionality for handling the [various types of balances on Moonbeam](/learn/core-concepts/balances/#moonbeam-account-balances){target=\_blank}, setting the free balance, transferring balances, and more. This guide will show you how to interact with DEV tokens, the native protocol tokens for the Moonbase Alpha TestNet, via the ERC-20 precompile. You can also follow and adapt this guide to learn how to use GLMR or MOVR as an ERC-20 token. The precompile is located at the following address: === "Moonbeam" ```text {{networks.moonbeam.precompiles.erc20 }} ``` === "Moonriver" ```text {{networks.moonriver.precompiles.erc20 }} ``` === "Moonbase Alpha" ```text {{networks.moonriver.precompiles.erc20 }} ``` !!! note There can be some unintended consequences when using the precompiled contracts on Moonbeam. Please refer to the [Security Considerations](/learn/core-concepts/security/){target=\_blank} page for more information. ## The ERC-20 Solidity Interface {: #the-erc20-interface } The [`ERC20.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/balances-erc20/ERC20.sol){target=\_blank} interface on Moonbeam follows the [EIP-20 Token Standard](https://eips.ethereum.org/EIPS/eip-20){target=\_blank} which is the standard API interface for tokens within smart contracts. The standard defines the required functions and events that a token contract must implement to be interoperable with different applications. The interface includes the following functions: ??? function "**name**() - read-only function that returns the name of the token" === "Parameters" None. ??? function "**symbol**() - read-only function that returns the symbol of the token" === "Parameters" None. ??? function "**decimals**() - read-only function that returns the decimals of the token" === "Parameters" None. ??? function "**totalSupply**() - read-only function that returns the total number of tokens in existence" === "Parameters" None. ??? function "**balanceOf**(*address* who) - read-only function that returns the balance of the specified address" === "Parameters" - `who` - address of the account to query the balance of ??? function "**allowance**(*address* owner, *address* spender) - read-only function that checks and returns the amount of tokens that a spender is allowed to spend on behalf of the owner" === "Parameters" - `owner` - address of the account that owns the tokens - `spender` - address of the account allowed to spend the tokens ??? function "**transfer**(*address* to, *uint256* value) - transfers a given amount of tokens to a specified address and returns `true` if the transfer was successful" === "Parameters" - `to` - address of the recipient - `value` - uint256 amount of tokens to transfer ??? function "**approve**(*address* spender, *uint256* value) - approves the provided address to spend a specified amount of tokens on behalf of `msg.sender`. Returns `true` if successful" === "Parameters" - `spender` - address to be approved to spend the tokens - `value` - uint256 amount of tokens to be approved for spending ??? function "**transferFrom**(*address* from, *address* to, *uint256* value) - transfers tokens from one given address to another given address and returns `true` if successful" === "Parameters" - `from` - address to transfer tokens from - `to` - address to transfer tokens to - `value` - uint256 amount of tokens to transfer !!! note The ERC-20 standard does not specify the implications of multiple calls to `approve`. Changing an allowance with this function numerous times enables a possible attack vector. To avoid incorrect or unintended transaction ordering, you can first reduce the `spender` allowance to `0` and then set the desired allowance afterward. For more details on the attack vector, you can check out the [ERC-20 API: An Attack Vector on Approve/TransferFrom Methods](https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/edit#){target=\_blank} overview. The interface also includes the following required events: - **Transfer**(*address indexed* from, *address indexed* to, *uint256* value) - emitted when a transfer has been performed - **Approval**(*address indexed* owner, *address indexed* spender, *uint256* value) - emitted when an approval has been registered !!! note The ERC-20 precompile does not include `deposit` and `withdraw` functions and subsequent events that are expected from a wrapped token contract, such as WETH. ## Interact with the Solidity Interface {: #interact-with-the-solidity-interface } ### Checking Prerequisites {: #checking-prerequisites } To follow along with this tutorial, you will need to have: - [MetaMask installed and connected to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank} - Create or have two accounts on Moonbase Alpha to test out the different features in the ERC-20 precompile - At least one of the accounts will need to be funded with `DEV` tokens. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} ### Add Token to MetaMask {: #add-token-to-metamask } If you want to interact with Moonbase Alpha DEV tokens like you would with an ERC-20 in MetaMask, you can create a custom token using the precompile address. To get started, open up MetaMask and make sure you are [connected to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank} and: 1. Switch to the **Assets** tab 2. Click on **Import tokens** ![Import Tokens from Assets Tab in MetaMask](/images/builders/ethereum/precompiles/ux/erc20/erc20-1.webp) Now, you can create a custom token: 1. Enter the precompile address for the token contract address - `{{networks.moonbase.precompiles.erc20 }}`. As soon as you enter the address, the **Token Symbol** and **Token Decimal** fields should automatically populate. If they don't you can enter `DEV` for the symbol and `18` for the decimal places 2. Click **Add Custom Token** ![Add Custom Token](/images/builders/ethereum/precompiles/ux/erc20/erc20-2.webp) MetaMask will prompt you to import the tokens. You can review the token details and click **Import Tokens** to import DEV tokens into your wallet. ![Confirm and Import Tokens](/images/builders/ethereum/precompiles/ux/erc20/erc20-3.webp) And that's it! You've successfully added the DEV token as a custom ERC-20 token on the Moonbase Alpha TestNet. ### Remix Set Up {: #remix-set-up } You can interact with the ERC-20 precompile using [Remix](https://remix.ethereum.org){target=\_blank}. To add the precompile to Remix, you will need to: 1. Get a copy of [`ERC20.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/balances-erc20/ERC20.sol){target=\_blank} 2. Paste the file contents into a Remix file named `IERC20.sol` ### Compile the Contract {: #compile-the-contract } Next, you will need to compile the interface in Remix: 1. Click on the **Compile** tab, second from top 2. Compile the interface by clicking on **Compile IERC20.sol** ![Compiling IERC20.sol](/images/builders/ethereum/precompiles/ux/erc20/erc20-4.webp) If the interface was compiled successfully, you will see a green checkmark next to the **Compile** tab. ### Access the Contract {: #access-the-contract } Instead of deploying the ERC-20 precompile, you will access the interface given the address of the precompiled contract: 1. Click on the **Deploy and Run** tab directly below the **Compile** tab in Remix. Please note the precompiled contract is already deployed 2. Make sure **Injected Web3** is selected in the **ENVIRONMENT** dropdown. Once you select **Injected Web3**, you might be prompted by MetaMask to connect your account to Remix 3. Make sure the correct account is displayed under **ACCOUNT** 4. Ensure **IERC20 - IERC20.sol** is selected in the **CONTRACT** dropdown. Since this is a precompiled contract, there is no need to deploy any code. Instead you are going to provide the address of the precompile in the **At Address** field 5. Provide the address of the ERC-20 precompile: `{{networks.moonbase.precompiles.erc20}}` and click **At Address** ![Access the address](/images/builders/ethereum/precompiles/ux/erc20/erc20-5.webp) The **IERC20** precompile will appear in the list of **Deployed Contracts**. ### Get Basic Token Information {: #get-basic-token-information } The ERC-20 interface allows you to quickly obtain token information, including the token's total supply, name, symbol, and decimal places. You can get this information by following these steps: 1. Expand the **IERC20** contract under **Deployed Contracts** 2. Click **decimals** to get the decimal places of the Moonbase Alpha native protocol token 3. Click **name** to get the name of the token 4. Click **symbol** to get the symbol of the token 5. Click **totalSupply** to obtain the total supply of tokens in existence on Moonbase Alpha ![Total Supply](/images/builders/ethereum/precompiles/ux/erc20/erc20-6.webp) The response for each call will be displayed under the corresponding function. ### Get Account Balance {: #get-account-balance } You can check the balance of any address on Moonbase Alpha by calling the `balanceOf` function and passing in an address: 1. Expand the **balanceOf** function 2. Enter an address you would like to check the balance of for the **owner** 2. Click **call** ![Get Balance of an Account](/images/builders/ethereum/precompiles/ux/erc20/erc20-7.webp) Your balance will be displayed under the `balanceOf` function. ### Approve a Spend {: #approve-a-spend } To approve a spend, you'll need to provide an address for the spender and the number of tokens that the spender is allowed to spend. The spender can be an externally owned account or a smart contract. For this example, you can approve the spender to spend 1 DEV token. To get started, please follow these steps: 1. Expand the **approve** function 2. Enter the address of the spender. You should have created two accounts before starting, so you can use the second account as the spender 3. Enter the amount of tokens the spender can spend for the **value**. For this example, you can allow the spender to spend 1 DEV token in Wei units (`1000000000000000000`) 4. Click **transact** 5. MetaMask will pop up, and you will be prompted to review the transaction details. Click **View full transaction details** to review the amount to be sent and the address of the spender 6. If everything looks ok, you can click **Confirm** to send the transaction ![Confirm Approve Transaction](/images/builders/ethereum/precompiles/ux/erc20/erc20-8.webp) After the transaction has successfully gone through, you'll notice that the balance of your account hasn't changed. This is because you have only approved the spend for the given amount, and the spender hasn't spent the funds. In the next section, you will use the `allowance` function to verify that the spender is able to spend 1 DEV token on your behalf. ### Get Allowance of Spender {: #get-allowance-of-spender } To check that the spender received the allowance approved in the [Approve a Spend](#approve-a-spend) section, you can: 1. Expand the **allowance** function 2. Enter your address for the **owner** 3. Enter the address of the **spender** that you used in the previous section 4. Click **call** ![Get Allowance of Spender](/images/builders/ethereum/precompiles/ux/erc20/erc20-9.webp) Once the call is complete, the allowance of the spender will be displayed, which should be equivalent to 1 DEV token (`1000000000000000000`). ### Send Transfer {: #send-transfer } To do a standard transfer and send tokens from your account directly to another account, you can call the `transfer` function by following these steps: 1. Expand the **transfer** function 2. Enter the address to send DEV tokens to. You should have created two accounts before starting, so you can use the second account as the recipient 3. Enter the amount of DEV tokens to send. For this example, you can send 1 DEV token (`1000000000000000000`) 4. Click **transact** 5. MetaMask will pop up, you can review the transaction details, and if everything looks good, click **Confirm** ![Send Standard Transfer](/images/builders/ethereum/precompiles/ux/erc20/erc20-10.webp) Once the transaction is complete, you can [check your balance](#get-account-balance) using the `balanceOf` function or by looking at MetaMask, and notice that this time your balance decreased by 1 DEV token. You can also use the `balanceOf` function to ensure that the recipients balance has increased by 1 DEV token as expected. ### Send Transfer From Specific Account {: #send-transferfrom } So far, you should have approved an allowance of 1 DEV token for the spender and sent 1 DEV token via the standard `transfer` function. The `transferFrom` function varies from the standard `transfer` function as it allows you to define the address to which you want to send the tokens. So you can specify an address that has an allowance or your address as long as you have funds. For this example, you will use the spender's account to initiate a transfer of the allowed funds from the owner to the spender. The spender can send the funds to any account, but you can send the funds from the owner to the spender for this example. First, you need to switch to the spender's account in MetaMask. Once you switch to the spender's account, you'll notice that the selected address in Remix under the **Accounts** tab is now the spender's. ![Switch accounts Remix](/images/builders/ethereum/precompiles/ux/erc20/erc20-11.webp) Next, you can initiate and send the transfer, to do so: 1. Expand the **transferFrom** function 2. Enter your address as the owner in the **from** field 3. Enter the recipient address, which should be the spender's address, in the **to** field 4. Enter the amount of DEV tokens to send. Again, the spender is currently only allowed to send 1 DEV token, so enter `1000000000000000000` 5. Click **transact** ![Send Standard Transfer](/images/builders/ethereum/precompiles/ux/erc20/erc20-12.webp) Once the transaction is complete, you can [check the balance](#get-account-balance) of the owner and spender using the `balanceOf` function. The spender's balance should have increased by 1 DEV token, and their allowance should now be depleted. To verify that the spender no longer has an allowance, you can call the `allowance` function, passing in the owner and spender's addresses. You should receive a result of 0. ![Zero Allowance](/images/builders/ethereum/precompiles/ux/erc20/erc20-13.webp) And that's it! You've successfully interacted with the ERC-20 precompile using MetaMask and Remix! --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/precompiles/ux/ --- BEGIN CONTENT --- --- title: Improve User Experience with Precompiles description: Enhance the user experience on Moonbeam with precompiled contracts that allow seamless batch transactions and gasless operations for a smoother workflow. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/verify-contracts/api-verification/ --- BEGIN CONTENT --- --- title: Verify Smart Contracts through APIs description: Learn how to verify smart contracts on Moonbeam-based networks using one of the available API-based verification methods. categories: Ethereum Toolkit --- # API-based Contract Verification ## Introduction {: #introduction } Verifying smart contracts greatly improves their transparency and security. Smart contracts deployed on Moonbeam networks can be verified through API-based tools, including Moonscan API and Sourcify. This page will outline the steps for using these API-based tools for verifying smart contracts, or retrieving verification status and metadata of smart contracts on Moonbeam networks. ## Using Moonscan API {: #using-moonscan-api } [Moonscan](https://moonscan.io){target=\_blank} is an official fork of Etherscan that can be used to view and search on-chain data, and comes with a suite of developer tools and analytics to interact with data on Moonbeam networks. The [Etherscan API](https://docs.etherscan.io){target=\_blank} provides a variety of endpoints for verifying smart contracts, retrieving verified contract ABI and source code, and interacting with verified contracts on Moonbeam networks. ### Generating an Etherscan API Key {: #generating-an-etherscan-api-key } Before using the Moonscan API, you need to generate an Etherscan API key. Please follow the instructions in [the key generation section](/builders/ethereum/verify-contracts/etherscan-plugins/#generating-an-etherscan-api-key){target=\_blank} of the Etherscan plug-in verification page, as the API keys generated are used for both. ### Moonscan Public API URL {: #moonscan-public-api-url } The Moonscan API URL for Moonbeam networks is as follows: === "Moonbeam" ```text https://api-moonbeam.moonscan.io/api ``` === "Moonriver" ```text https://api-moonriver.moonscan.io/api ``` === "Moonbase Alpha" ```text https://api-moonbase.moonscan.io/api ``` ### Verify Source Code {: #verify-source-code } To verify a deployed contract's source code using the Moonscan API, you must form a POST request containing all the relevant contract creation information, and send the request to Moonscan's REST API. The following is sample code using JavaScript and [Axios](https://axios-http.com/docs/intro){target=\_blank}, an HTTP client: === "Moonbeam" ```javascript // Submit Source Code for Verification const response = await axios.post( 'https://api-moonbeam.moonscan.io/api', { apikey: 'INSERT_API_KEY', module: 'contract', action: 'verifysourcecode', contractAddress: 'INSERT_CONTRACT_ADDRESS', sourceCode: 'INSERT_SOURCE_CODE', // flattened if necessary codeformat: 'solidity-single-file', // or you can use "solidity-standard-json-input" contractname: 'INSERT_CONTRACT_NAME', // if codeformat = solidity-standard-json-input, then enter contractname as ex: erc20.sol:erc20 compilerversion: 'INSERT_COMPILER_VERSION', // see https://etherscan.io/solcversions for list of support versions optimizationUsed: 0, // 0 = no optimization, 1 = optimization was used (applicable when codeformat=solidity-single-file) runs: 200, // set to 200 as default unless otherwise (applicable when codeformat=solidity-single-file) constructorArguments: 'INSERT_CONSTRUCTOR_ARGUMENTS', // if applicable evmversion: 'INSERT_EVM_VERSION', // options: homestead, tangerineWhistle, spuriousDragon, byzantium, constantinople, petersburg, istanbul (applicable when codeformat=solidity-single-file) licenseType: 1, // valid codes 1-14 where 1=No License ... 14=Business Source License 1.1, see https://etherscan.io/contract-license-types libraryname1: 'INSERT_LIBRARY_NAME', // if applicable, enter the name of the first library used, i.e. SafeMath (up to 10 libraries can be used) libraryaddress1: 'INSERT_LIBRARY_ADDRESS', // if applicable, enter the address of the first library used libraryname2: 'INSERT_LIBRARY_NAME', // if applicable, enter the name of the second library used libraryaddress2: 'INSERT_LIBRARY_ADDRESS', // if applicable, enter the address of the second library used // ... }, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } ); if (response.data.status == '1') { // 1 = submission success, use the guid returned (response.data.result) to check the status of your submission // average time of processing is 30-60 seconds console.log( response.data.status + '; ' + response.data.message + '; ' + response.data.result ); // response.data.result is the GUID receipt for the submission, you can use this guid for checking the verification status } else { // 0 = error console.log( response.data.status + '; ' + response.data.message + '; ' + response.data.result ); } ``` === "Moonriver" ```javascript // Submit Source Code for Verification const response = await axios.post( 'https://api-moonriver.moonscan.io/api', { apikey: 'INSERT_API_KEY', module: 'contract', action: 'verifysourcecode', contractAddress: 'INSERT_CONTRACT_ADDRESS', sourceCode: 'INSERT_SOURCE_CODE', // flattened if necessary codeformat: 'solidity-single-file', // or you can use "solidity-standard-json-input" contractname: 'INSERT_CONTRACT_NAME', // if codeformat = solidity-standard-json-input, then enter contractname as ex: erc20.sol:erc20 compilerversion: 'INSERT_COMPILER_VERSION', // see https://etherscan.io/solcversions for list of support versions optimizationUsed: 0, // 0 = no optimization, 1 = optimization was used (applicable when codeformat=solidity-single-file) runs: 200, // set to 200 as default unless otherwise (applicable when codeformat=solidity-single-file) constructorArguments: 'INSERT_CONSTRUCTOR_ARGUMENTS', // if applicable evmversion: 'INSERT_EVM_VERSION', // options: homestead, tangerineWhistle, spuriousDragon, byzantium, constantinople, petersburg, istanbul (applicable when codeformat=solidity-single-file) licenseType: 1, // valid codes 1-14 where 1=No License ... 14=Business Source License 1.1, see https://etherscan.io/contract-license-types libraryname1: 'INSERT_LIBRARY_NAME', // if applicable, enter the name of the first library used, i.e. SafeMath (up to 10 libraries can be used) libraryaddress1: 'INSERT_LIBRARY_ADDRESS', // if applicable, enter the address of the first library used libraryname2: 'INSERT_LIBRARY_NAME', // if applicable, enter the name of the second library used libraryaddress2: 'INSERT_LIBRARY_ADDRESS', // if applicable, enter the address of the second library used // ... }, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } ); if (response.data.status == '1') { // 1 = submission success, use the guid returned (response.data.result) to check the status of your submission // average time of processing is 30-60 seconds console.log( response.data.status + '; ' + response.data.message + '; ' + response.data.result ); // response.data.result is the GUID receipt for the submission, you can use this guid for checking the verification status } else { // 0 = error console.log( response.data.status + '; ' + response.data.message + '; ' + response.data.result ); } ``` === "Moonbase Alpha" ```javascript // Submit Source Code for Verification const response = await axios.post( 'https://api-moonbase.moonscan.io/api', { apikey: 'INSERT_API_KEY', module: 'contract', action: 'verifysourcecode', contractAddress: 'INSERT_CONTRACT_ADDRESS', sourceCode: 'INSERT_SOURCE_CODE', // flattened if necessary codeformat: 'solidity-single-file', // or you can use "solidity-standard-json-input" contractname: 'INSERT_CONTRACT_NAME', // if codeformat = solidity-standard-json-input, then enter contractname as ex: erc20.sol:erc20 compilerversion: 'INSERT_COMPILER_VERSION', // see https://etherscan.io/solcversions for list of support versions optimizationUsed: 0, // 0 = no optimization, 1 = optimization was used (applicable when codeformat=solidity-single-file) runs: 200, // set to 200 as default unless otherwise (applicable when codeformat=solidity-single-file) constructorArguments: 'INSERT_CONSTRUCTOR_ARGUMENTS', // if applicable evmversion: 'INSERT_EVM_VERSION', // options: homestead, tangerineWhistle, spuriousDragon, byzantium, constantinople, petersburg, istanbul (applicable when codeformat=solidity-single-file) licenseType: 1, // valid codes 1-14 where 1=No License ... 14=Business Source License 1.1, see https://etherscan.io/contract-license-types libraryname1: 'INSERT_LIBRARY_NAME', // if applicable, enter the name of the first library used, i.e. SafeMath (up to 10 libraries can be used) libraryaddress1: 'INSERT_LIBRARY_ADDRESS', // if applicable, enter the address of the first library used libraryname2: 'INSERT_LIBRARY_NAME', // if applicable, enter the name of the second library used libraryaddress2: 'INSERT_LIBRARY_ADDRESS', // if applicable, enter the address of the second library used // ... }, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } ); if (response.data.status == '1') { // 1 = submission success, use the guid returned (response.data.result) to check the status of your submission // average time of processing is 30-60 seconds console.log( response.data.status + '; ' + response.data.message + '; ' + response.data.result ); // response.data.result is the GUID receipt for the submission, you can use this guid for checking the verification status } else { // 0 = error console.log( response.data.status + '; ' + response.data.message + '; ' + response.data.result ); } ``` Upon successful submission, a GUID will be returned as a part of the result. This GUID can be used to check for the submission status. === "Moonbeam" ```bash curl https://api-moonbeam.moonscan.io/api ?module=contract &action=checkverifystatus &guid=INSERT_GUID_FROM_RESPONSE &apikey=INSERT_API_KEY ``` === "Moonriver" ```bash curl https://api-moonriver.moonscan.io/api ?module=contract &action=checkverifystatus &guid=INSERT_GUID_FROM_RESPONSE &apikey=INSERT_API_KEY ``` === "Moonbase Alpha" ```bash curl https://api-moonbase.moonscan.io/api ?module=contract &action=checkverifystatus &guid=INSERT_GUID_FROM_RESPONSE &apikey=INSERT_API_KEY ``` ### Retrieve Contract ABI for Verified Contracts {: #retrieve-contract-abi-for-verified-contracts } Once your contract is verified on Moonscan, you can use the following endpoint to retrieve the contract ABI: === "Moonbeam" ```bash curl https://api-moonbeam.moonscan.io/api ?module=contract &action=getabi &address=INSERT_CONTRACT_ADDRESS &apikey=INSERT_API_KEY ``` === "Moonriver" ```bash curl https://api-moonriver.moonscan.io/api ?module=contract &action=getabi &address=INSERT_CONTRACT_ADDRESS &apikey=INSERT_API_KEY ``` === "Moonbase Alpha" ```bash curl https://api-moonbase.moonscan.io/api ?module=contract &action=getabi &address=INSERT_CONTRACT_ADDRESS &apikey=INSERT_API_KEY ``` ### Retrieve Contract Source Code for Verified Contracts {: #retrieve-contract-source-code-for-verified-contracts } Once your contract is verified on Moonscan, you can use the following endpoint to retrieve the contract source code: === "Moonbeam" ```bash curl https://api-moonbeam.moonscan.io/api ?module=contract &action=getsourcecode &address=INSERT_CONTRACT_ADDRESS &apikey=INSERT_API_KEY ``` === "Moonriver" ```bash curl https://api-moonriver.moonscan.io/api ?module=contract &action=getsourcecode &address=INSERT_CONTRACT_ADDRESS &apikey=INSERT_API_KEY ``` === "Moonbase Alpha" ```bash curl https://api-moonbase.moonscan.io/api ?module=contract &action=getsourcecode &address=INSERT_CONTRACT_ADDRESS &apikey=INSERT_API_KEY ``` ## Using Sourcify API {: #using-sourcify-api } [Sourcify](https://sourcify.dev){target=\_blank} is a multi-chain decentralized automated contract verification service, and maintains a public repository of contract metadata. Sourcify also provides a public server API for verification, and checking if a contract is verified, and a repository API for retrieving metadata files. ### Sourcify Public Server URL {: #sourcify-public-server-url } Soucify API endpoints can be accessed through the following public servers: === "Production" ```text https://sourcify.dev/server ``` === "Staging" ```text https://staging.sourcify.dev/server ``` ### Moonbeam Network Chain ID's {: #moonbeam-network-chain-ids } Sourcify uses chain ID's to identify the target network(s) for the request. The chain ID's of Moonbeam networks are as follows: === "Moonbeam" ```text {{ networks.moonbeam.chain_id }} ``` === "Moonriver" ```text {{ networks.moonriver.chain_id }} ``` === "Moonbase Alpha" ```bash {{ networks.moonbase.chain_id }} ``` ### Perfect vs. Partial Match {: #full-vs-partial-match } Sourcify supports two types of verification match results. Full matches (sometimes referred as perfect matches) refer to the cases when the bytecode of the deployed contract is byte-by-byte the same as compilation output of the given source code files under the compilation settings defined in the metadata file. Partial matches refer to cases when the deployed bytecode of the onchain contract match the bytecode resulting from the recompilation with the metadata and the source files except the metadata hash. For partial matches, the deployed contract and the given source code and metadata are functionally the same, but there are differences in source code comments, variable names, or other metadata fields such as source paths. ### Verify Contract {: #verify-contract } A POST request is used to verify a contract on Sourcify. The following is sample code using JavaScript: === "Moonbeam" ```javascript // Submit Contract Source Code and Metadata for Verification const response = await axios.post('https://sourcify.dev/server/verify', { address: 'INSERT_CONTRACT_ADDRESS', chain: {{ networks.moonbeam.chain_id }}, // chain ID of Moonbeam files: { 'metadata-1.json': 'INSERT_JSON_FILE', // metadata file for contract file 1 'metadata-2.json': 'INSERT_JSON_FILE', // metadata file for contract file 2 'file1-name.sol': 'INSERT_SOL_FILE', // contract source file 1 'file2-name.sol': 'INSERT_SOL_FILE', // contract source file 2 //... }, chosenContract: 1, // (optional) index of the contract, if the provided files contain multiple metadata files }); if (result.status == 'perfect') { // perfect match console.log(result.status + ';' + result.address); } else if (result.status == 'partial') { // partial match console.log(result.status + ';' + result.address); } else { // non-matching console.log(result.status + ';' + result.address); } ``` === "Moonriver" ```javascript // Submit Contract Source Code and Metadata for Verification const response = await axios.post('https://sourcify.dev/server/verify', { address: 'INSERT_CONTRACT_ADDRESS', chain: {{ networks.moonriver.chain_id }}, // chain ID of Moonriver files: { 'metadata-1.json': 'INSERT_JSON_FILE', // metadata file for contract file 1 'metadata-2.json': 'INSERT_JSON_FILE', // metadata file for contract file 2 'file1-name.sol': 'INSERT_SOL_FILE', // contract source file 1 'file2-name.sol': 'INSERT_SOL_FILE', // contract source file 2 //... }, chosenContract: 1, // (optional) index of the contract, if the provided files contain multiple metadata files }); if (result.status == 'perfect') { // perfect match console.log(result.status + ';' + result.address); } else if (result.status == 'partial') { // partial match console.log(result.status + ';' + result.address); } else { // non-matching console.log(result.status + ';' + result.address); } ``` === "Moonbase Alpha" ```javascript // Submit Contract Source Code and Metadata for Verification const response = await axios.post('https://sourcify.dev/server/verify', { address: 'INSERT_CONTRACT_ADDRESS', chain: {{ networks.moonbase.chain_id }}, // chain ID of Moonbase Alpha files: { 'metadata-1.json': 'INSERT_JSON_FILE', // metadata file for contract file 1 'metadata-2.json': 'INSERT_JSON_FILE', // metadata file for contract file 2 'file1-name.sol': 'INSERT_SOL_FILE', // contract source file 1 'file2-name.sol': 'INSERT_SOL_FILE', // contract source file 2 //... }, chosenContract: 1, // (optional) index of the contract, if the provided files contain multiple metadata files }); if (result.status == 'perfect') { // perfect match console.log(result.status + ';' + result.address); } else if (result.status == 'partial') { // partial match console.log(result.status + ';' + result.address); } else { // non-matching console.log(result.status + ';' + result.address); } ``` Alternatively, you can also use [the Sourcify hosted GUI](https://sourcify.dev/#/verifier){target=\_blank} to submit a contract for verification. ### Check Verification Status by Address and Chain ID {: check-verification-status-by-address-and-chain-id } Sourcify provides endpoints for checking the verification status of contracts on multiple EVM chains at once. This can be done through URL parameters, by specifying the contract addresses and the chain ID's of the networks. There are two variations of this endpoint, one for perfect matching and one for partial matching: === "Perfect Match" ```bash curl https://sourcify.dev/server/check-by-addresses ?addresses={INSERT_ADDRESS_1, INSERT_ADDRESS_2, ...} &chainIds={INSERT_CHAIN_ID_1, INSERT_CHAIN_ID_2, ...} ``` === "Partial Match" ```bash curl https://sourcify.dev/server/check-all-by-addresses ?addresses={INSERT_ADDRESS_1, INSERT_ADDRESS_2, ...} &chainIds={INSERT_CHAIN_ID_1, INSERT_CHAIN_ID_2, ...} ``` An example response will be a JSON object of the following structure: ```json [ { "address": "address1", "status": "perfect", "chainIds": [ "chainId1", "chaindId2" ] }, { "address": "address2", "status": "partial", "chainIds": [ "chaindId2" ] } ] ``` ### Retrieve Contract Source Files for Verified Contracts {: get-contract-source-files-for-verified-contracts } You can also retrieve the source files of verified contracts from the Sourcify repository. There are two variations of this endpoint, one for the source files of perfect matches: === "Moonbeam" ```bash curl https://sourcify.dev/server/files/{{ networks.moonbeam.chain_id }}/INSERT_CONTRACT_ADDRESS ``` === "Moonriver" ```bash curl https://sourcify.dev/server/files/{{ networks.moonriver.chain_id }}/INSERT_CONTRACT_ADDRESS ``` === "Moonbase Alpha" ```bash curl https://sourcify.dev/server/files/{{ networks.moonbase.chain_id }}/INSERT_CONTRACT_ADDRESS ``` And one for the source files of both perfect and partial matches: === "Moonbeam" ```bash curl https://sourcify.dev/server/files/any/{{ networks.moonbeam.chain_id }}/INSERT_CONTRACT_ADDRESS ``` === "Moonriver" ```bash curl https://sourcify.dev/server/files/any/{{ networks.moonriver.chain_id }}/INSERT_CONTRACT_ADDRESS ``` === "Moonbase Alpha" ```bash curl https://sourcify.dev/server/files/any/{{ networks.moonbase.chain_id }}/INSERT_CONTRACT_ADDRESS ``` ### Using Sourcify with Foundry {: #using-sourcify-with-foundry } Foundry's Forge tool has built-in support for Sourcify verification similar to how it has [built-in support for Etherscan](/builders/ethereum/verify-contracts/etherscan-plugins/#using-foundry-to-verify){target=\_blank}. The example in this section of the guide will use the `MyToken.sol` contract that was created in the [Using Foundry to Deploy to Moonbeam](/builders/ethereum/dev-env/foundry/){target=\_blank} guide. A Foundry project that uses Sourcify must have their compiler emit metadata files. This can be configured in the `foundry.toml` file: ```toml [profile.default] # Input your custom or default config options here extra_output_files = ["metadata"] ``` If you have already deployed the example contract, you can verify it with the `verify-contract` command. Before you can verify the contract, you will need to ABI-encode the constructor arguments. To do so for the example contract, you can run the following command: ```bash cast abi-encode "constructor(uint256)" 100 ``` The result should be `0x0000000000000000000000000000000000000000000000000000000000000064`. You can then verify the contract using the following command: === "Moonbeam" ```bash forge verify-contract --chain-id {{ networks.moonbeam.chain_id }} \ --constructor-args 0x0000000000000000000000000000000000000000000000000000000000000064 \ --verifier sourcify INSERT_CONTRACT_ADDRESS src/MyToken.sol:MyToken ``` === "Moonriver" ```bash forge verify-contract --chain-id {{ networks.moonriver.chain_id }} \ --constructor-args 0x0000000000000000000000000000000000000000000000000000000000000064 \ --verifier sourcify INSERT_CONTRACT_ADDRESS src/MyToken.sol:MyToken ``` === "Moonbase Alpha" ```bash forge verify-contract --chain-id {{ networks.moonbase.chain_id }} \ --constructor-args 0x0000000000000000000000000000000000000000000000000000000000000064 \ --verifier sourcify INSERT_CONTRACT_ADDRESS src/MyToken.sol:MyToken ``` ![Foundry Verify](/images/builders/ethereum/verify-contracts/api-verification/api-1.webp) If you wanted to deploy the example contract and verify at the same time, then you would use the following command: === "Moonbeam" ```bash forge create --rpc-url {{ networks.moonbeam.rpc_url }} \ --constructor-args 100 \ --verify --verifier sourcify \ --private-key INSERT_YOUR_PRIVATE_KEY \ src/MyToken.sol:MyToken ``` === "Moonriver" ```bash forge create --rpc-url {{ networks.moonriver.rpc_url }} \ --constructor-args 100 \ --verify --verifier sourcify \ --private-key INSERT_YOUR_PRIVATE_KEY \ src/MyToken.sol:MyToken ``` === "Moonbase Alpha" ```bash forge create --rpc-url {{ networks.moonbase.rpc_url }} \ --constructor-args 100 \ --verify --verifier sourcify \ --private-key INSERT_YOUR_PRIVATE_KEY \ src/MyToken.sol:MyToken ``` ![Foundry Contract Deploy and Verify](/images/builders/ethereum/verify-contracts/api-verification/api-2.webp) --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/verify-contracts/block-explorers/ --- BEGIN CONTENT --- --- title: Verify Smart Contracts on Block Explorers description: Learn how to verify smart contracts on Moonbeam-based networks using one of the available block explorers, such as Moonscan. categories: Ethereum Toolkit --- # Verify Smart Contracts using Block Explorers ## Introduction {: #introduction } Verifying smart contracts on a block explorer is a great way to improve the transparency and security of deployed smart contracts on Moonbeam. Users can directly view the source code for verified smart contracts, and for some block explorers, they can also directly interact with the contract's public methods through the block explorer's interface. This page will outline the steps for verifying smart contracts on Moonbeam networks through block explorers. ## Deploying the Contract {: #deploying-the-contract } In order to verify a smart contract on a block explorer, the contract must first be deployed on the target network. This tutorial will be about deploying the smart contract to [Moonbase Alpha](/builders/get-started/networks/moonbase/){target=\_blank}, but it can be adapted for Moonbeam or Moonriver. You can check out this page for a tutorial on [deploying smart contracts](/builders/ethereum/libraries/){target=\_blank} using Ethereum libraries on Moonbeam. You may also use a developer tool such as [Remix](/builders/ethereum/dev-env/remix/#deploying-a-contract-to-moonbeam-using-remix){target=\_blank}, [Hardhat](/builders/ethereum/dev-env/hardhat/){target=\_blank}, or another tool if preferred, to deploy the smart contract to Moonbeam. This tutorial will use the same contract as the above deployment tutorial for the contract verification example. The contract used is a simple incrementer, arbitrarily named `Incrementer.sol`. The Solidity code is the following: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Incrementer { uint256 public number; constructor(uint256 _initialNumber) { number = _initialNumber; } function increment(uint256 _value) public { number = number + _value; } function reset() public { number = 0; } } ``` ### Collecting Information for Contract Verification You will need to collect some information related to the contract's compiler and deployment in order to verify it successfully. 1. Take note of the Solidity compiler version used to compile and deploy the contract. The Solidity compiler version can usually be selected or specified in the deployment tool used 2. Take note of any SPDX license identifier used at the beginning of the Solidity source file (this example uses an MIT license): ```solidity // SPDX-License-Identifier: MIT ``` 3. (Optional) If optimization is enabled during compilation, take note of the value of the optimization runs parameter 4. (Optional) If the contract constructor method accepts arguments, take note of the [ABI-encoded form](https://docs.soliditylang.org/en/develop/abi-spec.html) of the constructor arguments 5. After deployment, take note of the deployed contract address of the smart contract. The deployment address of the contract can be found either in the console output if using a command-line-based tool such as Hardhat, or an Ethereum library, or it can be copied from the GUI in tools such as Remix IDE ![Example Compiler Options in Remix IDE](/images/builders/ethereum/verify-contracts/block-explorers/verify-contract-1.webp) ![Contract Address in Remix IDE](/images/builders/ethereum/verify-contracts/block-explorers/verify-contract-2.webp) ## Verify the Contract {: #verifying-the-contract } The next step will be verifying the smart contract in an EVM-compatible explorer for the Moonbeam network that you deployed to. ### Moonscan {: #moonscan } Take the following steps to verify the contract on Moonscan: 1. Go to the [Verify & Publish Contract Source Code](https://moonbase.moonscan.io/verifyContract) page of Moonscan 2. Fill in the contract's deployed address in the first field, including the `0x` prefix 3. Select the compiler type. For the current `Incrementer.sol` example, select **Solidity (Single file)** 4. After selecting the compiler type, select the compiler version used to compile the contract. If the compiler version used was a nightly commit, uncheck the box under the field to select the nightly version 5. Select the open-source license used. For the current `Incrementer.sol` example, select the option **MIT License (MIT)**. If there was none used, select **No License (None)** 6. Click the **Continue** button at the bottom of the form to continue on to the next page ![First Page Screenshot](/images/builders/ethereum/verify-contracts/block-explorers/verify-contract-3.webp) On the second page, the **Contract Address**, **Compiler**, and **Constructor Arguments** fields should be prefilled. Fill in the rest of the information: 1. Copy and paste the entirety of the contract's content into the text field labeled as such 2. (Optional) Select **Yes** for **Optimization** if it was enabled during compilation, and fill in the number of runs under **Misc Settings/Runs(Optimizer)** 3. (Optional) Add contract libraries and their addresses, if any were used in the contract 4. (Optional) Check any other optional fields that may apply to your contract, and fill them out accordingly 5. Click on the CAPTCHA at the bottom and the **Verify and Publish** button to confirm and begin verification ![Second Page Screenshot](/images/builders/ethereum/verify-contracts/block-explorers/verify-contract-4.webp) After a short wait, the result of verification will be displayed in the browser, and a success result page will display the contract's ABI-encoded constructor arguments, the contract name, bytecode, and ABI. ![Result Page Screenshot](/images/builders/ethereum/verify-contracts/block-explorers/verify-contract-5.webp) ## Smart Contract Flattening {: #smart-contract-flattening } For verifying smart contracts that are made up of multiple files, the process is slightly different and requires some pre-processing to combine all the dependencies of the target smart contract into a single Solidity file. This pre-processing is usually referred to as smart contract flattening. There are a number of tools that can be used to flatten a multi-part smart contract into a single Solidity file, such as [Hardhat's Flatten task](https://hardhat.org/hardhat-runner/docs/advanced/flattening){target=\_blank}. Please refer to the respective smart contract flattening tool's documentation for more detailed instructions on its usage. After flattening the multi-part smart contract, it can be verified using the new flattened Solidity file on a block explorer in the same way that a single-file smart contract is verified, as described in this tutorial. ### Verify Multi-Part Smart Contract on Moonscan {: #verify-multi-part-smart-contract-on-moonscan } For verifying on Moonscan, there is a built-in feature to process multi-part smart contracts. Select **Solidity (Multi-part files)** under **Compiler Type** (step 3 of the above example). Then, on the next page, select and upload all the different Solidity files that the contract consists of, including their nested dependency contract files. ![Moonscan Multifile Page](/images/builders/ethereum/verify-contracts/block-explorers/verify-contract-6.webp) Aside from that, the process is largely the same as verifying single-file contracts on Moonscan. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/verify-contracts/etherscan-plugins/ --- BEGIN CONTENT --- --- title: Verify Smart Contracts with Plugins description: Learn how to verify smart contracts on Moonbeam networks using built-in tools from Hardhat and Foundry that support Moonscan’s API. categories: Ethereum Toolkit --- # Verify Smart Contracts with Etherscan Plugins ## Introduction {: #introduction } Verifying smart contracts is a great way of improving the transparency and security of contracts deployed on Moonbeam. Hardhat and Foundry integrate with Etherscan's contract verification service to automate the process of verifying contracts by locally detecting which contracts to verify and which Solidity libraries are required, if any. The Hardhat plugin integrates seamlessly into your [Hardhat](https://hardhat.org){target=\_blank} project. [Foundry](https://github.com/foundry-rs/foundry){target=\_blank} also has Etherscan capabilities, but they are built into its Forge tool instead of being included in a separate plugin. This guide will show you how to use both plugins to verify smart contracts deployed on Moonbase Alpha. This guide can also be adapted for Moonbeam and Moonriver. ## Checking Prerequisites {: #checking-prerequisites } To follow along with this tutorial, you will need to have: - [MetaMask installed and connected to the Moonbase Alpha](/tokens/connect/metamask/){target=\_blank} TestNet - An account funded with `DEV` tokens. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} - An Etherscan API key - Git installed and configured ## Generating an Etherscan API Key {: generating-an-etherscan-api-key } To verify contracts on Moonscan for any Moonbeam network, you’ll need an [Etherscan API key](https://docs.etherscan.io/etherscan-v2/getting-an-api-key){target=\_blank}. Because Moonscan is part of Etherscan’s ecosystem, a single key works across all supported networks. To create an [Etherscan account](https://etherscan.io/){target=\_blank} and generate your key, follow these steps: 1. Click **Sign In** 2. Select **Click to sign up** and then register your new account ![Sign up for Moonscan](/images/builders/ethereum/verify-contracts/etherscan-plugins/plugins-1.webp) Once you have an account and are signed in, you will then be able to create an API key. 1. Select **API Dashboard** from the left side menu 2. To add a new key, click the **+ Add** button ![Add an API key](/images/builders/ethereum/verify-contracts/etherscan-plugins/plugins-2.webp) You will then be prompted to enter in an **AppName** for your API key and once you enter a name and click **Continue** it will appear in your list of API keys. ## Using the Hardhat Etherscan Plugin {: #using-the-hardhat-verify-plugin } The example in this section of the guide will be based off of the `Box.sol` contract that was created in the [Using Hardhat to Deploy To Moonbeam](/builders/ethereum/dev-env/hardhat/){target=\_blank} guide. To get started with the Hardhat Etherscan plugin, you will need to first install the plugin library: ```bash npm install --save-dev @nomicfoundation/hardhat-verify ``` You can add your Etherscan API key to the `hardhat.config.js` file. From within your Hardhat project, open your `hardhat.config.js` file. You'll need to import the `hardhat-verify` plugin, your Etherscan API key, and add the config for Etherscan: ```js require('@nomicfoundation/hardhat-verify'); module.exports = { networks: { moonbeam: { ... }, moonriver: { ... }, moonbaseAlpha: { ... } }, etherscan: { apiKey: { moonbeam: 'INSERT_ETHERSCAN_API_KEY', moonriver: 'INSERT_ETHERSCAN_API_KEY', moonbaseAlpha: 'INSERT_ETHERSCAN_API_KEY', }, }, }; ``` To verify the contract, you will run the `verify` command and pass in the address of the deployed contract and the network where it's deployed: ```bash npx hardhat verify --network moonbase INSERT_CONTRACT_ADDRESS ``` In your terminal you should see the source code for your contract was successfully submitted for verification. If the verification was successful, you should see **Successfully verified contract** and there will be a link to the contract code on [Moonscan for Moonbase Alpha](https://moonbase.moonscan.io){target=\_blank}.
npx hardhat verify --network moonbase 0x5d73ecDB4652173b881893235B64F1a0BdE22dD6
Successfully submitted source code for contract contracts/Box.sol:Box at 0x5d73ecDB4652173b881893235B64F1a0BdE22dD6 for verification on the block explorer. Waiting for verification result...
Successfully verified contract Box on Etherscan. https://moonbase.moonscan.io/address/0x5d73ecDB4652173b881893235B64F1a0BdE22dD6#code
If you're verifying a contract that has constructor arguments, you'll need to run the above command and add the constructor arguments used to deploy the contract at the end of the command. For example: ```bash npx hardhat verify --network moonbase INSERT_CONTRACT_ADDRESS INSERT_CONSTRUCTOR_ARGS ``` Please refer to the [Hardhat Verify documentation](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-verify){target=\_blank} for help with additional use cases such as: - [complex arguments](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-verify#complex-arguments){target=\_blank} - [libraries with undetectable addresses](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-verify#libraries-with-undetectable-addresses){target=\_blank} - using [multiple API keys](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-verify#multiple-api-keys-and-alternative-block-explorers){target=\_blank} - using the [`verify` command programmatically](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-verify#using-programmatically){target=\_blank} - [determining the correct constructor arguments](https://info.etherscan.com/determine-correct-constructor-argument-during-source-code-verification-on-etherscan/){target=\_blank} ## Using Foundry to Verify {: #using-foundry-to-verify } The example in this section of the guide will use the `MyToken.sol` contract that was created in the [Using Foundry to Deploy to Moonbeam](/builders/ethereum/dev-env/foundry/){target=\_blank} guide. In addition to the Foundry project, you will need an [Etherscan API key](https://etherscan.io/){target=\_blank} to verify your contract. If you have already deployed the example contract, you can verify it with the `verify-contract` command. Before you can verify the contract, you will need to ABI-encode the constructor arguments. To do so for the example contract, you can run the following command: ```bash cast abi-encode "constructor(uint256)" 100 ``` The result should be `0x0000000000000000000000000000000000000000000000000000000000000064`. You can then verify the contract using the following command: === "Moonbeam" ```bash forge verify-contract --chain-id {{ networks.moonbeam.chain_id }} \ YOUR_CONTRACT_ADDRESS \ --constructor-args 0x0000000000000000000000000000000000000000000000000000000000000064 \ src/MyToken.sol:MyToken \ --etherscan-api-key INSERT_YOUR_ETHERSCAN_API_KEY ``` === "Moonriver" ```bash forge verify-contract --chain-id {{ networks.moonriver.chain_id }} \ YOUR_CONTRACT_ADDRESS \ --constructor-args 0x0000000000000000000000000000000000000000000000000000000000000064 \ src/MyToken.sol:MyToken \ --etherscan-api-key INSERT_YOUR_ETHERSCAN_API_KEY ``` === "Moonbase Alpha" ```bash forge verify-contract --chain-id {{ networks.moonbase.chain_id }} \ YOUR_CONTRACT_ADDRESS \ --constructor-args 0x0000000000000000000000000000000000000000000000000000000000000064 \ src/MyToken.sol:MyToken \ --etherscan-api-key INSERT_YOUR_ETHERSCAN_API_KEY ```
forge verify-contract --chain-id 1284 \ YOUR_CONTRACT_ADDRESS \ --constructor-args 0x0000000000000000000000000000000000000000000000000000000000000064 \ src/MyToken.sol:MyToken \ --etherscan-api-key INSERT_YOUR_ETHERSCAN_API_KEY
Submitting verification for [src/MyToken. sol:MyToken] Ok("0×5A05EBOA18ee616bb5dac2C4D0a48991a83533d2" ) . Submitted contract for verification: Response:'OK' GUID:'f7iwagu9vspdrdfirbie1wp16cmuvfk3zvcsix9ey21t3a8ttt' URL: https: //moonbase.moonscan.io/address/0×5a05eb0a18ee616bb5dac2c4d0a48991a83533d2 Waiting for verification result... Contract successfully verified.
If you wanted to deploy the example contract and verify at the same time, then you would use the following command: === "Moonbeam" ```bash forge create --rpc-url {{ networks.moonbeam.rpc_url }} \ --constructor-args 100 \ --etherscan-api-key INSERT_YOUR_ETHERSCAN_API_KEY \ --verify --private-key YOUR_PRIVATE_KEY \ src/MyToken.sol:MyToken ``` === "Moonriver" ```bash forge create --rpc-url {{ networks.moonriver.rpc_url }} \ --constructor-args 100 \ --etherscan-api-key INSERT_YOUR_ETHERSCAN_API_KEY \ --verify --private-key YOUR_PRIVATE_KEY \ src/MyToken.sol:MyToken ``` === "Moonbase Alpha" ```bash forge create --rpc-url {{ networks.moonbase.rpc_url }} \ --constructor-args 100 \ --etherscan-api-key INSERT_YOUR_ETHERSCAN_API_KEY \ --verify --private-key YOUR_PRIVATE_KEY \ src/MyToken.sol:MyToken ```
forge create --rpc-url INSERT_RPC_API_ENDPOINT \ --constructor-args 100 \ --etherscan-api-key INSERT_YOUR_ETHERSCAN_API_KEY \ --verify --private-key YOUR_PRIVATE_KEY \ src/MyToken.sol:MyToken
Compiling... No files changed, compilation skipped Deployer: 0x0394c0EdFcCA370B20622721985B577850B0eb 75 Deployed to: 0d21b2653f61b5B5399A677D377D52D07C7668f67 Transaction hash: 0x80fff772b930f425ed3568f0b3d8844e5297691c78807c7b393c85910b7717 Starting contract verification... Waiting for etherscan to detect contract deployment...
Submitting verification for [src/MyToken.sol:MyToken]Ok("0x21b265361b5B5399A677D377D52D07C7668f67"). Submitted contract for verification: Response:'OK' GUID:'ebbliyrquc5itkavvhvmilanzu5rdqusikImgraanepjm8gpq' URL: https: //moonbase.moonscan.io/address/0x21b2653f61b55399a677d377d52d07c7668f67 Waiting for verification result... Contract successfully verified.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ethereum/verify-contracts/ --- BEGIN CONTENT --- --- title: Verify Smart Contracts description: Learn how to verify your Solidity smart contracts deployed to Moonbeam manually through block explorers and automatically through Etherscan plugins. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/get-started/create-account/ --- BEGIN CONTENT --- --- title: Create an Account description: To begin developing on Moonbeam, you must create an account. This guide will provide you with the information needed to create one to use on Moonbeam. categories: Basics --- # Create an Account ## Introduction {: #introduction } To get started developing on Moonbeam, developers must create an account. The most prevalent approach involves leveraging a wallet application, which facilitates generating and managing cryptographic keys essential for interacting with Moonbeam. Moonbeam uses H160 Ethereum-style accounts and ECDSA keys, represented in 20-byte addresses. If you already have an Ethereum account and its private key or mnemonic, you can use your account on Moonbeam. This guide will walk you through the step-by-step process of creating an account on Moonbeam. Whether you're new to blockchain technology or an experienced Ethereum user, this guide will provide all the information you need to get started. !!! note This guide does not pertain to a local Moonbeam development node. If you are using a development node, you don't need to worry about creating an account, as the node comes with ten pre-funded accounts for testing purposes. Please refer to the [Getting Started with a Local Moonbeam Development Node](/builders/get-started/networks/moonbeam-dev/){target=\_blank} guide for more information. ## Choose a Wallet {: #choose-a-wallet } A wallet is a software or hardware tool that allows you to securely store, manage, and interact with your digital assets, such as tokens or coins. Wallets store your private keys, which are essential for authorizing transactions on the network. You can review a list of wallets on the [Moonbeam DApp Directory](https://apps.moonbeam.network/moonbeam/app-dir?cat=wallets){target=\_blank}. ![View list of wallets on the Moonbeam DApp](/images/builders/get-started/create-account/create-account-1.webp) The list of wallets on the dApp is not exhaustive and may only cover some of the available options. You should be able to use any Ethereum-compatible wallet to generate an address and its associated private key. You can also check out any of the wallets in the [Connect to Moonbeam](/tokens/connect/){target=\_blank} section of the docs. ## Use Your Wallet to Create an Account {: #use-your-wallet-to-create-an-account } After you've selected a wallet and downloaded it, you'll most likely be prompted to create a new account or import an existing one the first time you open it. You'll want to create a new account. Depending on the wallet, when creating an account, you may be prompted to backup and restore a seed phrase, also referred to as a mnemonic or recovery phrase. This phrase is a sequence of generated words that serve as a backup mechanism for private keys. They typically consist of 12 to 24 words randomly selected from a predefined list. Seed phrases are used to derive private keys deterministically, meaning that the same sequence of words will always generate the same set of private keys. They are crucial for recovering access to a cryptocurrency wallet in case of loss or device failure. **Make sure you save the phrase in a safe place; if you lose access to this phrase, you'll lose access to any funds you hold in your account.** After saving your seed phrase, you can start developing on Moonbeam. Many wallets offer the option to export the private key linked to your account. By doing so, you can utilize your private key instead of the seed phrase during development. However, taking adequate precautions to securely store your private key or seed phrase while developing is essential. And that's it! Before sending your first transaction on a Moonbeam-based network, ensure you have the necessary [network configurations for your chosen network](/builders/get-started/networks/){target=\_blank} and an [RPC endpoint](/builders/get-started/endpoints/){target=\_blank} for the network. Once you have these items, you'll be able to follow along with tutorials like the [How to use Ethers.js](/builders/ethereum/libraries/ethersjs/){target=\_blank} or the [How to use Web3.js](/builders/ethereum/libraries/web3js/){target=\_blank} to send a transaction. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/get-started/endpoints/ --- BEGIN CONTENT --- --- title: Moonbeam API Providers and Endpoints description: Use one of the supported API providers to connect to a public endpoint or create custom JSON-RPC and WSS endpoints for Moonbeam-based networks. categories: JSON-RPC APIs, Reference --- # Network Endpoints ## Public Endpoints {: #public-endpoints } Moonbeam-based networks have two endpoints available for users to connect to: one for HTTPS and one for WSS. The endpoints in this section are for development purposes only and are not meant to be used in production applications. If you are looking for an API provider suitable for production use, you can check out the [Endpoint Providers](#endpoint-providers) section of this guide. ### Moonbeam {: #moonbeam } === "HTTPS" | Provider | RPC URL | Limits | |:-----------:|:------------------------------------------------------------------:|:-----------:| | Blast |
```https://moonbeam.public.blastapi.io```
| 80 req/sec | | Dwellir |
```https://moonbeam-rpc.dwellir.com```
| 20 req/sec | | OnFinality |
```https://moonbeam.api.onfinality.io/public```
| 40 req/sec | | UnitedBloc |
```https://moonbeam.unitedbloc.com```
| 32 req/sec | | RadiumBlock |
```https://moonbeam.public.curie.radiumblock.co/http```
| 200 req/sec | | 1RPC |
```https://1rpc.io/glmr```
| 10k req/day | | Grove |
```https://moonbeam.rpc.grove.city/v1/01fdb492```
| 5k req/day | === "WSS" | Provider | RPC URL | Limits | |:-----------:|:--------------------------------------------------------------:|:-----------:| | Blast |
```wss://moonbeam.public.blastapi.io```
| 80 req/sec | | Dwellir |
```wss://moonbeam-rpc.dwellir.com```
| 20 req/sec | | OnFinality |
```wss://moonbeam.api.onfinality.io/public-ws```
| 40 req/sec | | UnitedBloc |
```wss://moonbeam.unitedbloc.com```
| 32 req/sec | | RadiumBlock |
```wss://moonbeam.public.curie.radiumblock.co/ws```
| 200 req/sec | | 1RPC |
```wss://1rpc.io/glmr```
| 10k req/day | ### Moonriver {: #moonriver } === "HTTPS" | Provider | RPC URL | Limits | |:-----------:|:-------------------------------------------------------------------:|:-----------:| | Dwellir |
```https://moonriver-rpc.dwellir.com```
| 20 req/sec | | OnFinality |
```https://moonriver.api.onfinality.io/public```
| 40 req/sec | | UnitedBloc |
```https://moonriver.unitedbloc.com```
| 32 req/sec | | RadiumBlock |
```https://moonriver.public.curie.radiumblock.co/http```
| 200 req/sec | | Grove |
```https://moonriver.rpc.grove.city/v1/01fdb492```
| 5k req/day | === "WSS" | Provider | RPC URL | Limits | |:-----------:|:---------------------------------------------------------------:|:-----------:| | Dwellir |
```wss://moonriver-rpc.dwellir.com```
| 20 req/sec | | OnFinality |
```wss://moonriver.api.onfinality.io/public-ws```
| 40 req/sec | | UnitedBloc |
```wss://moonriver.unitedbloc.com```
| 32 req/sec | | RadiumBlock |
```wss://moonriver.public.curie.radiumblock.co/ws```
| 200 req/sec | ### Moonbase Alpha {: #moonbase-alpha } === "HTTPS" | Provider | RPC URL | Limits | |:-------------------:|:------------------------------------------------------------------:|:-----------:| | Dwellir |
```https://moonbase-rpc.dwellir.com```
| 20 req/sec | | OnFinality |
```https://moonbeam-alpha.api.onfinality.io/public```
| 40 req/sec | | Moonbeam Foundation |
```https://rpc.api.moonbase.moonbeam.network```
| 25 req/sec | | UnitedBloc |
```https://moonbase.unitedbloc.com```
| 32 req/sec | | RadiumBlock |
```https://moonbase.public.curie.radiumblock.co/http```
| 200 req/sec | === "WSS" | Provider | RPC URL | Limits | |:-------------------:|:-----------------------------------------------------------------:|:-----------:| | Dwellir |
```wss://moonbase-rpc.dwellir.com```
| 20 req/sec | | OnFinality |
```wss://moonbeam-alpha.api.onfinality.io/public-ws```
| 40 req/sec | | Moonbeam Foundation |
```wss://wss.api.moonbase.moonbeam.network```
| 25 req/sec | | UnitedBloc |
```wss://moonbase.unitedbloc.com```
| 32 req/sec | | RadiumBlock |
```wss://moonbase.public.curie.radiumblock.co/ws```
| 200 req/sec | #### Relay Chain {: #relay-chain } To connect to the Moonbase Alpha relay chain, you can use the following WS Endpoint: | Provider | RPC URL | |:--------:|:----------------------------------------------------------:| | OpsLayer |
```wss://relay.api.moonbase.moonbeam.network```
| ## RPC Endpoint Providers {: #endpoint-providers } You can create your own endpoint suitable for development or production use using any of the following API providers: - [1RPC](#1rpc) - [Blast](#blast) - [Chainstack](#chainstack) - [dRPC](#drpc) - [Dwellir](#dwellir) - [GetBlock](#getblock) - [Grove](#grove) - [OnFinality](#onfinality) - [UnitedBloc](#unitedbloc) ### 1RPC {: #1rpc} [1RPC](https://www.1rpc.io){target=_blank} is a free and private RPC relay that protects user privacy by preventing data collection, user tracking, phishing attempts from other parties. It tunnels user requests via distributed relays to other RPC providers whilst preventing the tracking of user metadata such as IP address, device information and wallet linkability with secure enclave technology. 1RPC is created to be an open initiative from the blockchain infrastructure community. They are motivated by a common good mission to help build a better Web3 and encourage anyone who values user privacy to join this open collaboration. Head over to [1RPC](https://www.1rpc.io){target=_blank} official site to set it up! ![1RPC](/images/builders/get-started/endpoints/endpoints-1.webp) ### Blast {: #blast} As a user of [Blast](https://blastapi.io){target=_blank} powered by Bware Labs, you will be able to obtain your own free endpoint allowing you to interact with Moonbeam, just by performing a few simple clicks within a user-friendly interface. To get started, you'll need to head to [Blast](https://blastapi.io){target=_blank}, and launch the app, and connect your wallet. Once your wallet is connected you will be able to create a project and then generate your own custom endpoint. To generate an endpoint: 1. Create a new project 2. Click on **Available Endpoints** 3. Select Moonbeam network for your endpoint 4. Confirm the selected network and Press **Activate** 5. You'll now see Moonbeam under **Active Endpoints**. Click on the network and you'll see your custom RPC and WSS endpoints on the next page ![Bware Labs](/images/builders/get-started/endpoints/endpoints-2.webp) ### Chainstack {: #chainstack } [Chainstack](https://chainstack.com/){target=_blank}, the Web3 infrastructure provider, offers free and paid endpoints for Moonbeam. The free Developer plan starts with 3 million monthly requests and 25 requests per second (RPS). You can easily scale with the paid plans. To start with a free Developer plan endpoint, sign up using an email or any social account, like GitHub or X (Twitter). 1. Visit [Chainstack](https://console.chainstack.com/){target=_blank} 2. Sign up 3. Deploy a Moonbeam node ![Chainstack](/images/builders/get-started/endpoints/endpoints-3.webp) ### dRPC.org {: #drpc } dRPC.org offers public and paid [Moonbeam RPC](https://drpc.org/chainlist/moonbeam){target=_blank} endpoints, providing an efficient, low-latency connection to blockchain nodes. The paid tiers include higher request limits, lower latency, and advanced analytics for optimized performance. How to use dRPC: 1. Sign up or log in at [dRPC.org](https://drpc.org/){target=_blank} 2. In the dashboard, create an API key 3. Click the key and select the desired endpoint For 24/7 support, join dRPC's [Discord](https://drpc.org/discord){target=_blank}. ### Dwellir {: #dwellir } [Dwellir](https://www.dwellir.com){target=_blank} is a blockchain operation service that ensures global scalability, low latency, and a 99.99% uptime guarantee, providing fast and reliable node operations wherever your business stands. The public endpoint service is geographically distributed bare metal servers globally. As the service is public, there are no sign-up or API keys to manage. To get started with a developer endpoint or dedicated node, you'll need to contact us: 1. Visit [Dwellir](https://www.dwellir.com/contact){target=_blank} 2. Submit your **email** and your node request ![Dwellir](/images/builders/get-started/endpoints/endpoints-4.webp) ### GetBlock {: #getblock } [GetBlock](https://getblock.io){target=_blank} is a service that provides instant API access to Moonbeam and Moonriver and is available through shared and dedicated nodes. [Dedicated nodes](https://docs.getblock.io/getting-started/plans-and-limits/choosing-your-plan#dedicated-nodes){target=_blank} provide access to a private server with fast speeds and without rate limits. [Shared nodes](https://docs.getblock.io/getting-started/plans-and-limits/choosing-your-plan#shared-nodes){target=_blank} provide a free API/add-on based endpoint for you to get started quickly. To get started with GetBlock, you can go to the [GetBlock registration page](https://account.getblock.io/sign-up){target=_blank} and sign up for a new account. Then, from your account **Dashboard**, you can view and manage your existing endpoints for multiple protocols, and also create new ones. Creating a new API/add-on based endpoint is simple, all you have to do is: 1. Fill the information for the desired protocol from the list of available blockchains 2. Choose the network you want your endpoint to point to (**Mainnet**, **Testnet**, etc) 3. Select **JSON-RPC** from the **API/Add-on** dropdown 4. Click the **Get** button at the far right and you're all set to go! ![GetBlock](/images/builders/get-started/endpoints/endpoints-5.webp) ### Grove {: #grove } [Grove](https://grove.city){target=_blank} is a decentralized RPC network that provides reliable Web3 infrastructure with enterprise-grade performance and security. Grove offers both free and paid tiers, with the free tier providing generous limits for development use, while paid plans offer higher throughput, dedicated support, and advanced features for production applications. Grove's decentralized approach ensures high availability and censorship resistance by distributing requests across multiple node operators. The network supports both JSON-RPC and WebSocket connections for real-time applications. To get started with Grove: 1. Visit the [Grove Portal](https://portal.grove.city/){target=_blank} and sign up for an account 2. From your dashboard, create a new application 3. Copy your Moonbeam or Moonriver endpoints 4. Start making requests to your custom Grove endpoint Grove provides detailed analytics, request monitoring, and flexible rate limiting to help you optimize your application's performance. ![Grove](/images/builders/get-started/endpoints/endpoints-6.webp) ### OnFinality {: #onfinality } [OnFinality](https://onfinality.io){target=_blank} provides a free API key based endpoint for customers in place of a public endpoint. Additionally, OnFinality offers paid tiers of service that offer increased rate limits and higher performance than those offered by the free tier. You also receive more in depth analytics of the usage of your application. To create a custom OnFinality endpoint, go to [OnFinality](https://onfinality.io){target=_blank} and sign up, or if you already have signed up you can go ahead and log in. From the OnFinality **Dashboard**, you can: 1. Click on **API Service** 2. Select the network from the dropdown 3. Your custom API endpoint will be generated automatically ![OnFinality](/images/builders/get-started/endpoints/endpoints-7.webp) ### UnitedBloc {: #unitedbloc } [UnitedBloc](https://medium.com/unitedbloc/unitedbloc-rpc-c84972f69457){target=_blank} is a collective of community collators from both Moonbeam and Moonriver. To provide value for the community, they offer public RPC services for the Moonbeam, Moonriver, and Moonbase Alpha networks. The public endpoint service is served by eight geographically distributed bare metal servers globally balanced via GeoDNS and regionally load balanced with NGINX. As the service is public, there are no sign-up or API keys to manage. The collators involved in this initiative are: - Blockshard (CH) - BloClick (ES) - BrightlyStake (IN) - CertHum (US) - GPValidator (PT) - Hetavalidation (AU) - Legend (AE) - PathrockNetwork (DE) - Polkadotters (CZ) - SIK | crifferent.de (DE) - StakeBaby (GR) - StakeSquid (GE) - TrueStaking (US) They also provide a [public Grafana dashboard](https://monitoring.unitedbloc.com:3030/public-dashboards/7444d2ab76ee45eda181618b0f0ecb98?orgId=1){target=_blank} with some cool metrics. Check the [public endpoints section](#public-endpoints) to get the relevant URL. You can contact them via their [Telegram channel](https://t.me/+tRvy3z5-Kp1mMGMx){target=_blank}, or read more about their initiative on their [blogpost page](https://medium.com/unitedbloc/unitedbloc-rpc-c84972f69457){target=_blank}. ## Lazy Loading with RPC Endpoint Providers {: #lazy-loading-with-RPC-Endpoint-Providers } Lazy loading lets a Moonbeam node operate while downloading network state in the background, eliminating the need to wait for full synchronization before use. To spin up a Moonbeam node with lazy loading, you'll need to either [download the Moonbeam release binary](/node-operators/networks/run-a-node/systemd/#the-release-binary){target=_blank} or [compile the binary](/node-operators/networks/run-a-node/compile-binary/#compile-the-binary){target=_blank}. You can activate lazy loading with the following flag: `--lazy-loading-remote-rpc 'INSERT-RPC-URL'` Lazy loading is highly resource-intensive, requiring many RPC requests to function. To avoid being throttled, it's recommended that you use a [dedicated endpoint](#endpoint-providers) (i.e., an endpoint with an API key) rather than a public endpoint. You will likely be rate-limited if you use lazy loading with a public endpoint. Upon spooling up a node with this feature, you'll see output like the following:
[Lazy loading 🌗]
You are now running the Moonbeam client in lazy loading mode, where data is retrieved
from a live RPC node on demand.
Using remote state from: https://moonbeam.unitedbloc.com
Forking from block: 8482853
To ensure the client works properly, please note the following:
1. *Avoid Throttling*: Ensure that the backing RPC node is not limiting the number of
requests, as this can prevent the lazy loading client from functioning correctly;
2. *Be Patient*: As the client may take approximately 20 times longer than normal to
retrieve and process the necessary data for the requested operation.
The service will start in 10 seconds...
### Overriding State with Lazy Loading By default, you won't see detailed logging in the terminal. To override this setting and show lazy loading logs, you can add the following flag to your command to start the Moonbeam node: `-l debug`. You can further customize your use of the lazy loading functionality with the following optional parameters: - **`--lazy-loading-block`** - specifies a block hash from which to start loading data. If not provided, the latest block will be used - **`--lazy-loading-delay-between-requests`** - the delay (in milliseconds) between RPC requests when using lazy loading. This parameter controls the amount of time to wait between consecutive RPC requests. This can help manage request rate and avoid overwhelming the server. Default value is `100` milliseconds - **`--lazy-loading-max-retries-per-request`** - the maximum number of retries for an RPC request when using lazy loading. Default value is `10` retries - **`--lazy-loading-runtime-override`** - path to a WASM file to override the runtime when forking. If not provided, it will fetch the runtime from the block being forked - **`--lazy-loading-state-overrides`** - path to a JSON file containing state overrides to be applied when forking #### Simple Storage Item Override The state overrides file should define the respective pallet, storage item, and value that you seek to override as follows: ```json [ { "pallet": "System", "storage": "SelectedCandidates", "value": "0x04f24ff3a9cf04c71dbc94d0b566f7a27b94566cac" } ] ``` #### Override an Account's Free Balance To override the balance of a particular account, you can override the account storage item of the system pallet for the respective account as follows: ```json [ { "pallet": "System", "storage": "Account", "key": "TARGET_ADDRESS", "value": "0x460c000002000000010000000600000069e10de76676d0800000000000000000040a556b0e032de12000000000000000004083a09e15c74c1b0100000000000000000000000000000000000000000000080" } ] ``` ??? note "Details about overriding account balances" Overriding an account balance, as shown above, can be a complex process. However, this guide will break it down into steps that are easy to follow. Before making any changes, you should obtain the existing value corresponding to the key (i.e., the account in this case). You can go to [**Chain State** on Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbeam.network#/chainstate){target=_blank} and query the System pallet by providing the account you'd like to query. Upon submitting the query, you'll get back a readable account structure like so: ```text { nonce: 3,142 consumers: 2 providers: 1 sufficients: 6 data: { free: 1,278,606,392,142,175,328,676 reserved: 348,052,500,000,000,000,000 frozen: 20,413,910,106,633,175,872 flags: 170,141,183,460,469,231,731,687,303,715,884,105,728 } } ``` While this is useful as a reference, the information you're looking for is the encoded storage key, which is accessible even without submitting the chain state query. In this instance, the encoded storage key corresponding to the system pallet and the selected account `0x3B939FeaD1557C741Ff06492FD0127bd287A421e` is: ```text 0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9b882fedb4f75b055c709ec5b66b5d9933b939fead1557c741ff06492fd0127bd287a421e ``` Note that this encoded storage key will change alongside any input changes, such as a different account being queried. Then, head over the **Raw Storage** tab on [Polkadot.js Apps](https://polkadot.js.org/apps/#/chainstate/raw){target=_blank}. Input the above storage key and submit the query. The response is the SCALE encoded account struct, a part of which contains the free balance information to be modified as part of this example: ```text 0x460c0000020000000100000006000000a4d92a6a4e6b3a5045000000000000000040a556b0e032de12000000000000004083a09e15c74c1b010000000000000000000000000000000000000000000080 ``` There is quite a bit of data encoded in the value field because it is a complex struct comprised of multiple values. The struct is comprised of: ```text struct AccountInfo { nonce: u32, // Transaction count consumers: u32, // Number of consumers providers: u32, // Number of providers sufficients: u32, // Number of sufficients data: AccountData { // The balance info free: u128, // Free balance reserved: u128, // Reserved balance frozen: u128, // Frozen balance flags: u128 // Account flags } } ``` You can associate each part of the SCALE encoded struct with the corresponding piece of Alice's account information that it represents: ```text 0x460c0000 // nonce (u32): 3,142 02000000 // consumers (u32): 2 01000000 // providers (u32): 1 06000000 // sufficients (u32): 6 a4d92a6a4e6b3a5045000000000000000 // free (u128): 1,278,606,392,142,175,328,676 40a556b0e032de1200000000000000000 // reserved (u128): 348,052,500,000,000,000,000 4083a09e15c74c1b01000000000000000 // frozen (u128): 20,413,910,106,633,175,872 00000000000000000000000000000080 // flags (u128): 170,141,183,460,469,231,731,687,303,715,884,105,728 ``` Remember that the values are little endian encoded. To convert the hexadecimal little endian encoded values to decimal, you can use [Substrate Utilities converter](https://www.shawntabrizi.com/substrate-js-utilities/){target=_blank}, using the **Balance to Hex (Little Endian)** converter. In this example, the existing free balance of `1,278,606,392,142,175,328,676` Wei or approximately `1278.60` DEV is `a4d92a6a4e6b3a5045`. The following example will change the value to `500,000` DEV, which is `500,000,000,000,000,000,000,000` Wei or `0x000080d07666e70de169` encoded as a hexadecimal little endian value. When properly padded to fit into the SCALE encoded storage value, it becomes `69e10de76676d08000000000000000000`, such that the table now looks like: ```text 0x460c0000 // nonce (u32): 3,142 02000000 // consumers (u32): 2 01000000 // providers (u32): 1 06000000 // sufficients (u32): 6 69e10de76676d08000000000000000000 // free (u128): 500,000,000,000,000,000,000,000 40a556b0e032de1200000000000000000 // reserved (u128): 348,052,500,000,000,000,000 4083a09e15c74c1b01000000000000000 // frozen (u128): 20,413,910,106,633,175,872 00000000000000000000000000000080 // flags (u128): 170,141,183,460,469,231,731,687,303,715,884,105,728 ``` Therefore, the SCALE encoded override value is as follows: ```text 0x460c000002000000010000000600000069e10de76676d0800000000000000000040a556b0e032de12000000000000000004083a09e15c74c1b0100000000000000000000000000000000000000000000080 ``` You can now specify the SCALE encoded override value in your `state-overrides.json` file as follows: ```json [ { "pallet": "System", "storage": "Account", "key": "0x3b939fead1557c741ff06492fd0127bd287a421e", "value": "0x460c000002000000010000000600000069e10de76676d0800000000000000000040a556b0e032de12000000000000000004083a09e15c74c1b0100000000000000000000000000000000000000000000080" } ] ``` To run lazy loading with the balance state override, you can use the following command: ```bash --lazy-loading-remote-rpc 'INSERT_RPC_URL' --lazy-loading-state-overrides ./state-overrides.json ``` #### Override an ERC-20 Token Balance To override an ERC-20 token balance, identify the storage slot in the EVM’s AccountStorages where the `balanceOf` data for the given token contract and account is stored. This storage slot is determined by the token contract’s H160 address and the corresponding H256 storage key. Once you have this slot, specify the new balance value in the `state-overrides.json` file to implement the override. In the example below, we override the token balance of the [Wormhole USDC Contract (`0x931715FEE2d06333043d11F658C8CE934aC61D0c`)](https://moonscan.io/address/0x931715FEE2d06333043d11F658C8CE934aC61D0c){target=_blank} for the account `0x3b939fead1557c741ff06492fd0127bd287a421e` to $5,000 USDC. Since Wormhole USDC uses 6 decimal places, $5,000 corresponds to `5000000000` in integer form, which is `0x12a05f200` in hexadecimal. ```json [ { "pallet": "EVM", "storage": "AccountStorages", "key": [ "0x931715FEE2d06333043d11F658C8CE934aC61D0c", "0x8c9902c0f94ae586c91ba539eb52087d3dd1578da91158308d79ff24a8d4f342" ], "value": "0x000000000000000000000000000000000000000000000000000000012a05f200" } ] ``` You can calculate the exact storage slot to override for your own account with the following script: ```js import { ethers } from 'ethers'; function getBalanceSlot(accountAddress) { // Convert address to bytes32 and normalize const addr = ethers.zeroPadValue(accountAddress, 32); // CAUTION! The storage slot used here is 5, which // is specific to Wormhole contracts // The storage slot index for other tokens may vary const packedData = ethers.concat([ addr, ethers.zeroPadValue(ethers.toBeHex(5), 32), ]); // Calculate keccak256 return ethers.keccak256(packedData); } // Example usage const address = 'INSERT_ADDRESS'; console.log(getBalanceSlot(address)); ``` You can apply the same process for other ERC-20 token contracts. The following sections demonstrate overrides for the `0x3B939FeaD1557C741Ff06492FD0127bd287A421e` account with various ERC-20 tokens. Remember to update the H160 token contract address whenever you switch to a different token. Also, you will need to recalculate the H256 storage slot for each distinct account whose balance you want to override. ??? code "Example: Override Wormhole BTC Token Balance" ```json [ { "pallet": "EVM", "storage": "AccountStorages", "key": [ "0xE57eBd2d67B462E9926e04a8e33f01cD0D64346D", "0x8c9902c0f94ae586c91ba539eb52087d3dd1578da91158308d79ff24a8d4f342" ], "value": "0x000000000000000000000000000000000000000000000000000000012a05f200" } ] ``` ??? code "Example: Override Wormhole ETH Token Balance" ```json [ { "pallet": "EVM", "storage": "AccountStorages", "key": [ "0xab3f0245B83feB11d15AAffeFD7AD465a59817eD", "0x8c9902c0f94ae586c91ba539eb52087d3dd1578da91158308d79ff24a8d4f342" ], "value": "0x000000000000000000000000000000000000000000000000000000012a05f200" } ] ``` ??? code "Example: Override WELL Token Balance" Because the [WELL token](https://moonbeam.moonscan.io/token/0x511ab53f793683763e5a8829738301368a2411e3){target=_blank} does not use a proxy implementation contract, the storage slot calculation differs. Instead of slot `5`, the balance mapping resides at slot `1`. You can determine the exact storage slot to override the WELL token balance for your own account using the following script: ```js import { ethers } from 'ethers'; function getBalanceSlot(accountAddress) { // Convert address to bytes32 and normalize const addr = ethers.zeroPadValue(accountAddress, 32); // Caution! The storage slot index used here is 1 // The storage slot index for other tokens may vary const packedData = ethers.concat([ addr, ethers.zeroPadValue(ethers.toBeHex(1), 32), ]); // Calculate keccak256 return ethers.keccak256(packedData); } // Example usage const address = 'INSERT_ADDRESS'; console.log(getBalanceSlot(address)); ``` Thus, the storage override would be: ```json [ { "pallet": "EVM", "storage": "AccountStorages", "key": [ "0x511aB53F793683763E5a8829738301368a2411E3", "0x728d3daf4878939a6bb58cbc263f39655bb57ea15db7daa0b306f3bf2c3f1227" ], "value": "0x000000000000000000000000000000000000000000000000000000012a05f200" } ] ``` ## Tracing RPC Endpoint Providers {: #tracing-providers } Tracing RPC endpoints allow you to access non-standard RPC methods, such as those that belong to Geth's `debug` and `txpool` APIs and OpenEthereum's `trace` module. To see a list of the supported non-standard RPC methods on Moonbeam for debugging and tracing, please refer to the [Debug API & Trace Module](/builders/ethereum/json-rpc/debug-trace/){target=_blank} guide. The following providers provide tracing RPC endpoints: - [OnFinality](#onfinality-tracing) ### OnFinality {: #onfinality-tracing } [OnFinality](https://onfinality.io){target=_blank}'s Trace API can be used to quickly get started tracing and debugging transactions on Moonbeam and Moonriver. It is only available to users on their [Growth and Ultimate plans](https://onfinality.io/pricing){target=_blank}. To use the Trace API, you simply call the trace method of your choice from your [private RPC endpoint](#onfinality). For a list of the supported networks and trace methods, please check out [OnFinality's Trace API documentation](https://documentation.onfinality.io/support/trace-api#TraceAPI-SupportedNetworks){target=_blank}. Please note that if you are tracing historic blocks, it is recommended to use your own dedicated trace node to backfill any data, and then once you're caught up, you can switch to using the Trace API. You can check out the [How to Deploy a Trace Node for Moonbeam on OnFinality](https://onfinality.medium.com/how-to-deploy-a-trace-node-for-moonbeam-on-onfinality-85683181d290){target=-_blank} post for more information on how to spin up your own dedicated trace node. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/get-started/explorers/ --- BEGIN CONTENT --- --- title: Block Explorers description: An overview of the currently available block explorers that may be used to navigate the Substrate and Ethereum layers of Moonbeam. categories: Basics --- # Block Explorers ## Introduction {: #introduction } Block explorers can be thought of as search engines for the blockchain. They allow users to search for information such as balances, contracts, and transactions. More advanced block explorers even offer indexing capabilities, which enable them to provide a complete set of information, such as ERC-20 tokens in the network. They might even offer API services to access it via external services. Moonbeam provides two different kinds of explorers: ones to query the Ethereum API and others dedicated to the Substrate API. All EVM-based transactions are accessible via the Ethereum API, while the Substrate API can be relied upon for Substrate-native functions such as governance and staking. The Substrate API also includes information about the EVM-based transactions, but only limited information is shown. ## Quick Links {: #quick-links } === "Moonbeam" | Block Explorer | Type | URL | |:--------------:|:---------:|:-------------------------------------------------------------------------------------------------------------------------------------:| | Moonscan | EVM | [https://moonbeam.moonscan.io/](https://moonbeam.moonscan.io){target=\_blank} | | Expedition | EVM | [https://moonbeam-explorer.netlify.app/?network=Moonbeam](https://moonbeam-explorer.netlify.app/?network=Moonbeam){target=\_blank} | | Subscan | Substrate | [https://moonbeam.subscan.io/](https://moonbeam.subscan.io){target=\_blank} | | Polkadot.js | Substrate | [https://polkadot.js.org/apps/#/explorer](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbeam.network#/explorer){target=\_blank} | === "Moonriver" | Block Explorer | Type | URL | |:--------------:|:---------:|:-----------------------------------------------------------------------------------------------------------------------------------------------:| | Moonscan | EVM | [https://moonriver.moonscan.io/](https://moonriver.moonscan.io){target=\_blank} | | Expedition | EVM | [https://moonbeam-explorer.netlify.app/?network=Moonriver](https://moonbeam-explorer.netlify.app/?network=Moonriver){target=\_blank} | | Subscan | Substrate | [https://moonriver.subscan.io/](https://moonriver.subscan.io){target=\_blank} | | Polkadot.js | Substrate | [https://polkadot.js.org/apps/#/explorer](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonrvier.moonbeam.network#/explorer){target=\_blank} | === "Moonbase Alpha" | Block Explorer | Type | URL | |:--------------:|:---------:|:----------------------------------------------------------------------------------------------------------------------------------------------:| | Moonscan | EVM | [https://moonbase.moonscan.io/](https://moonbase.moonscan.io){target=\_blank} | | Expedition | EVM | [https://moonbeam-explorer.netlify.app/?network=MoonbaseAlpha](https://moonbeam-explorer.netlify.app/?network=MoonbaseAlpha){target=\_blank} | | Subscan | Substrate | [https://moonbase.subscan.io/](https://moonbase.subscan.io){target=\_blank} | | Polkadot.js | Substrate | [https://polkadot.js.org/apps/#/explorer](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/explorer){target=\_blank} | === "Moonbeam Dev Node" | Block Explorer | Type | URL | |:--------------:|:---------:|:-------------------------------------------------------------------------------------------------------------------------------------------------:| | Expedition | EVM | [https://moonbeam-explorer.netlify.app/?network=MoonbeamDevNode](https://moonbeam-explorer.netlify.app/?network=MoonbeamDevNode){target=\_blank} | | Polkadot.js | Substrate | [https://polkadot.js.org/apps/#/explorer](https://polkadot.js.org/apps/?rpc=wss://ws%3A%2F%2F127.0.0.1%3A9944#/explorer){target=\_blank} | ## Ethereum API {: #ethereum-api } ### Moonscan {: #Moonscan } [Moonscan](https://moonscan.io){target=\_blank} is the primary Ethereum API block explorer for Moonbeam-based networks. Built by the Etherscan team, Moonscan provides a powerful, intuitive, and feature-rich experience. In addition to its comprehensive transaction and block data, Moonscan provides a number of [statistics and charts](https://moonbeam.moonscan.io/charts){target=\_blank}, such as average gas price, daily transactions, and block size charts. Other Moonscan features include: - [Collator leaderboard](https://moonbeam.moonscan.io/collators){target=\_blank} ranking collators by performance - [Contract source code verification](/builders/ethereum/verify-contracts/block-explorers/){target=\_blank}, accessible both via a web interface and an API - Ability to read and write state data of verified smart contracts - [Token approvals](https://moonscan.io/tokenapprovalchecker){target=\_blank} where you can view and revoke any of your prior token approvals - [Adding token information](/builders/get-started/token-profile/){target=\_blank} and creating a profile for ERC-20s, ERC-721s, and ERC-1155s deployed to Moonbeam-based networks. The profile can include links to your project, social media, price data, and other information pertaining to your token ![Moonbeam Moonscan](/images/builders/get-started/explorers/explorers-1.webp) ### Expedition {: #expedition } A Moonbeam-themed version of the [Expedition](https://github.com/xops/expedition){target=\_blank} explorer can be found in [this link](https://moonbeam-explorer.netlify.app){target=\_blank}. It is a basic JSON-RPC based explorer. By default, the explorer is connected to Moonbeam. However, you can switch to Moonriver or Moonbase Alpha, or connect it to a local dev node by following the next steps: 1. Click on the network text, where you'll be able to select between all different networks, including a **Moonbeam Development Node** running on `{{ networks.development.rpc_url }}` 2. In the case you want to connect to a specific RPC URL, select **Add Custom Chain** and enter the URL. For example, `http://localhost:9937` ![Expedition Explorer](/images/builders/get-started/explorers/explorers-2.webp) ## Substrate API {: #substrate-api } ### Subscan {: #subscan } [Subscan](https://moonbeam.subscan.io){target=\_blank} is the primary Substrate API block explorer for Moonbeam-based networks. Subscan is capable of parsing standard or custom modules. For example, this is useful to display information regarding the Staking, Governance, and EVM pallets (or modules). The code is all open-source and can be found in the [Subscan Essentials GitHub repo](https://github.com/subscan-explorer/subscan-essentials){target=\_blank}. ![Subscan Moonbeam](/images/builders/get-started/explorers/explorers-3.webp) ### Polkadot.js {: #polkadotjs } While not a full-featured block explorer, Polkadot.js Apps is a convenient option especially for users running local development nodes to view events and query transaction hashes. Polkadot.js Apps uses the WebSocket endpoint to interact with the Network. You can easily connect to [Moonbeam](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbeam.network#/explorer){target=\_blank}, [Moonriver](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonriver.moonbase.moonbeam.network#/explorer){target=\_blank}, or [Moonbase Alpha](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/explorer){target=\_blank}. ![Polkadot.js Moonbeam](/images/builders/get-started/explorers/explorers-4.webp) To connect it to a Moonbeam development node, you can follow the steps in the [Connecting Polkadot.js Apps to a Local Moonbeam Node](/builders/get-started/networks/moonbeam-dev/#connecting-polkadot-js-apps-to-a-local-moonbeam-node){target=\_blank} section of the [Getting Started with a Moonbeam Development Node](/builders/get-started/networks/moonbeam-dev/){target=\_blank} guide. The default port for this is `9944`. ![Polkadot.js Local Node](/images/builders/get-started/explorers/explorers-5.webp) --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/get-started/ --- BEGIN CONTENT --- --- title: Get Started with Moonbeam description: Everything you need to know to get started developing, deploying, and interacting with smart contracts on Moonbeam. dropdown_description: Everything you need to get started building template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/get-started/networks/ --- BEGIN CONTENT --- --- title: Get Started with Moonbeam-based Networks description: Learn how to get started developing on a Moonbeam development node, the Moonbase Alpha TestNet, Moonriver, or Moonbeam. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/get-started/networks/moonbase/ --- BEGIN CONTENT --- --- title: Moonbase Alpha Get Started Guide description: The Moonbeam TestNet, named Moonbase Alpha, is the easiest way to get started with a Polkadot environment. Follow this tutorial to connect to the TestNet. categories: Basics --- # Get Started with Moonbase Alpha ## Network Endpoints {: #network-endpoints } Moonbase Alpha has two types of endpoints available for users to connect to: one for HTTPS and one for WSS. If you're looking for your own endpoints suitable for production use, you can check out the [Endpoint Providers](/builders/get-started/endpoints/#endpoint-providers){target=\_blank} section of our documentation. Otherwise, to get started quickly you can use one of the following public HTTPS or WSS endpoints. === "HTTPS" | Provider | RPC URL | Limits | |:-------------------:|:------------------------------------------------------------------:|:-----------:| | Dwellir |
```https://moonbase-rpc.dwellir.com```
| 20 req/sec | | OnFinality |
```https://moonbeam-alpha.api.onfinality.io/public```
| 40 req/sec | | Moonbeam Foundation |
```https://rpc.api.moonbase.moonbeam.network```
| 25 req/sec | | UnitedBloc |
```https://moonbase.unitedbloc.com```
| 32 req/sec | | RadiumBlock |
```https://moonbase.public.curie.radiumblock.co/http```
| 200 req/sec | === "WSS" | Provider | RPC URL | Limits | |:-------------------:|:-----------------------------------------------------------------:|:-----------:| | Dwellir |
```wss://moonbase-rpc.dwellir.com```
| 20 req/sec | | OnFinality |
```wss://moonbeam-alpha.api.onfinality.io/public-ws```
| 40 req/sec | | Moonbeam Foundation |
```wss://wss.api.moonbase.moonbeam.network```
| 25 req/sec | | UnitedBloc |
```wss://moonbase.unitedbloc.com```
| 32 req/sec | | RadiumBlock |
```wss://moonbase.public.curie.radiumblock.co/ws```
| 200 req/sec | #### Relay Chain {: #relay-chain } To connect to the Moonbase Alpha relay chain, you can use the following WS Endpoint: | Provider | RPC URL | |:--------:|:----------------------------------------------------------:| | OpsLayer |
```wss://relay.api.moonbase.moonbeam.network```
| ## Quick Start {: #quick-start } For the [Web3.js library](/builders/ethereum/libraries/web3js/){target=\_blank}, you can create a local Web3 instance and set the provider to connect to Moonbase Alpha (both HTTP and WS are supported): ```js const { Web3 } = require('web3'); // Load Web3 library . . . // Create local Web3 instance - set Moonbase Alpha as provider const web3 = new Web3('https://rpc.api.moonbase.moonbeam.network'); ``` For the [Ethers.js library](/builders/ethereum/libraries/ethersjs/){target=\_blank}, define the provider by using `ethers.JsonRpcProvider(providerURL, {object})` and setting the provider URL to Moonbase Alpha: ```js const ethers = require('ethers'); // Load Ethers library const providerURL = 'https://rpc.api.moonbase.moonbeam.network'; // Define provider const provider = new ethers.JsonRpcProvider(providerURL, { chainId: 1287, name: 'moonbase-alphanet' }); ``` Any Ethereum wallet should be able to generate a valid address for Moonbeam (for example, [MetaMask](https://metamask.io){target=\_blank}). ## Chain ID {: #chain-id } Moonbase Alpha TestNet chain ID is: `1287`, which is `0x507` in hex. ## Block Explorers For Moonbase Alpha, you can use any of the following block explorers: - **Ethereum API (Etherscan Equivalent)** — [Moonscan](https://moonbase.moonscan.io){target=\_blank} - **Ethereum API JSON-RPC based** — [Moonbeam Basic Explorer](https://moonbeam-explorer.netlify.app/?network=MoonbaseAlpha){target=\_blank} - **Substrate API** — [Subscan](https://moonbase.subscan.io){target=\_blank} or [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/explorer){target=\_blank} For more information on each of the available block explorers, please head to the [Block Explorers](/builders/get-started/explorers/){target=\_blank} section of the documentation. ## Connect MetaMask If you already have MetaMask installed, you can easily connect MetaMask to the Moonbase Alpha TestNet: !!! note MetaMask will popup asking for permission to add Moonbase Alpha as a custom network. Once you approve permissions, MetaMask will switch your current network to Moonbase Alpha. If you do not have MetaMask installed, or would like to follow a tutorial to get started, please check out the [Interacting with Moonbeam using MetaMask](/tokens/connect/metamask/){target=\_blank} guide. ## Configuration {: #configuration } Please note the following gas configuration parameters. These values are subject to change in future runtime upgrades. | Variable | Value | |:---------------------:|:------------------------------------------:| | Minimum gas price | {{ networks.moonbase.min_gas_price }} Gwei | | Target block time | {{ networks.moonbase.block_time }} seconds | | Block gas limit | {{ networks.moonbase.gas_block }} | | Transaction gas limit | {{ networks.moonbase.gas_tx }} | ## Get Tokens {: #get-tokens } To start building on Moonbase Alpha, you can get DEV tokens from the Moonbase Alpha Faucet. For specific amounts, you can always reach out directly to us via our community channels. To request DEV tokens from the faucet, you can enter your address on the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} website. The faucet dispenses {{ networks.moonbase.website_faucet_amount }} every 24 hours. ![Moonbase Alpha Faucet Website.](/images/builders/get-started/networks/moonbase/moonbase-1.webp) !!! note Moonbase Alpha DEV tokens have no value. Please don't spam the faucet with unnecessary requests. ## Demo DApps {: #Demo-DApps } There are a variety of DApps deployed to Moonbase Alpha enabling you to experiment with various apps and integrations. You can also acquire a variety of test tokens through the [Moonbase ERC20 Minter](https://moonbase-minterc20.netlify.app){target=\_blank} or [Moonbeam Uniswap](https://moonbeam-swap.netlify.app/#/swap){target=\_blank} DApps. For example, [Moonbeam Uniswap](https://moonbeam-swap.netlify.app/#/swap){target=\_blank} can help you acquire cross-chain assets such as xcUNIT or xcKarura for testing XCM related functions. In the below table, you'll find each sample DApp, its associated URL, and GitHub repository. ### Quick Links {: #quick-links } | DApp | Description | Repository | |:------------------------------------------------------------------------------------------:|:------------------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------:| | [Moonbase ERC-20 Minter](https://moonbase-minterc20.netlify.app){target=\_blank} | ERC-20 Faucet | [https://github.com/papermoonio/moonbase-mintableERC20](https://github.com/papermoonio/moonbase-mintableERC20){target=\_blank} | | [Moonbeam Uniswap](https://moonbeam-swap.netlify.app/#/swap){target=\_blank} | Uniswap V2 Fork | [https://github.com/papermoonio/moonbeam-uniswap](https://github.com/papermoonio/moonbeam-uniswap){target=\_blank} | | [MoonLink Dashboard](https://moonlink-dashboard.netlify.app){target=\_blank} | Chainlink Demo | [https://github.com/papermoonio/moonlink-dashboard](https://github.com/papermoonio/moonlink-dashboard){target=\_blank} | | [MoonLotto Lottery](https://moonbase-moonlotto.netlify.app){target=\_blank} | TheGraph Demo | [Interface](https://github.com/papermoonio/moonlotto-interface){target=\_blank}, [Subgraph](https://github.com/papermoonio/moonlotto-subgraph){target=\_blank} | | [Moonbeam WalletConnect](https://moonbeam-walletconnect-demo.netlify.app){target=\_blank} | WalletConnect Demo | [https://github.com/papermoonio/moonbeam-walletconnect-demo](https://github.com/papermoonio/moonbeam-walletconnect-demo){target=\_blank} | | [MoonGas](https://moonbeam-gasinfo.netlify.app){target=\_blank} | Gas Price Tracker | [https://github.com/albertov19/moonbeam-gas-station](https://github.com/albertov19/moonbeam-gas-station){target=\_blank} | !!! note These DApps are intended for demonstration purposes only and may be incomplete or unsuitable for production deployments. ### Moonbase ERC20 Minter {: #moonbase-erc20-minter } The [Moonbase ERC-20 Minter](https://moonbase-minterc20.netlify.app){target=\_blank} enables you to mint a variety of ERC-20 test tokens corresponding to the 8 planets of the solar system, and Pluto. To mint tokens, first press **Connect MetaMask** in the upper right hand corner. Then scroll to the **Mint Tokens** section and the choose desired ERC-20 contract. Press **Submit Tx** and confirm the transaction in MetaMask. Each mint will grant you 100 tokens, and you can mint tokens for each contract once per hour. ![ERC20 Minter](/images/builders/get-started/networks/moonbase/moonbase-2.webp) ### Moonbeam Uniswap {: #moonbeam-uniswap } [Moonbeam Uniswap](https://moonbeam-swap.netlify.app/#/swap){target=\_blank} is a fork of [Uniswap-V2](https://blog.uniswap.org/uniswap-v2){target=\_blank} deployed to Moonbase Alpha. Notably, Moonbeam Uniswap allows developers to easily make a swap to acquire [cross-chain assets](/builders/interoperability/xcm/xc20/){target=\_blank} such as xcKarura or xcUNIT for XCM testing purposes. To perform your first swap, take the following steps: 1. Press **Select a token** 2. Connect your MetaMask wallet and ensure you're on the Moonbase Alpha network 3. Press **Choose a List** on the prompt 4. Select **Moon Menu** 5. Search for or select your desired asset from the list then continue with the swap ![Moonbeam Swap](/images/builders/get-started/networks/moonbase/moonbase-3.webp) !!! note If you see only a partial list of assets under **Moon Menu**, your browser may have cached an older version of **Moon Menu**. Clearing the cache and re-adding **Moon Menu** will resolve this. ### MoonLink Dashboard {: #moonlink-dashboard } The [MoonLink Dashboard](https://moonlink-dashboard.netlify.app){target=\_blank} showcases Chainlink price feeds in action. For more information, including a full listing of all Chainlink price feeds across all Moonbeam networks and a step-by-step guide of how to fetch price feed data, [head to the Oracles section of the Moonbeam Docs Site](/builders/integrations/oracles/chainlink/){target=\_blank}. You can also check out the [repository for the MoonLink Dashboard](https://github.com/papermoonio/moonlink-dashboard){target=\_blank}. ![MoonLink Dashboard](/images/builders/get-started/networks/moonbase/moonbase-4.webp) ### MoonLotto Lottery {: #moonlotto-lottery } [MoonLotto](https://moonbase-moonlotto.netlify.app){target=\_blank} is a simple lottery game on Moonbase Alpha derived from [The Graph's Example Subgraph](https://github.com/graphprotocol/example-subgraph){target=\_blank}. Purchasing a ticket costs 1 DEV and a winner is chosen each half hour if there are at least 10 participants. [MoonLotto.sol](https://github.com/papermoonio/moonlotto-subgraph/blob/main/contracts/MoonLotto.sol){target=\_blank} holds the contract logic for the lottery. To participate, take the following steps: 1. Connect your MetaMask wallet and ensure you're on the Moonbase Alpha network 2. Enter the address of the recipient of lotto ticket or check **I want to buy a ticket for my address** 3. Press **Submit on MetaMask** and confirm the transaction in MetaMask ![MoonLotto Lottery](/images/builders/get-started/networks/moonbase/moonbase-5.webp) ### Moonbeam WalletConnect {: #moonbeam-walletconnect } [Moonbeam WalletConnect](https://moonbeam-walletconnect-demo.netlify.app){target=\_blank} shows how easy it is to integrate [WalletConnect](https://walletconnect.com){target=\_blank} into your DApps and unlock support for a great variety of crypto wallets. Be sure to check out the [demo app repository](https://github.com/papermoonio/moonbeam-walletconnect-demo){target=\_blank} to see exactly how the WalletConnect integration works. To get started, you can take the following steps: 1. Press **Connect Wallet** 2. Scan the QR code using a [wallet compatible with WalletConnect](https://walletguide.walletconnect.network/){target=\_blank} ![Moonbeam WalletConnect](/images/builders/get-started/networks/moonbase/moonbase-6.webp) ### MoonGas {: #moongas } [MoonGas](https://moonbeam-gasinfo.netlify.app){target=\_blank} is a convenient dashboard for viewing the minimum, maximum, and average gas price of transactions in the prior block across all Moonbeam networks. Note, these statistics can fluctuate widely by block and occasionally include outlier values. You can check out the [repository for MoonGas](https://github.com/albertov19/moonbeam-gas-station){target=\_blank}. You'll notice that the minimum gas price for Moonbeam is {{ networks.moonbeam.min_gas_price }} Gwei, while the minimum for Moonriver is {{ networks.moonriver.min_gas_price }} Gwei and Moonbase Alpha is {{ networks.moonbase.min_gas_price }} Gwei. This difference stems from the [100 to 1 re-denomination of GLMR](https://moonbeam.network/news/moonbeam-foundation-announces-liquidity-programs-a-new-token-event-and-glmr-redenomination){target=\_blank} and thus the {{ networks.moonbeam.min_gas_price }} Gwei minimum on Moonbeam corresponds to a {{ networks.moonriver.min_gas_price }} Gwei minimum on Moonriver and a {{ networks.moonbase.min_gas_price }} Gwei on Moonbase. ![MoonGas](/images/builders/get-started/networks/moonbase/moonbase-7.webp) --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/get-started/networks/moonbeam-dev/ --- BEGIN CONTENT --- --- title: Run a Moonbeam Development Node description: Follow this tutorial to learn how to spin up your first Moonbeam development node, how to configure it for development purposes, and connect to it. categories: Basics --- # Getting Started with a Local Moonbeam Development Node
## Introduction {: #introduction } A Moonbeam development node is your own personal development environment for building and testing applications on Moonbeam. For Ethereum developers, it is comparable to the Hardhat Network. It enables you to get started quickly and easily without the overhead of a relay chain. You can spin up your node with the `--sealing` option to author blocks instantly, manually, or at a custom interval after transactions are received. By default, a block will be created when a transaction is received, which is similar to the default behavior of Hardhat Network's instamine feature. If you follow this guide to the end, you will have a Moonbeam development node running in your local environment with 10 prefunded [accounts](#pre-funded-development-accounts). !!! note This tutorial was created using the {{ networks.development.build_tag }} tag of [Moonbase Alpha](https://github.com/moonbeam-foundation/moonbeam/releases/tag/{{ networks.development.build_tag }}){target=\_blank}. The Moonbeam platform and the [Frontier](https://github.com/polkadot-evm/frontier){target=\_blank} components it relies on for Substrate-based Ethereum compatibility are still under very active development. The examples in this guide assume you have a MacOS or Ubuntu 22.04-based environment and will need to be adapted accordingly for Windows. ## Spin Up a Moonbeam Development Node {: #spin-up-a-node } There are two ways to get started running a Moonbeam node. You can use [Docker to run a pre-built binary](#getting-started-with-docker) or you can [compile the binary locally](#getting-started-with-the-binary-file) and set up a development node yourself. Using Docker is a quick and convenient way to get started, as you won't have to install Substrate and all the dependencies, and you can skip the node-building process as well. It does require you to [install Docker](https://docs.docker.com/get-started/get-docker/){target=\_blank}. On the other hand, if you decide you want to go through the process of building your development node, it could take roughly 30 minutes or longer to complete, depending on your hardware. ### Spin Up a Node with Docker {: #getting-started-with-docker } Using Docker enables you to spin up a node in a matter of seconds. Once you have Docker installed, you can take the following steps to spin up your node: 1. Execute the following command to download the latest Moonbeam image: ```bash docker pull moonbeamfoundation/moonbeam:{{ networks.development.build_tag }} ``` The tail end of the console log should look like this:
docker pull moonbeamfoundation/moonbeam:v0.43.0
v0.43.0: Pulling from moonbeamfoundation/moonbeam
b0a0cf830b12: Pull complete
fbff687640dd: Pull complete
58ea427410e2: Pull complete
811ba55e6e61: Pull complete
4316d5f1b914: Pull complete
128693ce218e: Pull complete
a3ac90b88463: Pull complete
Digest: sha256:86421aca2381265cd2e5283cb98705e24be0bc92a73937363f79d9d6e0d62088
Status: Downloaded newer image for moonbeamfoundation/moonbeam:v0.43.0
docker.io/moonbeamfoundation/moonbeam:v0.43.0
2. Spin up a Moonbeam development node by running the following Docker command, which will launch the node in instant seal mode for local testing so that blocks are authored instantly as transactions are received: === "Ubuntu" ```bash docker run --rm --name {{ networks.development.container_name }} --network host \ moonbeamfoundation/moonbeam:{{ networks.development.build_tag }} \ --dev --rpc-external ``` === "MacOS" ```bash docker run --rm --name {{ networks.development.container_name }} -p 9944:9944 \ moonbeamfoundation/moonbeam:{{ networks.development.build_tag }} \ --dev --rpc-external ``` === "Windows" ```bash docker run --rm --name {{ networks.development.container_name }} -p 9944:9944 ^ moonbeamfoundation/moonbeam:{{ networks.development.build_tag }} ^ --dev --rpc-external ``` !!! note On MacOS with silicon chips, Docker images may perform poorly. To improve performance, try [spinning up a Node with a Binary File](#getting-started-with-the-binary-file). If successful, you should see an output showing an idle state waiting for blocks to be authored:
docker run --rm --name moonbeam_development --network host \
moonbeamfoundation/moonbeam:v0.45.0 \
--dev --rpc-external

CLI parameter `--execution` has no effect anymore and will be removed in the future!
2025-07-10 09:04:26 Moonbeam Parachain Collator
2025-07-10 09:04:26 ✌️ version 0.46.0-d7df89e7161
2025-07-10 09:04:26 ❤️ by PureStake, 2019-2025
2025-07-10 09:04:26 📋 Chain specification: Moonbase Development Testnet
2025-07-10 09:04:26 🏷 Node name: black-and-white-sticks-9174
2025-07-10 09:04:26 👤 Role: AUTHORITY
2025-07-10 09:04:26 💾 Database: RocksDb at /tmp/substrateO3YeRz/chains/moonbase_dev/db/full
2025-07-10 09:04:26 🔨 Initializing Genesis block/state (state: 0xf7c4…5c0f, header-hash: 0x42bd…3b5b)
2025-07-10 09:04:26 Using default protocol ID "sup" because none is configured in the chain specs
2025-07-10 09:04:26 🏷 Local node identity is: 12D3KooWLcpczme2JeBEfLqmjqkzYVKTGKhhGmwSzHjRXGBVhDX7
2025-07-10 09:04:26 💻 Operating system: linux
2025-07-10 09:04:26 💻 CPU architecture: x86_64
2025-07-10 09:04:26 💻 Target environment: gnu
2025-07-10 09:04:26 💻 CPU: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
2025-07-10 09:04:26 💻 CPU cores: 12
2025-07-10 09:04:26 💻 Memory: 7946MB
2025-07-10 09:04:26 💻 Kernel: 6.4.16-linuxkit
2025-07-10 09:04:26 💻 Linux distribution: Debian GNU/Linux 12 (bookworm)
2025-07-10 09:04:26 💻 Virtual machine: yes
2025-07-10 09:04:26 📦 Highest known block at #0
2025-07-10 09:04:26 Running JSON-RPC server: addr=0.0.0.0:9944, allowed origins=["*"]
2025-07-10 09:04:26 🏁 CPU score: 1.14 GiBs
2025-07-10 09:04:26 〽️ Prometheus exporter started at 127.0.0.1:9615
2025-07-10 09:04:26 🏁 Memory score: 10.41 GiBs
2025-07-10 09:04:26 🏁 Disk score (seq. writes): 987.96 MiBs
2025-07-10 09:04:26 🏁 Disk score (rand. writes): 363.65 MiBs
2025-07-10 09:04:26 Development Service Ready
2025-07-10 09:04:26 💤 Idle (0 peers), best: #0 (0xa083…f354), finalized #0 (0xa083…f354), ⬇ 0 ⬆ 0
2025-07-10 09:04:26 💤 Idle (0 peers), best: #0 (0xa083…f354), finalized #0 (0xa083…f354), ⬇ 0 ⬆ 0
For more information on some of the flags and options used in the example, check out [Flags](#node-flags) and [Options](#node-options). If you want to see a complete list of all of the flags, options, and subcommands, open the help menu by running: ```bash docker run --rm --name {{ networks.development.container_name }} \ moonbeamfoundation/moonbeam \ --help ``` To continue with the tutorial, the next section is not necessary, as you've already spun up a node with Docker. You can skip ahead to the [Configure your Moonbeam Development Node](#configure-moonbeam-dev-node) section. ### Spin Up a Node with a Binary File {: #getting-started-with-the-binary-file } As an alternative to using Docker, you can spin up a node using the Moonbeam binary. This method is more time-consuming. Depending on your hardware, the process could take around 30 minutes to complete. !!! note If you know what you are doing, you can directly download the precompiled binaries attached to each release on the [Moonbeam release page](https://github.com/moonbeam-foundation/moonbeam/releases){target=\_blank}. These will not work in all systems. For example, the binaries only work with x86-64 Linux with specific versions of dependencies. The safest way to ensure compatibility is to compile the binary on the system where it will be run. To build the binary file, you can take the following steps: 1. Clone a specific tag of the Moonbeam repo, which you can find on the [Moonbeam GitHub repository](https://github.com/moonbeam-foundation/moonbeam){target=\_blank}: ```bash git clone -b {{ networks.development.build_tag }} https://github.com/moonbeam-foundation/moonbeam cd moonbeam ``` !!! note Spaces in the installation file path will cause a compilation error. 2. If you already have Rust installed, you can skip the next two steps. Otherwise, install Rust and its prerequisites [via Rust's recommended method](https://www.rust-lang.org/tools/install){target=\_blank} by executing: ```bash curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` 3. Update your PATH environment variable by running: ```bash source $HOME/.cargo/env ``` 4. Build the development node by running: !!! note If you are using Ubuntu 20.04 or 22.04, then you will need to make sure these additional dependencies have been installed before building the binary: ```bash apt install clang protobuf-compiler libprotobuf-dev pkg-config libssl-dev -y ``` For MacOS users, these dependencies can be installed via Homebrew: ```bash brew install llvm brew install protobuf ``` ```bash cargo build --release ``` Here is what the tail end of the build output should look like:
Compiling try-runtime-cli v0.9.0 (https://github.com/paritytech/substrate?branch=rococo-v1#401c24e8)
Compiling frame-benchmarking-cli v3.0.0 (https://github.com/paritytech/substrate?branch=rococo-v1#401c24e8)
Compiling cumulus-client-cli v0.1.0 (https://github.com/paritytech/cumulus?branch=rococo-v1#9d89ed65)
Compiling moonbeam-rpc-txpool v0.6.0 (/home/purestake/moonbeam/client/rpc/txpool)
Compiling moonbeam-rpc-debug v0.1.0 (/home/purestake/moonbeam/client/rpc/debug)
Compiling moonbeam-rpc-trace v0.6.0 (/home/purestake/moonbeam/client/rpc/trace)
Compiling cumulus-client-network v0.1.0 (https://github.com/paritytech/cumulus?branch=rococo-v1#9d89ed65)
Compiling cumulus-client-consensus-relay-chain v0.1.0 (https://github.com/paritytech/cumulus?branch=rococo-v1#9d89ed65)
Compiling polkadot-test-service v0.8.29 (https://github.com/paritytech/polkadot?branch=rococo-v1#b64741e6)
Compiling cumulus-client-collator v0.1.0 (https://github.com/paritytech/cumulus?branch=rococo-v1#9d89ed65)
Compiling cumulus-client-service v0.1.0 (https://github.com/paritytech/cumulus?branch=rococo-v1#9d89ed65)
Finished release [optimized] target(s) in 31m 17s
!!! note The initial build will take a while. Depending on your hardware, you should expect approximately 30 minutes for the build process to finish. Then, you will want to run the node in development mode using the following command: ```bash ./target/release/moonbeam --dev ``` !!! note For people not familiar with Substrate, the `--dev` flag is a way to run a Substrate-based node in a single-node developer configuration for testing purposes. When you run your node with the `--dev` flag, your node is started in a fresh state, and its state does not persist. You should see an output that looks like the following, showing an idle state waiting for blocks to be produced:
./target/release/moonbeam --dev
2025-07-10 09:04:26 Moonbeam Parachain Collator
2025-07-10 09:04:26 ✌️ version 0.46.0-d7df89e7161
2025-07-10 09:04:26 ❤️ by PureStake, 2019-2025
2025-07-10 09:04:26 📋 Chain specification: Moonbase Development Testnet
2025-07-10 09:04:26 🏷 Node name: black-and-white-sticks-9174
2025-07-10 09:04:26 👤 Role: AUTHORITY
2025-07-10 09:04:26 💾 Database: RocksDb at /tmp/substrateO3YeRz/chains/moonbase_dev/db/full
2025-07-10 09:04:26 🔨 Initializing Genesis block/state (state: 0x7c34…99c5, header-hash: 0xa083…f354)
2025-07-10 09:04:26 Using default protocol ID "sup" because none is configured in the chain specs
2025-07-10 09:04:26 🏷 Local node identity is: 12D3KooWLcpczme2JeBEfLqmjqkzYVKTGKhhGmwSzHjRXGBVhDX7
2025-07-10 09:04:26 💻 Operating system: linux
2025-07-10 09:04:26 💻 CPU architecture: x86_64
2025-07-10 09:04:26 💻 Target environment: gnu
2025-07-10 09:04:26 💻 CPU: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
2025-07-10 09:04:26 💻 CPU cores: 12
2025-07-10 09:04:26 💻 Memory: 7946MB
2025-07-10 09:04:26 💻 Kernel: 6.4.16-linuxkit
2025-07-10 09:04:26 💻 Linux distribution: Debian GNU/Linux 12 (bookworm)
2025-07-10 09:04:26 💻 Virtual machine: yes
2025-07-10 09:04:26 📦 Highest known block at #0
2025-07-10 09:04:26 Running JSON-RPC server: addr=0.0.0.0:9944, allowed origins=["*"]
2025-07-10 09:04:26 🏁 CPU score: 1.14 GiBs
2025-07-10 09:04:26 〽️ Prometheus exporter started at 127.0.0.1:9615
2025-07-10 09:04:26 🏁 Memory score: 10.41 GiBs
2025-07-10 09:04:26 🏁 Disk score (seq. writes): 987.96 MiBs
2025-07-10 09:04:26 🏁 Disk score (rand. writes): 363.65 MiBs
2025-07-10 09:04:26 Development Service Ready
2025-07-10 09:04:26 💤 Idle (0 peers), best: #0 (0xa083…f354), finalized #0 (0xa083…f354), ⬇ 0 ⬆ 0
2025-07-10 09:04:26 💤 Idle (0 peers), best: #0 (0xa083…f354), finalized #0 (0xa083…f354), ⬇ 0 ⬆ 0
For more information on some of the flags and options used in the example, check out the [Flags](#node-flags) and [Options](#node-options). If you want to see a complete list of all of the flags, options, and subcommands, open the help menu by running: ```bash ./target/release/moonbeam --help ``` ## Configure Your Moonbeam Development Node {: #configure-moonbeam-dev-node } Now that you know how to get a standard Moonbeam development node up and running, you may be wondering how you can configure it. The following sections will cover some common configurations you can use when you spin up your node. ### Common Flags to Configure Your Node {: #node-flags } Flags do not take an argument. To use a flag, add it to the end of a command. For example: ```bash ./target/release/moonbeam --dev ``` - **`--dev`** - specifies the development chain - **`--tmp`** - runs a temporary node in which all of the configuration will be deleted at the end of the process - **`--rpc-external`** - listen to all RPC and WebSocket interfaces ### Common Options to Configure Your Node {: #node-options } Options accept an argument to the right of the option. For example: ```bash ./target/release/moonbeam --dev --sealing 6000 ``` - **`-l ` or `--log `** - sets a custom logging filter. The syntax for the log pattern is `=`. For example, to print all of the JSON-RPC logs, the command would look like this: `-l json=trace` - **`--sealing `** - when blocks should be sealed in the dev service. Accepted arguments for interval: `instant`, `manual`, or a number representing the timer interval in milliseconds (for example, `6000` will have the node produce blocks every 6 seconds). The default is `instant``. Please refer to the [Configure Block Production](#configure-block-production) section below for more information - **`--rpc-port `** - sets the unified port for HTTP and WS connections. Accepts a port as the argument. Default is {{ networks.parachain.rpc }} - **`--ws-port `** - *deprecated as of [client v0.33.0](https://github.com/moonbeam-foundation/moonbeam/releases/tag/v0.33.0){target=\_blank}, use `--rpc-port` for HTTP and WS connections instead* - sets the WebSockets RPC server TCP port. As of [client v0.30.0](https://github.com/moonbeam-foundation/moonbeam/releases/tag/v0.30.0){target=\_blank}, it sets the unified port for both HTTP and WS connections. Accepts a port as the argument - **`--rpc-max-connections `** - specifies the combined HTTP and WS connection limit. The default is 100 connections - **`--ws-max-connections `** - *deprecated as of [client v0.33.0](https://github.com/moonbeam-foundation/moonbeam/releases/tag/v0.33.0){target=\_blank}, use `--rpc-max-connections` to limit the HTTP and WS connections instead* - this flag adjusts the combined HTTP and WS connection limit. The default is 100 connections - **`--rpc-cors `** - specifies the browser origins allowed to access the HTTP and WS RPC servers. The origins can be a comma-separated list of the origins to allow access, or you can also specify `null`. When running a development node, the default is to allow all origins For a complete list of flags and options, spin up your Moonbeam development node with `--help` added to the end of the command. ### Configure Block Production {: #configure-block-production } By default, your Moonbeam development node is spun up in instant seal mode, which instantly authors blocks as transactions are received. However, you can specify when blocks should be authored or sealed by using the `--sealing` option. The `--sealing` flag accepts any of the following arguments: - `instant` - as we already covered, this is the default option in which blocks are authored as soon as a transaction is received - `manual` - allows you to produce blocks manually. If a transaction is received, a block will not be produced until you manually create one - an interval in milliseconds - authors a block on a specific time interval. For example, if you set it to `6000`, you will have the node produce blocks every 6 seconds The flag should be appended to the start-up command in the following format: ```text --sealing ``` If you choose `manual`, you'll need to manually create the blocks yourself, which can be done with the `engine_createBlock` JSON-RPC method: ```text engine_createBlock(createEmpty: *bool*, finalize: *bool*, parentHash?: *BlockHash*) ``` For example, you can use the following snippet to manually create a block using [Ethers.js](/builders/ethereum/libraries/ethersjs/){target=\_blank}, an Ethereum library that makes it easy to interact with JSON-RPC methods: ```js import { ethers } from 'ethers'; const produceBlock = async () => { // Connect to the Ethereum node (if applicable, replace the URL with your node's address) const provider = new ethers.JsonRpcProvider( '{{ networks.development.rpc_url }}' ); // Set the custom JSON-RPC method and parameters const method = 'engine_createBlock'; const params = [true, true, null]; try { // Send the custom JSON-RPC call const result = await provider.send(method, params); } catch (error) { // Handle any errors that may occur console.error('Error:', error.message); } }; produceBlock(); ``` !!! note If you're unfamiliar with Ethers, please refer to the [Ethers.js](/builders/ethereum/libraries/ethersjs/){target=\_blank} documentation page to learn more. ## Prefunded Development Accounts {: #pre-funded-development-accounts } Moonbeam has a [unified accounts](/learn/core-concepts/unified-accounts/){target=\_blank} system, which enables users to have an Ethereum-styled H160 account that can interact with the Substrate API and the Ethereum API. As a result, you can interact with your account through [Polkadot.js Apps](/tokens/connect/polkadotjs/#connect-polkadotjs-apps){target=\_blank} or [MetaMask](/tokens/connect/metamask/){target=\_blank} (or any other [EVM wallet](/tokens/connect/){target=\_blank}). In addition, you can also use other [development tools](/builders/ethereum/dev-env/){target=\_blank}, such as [Remix](/builders/ethereum/dev-env/remix/){target=\_blank} and [Hardhat](/builders/ethereum/dev-env/hardhat/){target=\_blank}. Your Moonbeam development node comes with ten prefunded Ethereum-styled accounts for development. The addresses are derived from Substrate's canonical development mnemonic: ```text bottom drive obey lake curtain smoke basket hold race lonely fit walk ``` ??? note "Development account addresses and private keys" - Alith: - Public Address: `0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac` - Private Key: `0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133` - Baltathar: - Public Address: `0x3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0` - Private Key: `0x8075991ce870b93a8870eca0c0f91913d12f47948ca0fd25b49c6fa7cdbeee8b` - Charleth: - Public Address: `0x798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc` - Private Key: `0x0b6e18cafb6ed99687ec547bd28139cafdd2bffe70e6b688025de6b445aa5c5b` - Dorothy: - Public Address: `0x773539d4Ac0e786233D90A233654ccEE26a613D9` - Private Key: `0x39539ab1876910bbf3a223d84a29e28f1cb4e2e456503e7e91ed39b2e7223d68` - Ethan: - Public Address: `0xFf64d3F6efE2317EE2807d223a0Bdc4c0c49dfDB` - Private Key: `0x7dce9bc8babb68fec1409be38c8e1a52650206a7ed90ff956ae8a6d15eeaaef4` - Faith: - Public Address: `0xC0F0f4ab324C46e55D02D0033343B4Be8A55532d` - Private Key: `0xb9d2ea9a615f3165812e8d44de0d24da9bbd164b65c4f0573e1ce2c8dbd9c8df` - Goliath: - Public Address: `0x7BF369283338E12C90514468aa3868A551AB2929` - Private Key: `0x96b8a38e12e1a31dee1eab2fffdf9d9990045f5b37e44d8cc27766ef294acf18` - Heath: - Public Address: `0x931f3600a299fd9B24cEfB3BfF79388D19804BeA` - Private Key: `0x0d6dcaaef49272a5411896be8ad16c01c35d6f8c18873387b71fbc734759b0ab` - Ida: - Public Address: `0xC41C5F1123ECCd5ce233578B2e7ebd5693869d73` - Private Key: `0x4c42532034540267bf568198ccec4cb822a025da542861fcb146a5fab6433ff8` - Judith: - Public Address: `0x2898FE7a42Be376C8BC7AF536A940F7Fd5aDd423` - Private Key: `0x94c49300a58d576011096bcb006aa06f5a91b34b4383891e8029c21dc39fbb8b` Also included with the development node is an additional prefunded account used for testing purposes: - Gerald: - Public Address: `0x6Be02d1d3665660d22FF9624b7BE0551ee1Ac91b` - Private Key: `0x99b3c12287537e38c90a9219d4cb074a89a16e9cdb20bf85728ebd97c343e342` You can connect any of these accounts to [MetaMask](/tokens/connect/metamask/){target=\_blank}, [Talisman](/tokens/connect/talisman/){target=\_blank}, [Polkadot.js Apps](/tokens/connect/polkadotjs/){target=\_blank}, etc., using their private keys. ## Development Node Endpoints {: #access-your-development-node } You can access your Moonbeam development node using the following RPC and WSS endpoints: === "HTTP" ```text {{ networks.development.rpc_url }} ``` === "WSS" ```text {{ networks.development.wss_url }} ``` ## Block Explorers {: #block-explorers } For a Moonbeam development node, you can use any of the following block explorers: - **Substrate API** — [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:9944#/explorer){target=\_blank} on WS port `{{ networks.parachain.ws }}` - **Ethereum API JSON-RPC-based** — [Moonbeam Basic Explorer](https://moonbeam-explorer.netlify.app/?network=MoonbeamDevNode){target=\_blank} on HTTP port `{{ networks.parachain.ws }}` ## Debug, Trace, and TxPool APIs {: #debug-trace-txpool-apis } You can also gain access to some non-standard RPC methods by running a tracing node, which allows developers to inspect and debug transactions during runtime. Tracing nodes use a different Docker image than a standard Moonbeam development node. To learn how to run a Moonbeam development tracing node, check out the [Run a Tracing Node](/node-operators/networks/tracing-node/){target=\_blank} guide, and be sure to switch to the **Moonbeam Development Node** tab throughout the instructions. Then, to access the non-standard RPC methods with your tracing node, check out the [Debug & Trace](/builders/ethereum/json-rpc/debug-trace/){target=\_blank} guide. ## Purge a Development Node {: #purging-your-node } If you want to remove data associated with your node, you can purge it. The instructions for purging a node are different depending on how you initially spun up your node. ### Purge a Node Spun Up with Docker {: #purge-docker-node } If you spun up your node using Docker along with the `-v` flag to specify a mounted directory for your container, you will need to purge that directory. To do so, you can run the following command: ```bash sudo rm -rf {{ networks.moonbase.node_directory }}/* ``` If you followed the instructions in this guide and did not use the `-v` flag, you can stop and remove the Docker container. The associated data will be removed along with it. To do so, you can run the following command: ```bash sudo docker stop `CONTAINER_ID` && docker rm `CONTAINER_ID` ``` ### Purge a Node Spun up with a Binary File {: #purge-binary-node } When running a node via the binary file, data is stored in a local directory, typically located in `~/.local/shared/moonbeam/chains/development/db`. If you want to start a fresh instance of the node, you can either delete the content of the folder or run the following command inside the `moonbeam` folder: ```bash ./target/release/moonbeam purge-chain --dev -y ``` This will remove the data folder. Note that all chain data is now lost. To learn more about all of the available `purge-chain` commands, you can check out the [Purging Binary Data](/node-operators/networks/run-a-node/systemd/#purging-compiled-binary){target=\_blank} section of our documentation. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/get-started/networks/moonbeam/ --- BEGIN CONTENT --- --- title: Get Started with Moonbeam description: Learn how to connect to Moonbeam via RPC and WSS endpoints, how to connect MetaMask to Moonbeam, and about the available Moonbeam block explorers. categories: Basics --- # Get Started with Moonbeam ## Network Endpoints {: #network-endpoints } Moonbeam has two types of endpoints available for users to connect to: one for HTTPS and one for WSS. If you're looking for your own endpoints suitable for production use, you can check out the [Endpoint Providers](/builders/get-started/endpoints/#endpoint-providers){target=\_blank} section of our documentation. Otherwise, to get started quickly you can use one of the following public HTTPS or WSS endpoints: === "HTTPS" | Provider | RPC URL | Limits | |:-----------:|:------------------------------------------------------------------:|:-----------:| | Blast |
```https://moonbeam.public.blastapi.io```
| 80 req/sec | | Dwellir |
```https://moonbeam-rpc.dwellir.com```
| 20 req/sec | | OnFinality |
```https://moonbeam.api.onfinality.io/public```
| 40 req/sec | | UnitedBloc |
```https://moonbeam.unitedbloc.com```
| 32 req/sec | | RadiumBlock |
```https://moonbeam.public.curie.radiumblock.co/http```
| 200 req/sec | | 1RPC |
```https://1rpc.io/glmr```
| 10k req/day | | Grove |
```https://moonbeam.rpc.grove.city/v1/01fdb492```
| 5k req/day | === "WSS" | Provider | RPC URL | Limits | |:-----------:|:--------------------------------------------------------------:|:-----------:| | Blast |
```wss://moonbeam.public.blastapi.io```
| 80 req/sec | | Dwellir |
```wss://moonbeam-rpc.dwellir.com```
| 20 req/sec | | OnFinality |
```wss://moonbeam.api.onfinality.io/public-ws```
| 40 req/sec | | UnitedBloc |
```wss://moonbeam.unitedbloc.com```
| 32 req/sec | | RadiumBlock |
```wss://moonbeam.public.curie.radiumblock.co/ws```
| 200 req/sec | | 1RPC |
```wss://1rpc.io/glmr```
| 10k req/day | ## Quick Start {: #quick-start } Before getting started, make sure you've retrieved your own endpoint and API key from one of the custom [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. Then for the [Web3.js library](/builders/ethereum/libraries/web3js/){target=\_blank}, you can create a local Web3 instance and set the provider to connect to Moonbeam (both HTTP and WS are supported): ```js const { Web3 } = require('web3'); // Load Web3 library . . . // Create local Web3 instance - set Moonbeam as provider const web3 = new Web3('INSERT_RPC_API_ENDPOINT'); // Insert your RPC URL here ``` For the [Ethers.js library](/builders/ethereum/libraries/ethersjs/){target=\_blank}, define the provider by using `ethers.JsonRpcProvider(providerURL, {object})` and setting the provider URL to Moonbeam: ```js const ethers = require('ethers'); // Load Ethers library const providerURL = 'INSERT_RPC_API_ENDPOINT'; // Insert your RPC URL here // Define provider const provider = new ethers.JsonRpcProvider(providerURL, { chainId: 1284, name: 'moonbeam' }); ``` Any Ethereum wallet should be able to generate a valid address for Moonbeam (for example, [MetaMask](https://metamask.io){target=\_blank}). ## Chain ID {: #chain-id } Moonbeam chain ID is: `1284`, or `0x504` in hex. ## Block Explorers {: #block-explorers } For Moonbeam, you can use any of the following block explorers: - **Ethereum API (Etherscan Equivalent)** — [Moonscan](https://moonbeam.moonscan.io){target=\_blank} - **Ethereum API JSON-RPC based** — [Moonbeam Basic Explorer](https://moonbeam-explorer.netlify.app/?network=Moonbeam){target=\_blank} - **Substrate API** — [Subscan](https://moonbeam.subscan.io){target=\_blank} or [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbeam.network#/explorer){target=\_blank} For more information on each of the available block explorers, please head to the [Block Explorers](/builders/get-started/explorers/){target=\_blank} section of the documentation. ## Connect MetaMask {: #connect-metamask } If you already have MetaMask installed, you can easily connect MetaMask to Moonbeam: !!! note MetaMask will popup asking for permission to add Moonbeam as a custom network. Once you approve permissions, MetaMask will switch your current network to Moonbeam. If you do not have MetaMask installed, or would like to follow a tutorial to get started, please check out the [Interacting with Moonbeam using MetaMask](/tokens/connect/metamask/){target=\_blank} guide. ## Configuration {: #configuration } Please note the following gas configuration parameters. These values are subject to change in future runtime upgrades. | Variable | Value | |:---------------------:|:------------------------------------------:| | Minimum gas price | {{ networks.moonbeam.min_gas_price }} Gwei | | Target block time | {{ networks.moonbeam.block_time }} seconds | | Block gas limit | {{ networks.moonbeam.gas_block }} | | Transaction gas limit | {{ networks.moonbeam.gas_tx }} | --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/get-started/networks/moonriver/ --- BEGIN CONTENT --- --- title: Moonriver Get Started Guide description: Learn how to connect to Moonriver via RPC and WSS endpoints, how to connect MetaMask to Moonriver, and about the available Moonriver block explorers. categories: Basics --- # Get Started with Moonriver ## Network Endpoints {: #network-endpoints } Moonriver has two types of endpoints available for users to connect to: one for HTTPS and one for WSS. If you're looking for your own endpoints suitable for production use, you can check out the [Endpoint Providers](/builders/get-started/endpoints/#endpoint-providers){target=\_blank} section of our documentation. Otherwise, to get started quickly you can use one of the following public HTTPS or WSS endpoints: === "HTTPS" | Provider | RPC URL | Limits | |:-----------:|:-------------------------------------------------------------------:|:-----------:| | Dwellir |
```https://moonriver-rpc.dwellir.com```
| 20 req/sec | | OnFinality |
```https://moonriver.api.onfinality.io/public```
| 40 req/sec | | UnitedBloc |
```https://moonriver.unitedbloc.com```
| 32 req/sec | | RadiumBlock |
```https://moonriver.public.curie.radiumblock.co/http```
| 200 req/sec | | Grove |
```https://moonriver.rpc.grove.city/v1/01fdb492```
| 5k req/day | === "WSS" | Provider | RPC URL | Limits | |:-----------:|:---------------------------------------------------------------:|:-----------:| | Dwellir |
```wss://moonriver-rpc.dwellir.com```
| 20 req/sec | | OnFinality |
```wss://moonriver.api.onfinality.io/public-ws```
| 40 req/sec | | UnitedBloc |
```wss://moonriver.unitedbloc.com```
| 32 req/sec | | RadiumBlock |
```wss://moonriver.public.curie.radiumblock.co/ws```
| 200 req/sec | ## Quick Start {: #quick-start } Before getting started, make sure you've retrieved your own endpoint and API key from one of the custom [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. Then for the [Web3.js library](/builders/ethereum/libraries/web3js/){target=\_blank}, you can create a local Web3 instance and set the provider to connect to Moonriver (both HTTP and WS are supported): ```js const { Web3 } = require('web3'); // Load Web3 library . . . // Create local Web3 instance - set Moonriver as provider const web3 = new Web3('INSERT_RPC_API_ENDPOINT'); // Insert your RPC URL here ``` For the [Ethers.js library](/builders/ethereum/libraries/ethersjs/){target=\_blank}, define the provider by using `ethers.JsonRpcProvider(providerURL, {object})` and setting the provider URL to Moonriver: ```js const ethers = require('ethers'); // Load Ethers library const providerURL = 'INSERT_RPC_API_ENDPOINT'; // Insert your RPC URL here // Define provider const provider = new ethers.JsonRpcProvider(providerURL, { chainId: 1285, name: 'moonriver' }); ``` Any Ethereum wallet should be able to generate a valid address for Moonbeam (for example, [MetaMask](https://metamask.io){target=\_blank}). ## Chain ID {: #chain-id } Moonriver chain ID is: `1285`, or `0x505` in hex. ## Block Explorers {: #block-explorers } For Moonriver, you can use any of the following block explorers: - **Ethereum API (Etherscan Equivalent)** — [Moonscan](https://moonriver.moonscan.io){target=\_blank} - **Ethereum API JSON-RPC based** — [Moonbeam Basic Explorer](https://moonbeam-explorer.netlify.app/?network=Moonriver){target=\_blank} - **Substrate API** — [Subscan](https://moonriver.subscan.io){target=\_blank} or [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonriver.moonbeam.network#/explorer){target=\_blank} For more information on each of the available block explorers, please head to the [Block Explorers](/builders/get-started/explorers/) section of the documentation. ## Connect MetaMask {: #connect-metamask } If you already have MetaMask installed, you can easily connect MetaMask to Moonriver: !!! note MetaMask will popup asking for permission to add Moonriver as a custom network. Once you approve permissions, MetaMask will switch your current network to Moonriver. If you do not have MetaMask installed, or would like to follow a tutorial to get started, please check out the [Interacting with Moonbeam using MetaMask](/tokens/connect/metamask/) guide. ## Configuration {: #configuration } Please note the following gas configuration parameters. These values are subject to change in future runtime upgrades. | Variable | Value | |:---------------------:|:-------------------------------------------:| | Minimum gas price | {{ networks.moonriver.min_gas_price }} Gwei | | Target block time | {{ networks.moonriver.block_time }} seconds | | Block gas limit | {{ networks.moonriver.gas_block }} | | Transaction gas limit | {{ networks.moonriver.gas_tx }} | --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/get-started/quick-start/ --- BEGIN CONTENT --- --- title: Quickly Get Started description: Everything you need to know to get started developing, deploying, and interacting with smart contracts on Moonbeam. categories: Basics --- # Quick Start Guide for Developing on Moonbeam ## Quick Overview {: #overview } Moonbeam is a fully Ethereum-compatible smart contract platform on Polkadot. As such, you can interact with Moonbeam via the [Ethereum API](/builders/ethereum/){target=\_blank} and [Substrate API](/builders/substrate/){target=\_blank}. Although Moonbeam is a Substrate-based platform, Moonbeam uses a [unified accounts](/learn/core-concepts/unified-accounts/){target=\_blank} system, which replaces Substrate-style accounts and keys with Ethereum-style accounts and keys. As a result, you can interact with your Moonbeam account with [MetaMask](/tokens/connect/metamask/){target=\_blank}, [Ledger](/tokens/connect/ledger/){target=\_blank}, and other Ethereum-compatible wallets by simply adding Moonbeam's network configurations. Similarly, you can develop on Moonbeam using Ethereum [libraries](/builders/ethereum/libraries/){target=\_blank} and [development environments](/builders/ethereum/dev-env/){target=\_blank}. ## Moonbeam Networks {: #moonbeam-networks } To get started developing on Moonbeam, it's important to be aware of the various networks within the Moonbeam ecosystem. | Network | Network Type | Relay Chain | Native Asset Symbol | Native Asset Decimals | |:-----------------------------------------------------------------------------------------:|:-------------:|:--------------------------------------------------------------------------------:|:-------------------:|:---------------------:| | [Moonbeam](/builders/get-started/networks/moonbeam/){target=\_blank} | MainNet | [Polkadot](https://polkadot.com){target=\_blank} | GLMR | 18 | | [Moonriver](/builders/get-started/networks/moonriver/){target=\_blank} | MainNet | [Kusama](https://kusama.network){target=\_blank} | MOVR | 18 | | [Moonbase Alpha](/builders/get-started/networks/moonbase/){target=\_blank} | TestNet | [Alphanet relay](/learn/platform/networks/moonbase/#relay-chain){target=\_blank} | DEV | 18 | | [Moonbeam Development Node](/builders/get-started/networks/moonbeam-dev/){target=\_blank} | Local TestNet | None | DEV | 18 | !!! note A Moonbeam development node doesn't have a relay chain as its purpose is to be your own personal development environment where you can get started developing quickly without the overhead of a relay chain. ### Network Configurations {: #network-configurations } When working with developer tools, depending on the tool, you might need to configure Moonbeam to interact with the network. To do so, you can use the following information: === "Moonbeam" | Variable | Value | |:---------------:|:------------------------------------------------------------------------------------------------------:| | Chain ID |
```{{ networks.moonbeam.chain_id }}```
| | Public RPC URLs |
```https://moonbeam.public.blastapi.io```
```https://moonbeam.unitedbloc.com```
| | Public WSS URLs |
```wss://moonbeam.public.blastapi.io```
| === "Moonriver" | Variable | Value | |:---------------:|:--------------------------------------------------------------------------------------------------------:| | Chain ID |
```{{ networks.moonriver.chain_id }}```
| | Public RPC URLs |
```https://moonriver.public.blastapi.io```
```https://moonriver.unitedbloc.com```
| | Public WSS URLs |
```wss://moonriver.public.blastapi.io```
| === "Moonbase Alpha" | Variable | Value | |:---------------:|:-----------------------------------------------------------------------------------------------------------:| | Chain ID |
```{{ networks.moonbase.chain_id }}```
| | Public RPC URLs |
```https://moonbase-alpha.public.blastapi.io```
```{{ networks.moonbase.rpc_url }}```
| | Public WSS URLs |
```wss://moonbase-alpha.public.blastapi.io```
```{{ networks.moonbase.wss_url }}```
| === "Moonbeam Dev Node" | Variable | Value | |:-------------:|:----------------------------------------------------:| | Chain ID |
```{{ networks.development.chain_id }}```
| | Local RPC URL |
```{{ networks.development.rpc_url }}```
| | Local WSS URL |
```{{ networks.development.wss_url }}```
| !!! note You can create your own endpoint suitable for development or production from one of the [supported RPC providers](/builders/get-started/endpoints/#endpoint-providers){target=\_blank}. ### Block Explorers {: #explorers } Moonbeam provides two different kinds of explorers: ones to query the Ethereum API, and others dedicated to the Substrate API. All EVM-based transactions are accessible via the Ethereum API whereas the Substrate API can be relied upon for Substrate-native functions such as governance, staking, and some information about EVM-based transactions. For more information on each explorer, please check out the [Block Explorers](/builders/get-started/explorers/){target=\_blank} page. === "Moonbeam" | Block Explorer | Type | URL | |:--------------:|:---------:|:-------------------------------------------------------------------------------------------------------------------------------------:| | Moonscan | EVM | [https://moonbeam.moonscan.io/](https://moonbeam.moonscan.io){target=\_blank} | | Expedition | EVM | [https://moonbeam-explorer.netlify.app/?network=Moonbeam](https://moonbeam-explorer.netlify.app/?network=Moonbeam){target=\_blank} | | Subscan | Substrate | [https://moonbeam.subscan.io/](https://moonbeam.subscan.io){target=\_blank} | | Polkadot.js | Substrate | [https://polkadot.js.org/apps/#/explorer](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbeam.network#/explorer){target=\_blank} | === "Moonriver" | Block Explorer | Type | URL | |:--------------:|:---------:|:-----------------------------------------------------------------------------------------------------------------------------------------------:| | Moonscan | EVM | [https://moonriver.moonscan.io/](https://moonriver.moonscan.io){target=\_blank} | | Expedition | EVM | [https://moonbeam-explorer.netlify.app/?network=Moonriver](https://moonbeam-explorer.netlify.app/?network=Moonriver){target=\_blank} | | Subscan | Substrate | [https://moonriver.subscan.io/](https://moonriver.subscan.io){target=\_blank} | | Polkadot.js | Substrate | [https://polkadot.js.org/apps/#/explorer](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonrvier.moonbeam.network#/explorer){target=\_blank} | === "Moonbase Alpha" | Block Explorer | Type | URL | |:--------------:|:---------:|:----------------------------------------------------------------------------------------------------------------------------------------------:| | Moonscan | EVM | [https://moonbase.moonscan.io/](https://moonbase.moonscan.io){target=\_blank} | | Expedition | EVM | [https://moonbeam-explorer.netlify.app/?network=MoonbaseAlpha](https://moonbeam-explorer.netlify.app/?network=MoonbaseAlpha){target=\_blank} | | Subscan | Substrate | [https://moonbase.subscan.io/](https://moonbase.subscan.io){target=\_blank} | | Polkadot.js | Substrate | [https://polkadot.js.org/apps/#/explorer](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/explorer){target=\_blank} | === "Moonbeam Dev Node" | Block Explorer | Type | URL | |:--------------:|:---------:|:-------------------------------------------------------------------------------------------------------------------------------------------------:| | Expedition | EVM | [https://moonbeam-explorer.netlify.app/?network=MoonbeamDevNode](https://moonbeam-explorer.netlify.app/?network=MoonbeamDevNode){target=\_blank} | | Polkadot.js | Substrate | [https://polkadot.js.org/apps/#/explorer](https://polkadot.js.org/apps/?rpc=wss://ws%3A%2F%2F127.0.0.1%3A9944#/explorer){target=\_blank} | ## Funding TestNet Accounts {: #testnet-tokens } To get started developing on one of the TestNets, you'll need to fund your account with DEV tokens to send transactions. Please note that DEV tokens have no real value and are for testing purposes only. | TestNet | Where To Get Tokens From | |:-----------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| | [Moonbase Alpha](/builders/get-started/networks/moonbase/){target=\_blank} | The [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} website.
The faucet dispenses {{ networks.moonbase.website_faucet_amount }} every 24 hours | | [Moonbeam Development Node](/builders/get-started/networks/moonbeam-dev/){target=\_blank} | Any of the [ten pre-funded accounts](/builders/get-started/networks/moonbeam-dev/#pre-funded-development-accounts){target=\_blank} that come with your
development node | ## Development Tools {: #development-tools } As Moonbeam is a Substrate-based chain that is fully Ethereum-compatible, you can use Substrate-based tools and Ethereum-based tools. ### JavaScript Tools {: #javascript } === "Ethereum" | Tool | Type | |:------------------------------------------------------------------------:|:---------------:| | [Ethers.js](/builders/ethereum/libraries/ethersjs/){target=\_blank} | Library | | [Web3.js](/builders/ethereum/libraries/web3js/){target=\_blank} | Library | | [Hardhat](/builders/ethereum/dev-env/hardhat/){target=\_blank} | Dev Environment | | [OpenZeppelin](/builders/ethereum/dev-env/openzeppelin/){target=\_blank} | Dev Environment | | [Remix](/builders/ethereum/dev-env/remix/){target=\_blank} | Dev Environment | | [Scaffold-Eth](/builders/ethereum/dev-env/scaffold-eth/){target=\_blank} | Dev Environment | | [thirdweb](/builders/ethereum/dev-env/thirdweb/){target=\_blank} | Dev Environment | | [Waffle & Mars](/builders/ethereum/dev-env/waffle-mars/){target=\_blank} | Dev Environment | === "Substrate" | Tool | Type | |:---------------------------------------------------------------------------------:|:-------:| | [Polkadot.js API](/builders/substrate/libraries/polkadot-js-api/){target=\_blank} | Library | ### Python Tools {: #python } === "Ethereum" | Tool | Type | |:---------------------------------------------------------------:|:---------------:| | [Web3.py](/builders/ethereum/libraries/web3py/){target=\_blank} | Library | | [Ape](/builders/ethereum/dev-env/ape/){target=\_blank} | Dev Environment | === "Substrate" | Tool | Type | |:-----------------------------------------------------------------------------------------------:|:-------:| | [Py Substrate Interface](/builders/substrate/libraries/py-substrate-interface/){target=\_blank} | Library | --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/get-started/token-profile/ --- BEGIN CONTENT --- --- title: Add Token Information on Moonscan description: Add token information and create a token profile on Moonscan for ERC-20, ERC-721, and ERC-1155 tokens deployed to Moonbeam-based networks. categories: Tokens and Accounts, Ethereum Toolkit --- # Add Token Information on Moonscan ## Introduction {: #introduction } This tutorial will guide you through the process of adding a profile for your ERC-20, ERC-721, or ERC-1155 tokens to [Moonscan](https://moonscan.io){target=\_blank}. ​​Moonscan is a block explorer and analytics platform for EVM-compatible chains. It is an integration of Moonbeam and Etherscan, and it allows users and developers to have access to developer tools and network statistics that provide granular insights into the EVM of Moonriver and Moonbeam. Developers can create a profile for their tokens on Moonriver and Moonbeam. The profile captures basic information about the project behind the token, social media links, links to price data, and other information pertaining to the project’s token sales. ![Example token profile](/images/builders/get-started/token-profile/profile-1.webp) This tutorial will show you how to create a profile on Moonscan of a sample ERC-20 token, called DemoToken (DEMO), deployed to Moonriver. These instructions can be adapted for any of the Moonbeam-based networks, as well as for an ERC-721 or ERC-1155 token. ## Checking Prerequisites {: #checking-prerequisites } To follow along with this tutorial, you will need to have the following: - A [Moonscan Account](https://moonscan.io/register){target=\_blank} You will need to verify ownership of the token contract address later on in this guide. You can either do this manually or automatically, but if you choose to do it automatically you'll also need the following: - Access to the account that deployed the token contract, so you can sign messages as the owner - MetaMask installed and connected to the network where the token is deployed to ## Getting Started {: #getting-started } To get started, you'll need to make sure that you are logged into your Moonscan account. Once you’re signed into your account, you can go to the token page of the token you want to add a profile for. For ERC-20s, you can search the name of the token in the search bar. Or for any token, you can manually enter in the URL. === "Moonbeam" ```text https://moonscan.io/token/INSERT_CONTRACT_ADDRESS ``` === "Moonriver" ```text https://moonriver.moonscan.io/token/INSERT_CONTRACT_ADDRESS ``` === "Moonbase Alpha" ```text https://moonbase.moonscan.io/token/INSERT_CONTRACT_ADDRESS ``` Next to Social Profiles, you can click on **Update**. ![Update token](/images/builders/get-started/token-profile/profile-2.webp) You’ll be taken to the **Token Update Application Form**. If you haven’t verified your contract source code yet, you will need to do so before you can proceed to the next step. If you have already verified your contract, you can skip ahead to the [Verifying Address Ownership](#verifying-address-ownership) section. ## Verifying Contract Source Code {: #verifying-contract-source-code } You can verify your contract source code a couple of ways. You can directly verify it from Moonscan, or if you developed the contract with Hardhat or Foundry, you can also use their corresponding [Etherscan integrations](/builders/ethereum/verify-contracts/etherscan-plugins/){target=\_blank}. To verify your contract source code directly from Moonscan, you can click on the **tool** link. ![Token update application form](/images/builders/get-started/token-profile/profile-3.webp) You’ll be taken to the **Verify & Publish Contract Source Code** page where you can enter in details about the contract and how it was compiled. 1. Enter the token contract address 2. Select the **Compiler Type** from the dropdown 3. Choose the **Compile Version** you used 4. Then select an **Open Source License Type** 5. Review and click the **I agree to the terms of service** checkbox 6. Click **Continue** ![Verify & publish contract - page 1](/images/builders/get-started/token-profile/profile-4.webp) You’ll be taken to the next page where you can enter in the contract source code and specify additional settings and arguments used. 1. Contract Address and Compiler should already be filled in. If you enabled optimization, you can update the **Optimization** dropdown 2. Enter in a flattened version of the contract source code. To flatten the contract, you can use the Flattener Remix plugin 3. Update the **Constructor Arguments**, **Contract Library Address**, and **Misc Settings** sections if needed 4. Click **I’m not a robot** 5. Finally, click **Verify and Publish** ![Verify & publish contract - page 2](/images/builders/get-started/token-profile/profile-5.webp) Now that your contract source code has been verified, you can move on to the next step, verifying that you’re the contract address owner. ## Verifying Address Ownership {: #verifying-address-ownership } From the **Token Update Application Form** page, you should see a message at the top of the screen that states you need to verify the contract address owner. To get started with this process, you can click on the **tool** link. ![Token update application form](/images/builders/get-started/token-profile/profile-6.webp) You’ll be taken to the **Verify Address Ownership** page, where you can choose to sign the message verifying your ownership either manually or by connecting to Web3. If you wish to verify ownership manually, you’ll need the message signature hash. Otherwise, if you connect to Web3, the hash will be calculated for you. ![Verify address ownership](/images/builders/get-started/token-profile/profile-7.webp) ### Sign Message Manually {: #sign-message-manually } If you wish to verify ownership manually, you’ll need the message signature hash. If you have calculated the hash yourself, you can click **Sign Message Manually**, enter the **Message Signature Hash**, and click **Verify Ownership**. ![Manually verify address ownership](/images/builders/get-started/token-profile/profile-8.webp) ### Connect to Web3 {: #connect-to-web3 } You can easily calculate the message signature hash using MetaMask. You will need to have the account you deployed the contract with loaded into MetaMask. Then you can click on **Connect to Web3** and MetaMask will pop-up. 1. Select the account to connect with, which should be the account you used to deploy the contract 2. Connect to the account ![Connect MetaMask account](/images/builders/get-started/token-profile/profile-9.webp) Back on the **Verify Address Ownership** page, you can take the following steps 1. Click **Sign with Web3** 2. MetaMask will pop-up and you can **Sign** the message ![Sign message on MetaMask to verify address ownership](/images/builders/get-started/token-profile/profile-10.webp) Once you’ve signed the message, you can then click **Click to Proceed**. You should now see that the **Message Signature Hash** has been automatically populated for you. All you have left to do is click **Verify Ownership**. ![Verify address ownership submission](/images/builders/get-started/token-profile/profile-11.webp) ## Creating the Profile {: #creating-the-profile } Now you can start filling in the necessary information to build the token profile, including project information, social media links, price data links, and more. You should make sure that all the links provided are working and are safe to visit before submitting. At a minimum you will need to fill in the following information: - **Request Type** - **Token Contract Address** - **Requester Name** - **Requester Email Address** - **Official Project Website** - **Official Project Email Address** - **Link to download a 32x32 png icon logo** - **Project Description** All of the other fields are optional. Once you’ve filled in the information, you can click **Submit** at the bottom of the page. ![Create token profile](/images/builders/get-started/token-profile/profile-12.webp) And that’s it! You’ve successfully created and submitted a profile for your token on Moonscan! The Moonscan team will review your submission as soon as possible and provide you with further instructions as needed. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/ --- BEGIN CONTENT --- --- title: A Hub for Developers Building on Moonbeam description: Guides for getting started and developing on Moonbeam. Learn how to use the Ethereum & Substrate APIs, XCM interoperability, and available integrations. template: main-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/analytics/dapplooker/ --- BEGIN CONTENT --- --- title: Dapplooker description: Use Dapplooker to analyze and query on-chain data, and create dashboards to visualize analytics for Moonbeam and Moonriver. categories: Integrations --- # Getting Started with Dapplooker ## Introduction {: #introduction } Developers on Moonriver and Moonbeam can use the [Dapplooker](https://dapplooker.com){target=\_blank} platform to analyze their on-chain data and run SQL queries. The integration gives projects the ability to create charts and dashboards to track their smart contracts and provide feedback on performance and adoption. Dapplooker analytics platform complements Moonbeam-based networks by helping users make sense of smart contracts without having to rely on an engineer or analyst. Dapplooker’s intuitive Visual SQL helps browse smart contract data in tabular form and write SQL queries using easy to use editor. Users can create, fork, and share dashboards with everyone. This guide will cover all of the details needed to register your project with the Dapplooker platform and how to build analytics using SQL editor. This guide can be adapted for use on Moonbeam, Moonriver, or Moonbase Alpha.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Checking Prerequisites {: #checking-prerequisites } To get started with this guide, you'll need to create or have a Dapplooker account. You can [signup](https://dapplooker.com/user/signup){target=\_blank} and create an account. If you've already signed up, you can [login](https://dapplooker.com/user/login){target=\_blank} to your account. ![Login to Dapplooker](/images/builders/integrations/analytics/dapplooker/dapplooker-1.webp) ## Connect Smart Contracts {: #connect-smart-contracts } To connect a smart contract to Dapplooker, you can click on the **My Projects** button at the top of the page. From the **Register Your Project** page, click **Connect Dapp** then select the **Connect Smart Contract** option. You can also browse and run analytics on already indexed DApps from the menu. ![Connect dapp](/images/builders/integrations/analytics/dapplooker/dapplooker-2.webp) You'll be prompted to enter in details about your project and contract: 1. Enter your project name 2. Enter the network your project lives on. The network can be either **Moonbeam**, **Moonriver**, or **Moonbase Alpha** 3. Toggle the slider if you have several instances of the same contract 4. Enter your contract address. If the contract address is verified on [Moonscan](https://moonscan.io){target=\_blank}, it will start appearing in autocomplete. You can select the contract address from autocomplete. If no contract address appears in autocomplete, you can input your contract address and click on the **+** button and then the upload button to upload the ABI 5. Enter your project's website 6. Upload your project's logo 7. Click **Register** and smart contract transactions events data syncing will start. It can take some time for complete data to be synced ![Register your dapp](/images/builders/integrations/analytics/dapplooker/dapplooker-3.webp) Once syncing is complete, you will get an email notification. Clicking on the link in the email will take you directly to your indexed data. ## Connect Subgraphs {: #connect-subgraphs } To connect a subgraph to Dapplooker, you can click on the **My Projects** button at the top of the page. From the **Register Your Project** page, click **Connect Dapp** then select the **Connect Subgraph** option. You can also browse and run analytics on already indexed Dapps from the menu. ![Connect dapp](/images/builders/integrations/analytics/dapplooker/dapplooker-4.webp) You'll be prompted to enter in details about your project and subgraph: 1. Enter your project name 2. Enter the network your project lives on. The network can be either **Moonbeam**, **Moonriver**, or **Moonbase Alpha** 3. Input your DApp subgraph endpoint 4. Enter your project's website 5. Upload your project's logo 6. Click **Register** and subgraph entities data syncing will start. It can take some time for complete data to be synced ![Register your dapp](/images/builders/integrations/analytics/dapplooker/dapplooker-5.webp) Once syncing is complete, you will get an email notification. Clicking on the link in the email will take you directly to your indexed data. ## Create Charts & Dashboards {: #create-charts-dashboards } To get started creating charts to visualize your data, you can click **Create a Chart** at the top of the page. From there you can choose to create a **Simple chart**, **Custom chart**, or **Native query** chart. For more information on creating each type of chart, you can take a look at the [Dapplooker documentation on creating charts](https://dapplooker.notion.site/Create-Charts-2ab63e91f4a04dab8b06dfbedb72730e){target=\_blank}. If you are interested in creating a dashboard, you can get started by clicking **Browse Data** at the top of the page. Then, click the **+** button and choose **New dashboard** from the dropdown menu. For more information on creating a dashboard, please refer to the [Dapplooker documentation on creating a dashboard](https://dapplooker.notion.site/Create-Dashboards-61981cf5fde54d32a905eef59491c108){target=\_blank}. You can publish charts and dashboards in private or public folders. Public charts and dashboards are accessible to everyone. You can also fork, edit, and create new charts and dashboards from public charts. ## Example Charts & Dashboards {: #example-dashboards } There are a collection of charts and dashboards available for you to view and build off of for both Moonbeam and Moonriver. To get started, you can take a look at the [Moonbeam Network Collection](https://analytics.dapplooker.com/collection/323-moonbeam-network-collection){target=\_blank} or the [Moonriver Network Collection](https://analytics.dapplooker.com/collection/79-moonriver-network-collection){target=\_blank}. There, you’ll find editable public charts and dashboards. To start editing any of the charts or dashboards, you can click on the list icon in the right hand corner between the **Summarize** button and the refresh icon. This opens the editor, where you can fully customize the existing chart or dashboard. Any changes you make will not automatically be saved. To create the chart or dashboard with your changes, you'll need to click **Save**. For more information on editing and creating the charts or dashboards, please refer to the [Dapplooker documentation site](https://dapplooker.notion.site/Features-24c6faca79a847e4ae499e907784bbfc){target=\_blank}. Another place you can start to view and build off of data is from the list of [Moonbeam Staking dashboards](https://analytics.dapplooker.com/browse/2/schema/moonbeam){target=\_blank} and the [Moonriver Staking dashboards](https://analytics.dapplooker.com/browse/2/schema/moonriver){target=\_blank}. ### Popular Dashboards {: #popular-dashboards } - [Moonbeam Staking Dashboard](https://dapplooker.com/dashboard/moonbeam-collator-dashboard-91){target=\_blank} - staking dashboards for collators and delegators on Moonbeam that includes APY data - [Moonriver Staking Dashboard](https://dapplooker.com/dashboard/moonriver-collator-dashboard-28){target=\_blank} - staking dashboards for collators and delegators on Moonriver that includes APY data - [Dapplooker Explorer for Moonbeam](https://dapplooker.com/browse/dashboards?sort=popular&tags=moonbeam&pg=1){target=\_blank} - find popular dashboards on Moonbeam - [Dapplooker Explorer for Moonriver](https://dapplooker.com/browse/dashboards?sort=popular&tags=moonriver&pg=1){target=\_blank} - find popular dashboards on Moonriver
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/analytics/ --- BEGIN CONTENT --- --- title: Analyze On-Chain Data description: Analyze on-chain smart contract data by building charts and dashboards to visualize data and track metrics for Moonbeam-based networks. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/analytics/zapper/ --- BEGIN CONTENT --- --- title: Portfolio Tracking on Moonbeam with Zapper description: Learn how to track your holdings on Moonbeam using Zapper and explore different DeFi platforms in the Moonbeam ecosystem. categories: Integrations --- # Portfolio Tracking with Zapper ## Introduction [Zapper](https://zapper.xyz){target=\_blank} is a Web3 application that enables users to explore on-chain data, manage their portfolios, and interact with decentralized finance (DeFi) protocols across multiple networks, including Moonbeam. Through their integration with Zapper, users can monitor and manage assets across Moonbeam’s DeFi ecosystem, including platforms such as Moonwell, StellaSwap, OmniLST, and Prime Protocol. This tutorial provides a detailed step-by-step guide for users and developers to integrate with Zapper and maximize their experience within the Moonbeam ecosystem. ## Get Started on Zapper You can navigate to [Zapper's official website](https://zapper.xyz){target=\_blank} and take the following steps to start interacting with the application: 1. Click on the **Connect Wallet** button at the top right corner ![Zapper main site](/images/builders/integrations/analytics/zapper/zapper-1.webp) 2. Select your preferred wallet from the supported options (e.g., MetaMask, Talisman, Coinbase Wallet) ![Zapper wallet modal](/images/builders/integrations/analytics/zapper/zapper-2.webp) 3. Follow the on-screen prompts to connect securely to Zapper ### Explore Your Portfolio Once your wallet is connected, Zapper will automatically detect and display your assets across supported networks, including Moonbeam. You can navigate to your main dashboard by clicking on **My profile** on the left sidebar or selecting it from the wallet icon on the top-right corner. The dashboard provides an overview of your holdings and activity split in the following categories: - **Summary** - displays your total assets, liabilities, and net worth across all networks - **Tokens** - lists all tokens held in your connected wallet, including GLMR (Moonbeam's native token) and any ERC-20 tokens - **DeFi** - shows active positions in Moonbeam-based DeFi platforms such as lending, liquidity pools, and staking - **NFTs** - displays any NFTs you own on Moonbeam or other supported chains - **Activity** - Zapper's dashboard provides real-time data, enabling efficient management of your on-chain activities ![Zapper Dashboard](/images/builders/integrations/analytics/zapper/zapper-3.webp) ### Engage with Moonbeam's DeFi Ecosystem Zapper provides access to view the activity on Moonbeam's DeFi protocols, such as: - [**Moonwell**](https://moonwell.fi/){target=\_blank} - for accessing lending and borrowing services - [**StellaSwap**](https://app.stellaswap.com/exchange/swap){target=\_blank} - for participating in token swaps and liquidity provision by depositing token pairs into StellaSwap's liquidity pools - [**OmniLST**](https://omni.ls/){target=\_blank} - for engaging in liquid staking opportunities (stake GLMR tokens to receive liquid staking tokens and use them in other DeFi applications) - [**Prime Protocol**](https://www.primeprotocol.xyz/){target=\_blank} - for managing cross-chain assets and accessing borrowing services (deposit assets as collateral to borrow across multiple chains) You can follow these steps to review any of the aforementioned protocols: 1. Select **Moonbeam** from the chain filter in the left sidebar. This will display the most trending dApps in the ecosystem. Click on the protocol you wish to explore ![Zapper DeFi Section](/images/builders/integrations/analytics/zapper/zapper-4.webp) 2. In the **Activity** tab, view the latest transactions for the selected protocol, including token swaps, LP or staking on StellaSwap, lending and borrowing on Moonwell, staked GLMR on OmniLST, and activity on other supported dApps ![StellaSwap on Zapper](/images/builders/integrations/analytics/zapper/zapper-5.webp) 3. View additional details for the selected protocol, including daily active users and daily transactions in the left sidebar, deployed smart contracts in the **Contracts** tab, and your holdings in the protocol via the **Properties** tab ### Access and Manage Moonbeam Assets Zapper also has an integrated modal for seamlessly swapping assets on Moonbeam. You can access this feature by selecting **Moonbeam** in the chain filter on the left sidebar and choosing the desired token on the right sidebar. ![Zapper Token Selection](/images/builders/integrations/analytics/zapper/zapper-6.webp) Inside the token page, you'll be able to see the asset's performance and details such as price action, volumes, holders and transactions. ![Zapper Swap Modal-1](/images/builders/integrations/analytics/zapper/zapper-7.webp) To perform a swap you'll need to access the swap modal by clicking on the **Buy**/**Sell** buttons in the left sidebar. Once inside the modal you can select the assets for swapping, input the desired quantity for the token you want to sell, and click on **Review order** to sign and submit the transaction. ![Zapper Swap Modal-2](/images/builders/integrations/analytics/zapper/zapper-8.webp) ## Integrate with Zapper's API Developers can leverage Zapper's API to enrich their applications with comprehensive DeFi data from the Moonbeam network. You can register for an API key by visiting the [Zapper API portal](https://protocol.zapper.xyz){target=\_blank}. An API key is necessary to authenticate your application and access Zapper's endpoints. Zapper offers several endpoints to fetch relevant data, such as: - **Balances** - retrieve asset balances for addresses on Moonbeam - **Transactions** - access transaction histories - **Prices** - obtain real-time token prices Furthermore, you can familiarize yourself with the [Zapper API documentation](https://protocol.zapper.xyz/docs/api){target=\_blank}, which provides detailed information on the available endpoints, request structures, and response formats. Depending on your preferred programming language, you can set up your environment to make HTTP requests to Zapper's API. Below is an example of retrieving token balances for a specified wallet address on Moonbeam using Node.js and [Axios](https://axios-http.com/docs/intro){target=\_blank}: ```javascript const axios = require('axios'); const API_KEY = 'INSERT_API_KEY'; const address = 'INSERT_WALLET_ADDRESS'; const chain = 'moonbeam'; axios.get(`https://api.zapper.xyz/v1/protocols/tokens/balances`, { params: { addresses: address, network: chain }, headers: { Authorization: `Bearer ${API_KEY}` } }) .then(response => { console.log(response.data); }) .catch(error => { console.error(error); }); ``` !!! note Ensure that your application handles API responses appropriately and includes error-handling mechanisms. By following this tutorial, users and developers will have effectively learned how to integrate with Zapper and use it for exploring multiple DApps in the Moonbeam network. ## Additional Resources You can also explore the [Zapper API GitHub repository](https://github.com/Zapper-fi/Docs){target=\_blank} for code examples and community contributions, or refer to [Zapper's integration guides](https://zapper.gitbook.io/integrations){target=\_blank} for detailed instructions and best practices.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/ --- BEGIN CONTENT --- --- title: Integrations on Moonbeam description: Learn about the available integrations on Moonbeam to ease your DApp development, including bridges, indexers, oracles, and wallets. dropdown_description: Tools and protocols to integrate with template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/indexers/covalent/ --- BEGIN CONTENT --- --- title: GoldRush API description: Querying blockchain data such as balances, transactions, transfers, token holders, and event logs on Moonbeam with the GoldRush (formerly Covalent) API. categories: Indexers and Queries --- # Getting Started with the GoldRush API ## Introduction {: #introduction } [GoldRush](https://goldrush.dev/){target=\_blank}, formerly known as Covalent, is a hosted blockchain data solution providing access to historical and current on-chain data for [100+ supported blockchains](https://goldrush.dev/docs/chains/overview#supported-chains){target=\_blank}, including [Moonbeam](https://goldrush.dev/docs/chains/moonbeam){target=\_blank}, [Moonriver](https://goldrush.dev/docs/chains/moonriver){target=\_blank}, and [Moonbase Alpha](https://goldrush.dev/docs/chains/moonbeam-moonbase-alpha){target=\_blank}. GoldRush maintains a full archival copy of every supported blockchain, meaning every balance, transaction, log event, and NFT asset data is available from the genesis block. This data is available via: - [Unified API](#unified-api-overview) - incorporate blockchain data into your app with a familiar REST API This guide will cover all of the details needed to get started with the [Foundational API](https://goldrush.dev/docs/goldrush-foundational-api/quickstart){target=\_blank} and how to access the API endpoints for Moonbeam using curl commands and JavaScript and Python snippets.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Unified API Overview {: #unified-api-overview } GoldRush's Unified API is a powerful but easy-to-use REST API that offers visibility to assets across all blockchain networks. It features a consistent request and response object format across networks. For example, a user can fetch all the token balances for a wallet address across any supported blockchain by changing the unique blockchain name or ID path parameter in the request URL. GoldRush's Unified API can offer more data flexibility than JSON-RPC interfaces, which are typically limited to queries on a specific block. It also allows queries on multiple objects and batch exports of data. ### Querying the Unified API {: #querying-the-unified-api } It's easy to get started querying the Unified API after you've secured a GoldRush API Key. Make sure you have [your API Key](https://goldrush.dev/platform/auth/register/){target=\_blank} which begins with `cqt_` or `ckey_`. You can interact with any of the API methods in the web interface of the GoldRush docs. To try out the token balances API, head to the [token balances docs](https://goldrush.dev/docs/api-reference/foundational-api/balances/get-token-balances-for-address){target=\_blank} and take the following steps: 1. Paste in your API key 2. Enter the desired `chainName`, such as `moonbeam-moonbase-alpha` for Moonbase Alpha. Reference the [Quick Start section](#quick-start) if you're unsure what the chainName should be for your desired network 3. Enter the address you wish to check the token balances of 4. Press **Send** [![Example API response in JSON](/images/builders/integrations/indexers/covalent/covalent-1.webp)](https://goldrush.mintlify.app/docs/api/balances/get-token-balances-for-address){target=\_blank} ### Quick Start {: #quick-start } If you're familiar with GoldRush and ready to dive in, you need the chainID and network name to get started. === "Moonbeam" | Parameter | Value | |:-----------:|:----------------------------------:| | `chainName` | `moonbeam-mainnet` | | `chainID` | `{{ networks.moonbeam.chain_id }}` | === "Moonriver" | Parameter | Value | |:-----------:|:-----------------------------------:| | `chainName` | `moonbeam-moonriver` | | `chainID` | `{{ networks.moonriver.chain_id }}` | === "Moonbase Alpha" | Parameter | Value | |:-----------:|:----------------------------------:| | `chainName` | `moonbeam-moonbase-alpha` | | `chainID` | `{{ networks.moonbase.chain_id }}` | ### Fundamentals of the Unified API {: #fundamentals-of-the-unified-api } - The GoldRush API is RESTful and it is designed around the main resources that are available through the web interface - The current version of the API is version 1 - The default return format for all endpoints is JSON - All requests require authentication; you will need [an API Key](https://goldrush.dev/platform/auth/register/){target=\_blank} to use the GoldRush API - The cost of an API call is denominated in credits and varies depending on the particular call. Upon creating an API key, you're given a substantial amount of free credits to get started (25,000 at the time of writing). You can track your usage of these free credits on the [GoldRush Dashboard](https://goldrush.dev/platform/){target=\_blank} - Note that free development API keys are rate limited to `4` requests per second. Subscribers to a professional plan can make up to `50` requests per second. - The root URL of the API is: `https://api.covalenthq.com/v1/` - All requests are done over HTTPS (calls over plain HTTP will fail) - The refresh rate of the APIs is real-time: 30s or two blocks, and batch 30m or 40 blocks ### Types of Endpoints {: #types-of-endpoints } The GoldRush API has three classes of endpoints: - **Class A** — endpoints that return enriched blockchain data applicable to all blockchain networks, eg: balances, transactions, log events, etc - **Class B** — endpoints that are for a specific protocol on a blockchain, e.g. Uniswap is Ethereum-only and is not applicable to other blockchain networks - **Class C** — endpoints that are community-built and maintained but powered by GoldRush infrastructure ### Sample Supported Endpoints {: #sample-supported-endpoints } For a full list of supported endpoints, refer to the [GoldRush API reference](https://goldrush.dev/docs/api-reference/foundational-api/cross-chain/get-address-activity){target=\_blank}. A subset of the supported endpoints include: - **Token balances**- get all token balances (native, ERC-20, ERC-721, ERC-1155) with current market prices for an address - **Native token balances**- retrieve native token balance for an address - **Get a transaction**- fetch and render a single transaction with decoded log events - **Transaction summary**- retrieve key wallet activity data for an address - **Earliest transactions**- get the earliest transactions for an address - **Recent transactions**- fetch the most recent transactions for an address - **Paginated transactions**- get paginated transactions for an address - **Bulk time bucket transactions**- fetch all transactions in 15-minute time buckets - **Block transactions**- get all transactions in a specific block - **ERC-20 token transfers**- fetch transfer history of a specific ERC-20 token for an address - **Cross-chain activity**- locate chains on which an address is active - **Token approvals**- get a list of token approvals for an address - **NFT approvals**- retrieve NFT approvals for an address ## Unified API Methods {: #unified-api-methods } For more information on each of the methods of the Unified API and for an interactive interface to try out each of the methods, be sure to check out the [GoldRush docs](https://goldrush.dev/docs/goldrush-foundational-api/overview){target=\_blank}. ### Balances {: #balances } ???+ function "Token Balances" The [token balances endpoint](https://goldrush.dev/docs/api-reference/foundational-api/balances/get-token-balances-for-address){target=\_blank} retrieves native tokens, fungible (ERC-20) tokens, and non-fungible (ERC-721 & ERC-1155) tokens associated with a given address. The returned data includes current market prices and additional token metadata. === "Parameters" - `chainName` *string* - e.g. `moonbeam-mainnet`, `moonbeam-moonriver`, or `moonbeam-moonbase-alpha` - `walletAddress` *string* - the address you wish to check the token balances of === "Example Request" ```bash curl --request GET \ --url https://api.covalenthq.com/v1/moonbeam-moonbase-alpha/address/0x569BE8d8b04538318e1722f6e375FD381D2da865/balances_v2/ \ --header 'Authorization: Bearer INSERT_API_KEY' ``` === "Example Response" ```bash { "data": { "address": "0x569be8d8b04538318e1722f6e375fd381d2da865", "updated_at": "2024-10-08T23:34:58.401269473Z", "next_update_at": "2024-10-08T23:39:58.401269913Z", "quote_currency": "USD", "chain_id": 1287, "chain_name": "moonbeam-moonbase-alpha", "items": [ { "contract_decimals": 18, "contract_name": "Mainnet2021", "contract_ticker_symbol": "MN21", "contract_address": "0xb59c01231fd65fb2da1e23a52abb946e2e13b333", "supports_erc": [ "erc20" ], "logo_url": "https://logos.covalenthq.com/tokens/1287/0xb59c01231fd65fb2da1e23a52abb946e2e13b333.png", "balance": "999999", "quote_rate": null, "quote": 0, "pretty_quote": "$0.00" }, { "contract_decimals": 18, "contract_name": "Dev", "contract_ticker_symbol": "DEV", "contract_address": "0x0000000000006d6f6f6e626173652d616c706861", "supports_erc": [ "erc20" ], "logo_url": "https://www.datocms-assets.com/86369/1669924256-moonbeam-1.png", "balance": "88335963638628211482", "quote_rate": 0, "quote": 0, "pretty_quote": "$0.00" } ], "pagination": null }, "error": false, "error_message": null, "error_code": null } ``` ??? function "Native Token Balances" The [native token balances endpoint](https://goldrush.dev/docs/api-reference/foundational-api/balances/get-native-token-balance){target=\_blank} retrieves the native token balance for a given address in a streamlined manner. === "Parameters" - `chainName` *string* - e.g. `moonbeam-mainnet`, `moonbeam-moonriver`, or `moonbeam-moonbase-alpha` - `walletAddress` *string* - the address you wish to check the token balances of === "Example Request" ```bash curl --request GET \ --url https://api.covalenthq.com/v1/moonbeam-moonbase-alpha/address/0x569BE8d8b04538318e1722f6e375FD381D2da865/balances_native/ \ --header 'Authorization: Bearer INSERT-API-KEY' ``` === "Example Response" ```bash { "data": { "address": "0x569be8d8b04538318e1722f6e375fd381d2da865", "updated_at": "2024-10-09T00:15:57.758041451Z", "quote_currency": "USD", "chain_id": 1287, "chain_name": "moonbeam-moonbase-alpha", "items": [ { "contract_decimals": 18, "contract_name": "Dev", "contract_ticker_symbol": "DEV", "contract_address": "0x0000000000006d6f6f6e626173652d616c706861", "supports_erc": [ "erc20" ], "logo_url": "https://www.datocms-assets.com/86369/1669924204-moonbeam.svg", "block_height": 8959160, "balance": "88335963638628211482", "quote_rate": null, "quote": null, "pretty_quote": null } ] }, "error": false, "error_message": null, "error_code": null } ``` ??? function "Get ERC-20 Token Transfers for Address" [Get ERC-20 Token Transfers for Address](https://goldrush.dev/docs/api-reference/foundational-api/balances/get-erc20-token-transfers-for-address){target=\_blank} is used to fetch the transfer-in and transfer-out of a token along with historical prices from an address, when provided both a wallet address and an ERC-20 token contract address === "Parameters" - `chainName` *string* - e.g. `moonbeam-mainnet`, `moonbeam-moonriver`, or `moonbeam-moonbase-alpha` - `walletAddress` *string* - the address you wish to query - `contractAddress` *string* - the ERC-20 token contract to query === "Example Request" ```bash curl --request GET \ --url 'https://api.covalenthq.com/v1/moonbeam-moonbase-alpha/address/0x3B939FeaD1557C741Ff06492FD0127bd287A421e/transfers_v2/?contract-address=0x37822de108AFFdd5cDCFDaAa2E32756Da284DB85' \ --header 'Authorization: Bearer INSERT_API_KEY' ``` === "Example Response" ```bash { "data": { "address": "0x3b939fead1557c741ff06492fd0127bd287a421e", "updated_at": "2024-10-09T02:02:58.842706507Z", "next_update_at": "2024-10-09T02:07:58.842707047Z", "quote_currency": "USD", "chain_id": 1287, "chain_name": "moonbeam-moonbase-alpha", "items": [ { "block_signed_at": "2022-04-29T17:41:36Z", "block_height": 2075113, "tx_hash": "0x7271982923345160707c397e412db1a75ceaa458fc1a5dc2c638dd60e58e60d2", "from_address": "0x3b939fead1557c741ff06492fd0127bd287a421e", "to_address": "0x37822de108affdd5cdcfdaaa2e32756da284db85", "value": "0", "gas_offered": 35009, "gas_spent": 32693, "gas_price": 2500000000, "fees_paid": "81732500000000", "transfers": [ { "tx_hash": "0x7271982923345160707c397e412db1a75ceaa458fc1a5dc2c638dd60e58e60d2", "from_address": "0x0000000000000000000000000000000000000000", "to_address": "0x3b939fead1557c741ff06492fd0127bd287a421e", "contract_name": "Mercury", "contract_ticker_symbol": "MERC", "contract_address": "0x37822de108affdd5cdcfdaaa2e32756da284db85", "transfer_type": "IN", "delta": "100000000000000000000" } ] }, { "block_signed_at": "2021-10-13T19:06:30Z", "block_height": 954752, "tx_hash": "0x7fb19c6b0ccf1dd87610c59a9cdc2f298ce6b39b32b396f900f1bf3c8f034b6b", "from_address": "0x3b939fead1557c741ff06492fd0127bd287a421e", "to_address": "0x8a1932d6e26433f3037bd6c3a40c816222a6ccd4", "value": "0", "gas_offered": 369444, "gas_spent": 99165, "gas_price": 1000000000, "fees_paid": "99165000000000", "transfers": [ { "tx_hash": "0x7fb19c6b0ccf1dd87610c59a9cdc2f298ce6b39b32b396f900f1bf3c8f034b6b", "from_address": "0x3b939fead1557c741ff06492fd0127bd287a421e", "to_address": "0x573db48e758cbc07a99afe67b8b7b23f671902c0", "contract_name": "Mercury", "contract_ticker_symbol": "MERC", "contract_address": "0x37822de108affdd5cdcfdaaa2e32756da284db85", "transfer_type": "OUT", "delta": "10000000000000000000000" } ] } ], "pagination": { "has_more": false, "page_number": 0, "page_size": 100, "total_count": null } }, "error": false, "error_message": null, "error_code": null } ``` ### Transactions {: #transactions } ???+ function "Get a transaction" [Get a transaction](https://goldrush.dev/docs/api-reference/foundational-api/transactions/get-a-transaction){target=\_blank} is used fetch and render a single transaction including its decoded log events. === "Parameters" - `chainName` *string* - e.g. `moonbeam-mainnet`, `moonbeam-moonriver`, or `moonbeam-moonbase-alpha` - `txHash` *string* - the transaction hash === "Example Request" ```bash curl --request GET \ --url https://api.covalenthq.com/v1/moonbeam-moonbase-alpha/transaction_v2/0xbbf16145833d6c906cd2e01254fabe17c59da711df9efacaacf50fc8453a2c60/ \ --header 'Authorization: Bearer INSERT_API_KEY' ``` === "Example Response" ```bash { "data": { "updated_at": "2024-10-09T00:33:57.799418189Z", "chain_id": 1287, "chain_name": "moonbeam-moonbase-alpha", "items": [ { "block_signed_at": "2024-09-27T22:23:54Z", "block_height": 8816296, "block_hash": "0x2f89cd5009b3c69de1eb4edf678a5dfb6c2366cb7da6945783a443133b3df44e", "tx_hash": "0xbbf16145833d6c906cd2e01254fabe17c59da711df9efacaacf50fc8453a2c60", "tx_offset": 1, "successful": true, "miner_address": "0xd34fedcefbaacbd74bd3d0bb80b3a67e6b2defb7", "from_address": "0x3b939fead1557c741ff06492fd0127bd287a421e", "from_address_label": null, "to_address": "0xffffffff1fcacbd218edc0eba20fc2308c778080", "to_address_label": null, "value": "0", "value_quote": null, "pretty_value_quote": null, "gas_metadata": { "contract_decimals": 18, "contract_name": "Dev", "contract_ticker_symbol": "DEV", "contract_address": "0x0000000000006d6f6f6e626173652d616c706861", "supports_erc": [ "erc20" ], "logo_url": "https://www.datocms-assets.com/86369/1669924204-moonbeam.svg" }, "gas_offered": 169164, "gas_spent": 110096, "gas_price": 31250000, "fees_paid": "13762000000000", "gas_quote": null, "pretty_gas_quote": null, "gas_quote_rate": null, "explorers": [ { "label": null, "url": "https://moonbase-blockscout.testnet.moonbeam.network/tx/0xbbf16145833d6c906cd2e01254fabe17c59da711df9efacaacf50fc8453a2c60" } ], "log_events": [ { "block_signed_at": "2024-09-27T22:23:54Z", "block_height": 8816296, "tx_offset": 1, "log_offset": 1, "tx_hash": "0xbbf16145833d6c906cd2e01254fabe17c59da711df9efacaacf50fc8453a2c60", "raw_log_topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x0000000000000000000000003b939fead1557c741ff06492fd0127bd287a421e", "0x0000000000000000000000004b8c667590e6a28497ea4be5facb7e9869a64eae" ], "sender_contract_decimals": 12, "sender_name": "xcUNIT", "sender_contract_ticker_symbol": "xcUNIT", "sender_address": "0xffffffff1fcacbd218edc0eba20fc2308c778080", "sender_address_label": null, "sender_logo_url": "https://logos.covalenthq.com/tokens/1287/0xffffffff1fcacbd218edc0eba20fc2308c778080.png", "supports_erc": [ "erc20" ], "sender_factory_address": null, "raw_log_data": "0x000000000000000000000000000000000000000000000000000000e8d4a51000", "decoded": { "name": "Transfer", "signature": "Transfer(indexed address from, indexed address to, uint256 value)", "params": [ { "name": "from", "type": "address", "indexed": true, "decoded": true, "value": "0x3b939fead1557c741ff06492fd0127bd287a421e" }, { "name": "to", "type": "address", "indexed": true, "decoded": true, "value": "0x4b8c667590e6a28497ea4be5facb7e9869a64eae" }, { "name": "value", "type": "uint256", "indexed": false, "decoded": true, "value": "1000000000000" } ] } } ] } ], "pagination": null }, "error": false, "error_message": null, "error_code": null } ``` ??? function "Get transaction summary for address" [Get transaction summary for address](https://goldrush.dev/docs/api-reference/foundational-api/transactions/get-transaction-summary-for-address){target=\_blank} retrieves key wallet activity data, including the first and most recent transactions, and total transaction count. It enables quick analysis of wallet age, inactive periods, and overall Web3 engagement levels. === "Parameters" - `chainName` *string* - e.g. `moonbeam-mainnet`, `moonbeam-moonriver`, or `moonbeam-moonbase-alpha` - `walletAddress` *string* - the address you wish to query === "Example Request" ```bash curl --request GET \ --url https://api.covalenthq.com/v1/moonbeam-moonbase-alpha/address/0x3B939FeaD1557C741Ff06492FD0127bd287A421e/transactions_summary/ \ --header 'Authorization: Bearer INSERT_API_KEY' ``` === "Example Response" ```bash { "data": { "updated_at": "2024-10-09T00:48:11.969915467Z", "address": "0x3b939fead1557c741ff06492fd0127bd287a421e", "chain_id": 1287, "chain_name": "moonbeam-moonbase-alpha", "items": [ { "total_count": 3066, "latest_transaction": { "block_signed_at": "2024-10-04T19:41:48Z", "tx_hash": "0x0923932a55c4366288cfc7a970e1d04895551d11f64d8f183877e8f6c19360bc", "tx_detail_link": "https://api.covalenthq.com/v1/moonbeam-moonbase-alpha/transaction_v2/0x0923932a55c4366288cfc7a970e1d04895551d11f64d8f183877e8f6c19360bc/" }, "earliest_transaction": { "block_signed_at": "2021-05-27T18:13:12Z", "tx_hash": "0xc94e0072477e2543d17662317d40e4785ac6bb327c2a7483021167684b8584f3", "tx_detail_link": "https://api.covalenthq.com/v1/moonbeam-moonbase-alpha/transaction_v2/0xc94e0072477e2543d17662317d40e4785ac6bb327c2a7483021167684b8584f3/" } } ] }, "error": false, "error_message": null, "error_code": null } ``` ??? function "Get earliest transactions for address (v3)" [Get earliest transactions for address](https://goldrush.dev/docs/api-reference/foundational-api/transactions/get-earliest-transactions-for-address-v3){target=\_blank} retrieves the earliest transactions involving an address. === "Parameters" - `chainName` *string* - e.g. `moonbeam-mainnet`, `moonbeam-moonriver`, or `moonbeam-moonbase-alpha` - `walletAddress` *string* - the address you wish to query === "Example Request" ```bash curl --request GET \ --url https://api.covalenthq.com/v1/moonbeam-moonbase-alpha/bulk/transactions/0x3B939FeaD1557C741Ff06492FD0127bd287A421e/ \ --header 'Authorization: Bearer INSERT_API_KEY' ``` === "Example Response" ```bash { "data": { "address": "0x3b939fead1557c741ff06492fd0127bd287a421e", "updated_at": "2024-10-09T01:12:17.851277100Z", "next_update_at": "2024-10-09T01:17:17.851280680Z", "quote_currency": "USD", "chain_id": 1287, "chain_name": "moonbeam-moonbase-alpha", "items": [ { "block_signed_at": "2021-05-27T18:13:12Z", "block_height": 6971, "tx_hash": "0xc94e0072477e2543d17662317d40e4785ac6bb327c2a7483021167684b8584f3", "from_address": "0xc10dc91c62c4854ffc0997776d495da3d8c79730", "to_address": null, "value": "0", "fees_paid": "1044522000000000", "gas_quote": null, "gas_quote_rate": null, "log_events": [ { "sender_name": "Mercury", "sender_contract_ticker_symbol": "MERC", "sender_address": "0x37822de108affdd5cdcfdaaa2e32756da284db85", "decoded": { "name": "Transfer", "params": [ { "name": "from", "value": "0x0000000000000000000000000000000000000000" }, { "name": "to", "value": "0x3b939fead1557c741ff06492fd0127bd287a421e" }, { "name": "value", "value": "100000000000000000000000" } ] } } ] }, { "block_signed_at": "2021-05-27T18:13:24Z", "block_height": 6972, "tx_hash": "0xc37137133cbb8b0810943a6625a7193b5b18d72b5e21a78103243f482c269e71", "from_address": "0xc10dc91c62c4854ffc0997776d495da3d8c79730", "to_address": null, "value": "0", "fees_paid": "1044486000000000", "gas_quote": null, "gas_quote_rate": null, "log_events": [ { "sender_name": "Venus", "sender_contract_ticker_symbol": "VEN", "sender_address": "0xcdf746c5c86df2c2772d2d36e227b4c0203cba25", "decoded": { "name": "Transfer", "params": [ { "name": "from", "value": "0x0000000000000000000000000000000000000000" }, { "name": "to", "value": "0x3b939fead1557c741ff06492fd0127bd287a421e" }, { "name": "value", "value": "100000000000000000000000" } ] } } ] } ] }, "error": false, "error_message": null, "error_code": null } ``` ??? function "Get recent transactions for address (v3)" [Get recent transactions for address](https://goldrush.dev/docs/api-reference/foundational-api/transactions/get-recent-transactions-for-address-v3){target=\_blank} retrieves the most recent transactions involving an address. === "Parameters" - `chainName` *string* - e.g. `moonbeam-mainnet`, `moonbeam-moonriver`, or `moonbeam-moonbase-alpha` - `walletAddress` *string* - the address you wish to query === "Example Request" ```bash curl --request GET \ --url https://api.covalenthq.com/v1/moonbeam-moonbase-alpha/address/0x3B939FeaD1557C741Ff06492FD0127bd287A421e/transactions_v3/ \ --header 'Authorization: Bearer INSERT_API_KEY' ``` === "Example Response" ```bash { "data": { "address": "0x3b939fead1557c741ff06492fd0127bd287a421e", "updated_at": "2024-10-09T01:16:10.410076422Z", "next_update_at": "2024-10-09T01:21:10.410077022Z", "quote_currency": "USD", "chain_id": 1287, "chain_name": "moonbeam-moonbase-alpha", "items": [ { "block_signed_at": "2024-10-04T19:41:48Z", "block_height": 8901780, "tx_hash": "0x0923932a55c4366288cfc7a970e1d04895551d11f64d8f183877e8f6c19360bc", "from_address": "0x3b939fead1557c741ff06492fd0127bd287a421e", "to_address": null, "value": "0", "fees_paid": "120825750000000", "gas_offered": 1010593, "gas_spent": 966606, "gas_price": 31250000, "gas_quote": null, "gas_quote_rate": null }, { "block_signed_at": "2024-09-27T22:23:54Z", "block_height": 8816296, "tx_hash": "0xbbf16145833d6c906cd2e01254fabe17c59da711df9efacaacf50fc8453a2c60", "from_address": "0x3b939fead1557c741ff06492fd0127bd287a421e", "to_address": "0xffffffff1fcacbd218edc0eba20fc2308c778080", "value": "0", "fees_paid": "13762000000000", "gas_offered": 169164, "gas_spent": 110096, "gas_price": 31250000, "gas_quote": null, "gas_quote_rate": null, "log_events": [ { "sender_name": "xcUNIT", "sender_contract_ticker_symbol": "xcUNIT", "sender_address": "0xffffffff1fcacbd218edc0eba20fc2308c778080", "decoded": { "name": "Transfer", "params": [ { "name": "from", "value": "0x3b939fead1557c741ff06492fd0127bd287a421e" }, { "name": "to", "value": "0x4b8c667590e6a28497ea4be5facb7e9869a64eae" }, { "name": "value", "value": "1000000000000" } ] } } ] } ] }, "error": false, "error_message": null, "error_code": null } ``` ??? function "Get paginated transactions for address (v3)" [Get paginated transactions for address (v3)](https://goldrush.dev/docs/api-reference/foundational-api/transactions/get-paginated-transactions-for-address-v3){target=\_blank} fetches the transactions involving an address and the specified page, starting from a 0 index. === "Parameters" - `chainName` *string* - e.g. `moonbeam-mainnet`, `moonbeam-moonriver`, or `moonbeam-moonbase-alpha` - `walletAddress` *string* - the address you wish to query - `page` *integer* - the requested page, 0-indexed. === "Example Request" ```bash curl --request GET \ --url https://api.covalenthq.com/v1/moonbeam-moonbase-alpha/address/0x3B939FeaD1557C741Ff06492FD0127bd287A421e/transactions_v3/page/2/ \ --header 'Authorization: Bearer INSERT_API_KEY' ``` === "Example Response" ```bash { "data": { "address": "0x3b939fead1557c741ff06492fd0127bd287a421e", "updated_at": "2024-10-09T01:37:36.277434751Z", "next_update_at": "2024-10-09T01:42:36.277435481Z", "quote_currency": "USD", "chain_id": 1287, "chain_name": "moonbeam-moonbase-alpha", "items": [ { "block_signed_at": "2021-06-08T18:22:00Z", "block_height": 93135, "tx_hash": "0x802eab122522f1ae23b911e8045d9de128acaa5c790d5df0c389240f23b7e17d", "from_address": "0x3b939fead1557c741ff06492fd0127bd287a421e", "to_address": null, "value": "0", "fees_paid": "1416680000000000", "gas_offered": 1455080, "gas_spent": 1416680, "gas_price": 1000000000, "gas_quote": null, "gas_quote_rate": null }, { "block_signed_at": "2021-06-08T18:21:48Z", "block_height": 93134, "tx_hash": "0xe82d29e37e8d324a22ed9ce70d0c85258c420cf98cc4161c35f4edb7c9ba09c0", "from_address": "0x3b939fead1557c741ff06492fd0127bd287a421e", "to_address": null, "value": "0", "fees_paid": "1712047000000000", "gas_offered": 1750447, "gas_spent": 1712047, "gas_price": 1000000000, "gas_quote": null, "gas_quote_rate": null } ] }, "error": false, "error_message": null, "error_code": null } ``` ??? function "Get bulk time bucket transactions for address (v3)" [Get bulk time bucket transactions for address (v3)](https://goldrush.dev/docs/api-reference/foundational-api/transactions/get-time-bucket-transactions-for-address-v3){target=\_blank} is used to fetch all transactions including their decoded log events in a 15-minute time bucket interval. === "Parameters" - `chainName` *string* - e.g. `moonbeam-mainnet`, `moonbeam-moonriver`, or `moonbeam-moonbase-alpha` - `walletAddress` *string* - the address you wish to query - `timeBucket` *integer* - The 0-indexed 15-minute time bucket. E.g. 8 9 Oct 2024 01:49 GMT = 1728420540 (Unix time). 1728420540/900 = 1920467 timeBucket. === "Example Request" ```bash curl --request GET \ --url https://api.covalenthq.com/v1/moonbeam-moonbase-alpha/bulk/transactions/0x28a2B98793Fd1E20Fd79824cd29D36D3eB9A8F0E/1920467/ \ --header 'Authorization: Bearer INSERT_API_KEY' ``` === "Example Response" ```bash { "data": { "address": "0x28a2b98793fd1e20fd79824cd29d36d3eb9a8f0e", "updated_at": "2024-10-09T01:47:40.617173773Z", "next_update_at": "2024-10-09T01:52:40.617176953Z", "quote_currency": "USD", "chain_id": 1287, "chain_name": "moonbeam-moonbase-alpha", "complete": true, "current_bucket": 1920467, "links": { "prev": "https://api.covalenthq.com/v1/moonbeam-moonbase-alpha/bulk/transactions/0x28a2b98793fd1e20fd79824cd29d36d3eb9a8f0e/1920466/", "next": "https://api.covalenthq.com/v1/moonbeam-moonbase-alpha/bulk/transactions/0x28a2b98793fd1e20fd79824cd29d36d3eb9a8f0e/1920468/" }, "items": [ { "block_signed_at": "2024-10-08T20:48:42Z", "block_height": 8957260, "tx_hash": "0x587f0121ea9c51b93e1915a20370f0a2f004adee99d00ef8d1c0f9cc681a9772", "from_address": "0x28a2b98793fd1e20fd79824cd29d36d3eb9a8f0e", "to_address": "0x916b54696a70588a716f899be1e8f2a5ffd5f135", "value": "0", "gas_offered": 582957, "gas_spent": 551928, "gas_price": 31250000, "fees_paid": "68991000000000", "log_events": [ { "sender_address": "0x916b54696a70588a716f899be1e8f2a5ffd5f135", "decoded": { "name": "SessionStarted", "signature": "SessionStarted(indexed uint64 chainId, indexed uint64 blockHeight, uint64 deadline)", "params": [ { "name": "chainId", "type": "uint64", "value": "1" }, { "name": "blockHeight", "type": "uint64", "value": "20923350" }, { "name": "deadline", "type": "uint64", "value": "8957360" } ] } } ] } ] }, "error": false, "error_message": null, "error_code": null } ``` ??? function "Get all transactions in a block by page (v3)" [Get all transactions in a block by page (v3)](https://goldrush.dev/docs/api-reference/foundational-api/transactions/get-all-transactions-in-a-block-by-page){target=\_blank} is used to fetch all transactions including their decoded log events in a block and further flag interesting wallets or transactions. === "Parameters" - `chainName` *string* - e.g. `moonbeam-mainnet`, `moonbeam-moonriver`, or `moonbeam-moonbase-alpha` - `blockHeight` *integer* - the request block height. Also accepts the `latest` keyword - `page` *integer* - the requested page, 0-indexed. === "Example Request" ```bash curl --request GET \ --url https://api.covalenthq.com/v1/moonbeam-moonbase-alpha/block/8960094/transactions_v3/page/0/ \ --header 'Authorization: Bearer INSERT_API_KEY' ``` === "Example Response" ```bash { "data": { "updated_at": "2024-10-09T01:54:34.371150099Z", "chain_id": 1287, "chain_name": "moonbeam-moonbase-alpha", "links": { "prev": null, "next": null }, "items": [ { "block_signed_at": "2024-10-09T01:51:42Z", "block_height": 8960094, "block_hash": "0x2a9cda3cfd23dffbe064932991568cae601d178717743eabc326222123d7ad44", "tx_hash": "0x4abfef674580260d3c837e1dc5b17b8bf809e620518e40d3731c6c1cfa5346d9", "tx_offset": 0, "successful": true, "miner_address": "0xeda33e2b5ffb97bb8b901b71b87e5791556fd46b", "from_address": "0xf5e8a439c599205c1ab06b535de46681aed1007a", "from_address_label": null, "to_address": "0x21e612506ab4792a5d22466c0b529bb9afe4e42b", "to_address_label": null, "value": "0", "value_quote": null, "pretty_value_quote": null, "gas_metadata": { "contract_decimals": 18, "contract_name": "Dev", "contract_ticker_symbol": "DEV", "contract_address": "0x0000000000006d6f6f6e626173652d616c706861", "supports_erc": [ "erc20" ], "logo_url": "https://www.datocms-assets.com/86369/1669924204-moonbeam.svg" }, "gas_offered": 505088, "gas_spent": 184528, "gas_price": 1200000000, "fees_paid": "221433600000000", "gas_quote": null, "pretty_gas_quote": null, "gas_quote_rate": null, "explorers": [ { "label": null, "url": "https://moonbase-blockscout.testnet.moonbeam.network/tx/0x4abfef674580260d3c837e1dc5b17b8bf809e620518e40d3731c6c1cfa5346d9" } ] } ] }, "error": false, "error_message": null, "error_code": null } ``` ??? function "Get all transactions in a block (v3)" [Get all transactions in a block (v3)](https://goldrush.dev/docs/api-reference/foundational-api/transactions/get-all-transactions-in-a-block){target=\_blank} is used to used to fetch all transactions including their decoded log events in a block and further flag interesting wallets or transactions. It takes a blockhash as a parameter and it does not accept a page parameter. === "Parameters" - `chainName` *string* - e.g. `moonbeam-mainnet`, `moonbeam-moonriver`, or `moonbeam-moonbase-alpha` - `blockHash` *integer* - the request block hash === "Example Request" ```bash curl --request GET \ --url https://api.covalenthq.com/v1/moonbeam-moonbase-alpha/block_hash/0x2a9cda3cfd23dffbe064932991568cae601d178717743eabc326222123d7ad44/transactions_v3/ \ --header 'Authorization: Bearer INSERT_API_KEY' ``` === "Example Response" ```bash { "data": { "updated_at": "2024-10-09T01:58:08.816101489Z", "chain_id": 1287, "chain_name": "moonbeam-moonbase-alpha", "items": [ { "block_signed_at": "2024-10-09T01:51:42Z", "block_height": 8960094, "block_hash": "0x2a9cda3cfd23dffbe064932991568cae601d178717743eabc326222123d7ad44", "tx_hash": "0x4abfef674580260d3c837e1dc5b17b8bf809e620518e40d3731c6c1cfa5346d9", "tx_offset": 0, "successful": true, "miner_address": "0xeda33e2b5ffb97bb8b901b71b87e5791556fd46b", "from_address": "0xf5e8a439c599205c1ab06b535de46681aed1007a", "from_address_label": null, "to_address": "0x21e612506ab4792a5d22466c0b529bb9afe4e42b", "to_address_label": null, "value": "0", "value_quote": null, "pretty_value_quote": null, "gas_metadata": { "contract_decimals": 18, "contract_name": "Dev", "contract_ticker_symbol": "DEV", "contract_address": "0x0000000000006d6f6f6e626173652d616c706861", "supports_erc": [ "erc20" ], "logo_url": "https://www.datocms-assets.com/86369/1669924204-moonbeam.svg" }, "gas_offered": 505088, "gas_spent": 184528, "gas_price": 1200000000, "fees_paid": "221433600000000", "gas_quote": null, "pretty_gas_quote": null, "gas_quote_rate": null, "explorers": [ { "label": null, "url": "https://moonbase-blockscout.testnet.moonbeam.network/tx/0x4abfef674580260d3c837e1dc5b17b8bf809e620518e40d3731c6c1cfa5346d9" } ] } ], "pagination": null }, "error": false, "error_message": null, "error_code": null } ``` ### Cross Chain {: #cross-chain } ???+ function "Get cross-chain activity for address" [Get cross-chain activity for address](https://goldrush.dev/docs/api-reference/foundational-api/cross-chain/get-address-activity){target=\_blank} is used to locate chains which an address is active on with a single API call === "Parameters" - `walletAddress` *string* - the address you wish to query === "Example Request" ```bash curl --request GET \ --url https://api.covalenthq.com/v1/address/0x3B939FeaD1557C741Ff06492FD0127bd287A421e/activity/ \ --header 'Authorization: Bearer INSERT_API_KEY' ``` === "Example Response" ```bash { "data": { "updated_at": "2024-10-09T02:08:22.594362014Z", "address": "0x3b939fead1557c741ff06492fd0127bd287a421e", "items": [ { "name": "matic-mainnet", "chain_id": "137", "is_testnet": false, "label": "Polygon Mainnet", "category_label": "Polygon", "logo_url": "https://www.datocms-assets.com/86369/1677870347-property-1-polygon-zkevm-icon-white.svg", "color_theme": { "hex": "#8247E5", "css_rgb": "rgb(130 71 229)" }, "last_seen_at": "2024-06-26T09:50:16Z" }, { "name": "moonbeam-mainnet", "chain_id": "1284", "is_testnet": false, "label": "Moonbeam Mainnet", "category_label": "Moonbeam", "logo_url": "https://www.datocms-assets.com/86369/1669924204-moonbeam.svg", "color_theme": { "hex": "#54CBC8", "css_rgb": "rgb(84 203 200)" }, "last_seen_at": "2024-10-04T01:11:42Z" } ] }, "error": false, "error_message": null, "error_code": null } ``` ### Security {: #security } ???+ function "Get token approvals for address" [Get token approvals for address](https://goldrush.dev/docs/api-reference/foundational-api/security/get-token-approvals-for-address){target=\_blank} is used to get a list of approvals across all token contracts categorized by spenders for a wallet’s assets === "Parameters" - `chainName` *string* - e.g. `moonbeam-mainnet`, `moonbeam-moonriver`, or `moonbeam-moonbase-alpha` - `walletAddress` *string* - the address you wish to query === "Example Request" ```bash curl --request GET \ --url https://api.covalenthq.com/v1/moonbeam-mainnet/approvals/0x3B939FeaD1557C741Ff06492FD0127bd287A421e/ \ --header 'Authorization: Bearer INSERT_API_KEY' ``` === "Example Response" ```bash { "data": { "address": "0x3b939fead1557c741ff06492fd0127bd287a421e", "updated_at": "2024-10-09T02:11:10.587740726Z", "quote_currency": "USD", "chain_id": 1284, "chain_name": "moonbeam-mainnet", "items": [ { "token_address": "0xffffffff1fcacbd218edc0eba20fc2308c778080", "token_address_label": "xcDOT", "ticker_symbol": "xcDOT", "contract_decimals": 10, "logo_url": "https://logos.covalenthq.com/tokens/1284/0xffffffff1fcacbd218edc0eba20fc2308c778080.png", "quote_rate": 4.169, "balance": "1655341603", "balance_quote": 0.6901119142907, "pretty_balance_quote": "$0.69", "spenders": [ { "spender_address": "0xbc7e02c4178a7df7d3e564323a5c359dc96c4db4", "spender_address_label": "Stella stDOT", "allowance": "UNLIMITED", "value_at_risk_quote": 0.6901119142907, "pretty_value_at_risk_quote": "$0.69", "risk_factor": "LOW RISK" } ] }, { "token_address": "0x818ec0a7fe18ff94269904fced6ae3dae6d6dc0b", "token_address_label": "USD Coin", "ticker_symbol": "USDC", "contract_decimals": 6, "logo_url": "https://logos.covalenthq.com/tokens/1284/0x818ec0a7fe18ff94269904fced6ae3dae6d6dc0b.png", "quote_rate": 0.09, "balance": "1", "balance_quote": 0, "pretty_balance_quote": "$0.00", "spenders": [ { "spender_address": "0x70085a09d30d6f8c4ecf6ee10120d1847383bb57", "spender_address_label": null, "allowance": "UNLIMITED", "value_at_risk_quote": 0, "pretty_value_at_risk_quote": "$0.00", "risk_factor": "LOW RISK" } ] } ] }, "error": false, "error_message": null, "error_code": null } ``` The GoldRush API offers many additional methods, including NFT, price, Bitcoin, and utility methods. Be sure to check out the [GoldRush API](https://goldrush.dev/docs/api-reference/foundational-api/cross-chain/get-address-activity){target=\_blank} for more information on each of these methods. ## API Parameters and Resources {: #api-parameters-and-resources } ### API Parameters {: #api-parameters } === "Moonbeam" | Parameter | Value | |:----------------------:|:---------------:| | Response Formats | JSON, CSV | | Real-Time Data Latency | 2 blocks | | Batch Data Latency | 30 minutes | | API Free Tier | Limit of 4 RPS | | API Premium Tier | Limit of 50 RPS | === "Moonriver" | Parameter | Value | |:----------------------:|:---------------:| | Response Formats | JSON, CSV | | Real-Time Data Latency | 2 blocks | | Batch Data Latency | 30 minutes | | API Free Tier | Limit of 4 RPS | | API Premium Tier | Limit of 50 RPS | === "Moonbase Alpha" | Parameter | Value | |:----------------------:|:---------------:| | Response Formats | JSON, CSV | | Real-Time Data Latency | 2 blocks | | Batch Data Latency | 30 minutes | | API Free Tier | Limit of 4 RPS | | API Premium Tier | Limit of 50 RPS | ### API Resources {: #api-resources } - [API Reference and In-Browser Endpoint Demo](https://goldrush.mintlify.app/docs/api/overview){target=\_blank} - [GoldRush Quickstart](https://goldrush.mintlify.app/docs/quickstart){target=\_blank} - [Written Guides](https://goldrush.dev/docs/unified-api/guides/?utm_source=moonbeam&utm_medium=partner-docs){target=\_blank} ## How to Use the Unified API {: #how-to-use-the-unified-api } First, make sure you have [your API Key](https://goldrush.dev/platform/auth/register/){target=\_blank} which begins with `cqt_` or `ckey_`. Once you have your API key, you can access any of the supported endpoints. To get information for a specific network, you must provide the chain ID. ### Checking Prerequisites {: #checking-prerequisites } To get started with the GoldRush API, you will need to have the following: - A free [GoldRush API Key](https://goldrush.dev/platform/auth/register/){target=\_blank} - MetaMask installed and [connected to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank} - An account with funds. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} ### Using Curl {: #using-curl } One of the supported endpoints is the token holders endpoint, which returns a list of all the token holders of a particular token. For this example, you can check the token holders for the ERTH token. The contract address for the ERTH token on Moonbase Alpha is `0x08B40414525687731C23F430CEBb424b332b3d35`. Try running the command below in a terminal window after replacing the placeholder with your API key. ```bash curl https://api.covalenthq.com/v1/1287/tokens/\ 0x08B40414525687731C23F430CEBb424b332b3d35/token_holders/ \ -u INSERT_YOUR_API_KEY: ``` !!! note The colon `:` after the API key is required to skip the password prompt. Unless you already owned some ERTH tokens, your address will be missing from that list. Head over to the [Moonbase Alpha ERC-20 Faucet](https://moonbase-minterc20.netlify.app){target=\_blank} to generate some ERTH tokens for yourself. Now repeat the same GoldRush API request as above. The GoldRush API updates in real-time, so you should now see your address in the list of token holders for the ERTH token. ### Using Javascript {: #using-javascript } Copy and paste the below code block into your preferred environment or [JSFiddle](https://jsfiddle.net){target=\_blank}. After setting the API key, set the address constant. Remember for Moonbase Alpha the chain ID is `{{ networks.moonbase.chain_id }}`. === "Using Fetch" ```js // Set your API key const apiKey = 'INSERT_YOUR_API_KEY'; function getData() { const address = '0xFEC4f9D5B322Aa834056E85946A32c35A3f5aDD8'; // example const chainId = '1287'; // Moonbase Alpha TestNet chain ID const url = new URL( `https://api.covalenthq.com/v1/${chainId}/address/${address}/balances_v2/` ); url.search = new URLSearchParams({ key: apiKey, }); // Use fetch API to get Covalent data fetch(url) .then((resp) => resp.json()) .then(function (data) { const result = data.data; console.log(result); return result; }); } getData(); ``` === "Using Async" ```js // Set your API key const apiKey = 'INSERT_YOUR_API_KEY'; const address = '0xFEC4f9D5B322Aa834056E85946A32c35A3f5aDD8'; // Example const chainId = '1287'; // Moonbase Alpha TestNet chain ID const url = new URL( `https://api.covalenthq.com/v1/${chainId}/address/${address}/balances_v2/` ); url.search = new URLSearchParams({ key: apiKey, }); async function getData() { const response = await fetch(url); const result = await response.json(); console.log(result); return result; } getData(); ``` The balances endpoint returns a list of all ERC-20 and NFT token balances, including ERC-721 and ERC-1155 balances, along with their current spot prices (if available). ![JavaScript Console Output](/images/builders/integrations/indexers/covalent/covalent-2.webp) ### Using Python {: #using-python } GoldRush doesn’t have an official API wrapper. To query the API directly, you will have to use the Python [requests library](https://pypi.org/project/requests){target=\_blank}. Install requests into your environment from the command line with `pip install requests`. Then import it and use it in your code. Use the HTTP verbs get methods to return the information from the API. Copy and paste the below code block into your preferred environment and run it. The output should look similar to the screenshot above, however the formatting may vary depending on your environment. ```python import requests def fetch_wallet_balance(address): api_url = "https://api.covalenthq.com" endpoint = f"/v1/1287/address/{address}/balances_v2/" url = api_url + endpoint response = requests.get(url, auth=("INSERT_YOUR_API_KEY", "")) print(response.json()) return response.json() # Example address request fetch_wallet_balance("0xFEC4f9D5B322Aa834056E85946A32c35A3f5aDD8") ``` !!! note The second parameter of `auth` is empty because no password is required—your API key is all that's needed.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/indexers/ --- BEGIN CONTENT --- --- title: Indexers and APIs description: Learn how to build your own API or consume API endpoints from any of the supported REST or GraphQL-based indexers on Moonbeam. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/indexers/moralis/ --- BEGIN CONTENT --- --- title: Interact with Moralis APIs description: Learn how Moralis' API suite empowers developers to retrieve and leverage various data sets from Moonbeam, Moonriver, and Moonbase Alpha. categories: Indexers and Queries --- # Access Moonbeam Data via Moralis APIs ## Introduction {: #introduction } As a one-stop solution for blockchain development, [Moralis](https://moralis.com/){target=\_blank} offers a comprehensive platform that empowers developers to create, launch, and scale decentralized applications (dApps) with ease. It provides a suite of tools and services designed to streamline the process of accessing Web3 data and interacting with blockchain networks. Its offerings are structured into these primary categories: - **EVM API** - The EVM API allows developers to query essential data for Ethereum Virtual Machine (EVM)-compatible blockchains. Moralis provides dedicated APIs for four key areas: NFTs, tokens, wallets, and general blockchain information - **Streams API** - the Streams API enables developers to listen for on-chain events, such as smart contract event emissions, in real-time. Popular use cases include real-time wallet notifications, asset monitoring, and gaming event notifications - **RPC API** - the RPC API offers a secure and reliable connection to various blockchain networks. It provides a high-performance gateway for developers to interact with blockchain nodes, ensuring stable and efficient communication between dApps and the blockchain This guide will show you how to access the API endpoints for Moonbeam using curl commands and the Moralis SDK using JavaScript and Python snippets.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Checking Prerequisites {: #checking-prerequisites } To interact with Moralis' API endpoints, an account and API key are required. Head to the [sign up page](https://admin.moralis.com/register){target=\_blank} to create an account. Once you're in, navigate to the **API keys** section. There, you can generate your own unique API key. Be sure to copy it for future use. ![Moralis API key](/images/builders/integrations/indexers/moralis/moralis-1.webp) ## Querying the EVM API {: #querying-the-evm-api } With the API key, you can try Moralis' REST APIs. The following examples show how the EVM API works: Get the token balance of a wallet: ```bash curl --request GET \ --url 'https://deep-index.moralis.io/api/v2.2/0xd4d7fb1f98dD66f6D1f393E8e237AdF74c31F3ea/erc20?chain=moonbeam' \ --header 'accept: application/json' \ --header 'X-API-Key: INSERT_YOUR_API_KEY' ``` Get the list of owners of an NFT: ```bash curl --request GET \ --url 'https://deep-index.moralis.io/api/v2.2/nft/0xfffffffffffffffffffffffffffffffffffffffff/owners?chain=moonbeam&format=decimal' \ --header 'accept: application/json' \ --header 'X-API-Key: INSERT_YOUR_API_KEY' ``` For a comprehensive overview of EVM APIs and their capabilities, please refer to Moralis' [official documentation](https://docs.moralis.io/web3-data-api/evm/reference){target=\_blank}. ## Using the Moralis SDK {: #using-the-moralis-SDK } Moralis has an SDK that allows developers to seamlessly integrate Moralis' API into their backend infrastructure. This SDK offers a wide array of features, including: - Data querying from EVM APIs - Integration of Web3 authentication - A collection of utility functions for efficient data transformation and formatting Moralis currently provides official SDK support for two primary programming languages: - Node.js - Python You can install Moralis SDK with the following commands: === "npm" ```bash npm install moralis ``` === "yarn" ```bash yarn add moralis ``` === "pnpm" ```bash pnpm add moralis ``` === "pip" ```bash pip install moralis ``` Once the SDK is ready, you can leverage it to query Moralis APIs. Here's an example of how to interact with the EVM API using a JSON-RPC interface: === "JavaScript" ```js import Moralis from 'moralis'; try { await Moralis.start({ apiKey: 'INSERT_YOUR_API_KEY', }); const response = await Moralis.EvmApi.block.getBlock({ chain: '0x504', blockNumberOrHash: '1', }); console.log(response.raw); } catch (e) { console.error(e); } ``` === "Python" ```python from moralis import evm_api api_key = "INSERT_YOUR_API_KEY" params = {"chain": "moonbeam", "block_number_or_hash": "1"} result = evm_api.block.get_block( api_key=api_key, params=params, ) print(result) ``` For more information on advanced features and configurations within the Moralis SDK, please refer to the official [JavaScript](https://moralisweb3.github.io/Moralis-JS-SDK/Introduction){target=\_blank} and [Python](https://moralisweb3.github.io/Moralis-Python-SDK/){target=\_blank} documentation. ## Accessing the Stream API {: #accessing-stream-api } The [Moralis Streams API](https://docs.moralis.io/streams-api/evm){target=\_blank} is a tool for developers to listen to and react to events happening on blockchains in real time. This API lets you listen for specific events, such as a new transaction being added to a block, a particular smart contract function being called, or an NFT being transferred and delivering the event via Webhook. Head over to the **Streams** page from your Moralis dashboard and click **Create a new stream** to get started. ![stream API page](/images/builders/integrations/indexers/moralis/moralis-2.webp) To get started quickly, choose a predefined template. This example focuses on transactions related to xcDOT. Select the **Contract Activity** template to listen for events related specifically to xcDOT. ![template selection page](/images/builders/integrations/indexers/moralis/moralis-3.webp) On the next page, enter the following details: 1. Enter the smart contract address for [xcDOT](https://moonscan.io/token/0xffffffff1fcacbd218edc0eba20fc2308c778080){target=\_blank}: ``` 0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080 ``` 2. Select **Moonbeam** from the available network options. Moralis supports listening to events on Moonbeam, Moonriver, and Moonbase Alpha 3. Customize the events you want to receive. For this example, choose **All contract events**. You may also test the stream to confirm it captures the needed data 4. Connect the stream to an endpoint to receive updates from Moralis 5. Click **Save** to activate your stream ![details input page](/images/builders/integrations/indexers/moralis/moralis-4.webp) Now you're all set. Once you activate your stream, it will be added to your list of streams on your dashboard. ![List of streams on Moralis dashboard](/images/builders/integrations/indexers/moralis/moralis-5.webp) ## Accessing the RPC API {: #accessing-rpc-api } To use the Moralis Moonbeam RPC endpoint, visit the **Nodes** page, click **Create Node**, and take the following steps: 1. Select **Moonbeam** as the protocol 2. Choose **Mainnet** as the chain 3. Click **Create Node** ![RPC API setup page](/images/builders/integrations/indexers/moralis/moralis-6.webp) Your RPC endpoint will be generated for you to easily copy, and your Moonbeam node will be up and running in seconds, ready to handle your RPC requests. You can view your nodes at any time from your dashboard. ![node ready page](/images/builders/integrations/indexers/moralis/moralis-7.webp) And that's it! Hope this guide has been helpful. For advanced features and more complex use cases, refer to [the official Moralis documentation](https://docs.moralis.io/) for further details.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/indexers/subquery/ --- BEGIN CONTENT --- --- title: Index Data with SubQuery & GraphQL description: Learn how to use SubQuery to index Substrate and EVM chain data for Moonbeam and Moonriver, and query the data using GraphQL. categories: Indexers and Queries --- # Indexing Moonbeam with SubQuery ## Introduction {: #introduction } [SubQuery](https://subquery.network){target=\_blank} is a data aggregation layer that operates between the layer-1 blockchains (such as Moonbeam and Polkadot) and DApps. This service unlocks blockchain data and transforms it into a queryable state so that it can be used in intuitive applications. It allows DApp developers to focus on their core use case and front end without needing to waste time on building a custom back end for data processing. SubQuery supports indexing the Ethereum Virtual Machine (EVM) and Substrate data for any of the Moonbeam networks. A key advantage of using SubQuery is that you can flexibly collect query data across both Moonbeam's EVM and Substrate code with a single project and tool, and then query this data using GraphQL. For example, SubQuery can filter and query EVM logs and transactions in addition to Substrate data sources. SubQuery introduces more advanced filters than other indexers, allowing filtering of non-contract transactions, transaction senders, contracts, and indexed log arguments, so developers can build a wide variety of projects that cater to their specific data needs. This quick-start guide will show you how to create a SubQuery project and configure it to index Substrate and EVM data on Moonbeam.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Checking Prerequisites {: #checking-prerequisites } Later on in this guide, you have the option of deploying your project to a locally running SubQuery node. To do so, you need to have the following installed on your system: - [Docker](https://docs.docker.com/get-started/get-docker/){target=\_blank} - [Docker Compose](https://docs.docker.com/compose/install){target=\_blank} !!! note If Docker Compose was installed for Linux via the `sudo apt install docker-compose` command, you might run into some errors later on in the guide. Please be sure to follow the instructions for Linux from the official [Install Docker Compose](https://docs.docker.com/compose/install){target=\_blank} guide. ## Create a Project {: #create-a-project } To get started, you'll need to [create a SubQuery project](https://subquery.network/doc/quickstart/quickstart.html){target=\_blank}: 1. Globally install the [SubQuery CLI](https://subquery.network/doc/indexer/quickstart/quickstart.html#_1-install-the-subquery-cli){target=\_blank}: === "npm" ```bash npm install -g @subql/cli ``` === "yarn" ```bash yarn global add @subql/cli ``` !!! note Using yarn to install `@subql/cli` is discouraged due to its poor dependency management, which can result in various errors. 2. Initialize your SubQuery project using the following command: ```bash subql init PROJECT_NAME ``` 3. You'll be prompted to answer a series of questions: 1. For the **Select a network family** question, although Moonbeam is EVM compatible, the Moonbeam templates are under the **Polkadot** family, so you can choose **Polkadot**
subql init moonbeam-demo ? Select a network family EVM Networks Algorand Cosmos Concordium NEAR > Polkadot Stellar
2. The next screen will prompt you to **Select a network**. You can choose between Moonbeam and Moonriver !!! note To build a project on Moonbase Alpha, you can select either network and adapt it later on
subql init moonbeam-demo ? Select a network family Polkadot ? Select a network Humanode HydraDX Integritee Shell Interlay Karura Khala KILT Spiritnet Kusama Kylin > Moonbeam Moonriver Nodle OriginTrail Parallel Parallel Heiko Polkadex Polkadot Quartz Shiden Kusama Asset Hub (Statemine) (Move up and down to reveal more choices)
3. You'll be prompted to **Select a template project**. Depending on the network you chose in the prior step, the template options may vary === "Moonbeam" | Template | Description | |:--------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------:| | `moonbeam-evm-starter` | A starter EVM project that indexes ERC-20 `Transfer` events and `approve` calls | | `moonbeam-substrate-evm-starter` | A starter Substrate and EVM project that indexes ERC-20 `Transfer` events and calls to the Staking Pallet's `joinCandidates` and `executeLeaveCandidates` extrinsics | | `Moonbeam-starter` | A starter Substrate project that indexes balance transfers through the Balances Pallet | === "Moonriver" | Template | Description | |:-----------------------:|:--------------------------------------------------------------------------------------:| | `moonriver-evm-starter` | A starter EVM project that indexes ERC-20 `Transfer` events and `approve` calls | | `Moonriver-starter` | A starter Substrate project that indexes balance transfers through the Balances Pallet |
subql init moonbeam-demo ? Select a network family Polkadot ? Select a network Moonbeam ? Select a template project > moonbeam-evm-starter moonbeam-substrate-evm-starter Moonbeam-starter Other Enter a custom git endpoint
4. You'll be prompted to add additional information, such as the RPC endpoint, the project's author, and the description of the project. For these, you can just hit enter and accept the default or customize them as you see fit !!! note To avoid hitting the rate limits of public RPC endpoints, it is recommended to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}
subql init moonbeam-demo ? Select a network family Polkadot ? Select a network Moonbeam ? Select a template project Moonbeam-starter RPC endpoint: [wss://moonbeam.api.onfinality.io/public-ws]: Author [SubQuery Team]: Description [This project can be used as a starting p...]: Preparing project... done moonbeam-demo is ready
4. After you've gone through all of the prompts, the starter project will be cloned. You'll just need to install dependencies from within the project directory: === "npm" ```bash cd PROJECT_NAME && npm install ``` === "yarn" ```bash cd PROJECT_NAME && yarn install ``` ## Configure the Network {: #configure-the-network } The template projects already come pre-configured for the network selected while initializing your project. However, if you're working off of an existing project or want to configure your project for Moonbase Alpha instead of Moonbeam or Moonriver, you can update the network configurations in the `project.ts` file. The `network` configuration is as follows for each network: === "Moonbeam" ```ts network: { chainId: '0xfe58ea77779b7abda7da4ec526d14db9b1e9cd40a217c34892af80a9b332b76d', endpoint: ['{{ networks.moonbeam.rpc_url }}'], chaintypes: { file: ./dist/chaintypes.js, }, }, ``` === "Moonriver" ```ts network: { chainId: '0x401a1f9dca3da46f5c4091016c8a2f26dcea05865116b286f60f668207d1474b', endpoint: ['{{ networks.moonriver.rpc_url }}'], chaintypes: { file: ./dist/chaintypes.js, }, }, ``` === "Moonbase Alpha" ```ts network: { chainId: '0x91bc6e169807aaa54802737e1c504b2577d4fafedd5a02c10293b1cd60e39527', endpoint: ['{{ networks.moonbase.rpc_url }}'], chaintypes: { file: ./dist/chaintypes.js, }, }, ``` To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. ## Modify the GraphQL Schema {: #modify-the-graphql-schema } In the `schema.graphql` file, you can use GraphQL entities to define the shape of your data. Once you've edited the GraphQL schema for your needs, you'll need to generate the required GraphQL models. To do so, you can run the following command: === "npm" ```bash npm run codegen ``` === "yarn" ```bash yarn codegen ```
npm run codegen > moonbeam-demo@0.0.4 codegen > subql codegen ============================== ---------Subql Codegen--------- ============================== Project manifest generated to /home/papermoon/moonbeam-demo/project.yaml * Schema Transfer generated ! * Schema Account generated ! * Models index generated ! * Types index generated !
The generated models will be created in the `src/types/models` directory. These models will be used in the mapping handlers that process the indexed data. !!! note If you make changes to the `schema.graphql` file, you'll need to regenerate your types. ## Index Substrate Data {: #index-substrate-data } The `project.ts` file is the entry point into your indexer; it defines what type of data to index and the mapping functions that are responsible for handling and processing the indexed data. To index Substrate data, you'll need to ensure that the type of the `project` is `SubstrateProject`. ```ts const project: SubstrateProject = { ... } ``` ### The Substrate Data Source {: #the-substrate-data-source } In the `project.dataSources` array, you'll define the Substrate data source and the data to be indexed. The format of the data source is as follows: ```ts datasources: [ { kind: 'substrate/Runtime', startBlock: INSERT_START_BLOCK, endBlock: INSERT_END_BLOCK, mapping: { file: './dist/index.js', handlers: [ { kind: 'INSERT_HANDLER_KIND', handler: 'INSERT_HANDLER_FUNCTION_NAME', filter: { 'INSERT_FILTER_TYPE': 'INSERT_FILTER', }, }, ], }, }, ], ``` Each property can be defined as follows: - `kind` - the kind of data source that you'll use, which for Substrate data is the `substrate/Runtime` source - `startBlock` - (optional) the block from which the indexer will start processing blocks - `endBlock` - (optional) after this block, the indexer will stop processing blocks - `mapping` - the data to be indexed and the handlers for the data - `file` - the entry path for the mapping - `handlers` - the handlers for specific kinds of data - `kind` - the kind of handler. For Substrate data, there are three kinds: `substrateBlockHandler`, `substrate/EventHandler`, and `substrate/CallHandler` - `handler` - the name of the handler function that will process this data - `filter` - (optional) the filter type and data that will trigger a mapping handler. For example, what block, event, or extrinsic to index ### Substrate Mapping Handlers {: #substrate-mapping-handlers } Using only certain handlers and filters will improve your indexer's efficiency. The handlers available for Substrate data are as follows: - The [block handler](https://subquery.network/doc/indexer/build/mapping/polkadot.html#block-handler){target=\_blank} is used to index block data and is called once for every block. As such, this type of handler will slow your project down significantly and should only be used if absolutely necessary. The supported filters for the block handler are: `specVersion`, `modulo`, and `timestamp` | Filter | Description | Example | |:-------------:|:-------------------------------------------------------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------:| | `specVersion` | Filters the blocks that fall into a spec version range | `specVersion: [null, 2000]`
`# Indexes blocks with a spec`
`version between 0 - 2000` | | `modulo` | Filters the blocks at an interval | `modulo: 50 # Indexes every 50 blocks` | | `timestamp` | Filters the blocks at a time interval (in UTC).
Accepts a valid [cron expression](https://github.com/roccivic/cron-converter){target=\_blank} | `timestamp: '*5/ * * * *'`
`# Indexes blocks every 5 minutes` | - The [event handler](https://subquery.network/doc/indexer/build/mapping/polkadot.html#event-handler){target=\_blank} is used to index certain Substrate events that are part of the runtime. The supported filters for the event handler are: `module` and `method` | Filter | Description | Example | |:--------:|:-----------------------------------------------------:|:--------------------:| | `module` | Filters the pallet (module) that the event belongs to | `module: 'balances'` | | `method` | Filters the event | `method: 'Transfer'` | - The [call handler](https://subquery.network/doc/indexer/build/mapping/polkadot.html#call-handler){target=\_blank} is used to index certain Substrate extrinsics. The supported filters for the call handler are: `module`, `method`, `success`, and `isSigned` | Filter | Description | Example | |:----------:|:-----------------------------------------------------:|:--------------------:| | `module` | Filters the pallet (module) that extrinsic belongs to | `module: 'balances'` | | `method` | Filters the extrinsic | `method: 'Transfer'` | | `success` | Filters extrinsics based on outcome | `success: true` | | `isSigned` | Filters extrinsics based on whether they're signed | `isSigned: true` | ## Index Ethereum Data {: #index-ethereum-data } The `project.ts` file is the entry point into your indexer; it defines what type of data to index and the mapping functions that are responsible for handling and processing the indexed data. To index Substrate data, you'll need to ensure that the type of the `project` is `SubstrateProject`. ```ts const project: SubstrateProject = { ... } ``` ### The EVM Data Source {: #the-evm-data-source } In the `project.dataSources` array, you'll define the EVM data source and the data to be indexed. The EVM data source is powered by a data processor specifically made to work with Moonbeam’s implementation of Frontier. It allows you to reference specific ABI resources used by the processor to parse arguments and the smart contract address that the events are from or the call is made to. In general, it acts as middleware that can provide extra filtering and data transformation. The format of the data source is as follows: ```ts datasources: [ { kind: 'substrate/FrontierEvm', startBlock: INSERT_START_BLOCK, endBlock: INSERT_END_BLOCK, processor: { file: './node_modules/@subql/frontier-evm-processor/dist/bundle.js', options: { abi: '', address: '', }, }, assets: '' mapping: { file: './dist/index.js', handlers: [ { kind: 'INSERT_HANDLER_KIND', handler: 'INSERT_HANDLER_FUNCTION_NAME', filter: { 'INSERT_FILTER_TYPE': 'INSERT_FILTER', }, }, ], }, }, ], ``` Each property can be defined as follows: - `kind` - the kind of data source that you'll use, which for EVM data is the `substrate/FrontierEVM` source - `startBlock` - (optional) the block from which the indexer will start processing blocks - `endBlock` - (optional) after this block, the indexer will stop processing blocks - `processor` - the Frontier EVM data processor configuration - `file` - the file where the data processor code lives - `options` - (optional) the [processor options](https://subquery.network/doc/build/substrate-evm.html#processor-options){target=\_blank} specific to the Frontier EVM processor - `abi` - (optional) the ABI that is used to parse arguments. The `abi` value must be a key in the `assets` configuration - `address` - (optional) the contract address where the event is emitted from or the call is made to. Using `null` will capture contract creation calls - `assets` - (optional) an object of external asset ABI files - `mapping` - the data to be indexed and the handlers for the data - `file` - the entry path for the mapping - `handlers` - the handlers for specific kinds of data - `kind` - the kind of handler. For EVM data, there are two kinds: `substrate/FrontierEvmCall` and `substrate/FrontierEvmEvent` - `handler` - the name of the handler function that will process this data - `filter` - (optional) the filter type and data that will trigger a mapping handler. For example, what block, event, or extrinsic to index ### Frontier EVM Mapping Handlers {: #evm-mapping-handlers } Using only certain handlers and filters will improve your indexer's efficiency. The handlers available for EVM data are as follows: - The [Frontier EVM call handler](https://subquery.network/doc/indexer/build/substrate-evm.html#call-handlers){target=\_blank} is used to index transactions that are formatted based on [Ethers `TransactionResponse` type](https://docs.ethers.org/v5/api/providers/types/#providers-TransactionResponse){target=\_blank}, but varies slightly. For information on the exact changes, please refer to [SubQuery's documentation](https://subquery.network/doc/indexer/build/substrate-evm.html#handler-functions){target=\_blank}. The supported filters for the call handler are: `function` and `from` | Filter | Description | Example | |:----------:|:---------------------------------------------------------:|:-----------------------------------------------------------------------------:| | `function` | Filters the call by function signature or selector | `function: '0x095ea7b3'`
`function: 'approve(address to,uint256 value)'` | | `from` | Filters the call by the address that sent the transaction | `from: '0x6bd193ee6d2104f14f94e2ca6efefae561a4334b'` | - The [Frontier EVM event handler](https://subquery.network/doc/indexer/build/substrate-evm.html#event-handlers){target=\_blank} is used to index certain EVM events. The supported filter for the event handler is: `topics` | Filter | Description | Example | |:--------:|:----------------------------------------------------------------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------:| | `topics` | Filters the event log by topics, which follows the [Ethereum JSON-RPC log filters](https://docs.ethers.org/v5/concepts/events/){target=\_blank} | `topics: 'Transfer(address indexed from,address indexed to,uint256 value)'` | ## Run Your Indexer {: #run-your-indexer } To run your indexer locally using Docker, you can take the following steps: 1. Build your project: === "npm" ```bash npm run build ``` === "yarn" ```bash yarn build ```
npm run build > moonbeam-demo@0.0.4 build > subql build Project manifest generated to /home/papermoon/moonbeam-demo/project.yaml Building and packing code ... Done!
!!! note If you make changes to the `project.ts` file, you'll need to rebuild your project. 2. Start up the Docker container for your indexer: === "npm" ```bash npm run start:docker ``` === "yarn" ```bash yarn start:docker ```
t found at block 171198 subquery-node_1 | 2025-04-07T04:29:52.601Z <sandbox-#3> INFO New transfer event found at block 171203 subquery-node_1 | 2025-04-07T04:29:52.663Z <sandbox-#3> INFO New transfer event found at block 171205 subquery-node_1 | 2025-04-07T04:29:52.701Z <benchmark> INFO INDEXING: 3148.19 blocks/s. Target height: 5,105,255. Current height: 171,205. Estimated time remaining: 0 days 00 hours 26 mins subquery-node_1 | 2025-04-07T04:29:52.710Z <sandbox-#3> INFO New transfer event found at block 171205 subquery-node_1 | 2025-04-07T04:29:52.717Z <sandbox-#3> INFO New transfer event found at block 171205 subquery-node_1 | 2025-04-07T04:29:52.739Z <sandbox-#3> INFO New transfer event found at block 171205 subquery-node_1 | 2025-04-07T04:29:52.750Z <sandbox-#3> INFO New transfer event found at block 171205 subquery-node_1 | 2025-04-07T04:29:52.765Z <sandbox-#3> INFO New transfer event found at block 171205 subquery-node_1 | 2025-04-07T04:29:52.780Z <sandbox-#3> INFO New transfer event found at block 171205 subquery-node_1 | 2025-04-07T04:29:52.807Z <sandbox-#3> INFO New transfer event found at block 171205 subquery-node_1 | 2025-04-07T04:29:52.826Z <sandbox-#3> INFO New transfer event found at block 171205 subquery-node_1 | 2025-04-07T04:29:52.864Z <sandbox-#3> INFO New transfer event
3. Head to `http://localhost:3000` to open the GraphQL playground and submit queries. You can open up the **DOCS** or **SCHEMA** tab on the playground as a reference when creating your queries !!! note It may take a few minutes before the GraphQL server is ready. You'll be able to access the playground after you see the following log: ```bash substrate-demo-graphql-engine-1 | INFO Started playground at `http://localhost:3000` ``` ![The GraphQL playground in the browser.](/images/builders/integrations/indexers/subquery/subquery-1.webp) And that's it! For a step-by-step tutorial on how to use the `moonbeam-substrate-evm-starter` template project, you can refer to [SubQuery's Moonbeam (EVM) Quick Start documentation](https://subquery.network/doc/indexer/quickstart/quickstart_chains/polkadot-moonbeam.html){target=\_blank}.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/indexers/subsquid/ --- BEGIN CONTENT --- --- title: Index Data with SQD (formerly Subsquid) description: Learn how to use SQD (Subsquid), a query node framework for Substrate-based chains, to index and process Substrate and EVM data for Moonbeam and Moonriver. categories: Indexers and Queries --- # Indexing Moonbeam with SQD (formerly Subsquid) ## Introduction {: #introduction } [SQD (formerly Subsquid)](https://www.sqd.ai/){target=\_blank} is a data network that allows rapid and cost-efficient retrieval of blockchain data from 100+ chains using SQD’s decentralized data lake and open-source SDK. In very simple terms, SQD can be thought of as an ETL (extract, transform, and load) tool with a GraphQL server included. It enables comprehensive filtering, pagination, and even full-text search capabilities. SQD has native and full support for both Ethereum Virtual Machine (EVM) and Substrate data. Since Moonbeam is a Substrate-based smart contact platform that is EVM-compatible, SQD can be used to index both EVM and Substrate-based data. SQD offers a Substrate Archive and Processor and an EVM Archive and Processor. The Substrate Archive and Processor can be used to index both Substrate and EVM data. This allows developers to extract on-chain data from any of the Moonbeam networks and process EVM logs as well as Substrate entities (events, extrinsics, and storage items) in one single project and serve the resulting data with one single GraphQL endpoint. If you exclusively want to index EVM data, it is recommended to use the EVM Archive and Processor. This quick-start guide will show you how to create Substrate and EVM projects with SQD and configure it to index data on Moonbeam. For a more comprehensive end-to-end tutorial, be sure to check out [Index a Local Moonbeam Development Node with SQD](/tutorials/integrations/local-subsquid/){target=\_blank}.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Checking Prerequisites {: #checking-prerequisites } To get started with SQD, you'll need to have the following: - [Node.js](https://nodejs.org/en/download/package-manager){target=\_blank} version 16 or newer - [Docker](https://docs.docker.com/get-started/get-docker/){target=\_blank} - [Squid CLI](https://docs.sqd.ai/squid-cli/installation/){target=\_blank} !!! note The Squid template is not compatible with `yarn`, so you'll need to use `npm` instead. ## Index Substrate Data on Moonbeam {: #index-substrate-calls-events } To get started indexing Substrate data on Moonbeam, you'll need to create a SQD project and configure it for Moonbeam by taking the following steps: 1. Create a SQD project based on the Substrate template by running: ```bash sqd init INSERT_SQUID_NAME --template substrate ``` For more information on getting started with this template, please check out the [Quickstart: Substrate chains](http://docs.sqd.ai/quickstart/quickstart-substrate/){target=\_blank} guide on SQD's documentation site. 2. Navigate into the root directory of your Squid project and install dependencies by running: ```bash npm ci ``` 3. To configure your SQD project to run on Moonbeam, you'll need to update the `typegen.json` file. The `typegen.json` file is responsible for generating TypeScript interface classes for your data. Depending on the network you're indexing data on, the `specVersions` value in the `typegen.json` file should be configured as follows: === "Moonbeam" ```json "specVersions": "https://v2.archive.subsquid.io/metadata/moonbeam", ``` === "Moonriver" ```json "specVersions": "https://v2.archive.subsquid.io/metadata/moonriver", ``` === "Moonbase Alpha" ```json "specVersions": "https://v2.archive.subsquid.io/metadata/moonbase", ``` 4. Modify the `src/processor.ts` file, which is where Squids instantiate the processor, configure it, and attach handler functions. The processor fetches historical on-chain data from an [Archive](https://docs.sqd.ai/glossary/#archives){target=\_blank}, which is a specialized data lake. You'll need to configure your processor to pull data from the Archive that corresponds to the [network](http://docs.sqd.ai/substrate-indexing/supported-networks/){target=\_blank} you are indexing data on: === "Moonbeam" ```ts const processor = new SubstrateBatchProcessor(); processor.setDataSource({ chain: '{{ networks.moonbeam.rpc_url }}', // Resolves to 'https://v2.archive.subsquid.io/network/moonbeam-mainnet' archive: lookupArchive('moonbeam', {type: 'Substrate', release: 'ArrowSquid'}), }) ``` === "Moonriver" ```ts const processor = new SubstrateBatchProcessor(); processor.setDataSource({ chain: '{{ networks.moonriver.rpc_url }}', // Resolves to 'https://v2.archive.subsquid.io/network/moonriver-mainnet' archive: lookupArchive('moonriver', {type: 'Substrate', release: 'ArrowSquid'}), }) ``` === "Moonbase Alpha" ```ts const processor = new SubstrateBatchProcessor(); processor.setDataSource({ chain: '{{ networks.moonbase.rpc_url }}', // Resolves to 'https://v2.archive.subsquid.io/network/moonbase-testnet' archive: lookupArchive('moonbase', {type: 'Substrate', release: 'ArrowSquid'}), }) ``` !!! note To configure your project for Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. 5. There's one more quick change to make to the template. The SQD Substrate template is configured to process Substrate account types, but Moonbeam uses Ethereum-style accounts. The `getTransferEvents` function in the `src/main.ts` file will iterate through the events ingested by `processor.ts` and store the relevant `transfer` events in the database. In the `getTransferEvents` function, remove the ss58 encoding of the `from` and `to` fields. In an unmodified Substrate template, the `from` and `to` fields are ss58 encoded as shown: ```ts from: ss58.codec('kusama').encode(rec.from), to: ss58.codec('kusama').encode(rec.to), ``` After removing the ss58 encoding, the respective lines are: ```ts from: rec.from, to: rec.to, ``` And that's all you have to do to configure your SQD project to index Substrate data on Moonbeam! Now you can update the `schema.graphql`, `typegen.json`, `src/main.ts`, and `src/processor.ts` files to index the data you need for your project! Next, take the steps in the [Run your Indexer](#run-your-indexer) section to run your indexer and query your Squid. ## Index Ethereum Data on Moonbeam {: #index-ethereum-contracts } To get started indexing EVM data on Moonbeam, you'll need to create a SQD project and configure it for Moonbeam by taking the following steps: 1. You can create a SQD project for EVM data by using the generic [EVM template](https://github.com/subsquid-labs/squid-evm-template){target=\_blank} or you can use the [ABI template](https://github.com/subsquid-labs/squid-abi-template){target=\_blank} for indexing data related to a specific contract: === "EVM" ```bash sqd init INSERT_SQUID_NAME --template evm ``` === "ABI" ```bash sqd init INSERT_SQUID_NAME --template abi ``` For more information on getting started with both of these templates, please check out the following SQD docs: - [Quickstart: EVM chains](http://docs.sqd.ai/quickstart/quickstart-ethereum/){target=\_blank} - [Quickstart: generate from ABI](http://docs.sqd.ai/quickstart/quickstart-abi/){target=\_blank} 2. Navigate into the root directory of your Squid project and install dependencies by running: ```bash npm ci ``` 3. Modify the `src/processor.ts` file, which is where Squids instantiate the processor, configure it, and attach handler functions. The processor fetches historical on-chain data from an [Archive](https://docs.sqd.ai/glossary/#archives){target=\_blank}, which is a specialized data lake. You'll need to configure your processor to pull data from the Archive that corresponds to the [network](http://docs.sqd.ai/evm-indexing/supported-networks/){target=\_blank} you are indexing data on: === "Moonbeam" ```ts const processor = new EvmBatchProcessor(); processor.setDataSource({ chain: '{{ networks.moonbeam.rpc_url }}', // Resolves to 'https://v2.archive.subsquid.io/network/moonbeam-mainnet' archive: lookupArchive('moonbeam', { type: 'EVM' }) }) ``` === "Moonriver" ```ts const processor = new EvmBatchProcessor(); processor.setDataSource({ chain: '{{ networks.moonriver.rpc_url }}', // Resolves to 'https://v2.archive.subsquid.io/network/moonriver-mainnet' archive: lookupArchive('moonriver', { type: 'EVM' }), }) ``` === "Moonbase Alpha" ```ts const processor = new EvmBatchProcessor(); processor.setDataSource({ chain: '{{ networks.moonbase.rpc_url }}', // Resolves to 'https://v2.archive.subsquid.io/network/moonbase-testnet' archive: lookupArchive('moonbase', { type: 'EVM' }), }) ``` !!! note To configure your project for Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. And that's all you have to do to configure your SQD project to index EVM data on Moonbeam! Now you can update the `schema.graphql`, `src/main.ts`, and `src/processor.ts` files to index the data you need for your project! Continue with the steps in the following section to run your indexer and query your Squid. ## Run Your Indexer {: #run-your-indexer } These steps apply to both Substrate and EVM indexers. Running your SQD indexer after you've properly configured it takes only a few steps: 1. Launch Postgres by running: ```bash sqd up ``` 2. Inspect and run the processor: ```bash sqd process ``` 3. Open a separate terminal window in the same directory, then start the GraphQL server: ```bash sqd serve ``` 4. You can query your template Substrate or EVM Squid with the below sample queries. If you've modified the template Squid to index different data, you'll need to modify this query accordingly === "Substrate Indexer" ```graphql query MyQuery { accountsConnection(orderBy: id_ASC) { totalCount } } ``` === "EVM Indexer" ```graphql query MyQuery { burns(orderBy: value_DESC) { address block id txHash value } } ``` If you're interested in a step-by-step tutorial to get started indexing data on Moonbeam, you can check out the [Index NFT Token Transfers on Moonbeam with SQD](/tutorials/integrations/nft-subsquid/){target=\_blank} tutorial!
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/indexers/thegraph/ --- BEGIN CONTENT --- --- title: Build APIs with The Graph description: Learn how to build APIs, called subgraphs, to store and fetch on-chain data for a given smart contract using The Graph indexing protocol on Moonbeam. categories: Indexers and Queries --- # Using The Graph on Moonbeam
## Introduction {: #introduction } Indexing protocols organize information so that applications can access it more efficiently. For example, Google indexes the entire Internet to provide information rapidly when you search for something. [The Graph](https://thegraph.com/){target=\_blank} is a decentralized and open-source indexing protocol for querying networks like Ethereum. In short, it provides a way to efficiently store data emitted by events from smart contracts so that other projects or dApps can access it easily. Furthermore, developers can build APIs called subgraphs. Users or other developers can use subgraphs to query data specific to a set of smart contracts. Data is fetched with a standard GraphQL API. You can visit The Graph's documentation site to learn [about The Graph protocol](https://thegraph.com/docs/en/about/#what-the-graph-is){target=\_blank}. Due to the support of Ethereum tracing modules on Moonbeam, The Graph can index blockchain data on Moonbeam. This guide takes you through the creation of a subgraph based on the [Exiled Racers Game Asset contract](https://moonscan.io/address/0x515e20e6275CEeFe19221FC53e77E38cc32b80Fb){target=\_blank} on Moonbeam.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Create a Subgraph {: #create-a-subgraph } You can quickly create a subgraph from an existing contract. To get started, you'll follow these steps: 1. Initialize your subgraph project 2. Deploy your subgraph to the Subgraph Studio 3. Publish your subgraph to The Graph's decentralized network 4. Query your subgraph from your dApp !!! note You can query your subgraph via the free, rate-limited development query URL, which can be used for development and staging. The free plan includes 100,000 queries per month. If you need to make more queries or want a production-ready plan, please check out [The Graph's documentation](https://thegraph.com/docs/en/subgraphs/billing/){target=\_blank}. ### Create a Subgraph on Subgraph Studio {: #create-a-subgraph } To initialize your subgraph, you must head to the [Subgraph Studio](https://thegraph.com/studio/){target=\_blank} and connect your wallet. After you've connected your wallet, you'll be prompted to add an email address, which will be used to send notifications about your account. You can only associate one account with your email address, so make sure you've connected the account you intend to continue to use. After you get your email address set up and verified, you can create a subgraph from your dashboard by clicking **Create a Subgraph**. ![Create a subgraph](/images/builders/integrations/indexers/the-graph/thegraph-1.webp) Then, you can: 1. Enter a name. Note that it is recommended to use title case for the name (i.e., Subgraph Name Chain Name); the name cannot be changed once it has been created 2. Click **Create Subgraph** ![Enter a name for your subgraph](/images/builders/integrations/indexers/the-graph/thegraph-2.webp) You will then land on your subgraph's page. Here, you can add additional information about your subgraph, such as the description, source code URL, website URL, and categories your subgraph belongs to. You'll also find all the CLI commands you need to initialize and deploy your subgraph. ![The landing page for your subgraph](/images/builders/integrations/indexers/the-graph/thegraph-3.webp) ### Install Graph CLI⁠ {: #install-graph-cli } To install Graph CLI on your local machine, run the following: === "npm" ```bash npm install -g @graphprotocol/graph-cli ``` === "yarn" ```bash yarn global add @graphprotocol/graph-cli ``` ### Initialize Your Subgraph⁠ {: #initialize-your-subgraph } Before you initialize your subgraph, you should verify the contract address from which you want to query data on Moonscan. This is so the Graph CLI can pull in the ABI directly from Moonscan for you. To learn how to verify your contracts, please refer to the [Verify Contracts](/builders/ethereum/verify-contracts/){target=\_blank} section of the docs. You'll need to grab the initialization command from your subgraph's page on Subgraph Studio to initialize your subgraph. Or, if you know the name of your subgraph, you can use the following command: ```bash graph init INSERT_SUBGRAPH_NAME ``` To initialize your subgraph, you'll need to provide some additional information, which you will be prompted to provide in your terminal: 1. For **Protocol**, select **ethereum**, as Moonbeam is an Ethereum-compatible chain 2. Hit enter for **Subgraph slug** to use the default one provided, or change as needed 3. Again, hit enter for **Directory to create the subgraph in** to use the default one provided, or change as needed 4. For **Ethereum network**, scroll down and select the Moonbeam network you are working with. Note that the Moonbase Alpha TestNet is labeled as **mbase** 5. Enter the contract address to index and query data from. The CLI will attempt to fetch the ABI from Moonscan. If it doesn't work, make sure that your contract has been verified and retry if needed. Otherwise, you will need to input it manually as a JSON file after your project has been successfully created. If you don't have a smart contract in mind and want to follow along with the tutorial, you can use the EXR contract address: ``` 0x515e20e6275CEeFe19221FC53e77E38cc32b80Fb ``` 6. Enter a start block. The start block allows you to save time by only indexing the necessary blocks. To get all of the data for this contract, you can use the block the contract was deployed 7. **Contract Name** should be automatically populated for you, but if not, manually enter the name of the contract 8. For **Index contract events as entities**, it is recommended to set this to **true**, as it will automatically add mappings to your subgraph for every event emitted. In other words, you'll be able to capture and store the data emitted by these events The CLI will generate your project for you, and you can continue to add additional contracts as needed.
graph init moonbeam-demo · ethereum · moonbeam-demo · moonbeam-demo · moonbeam · 0x515e20e6275CEeFe19221FC53e77E38cc32b80Fb ✖ Failed to fetch Start Block: Failed to fetch contract creation transaction hash · false · 1137478 · EXRGameAsset · true Generate subgraph Write subgraph to directory Create subgraph scaffold Initialize networks config Initialize subgraph repository Install dependencies with yarn Generate ABI and schema types with yarn codegen Subgraph moonbeam-demo created in moonbeam-demo
Your project will be created using the slug name you provided in step two. At this time, you can feel free to check out the project and modify the logic as needed for your project. For more information on how to write a subgraph, check out [The Graph's documentation](https://thegraph.com/docs/en/subgraphs/developing/creating/starting-your-subgraph/){target=\_blank}. Note that for this quick start example, if you selected to index contract events as entities, you don't need to modify anything; you can deploy the project as is. ## Deploy a Subgraph {: #deploy } To deploy your subgraph to Subgraph Studio, change to the subgraph directory in your terminal and run the following commands: 1. Generate types for your smart contract ABIs and the subgraph schema ```bash graph codegen ```
graph codegen Skip migration: Bump mapping apiVersion from 0.0.1 to 0.0.2 Skip migration: Bump mapping apiVersion from 0.0.2 to 0.0.3 Skip migration: Bump mapping apiVersion from 0.0.3 to 0.0.4 Skip migration: Bump mapping specVersion from 0.0.1 to 0.0.2 Skip migration: Bump mapping specVersion from 0.0.2 to 0.0.4 ✔ Apply migrations ✔ Load subgraph from subgraph.yaml Load contract ABI from abis/EXRGameAsset.json ✔ Load contract ABIs Generate types for contract ABI: EXRGameAsset (abis/EXRGameAsset.json) Write types to generated/EXRGameAsset/EXRGameAsset.ts ✔ Generate types for contract ABIs ✔ Generate types for data source templates ✔ Load data source template ABIs ✔ Generate types for data source template ABIs ✔ Load GraphQL schema from schema.graphql Write types to generated/schema.ts ✔ Generate types for GraphQL schema
2. Compile your subgraph to Wasm ```bash graph build ```
graph build Skip migration: Bump mapping apiVersion from 0.0.1 to 0.0.2 Skip migration: Bump mapping apiVersion from 0.0.2 to 0.0.3 Skip migration: Bump mapping apiVersion from 0.0.3 to 0.0.4 Skip migration: Bump mapping specVersion from 0.0.1 to 0.0.2 Skip migration: Bump mapping specVersion from 0.0.2 to 0.0.4 ✔ Apply migrations ✔ Load subgraph from subgraph.yaml Compile data source: EXRGameAsset => build/EXRGameAsset/EXRGameAsset.wasm ✔ Compile subgraph Copy schema file build/schema.graphql Write subgraph file build/EXRGameAsset/abis/EXRGameAsset.json Write subgraph manifest build/subgraph.yaml ✔ Write compiled subgraph to build/
3. Authenticate your subgraph with your deploy key. The exact command containing the deploy key can be found on your subgraph's page in Subgraph Studio ```bash graph auth INSERT_DEPLOY_KEY ```
graph auth eb6... Deploy key set for https://api.studio.thegraph.com/deploy/
4. Deploy your subgraph and specify the slug for it. Again, you can get the exact command from your subgraph's page in Subgraph Studio ```bash graph deploy INSERT_SUBGRAPH_SLUG ``` You will be asked for a version label. You can enter something like v0.0.1, but you're free to choose the format
graph deploy moonbeam-demo v0.1 Skip migration: Bump mapping apiVersion from 0.0.1 to 0.0.2 Skip migration: Bump mapping apiVersion from 0.0.2 to 0.0.3 Skip migration: Bump mapping apiVersion from 0.0.3 to 0.0.4 Skip migration: Bump mapping specVersion from 0.0.1 to 0.0.2 Skip migration: Bump mapping specVersion from 0.0.2 to 0.0.4 ✔ Apply migrations ✔ Load subgraph from subgraph.yaml Compile data source: EXRGameAsset => build/EXRGameAsset/EXRGameAsset.wasm ✔ Compile subgraph Copy schema file build/schema.graphql Write subgraph file build/EXRGameAsset/abis/EXRGameAsset.json Write subgraph manifest build/subgraph.yaml ✔ Write compiled subgraph to build/ ✔ Compile subgraph ✔ Compile subgraph Add file to IPFS build/schema.graphql .. QmQfQiQLmtgpibjDDgP83YfczUzLbuXhKa8FevB58LLuP2 Add file to IPFS build/EXRGameAsset/abis/EXRGameAsset.json .. QmdXKywXz8MkUvbW5YrPiBzbGKgcMjZbbLjRjWtgGcruXT Add file to IPFS build/EXRGameAsset/EXRGameAsset.wasm .. QmSLqNWtL6Uvku5adann325ruz8AgjfqLmn1NFLpZ8JcKK ✔ Upload subgraph to IPFS
Build completed: QmUHKw4sthmV6ve1YqFJMNvkviYf3sWzVA3qk4xjx5587q
Deployed to https://thegraph.com/studio/subgraph/moonbeam-demo
Subgraph endpoints: Queries (HTTP): https://api.studio.thegraph.com/query/80185/moonbeam-demo/v0.1
Once you've successfully deployed your subgraph, you can query it using the subgraph endpoint that was printed to your terminal. ### Test Your Subgraph⁠ {: #test-your-subgraph } You can test your subgraph by making a query in the **Playground** section of your subgraph's page on Subgraph Studio. ![The playground page for your subgraph](/images/builders/integrations/indexers/the-graph/thegraph-4.webp) To test from your dApp, you can use the API endpoint that was printed to your terminal. You can also find the endpoint on your subgraph's page in Subgraph Studio under the **Details** tab. ![The playground page for your subgraph](/images/builders/integrations/indexers/the-graph/thegraph-5.webp) You can use the following example code to query your subgraph. First, you'll need to install [Axios](https://axios-http.com/docs/intro){target=\_blank}: === "npm" ```bash npm install axios ``` === "yarn" ```bash yarn add axios ``` Then, use the code snippet below. Be sure to insert your own query and endpoint: ```js import axios from 'axios'; const graphqlQuery = `query MyQuery { gameAssetMinteds { blockNumber transactionHash id tokenId } }`; const queryUrl = 'INSERT_QUERY_URL'; // Will look something like this: // https://api.studio.thegraph.com/query/80185/moonbeam-demo/version/latest const graphQLRequest = { method: 'post', url: queryUrl, data: { query: graphqlQuery, }, }; // Send the GraphQL query axios(graphQLRequest) .then((response) => { // Handle the response here const data = response.data.data; console.log(data); }) .catch((error) => { // Handle any errors console.error(error); }); ``` ### Publish Your Subgraph to The Graph's Decentralized Network {: #publish-your-subgraph } Once your subgraph is ready for production, you can publish it to the decentralized network. !!! note Publishing requires Arbitrum ETH. When upgrading your subgraph, a small amount is airdropped to facilitate your initial protocol interactions. For publishing instructions, please refer to [The Graph's documentation](https://thegraph.com/docs/en/subgraphs/developing/publishing/publishing-a-subgraph/){target=\_blank}. ### Additional Resources {: #additional-resources } - To explore all the ways you can optimize and customize your subgraph for better performance, read more about [creating a subgraph](https://thegraph.com/docs/en/subgraphs/developing/creating/starting-your-subgraph/){target=\_blank} - For more information on querying data from your subgraph, check out the [Querying the Graph](https://thegraph.com/docs/en/subgraphs/querying/introduction/){target=\_blank} guide
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/oracles/api3/ --- BEGIN CONTENT --- --- title: Request Off-Chain Data with API3 description: Learn how to use API3 to request and receive off-chain data from within your smart contracts using API3 Airnodes and dAPIs (data feeds) on Moonbeam networks. categories: Oracle Nodes --- # Use API3 To Request Off-Chain Data on Moonbeam ## Introduction {: #introduction } API3 is a decentralized solution for delivering traditional API services to smart contract platforms in an easily accessible and scalable way. It is governed by a Decentralized Autonomous Organization (DAO), the API3 DAO. API3 enables developers to access off-chain resources from within their smart contracts without worrying about security implications. API3 makes this possible through Airnodes, which are first-party oracles, and on-chain data feeds sourced from these oracles. Developers can use [Airnode](https://airnode-docs.api3.org/reference/airnode/latest/understand/){target=_blank} to request off-chain data inside their smart contracts on Moonbeam networks. An Airnode is a first-party oracle that pushes off-chain API data to your on-chain contract. Airnode lets API providers easily run their own first-party oracle nodes. That way, they can provide data to any on-chain dApp interested in their services, all without an intermediary. An on-chain smart contract requests the [RRP (Request Response Protocol)](https://airnode-docs.api3.org/reference/airnode/latest/developers/){target=_blank} contract ([`AirnodeRrpV0.sol`](https://github.com/api3dao/airnode/blob/v0.11/packages/airnode-protocol/contracts/rrp/AirnodeRrpV0.sol){target=_blank}) that adds the request to the event logs. The Airnode then accesses the event logs, fetches the API data, and performs a callback to the requester with the requested data. ![A diagram detailing the Airnode flow.](/images/builders/integrations/oracles/api3/api3-1.webp)
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Request Off-Chain Data From an Airnode {: #calling-an-airnode } Requesting off-chain data essentially involves triggering an Airnode and getting its response through your smart contract. The smart contract in this case would be the requester contract, which will make a request to the desired off-chain Airnode and then capture its response. The requester calling an Airnode primarily focuses on two tasks: - Making the request - Accepting and decoding the response ![A diagram detailing the process of requesting off-chain data from an Airnode.](/images/builders/integrations/oracles/api3/api3-2.webp) Here is an example of a basic requester contract to request data from an Airnode: ```solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.9; import "@api3/airnode-protocol/contracts/rrp/requesters/RrpRequesterV0.sol"; import "@openzeppelin/contracts@4.9.5/access/Ownable.sol"; // A Requester that will return the requested data by calling the specified Airnode. contract Requester is RrpRequesterV0, Ownable { mapping(bytes32 => bool) public incomingFulfillments; mapping(bytes32 => int256) public fulfilledData; // Make sure you specify the right _rrpAddress for your chain while deploying the contract. constructor(address _rrpAddress) RrpRequesterV0(_rrpAddress) {} // To receive funds from the sponsor wallet and send them to the owner. receive() external payable { payable(owner()).transfer(address(this).balance); } // The main makeRequest function that will trigger the Airnode request. function makeRequest( address airnode, bytes32 endpointId, address sponsor, address sponsorWallet, bytes calldata parameters ) external { bytes32 requestId = airnodeRrp.makeFullRequest( airnode, // airnode address endpointId, // endpointId sponsor, // sponsor's address sponsorWallet, // sponsorWallet address(this), // fulfillAddress this.fulfill.selector, // fulfillFunctionId parameters // encoded API parameters ); incomingFulfillments[requestId] = true; } function fulfill(bytes32 requestId, bytes calldata data) external onlyAirnodeRrp { require(incomingFulfillments[requestId], "No such request made"); delete incomingFulfillments[requestId]; int256 decodedData = abi.decode(data, (int256)); fulfilledData[requestId] = decodedData; } // To withdraw funds from the sponsor wallet to the contract. function withdraw(address airnode, address sponsorWallet) external onlyOwner { airnodeRrp.requestWithdrawal( airnode, sponsorWallet ); } } ``` You can also try [deploying the example contract on Remix](https://remix.ethereum.org/#url=https://github.com/api3-ecosystem/remix-contracts/blob/master/contracts/RequesterWithWithdrawal.sol&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.9+commit.e5eed63a.js){target=_blank}. ### Contract Addresses {: #contract-addresses } The `_rrpAddress` is the main `airnodeRrpAddress`. The RRP contracts have already been deployed on-chain. The [addresses for the `_rrpAddress`](https://airnode-docs.api3.org/reference/airnode/latest/){target=_blank} on Moonbeam networks are as follows: === "Moonbeam" | Contract | Addresses | |:------------:|:----------------------------------:| | AirnodeRrpV0 | `{{ networks.moonbeam.api3.rrp }}` | === "Moonriver" | Contract | Addresses | |:------------:|:-----------------------------------:| | AirnodeRrpV0 | `{{ networks.moonriver.api3.rrp }}` | === "Moonbase Alpha" | Contract | Addresses | |:------------:|:----------------------------------:| | AirnodeRrpV0 | `{{ networks.moonbase.api3.rrp }}` | ### Request Parameters {: #request-params } The `makeRequest()` function expects the following parameters to make a valid request: - [**`airnode`**](https://airnode-docs.api3.org/reference/airnode/latest/concepts/airnode.html){target=_blank} - specifies the Airnode address - [**`endpointId`**](https://airnode-docs.api3.org/reference/airnode/latest/concepts/endpoint.html){target=_blank} - specifies which endpoint to be used - [**`sponsor`**](https://airnode-docs.api3.org/reference/airnode/latest/concepts/sponsor.html){target=_blank} and [**`sponsorWallet`**](https://airnode-docs.api3.org/reference/airnode/latest/concepts/sponsor.html#sponsorwallet){target=_blank} - specifies which wallet will be used to fulfill the request - [**`parameters`**](https://airnode-docs.api3.org/reference/airnode/latest/specifications/reserved-parameters.html){target=_blank} - specifies the API and Reserved Parameters (see [Airnode ABI specifications](https://airnode-docs.api3.org/reference/airnode/latest/specifications/airnode-abi.html){target=_blank} for how these are encoded). Parameters can be encoded off-chain using the `@airnode-abi` library ### Response Parameters {: #response-params } The callback to the requester contract contains two parameters: - [**`requestId`**](https://airnode-docs.api3.org/reference/airnode/latest/concepts/request.html#requestid){target=_blank} - first acquired when making the request and passed here as a reference to identify the request for which the response is intended - **`data`** - in case of a successful response, this is the requested data encoded and contains a timestamp in addition to other response data. Decode it using the `decode()` function from the `abi` object !!! note Sponsors should not fund a `sponsorWallet` with more than they can trust the Airnode with, as the Airnode controls the private key to the `sponsorWallet`. The deployer of such Airnode undertakes no custody obligations, and the risk of loss or misuse of any excess funds sent to the `sponsorWallet` remains with the sponsor. ## dAPIs: API3 Data Feeds {: #dapis } [dAPIs](https://docs.api3.org/oev-searchers/in-depth/data-feeds/){target=_blank} are continuously updated streams of off-chain data, such as the latest cryptocurrency, stock, and commodity prices. They can power decentralized applications such as DeFi lending, synthetic assets, stablecoins, derivatives, NFTs, and more. The data feeds are continuously updated by [first-party oracles](https://docs.api3.org/oev-searchers/glossary.html#first-party-oracles){target=_blank} using signed data. DApp owners can read the on-chain value of any dAPI in real-time. Because they are composed of first-party data feeds, dAPIs offer security, transparency, cost-efficiency, and scalability in a turnkey package. ![The API3 Market dashboard.](/images/builders/integrations/oracles/api3/api3-3.webp) To learn more about how dAPIs work, please refer to [API3's documentation](https://docs.api3.org/oev-searchers/in-depth/data-feeds/){target=_blank}. ### Subscribe to dAPIs {: #subscribing-to-dapis } The [API3 Market](https://market.api3.org/){target=_blank} lets users access dAPIs on [Moonbeam](https://market.api3.org/moonbeam){target=_blank}, [Moonriver](https://market.api3.org/moonriver){target=_blank}, and the [Moonbase Alpha TestNet](https://market.api3.org/moonbeam-testnet){target=_blank} (currently labeled as the Moonbeam TestNet). From the [API3 Market home page](https://market.api3.org/){target=_blank}, you can search for a given chain. After selecting the chain, you can view the list of available dAPIs and click on one for more information. For example, you can click on the `USDT/USD` pair available for Moonbeam to view the parameters of the dAPI, including the deviation and the heartbeat. The supported parameters for dAPIs are: | Deviation | Heartbeat | |-----------|-----------| | 0.25% | 24 hours | | 0.5% | 24 hours | | 1% | 24 hours | | 5% | 24 hours | ![The USDT/USD dAPI detail page.](/images/builders/integrations/oracles/api3/api3-4.webp) ### Configure and Activate a dAPI {: #select-a-dapi } Once you've selected a dAPI to interact with, check the expiration date and update the parameters as needed. You can update the parameters and extend the subscription by purchasing a new configuration. If the dAPI has been activated and the configurations listed will work for you, you can skip ahead to the next section to learn how to [interact with the dAPI](#get-data). To purchase a plan with new configurations, click on **Purchase new plan** and take the following steps: 1. Select your parameters 2. Click on **Connect Wallet** ![The activate data feed page.](/images/builders/integrations/oracles/api3/api3-5.webp) Once connected, you'll be able to purchase your new plan. Click on **Purchase** and sign the transaction. After the transaction has been confirmed, you will be able to see the updated configuration for the dAPI. ### Get Data from a dAPI {: #get-data} To interact with a dAPI, you'll need to get the proxy address for it. Click on the **Integrate** button from the dAPI details page. Then, on the integration page, copy the proxy address. ![The integrate data feed page.](/images/builders/integrations/oracles/api3/api3-6.webp) With the proxy address in hand, you'll be able to integrate the dAPI into a smart contract. Here's an example of a basic contract that reads from a dAPI: ```solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.17; import "@openzeppelin/contracts@4.9.5/access/Ownable.sol"; import "@api3/contracts/api3-server-v1/proxies/interfaces/IProxy.sol"; contract DataFeedReaderExample is Ownable { // The proxy contract address obtained from the API3 Market UI address public proxyAddress; // Updating the proxy contract address is a security-critical // action. In this example, only the owner is allowed to do so function setProxyAddress(address _proxyAddress) public onlyOwner { proxyAddress = _proxyAddress; } function readDataFeed() external view returns (int224 value, uint256 timestamp) { // Use the IProxy interface to read a dAPI via its // proxy contract (value, timestamp) = IProxy(proxyAddress).read(); // If you have any assumptions about `value` and `timestamp`, // make sure to validate them after reading from the proxy } } ``` The example contract contains two functions: - `setProxyAddress()` - used to set the address of the dAPI proxy contract - `readDataFeed()` - a `view` function that returns the latest price of the set dAPI [Try deploying it on Remix](https://remix.ethereum.org/#url=https://github.com/api3-ecosystem/remix-contracts/blob/master/contracts/DapiReader.sol&lang=en&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.18+commit.87f61d96.js){target=_blank}! ## Additional Resources {: #additional-resources } Here are some additional developer resources: - [API3 Market](https://market.api3.org/moonbeam){target=_blank} - [API3 Docs](https://docs.api3.org){target=_blank} - [API3 DAO GitHub](https://github.com/api3dao){target=_blank} - [API3 Medium](https://medium.com/api3){target=_blank} - [API3 YouTube](https://www.youtube.com/API3DAO){target=_blank}
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/oracles/band-protocol/ --- BEGIN CONTENT --- --- title: Band Protocol Oracle description: How to request data from a Band Protocol Oracle in your Moonbeam Ethereum DApp using smart contracts or JavaScript. categories: Oracle Nodes --- # Band Protocol Oracle ## Introduction {: #introduction } Developers have two ways to fetch prices from Band’s oracle infrastructure. On one hand, they can use Band’s smart contracts on Moonbeam. Doing so, they access data that is on-chain and is updated either at regular intervals or when price slippage is more than a target amount (different for each token). On the other hand, devs can use the JavaScript helper library, which uses an API endpoint to fetch the data using similar functions as those from the smart contracts, but this implementation bypasses the blockchain entirely. This can be useful if your DApp front-end needs direct access to the data. The Aggregator Contract address can be found in the following table: | Network | | Aggregator Contract Address | |:--------------:|-|:------------------------------------------:| | Moonbase Alpha | | 0xDA7a001b254CD22e46d3eAB04d937489c93174C3 |
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Supported Token {: #supported-token } Price queries with any denomination are available as long as the base and quote symbols are supported (_base_/_quote_). For example: - `BTC/USD` - `BTC/ETH` - `ETH/EUR` At the time of writing, the list of supported symbols can be found on the [Band Standard Dataset](https://data.bandprotocol.com){target=\_blank} page of the Band website. There are more than 146 price pairs available to query. ## Querying Prices {: #querying-prices } As stated before, developers can leverage two methods to query prices from Band's oracle: - Band's smart contract on Moonbeam (deployed to Moonbase Alpha TestNet for now) - JavaScript helper library ## Get Data Using Smart Contracts {: #get-data-using-smart-contracts } Contracts can query on-chain data, such as token prices, from Band's oracle by implementing the interface of the `StdReference` contract, which exposes the `getReferenceData` and `getReferenceDataBulk` functions. The first function, `getReferenceData`, takes two strings (the base and the quote symbol) as the inputs. The function queries the `StdReference` contract for the latest rates available for those two tokens. It returns a `ReferenceData` struct. The `ReferenceData` struct has the following elements: - Rate: the exchange rate in terms of _base/quote_. The value returned is multiplied by 1018 - Last updated base: the last time when the base price was updated (since UNIX epoch) - Last updated quote: the last time when the quoted price was updated (since UNIX epoch) ```js struct ReferenceData { uint256 rate; uint256 lastUpdatedBase; uint256 lastUpdatedQuote; } ``` The second function, `getReferenceDataBulk`, takes information as data arrays. For example, if you pass in `['BTC','BTC','ETH']` as base and `['USD','ETH','EUR']` as quote, the `ReferenceData`returned array contains the information regarding the following pairs: - `BTC/USD` - `BTC/ETH` - `ETH/EUR` ### Example Contract {: #example-contract } The following smart contract code provides some simple examples of the `StdReference` contract and the `getReferenceData` function - these are not meant for production. The `IStdReference.sol` interface defines ReferenceData structure and the functions available to make the queries. ```solidity pragma solidity 0.6.11; pragma experimental ABIEncoderV2; interface IStdReference { /// A structure returned whenever someone requests for standard reference data. struct ReferenceData { uint256 rate; // base/quote exchange rate, multiplied by 1e18. uint256 lastUpdatedBase; // UNIX epoch of the last time when base price gets updated. uint256 lastUpdatedQuote; // UNIX epoch of the last time when quote price gets updated. } /// Returns the price data for the given base/quote pair. Revert if not available. function getReferenceData(string memory _base, string memory _quote) external view returns (ReferenceData memory); /// Similar to getReferenceData, but with multiple base/quote pairs at once. function getReferenceDataBulk(string[] memory _bases, string[] memory _quotes) external view returns (ReferenceData[] memory); } ``` Next, you can use the following `DemoOracle` script. It provides four functions: - **getPrice**(*string[]* base, *string[]* quotes) - a _view_ function that queries a single base. In this example, the price of `BTC` quoted in `USD` - **getMultiPrices**(*string[]* bases, *string[]* quotes) - a _view_ function that queries multiple bases. In this example, the price of `BTC` and `ETH`, both quoted in `USD` - **savePrice**(*string* base, *string* quote) - a _public_ function that queries the _base/quote_ pair. Each element is provided as separate strings, for example `_base = "BTC", _quotes = "USD"`. This sends a transaction and modifies the `price` variable stored in the contract - **saveMultiPrices**(*string[]* bases, *string[]* quotes) - a _public_ function that queries each _base/quote_ pair. Each element is provided as a string array. For example, `_bases = ["BTC","ETH"], _quotes = ["USD","USD"]`. This sends a transaction and modifies the `prices` array stored in the contract, which will hold the price of each pair in the same order as specified in the input When deployed, the constructor function needs the Aggregator Contract address for the target network. ```solidity pragma solidity 0.6.11; pragma experimental ABIEncoderV2; import "./IStdReference.sol"; contract DemoOracle { IStdReference ref; uint256 public price; uint256[] public pricesArr; constructor(IStdReference _ref) public { ref = _ref; // Aggregator Contract Address // Moonbase Alpha 0xDA7a001b254CD22e46d3eAB04d937489c93174C3 } function getPrice(string memory _base, string memory _quote) external view returns (uint256){ IStdReference.ReferenceData memory data = ref.getReferenceData(_base,_quote); return data.rate; } function getMultiPrices(string[] memory _bases, string[] memory _quotes) external view returns (uint256[] memory){ IStdReference.ReferenceData[] memory data = ref.getReferenceDataBulk(_bases,_quotes); uint256 len = _bases.length; uint256[] memory prices = new uint256[](len); for (uint256 i = 0; i < len; i++) { prices[i] = data[i].rate; } return prices; } function savePrice(string memory _base, string memory _quote) external { IStdReference.ReferenceData memory data = ref.getReferenceData(_base,_quote); price = data.rate; } function saveMultiPrices( string[] memory _bases, string[] memory _quotes ) public { require(_bases.length == _quotes.length, "BAD_INPUT_LENGTH"); uint256 len = _bases.length; IStdReference.ReferenceData[] memory data = ref.getReferenceDataBulk(_bases,_quotes); delete pricesArr; for (uint256 i = 0; i < len; i++) { pricesArr.push(data[i].rate); } } } ``` ### Try it in Moonbase Alpha {: #try-it-in-moonbase alpha } There is predeployed contract available in the Moonbase Alpha TestNet (at address `0xf15c870344c1c02f5939a5C4926b7cDb90dEc655`) so you can easily check the information fed from Band Protocol's oracle. To do so, you need the following interface contract: ```solidity pragma solidity 0.6.11; pragma experimental ABIEncoderV2; interface TestInterface { function getPrice(string memory _base, string memory _quote) external view returns (uint256); function getMultiPrices(string[] memory _bases, string[] memory _quotes) external view returns (uint256[] memory); } ``` With it, you will have two view functions available - very similar to the previous examples: - **getPrice**(*string* base, *string* quote) - provides the price feed for a single base/quote pair that is given as input to the function, that is, "BTC", "USD" - **getMultiPrices**(*string[]* bases, *string[]* quotes) - provides the price feed for a multiple base/quote pairs that are given as input to the function, that is, ["BTC", "ETH", "ETH"], ["USD", "USD", "EUR"] For example, using [Remix](/builders/ethereum/dev-env/remix/){target=\_blank}, you can easily query the `BTC/USD` price pair using this interface. After creating the file and compiling the contract, head to the **Deploy and Run Transactions** tab, enter the contract address (`0xf15c870344c1c02f5939a5C4926b7cDb90dEc655`) and click on **At Address**. Make sure you have set the **ENVIRONMENT** to **Injected Web3** so you are connected to Moonbase Alpha. ![Band Protocol Remix deploy](/images/builders/integrations/oracles/band/band-demo-1.webp) This will create an instance of the demo contract that you can interact with. Use the functions `getPrice()` and `getMultiPrices()` to query the data of the corresponding pair. ![Band Protocol Remix check price](/images/builders/integrations/oracles/band/band-demo-2.webp) ## BandChain.js JavaScript Helper Library {: #bandchainjs-javascript-helper-library } The helper library also supports a similar `getReferenceData` function. To get started, the library needs to be installed: ```bash npm install @bandprotocol/bandchain.js ``` The library provides a constructor function that requires an endpoint to point to. This returns an instance that then enables all the necessary methods, such as the `getReferenceData` function. When querying for information, the function accepts an array where each element is the _base/quote_ pair needed. For example: ```text getReferenceData(['BTC/USD', 'BTC/ETH', 'ETH/EUR']) ``` Then, it returns an array object with the following structure: ```js [ { pair: 'BTC/USD', rate: rate, updated: { base: lastUpdatedBase, quote: lastUpdatedQuote} }, { pair: 'BTC/ETH', rate: rate, updated: { base: lastUpdatedBase, quote: lastUpdatedQuote} }, { pair: 'ETH/EUR', rate: rate, updated: { base: lastUpdatedBase, quote: lastUpdatedQuote} }, ] ``` Where `lastUpdatedBase` and `lastUpdatedQuote` are the last time when the base and quote prices were updated respectively (since UNIX epoch). ### Example Usage {: #example-usage } The following JavaScript script provides a simple example of the `getReferenceData` function. ```js const BandChain = require('@bandprotocol/bandchain.js'); const queryData = async () => { const endpoint = 'https://poa-api.bandchain.org'; const bandchain = new BandChain(endpoint); const dataQuery = await bandchain.getReferenceData([ 'BTC/USD', 'BTC/ETH', 'ETH/EUR', ]); console.log(dataQuery); }; queryData(); ``` You can execute this code with a node, and the following `dataQuery` output should look like this:
node getData.js [ { pair: 'BTC/USD', rate: 15787.679999999998, updated: { base: 1605181892, quote: 1605181910 } }, { pair: 'BTC/ETH', rate: 34.31432980503814, updated: { base: 1605181892, quote: 1605181892 } }, { pair: 'ETH/EUR', rate: 389.47110012528356, updated: { base: 1605181892, quote: 1605180505 } } ]
Note that compared to the request done via smart contracts, the result is given directly in the correct units.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/oracles/chainlink/ --- BEGIN CONTENT --- --- title: Chainlink Oracle description: Review price feed contracts for Moonbeam-based networks and learn how to request data from a Chainlink Oracle in your DApp using smart contracts or JavaScript. categories: Oracle Nodes --- # Chainlink Oracle ## Introduction {: #introduction } Developers can now use [Chainlink's decentralized Oracle network](https://chain.link){target=\_blank} to fetch data from a Moonbeam-based network. There are two main architectures: [Price Feeds](https://docs.chain.link/architecture-overview/architecture-decentralized-model){target=\_blank} and [Basic Request Model](https://docs.chain.link/architecture-overview/architecture-request-model?parent=gettingStarted){target=\_blank}. Price Feeds contain real-time price data that is continuously updated by Oracle operators in a smart contract so that other smart contracts can fetch and consume it. The Basic Request Model describes an on-chain architecture for requesting data from a single oracle source. This guide will show you how to fetch the latest price data using both architectures.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Price Feeds {: #price-feeds } Before going into fetching the data itself, it is important to understand the basics of price feeds. In a standard configuration, each price feed is updated by a decentralized oracle network. Each oracle node is rewarded for publishing the price data to the [aggregator contract](https://github.com/smartcontractkit/chainlink-evm/blob/develop/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol){target=\_blank}. The aggregator contract receives periodic data updates from the network of oracles and aggregates and stores the data on-chain so that consumers can easily fetch it. However, the information is only updated if a minimum number of responses from oracle nodes are received (during an aggregation round). The end-user can retrieve price feeds with read-only operations via an aggregator interface, or via a Consumer interface through the Proxy. ![Price Feed Diagram](/images/builders/integrations/oracles/chainlink/chainlink-price-feed.webp) ### Fetch Price Data {: #fetch-price-data } There are data feed contracts available for Moonbeam-based networks to help simplify the process of requesting price feeds. In the current configuration for Moonbase Alpha, the Moonbeam team is running only one oracle node that fetches the price from a single API source. Price data is checked and updated in the smart contracts every 12 hours. As such, the price feeds on Moonbase Alpha are not authoritative and are for testing purposes only. The Moonbeam and Moonriver data feed contracts are updated by multiple Chainlink nodes on a regular basis. The data lives in a series of smart contracts (one per price feed) and can be fetched with the aggregator interface: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface AggregatorV3Interface { /** * Returns the decimals to offset on the getLatestPrice call */ function decimals() external view returns (uint8); /** * Returns the description of the underlying price feed aggregator */ function description() external view returns (string memory); /** * Returns the version number representing the type of aggregator the proxy points to */ function version() external view returns (uint256); /** * Returns price data about a specific round */ function getRoundData(uint80 _roundId) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound); /** * Returns price data from the latest round */ function latestRoundData() external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound); } ``` As seen above in the interface, there are five functions for fetching data: `decimals`, `description`, `version`, `getRoundData`, and `latestRoundData`. Currently, there are data feed contracts for [Moonbeam](https://docs.chain.link/data-feeds/price-feeds/addresses/?network=moonbeam&page=1){target=\_blank}, [Moonriver](https://docs.chain.link/data-feeds/price-feeds/addresses/?network=moonriver&page=1){target=\_blank}, and Moonbase Alpha for the following price pairs (proxy addresses): === "Moonbeam" | Base/Quote | Data Feed Contract (Proxy Address) | |:-----------:|:-----------------------------------------------------:| | ATOM to USD | {{ networks.moonbeam.chainlink.feed.proxy.atom_usd }} | | BNB to USD | {{ networks.moonbeam.chainlink.feed.proxy.bnb_usd }} | | BTC to USD | {{ networks.moonbeam.chainlink.feed.proxy.btc_usd }} | | DOT to USD | {{ networks.moonbeam.chainlink.feed.proxy.dot_usd }} | | ETH to USD | {{ networks.moonbeam.chainlink.feed.proxy.eth_usd }} | | FRAX to USD | {{ networks.moonbeam.chainlink.feed.proxy.frax_usd }} | | GLMR to USD | {{ networks.moonbeam.chainlink.feed.proxy.glmr_usd }} | | LINK to USD | {{ networks.moonbeam.chainlink.feed.proxy.link_usd }} | | USDC to USD | {{ networks.moonbeam.chainlink.feed.proxy.usdc_usd }} | === "Moonriver" | Base/Quote | Data Feed Contract (Proxy Address) | |:------------:|:-------------------------------------------------------:| | 1INCH to USD | {{ networks.moonriver.chainlink.feed.proxy.inch_usd }} | | AAVE to USD | {{ networks.moonriver.chainlink.feed.proxy.aave_usd }} | | ANKR to USD | {{ networks.moonriver.chainlink.feed.proxy.ankr_usd }} | | AVAX to USD | {{ networks.moonriver.chainlink.feed.proxy.avax_usd }} | | AXS to USD | {{ networks.moonriver.chainlink.feed.proxy.axs_usd }} | | BNB to USD | {{ networks.moonriver.chainlink.feed.proxy.bnb_usd }} | | BTC to USD | {{ networks.moonriver.chainlink.feed.proxy.btc_usd }} | | BUSD to USD | {{ networks.moonriver.chainlink.feed.proxy.busd_usd }} | | CAKE to USD | {{ networks.moonriver.chainlink.feed.proxy.cake_usd }} | | COMP to USD | {{ networks.moonriver.chainlink.feed.proxy.comp_usd }} | | CRV to USD | {{ networks.moonriver.chainlink.feed.proxy.crv_usd }} | | DAI to USD | {{ networks.moonriver.chainlink.feed.proxy.dai_usd }} | | DOT to USD | {{ networks.moonriver.chainlink.feed.proxy.dot_usd }} | | ETH to USD | {{ networks.moonriver.chainlink.feed.proxy.eth_usd }} | | EUR to USD | {{ networks.moonriver.chainlink.feed.proxy.eur_usd }} | | FRAX to USD | {{ networks.moonriver.chainlink.feed.proxy.frax_usd }} | | FTM to USD | {{ networks.moonriver.chainlink.feed.proxy.ftm_usd }} | | FXS to USD | {{ networks.moonriver.chainlink.feed.proxy.fxs_usd }} | | KSM to USD | {{ networks.moonriver.chainlink.feed.proxy.ksm_usd }} | | LINK to USD | {{ networks.moonriver.chainlink.feed.proxy.link_usd }} | | LUNA to USD | {{ networks.moonriver.chainlink.feed.proxy.luna_usd }} | | MANA to USD | {{ networks.moonriver.chainlink.feed.proxy.mana_usd }} | | MIM to USD | {{ networks.moonriver.chainlink.feed.proxy.mim_usd }} | | MKR to USD | {{ networks.moonriver.chainlink.feed.proxy.mkr_usd }} | | MOVR to USD | {{ networks.moonriver.chainlink.feed.proxy.movr_usd }} | | SAND to USD | {{ networks.moonriver.chainlink.feed.proxy.sand_usd }} | | SNX to USD | {{ networks.moonriver.chainlink.feed.proxy.snx_usd }} | | SUSHI to USD | {{ networks.moonriver.chainlink.feed.proxy.sushi_usd }} | | THETA to USD | {{ networks.moonriver.chainlink.feed.proxy.theta_usd }} | | UNI to USD | {{ networks.moonriver.chainlink.feed.proxy.uni_usd }} | | USDC to USD | {{ networks.moonriver.chainlink.feed.proxy.usdc_usd }} | | USDT to USD | {{ networks.moonriver.chainlink.feed.proxy.usdt_usd }} | | XRP to USD | {{ networks.moonriver.chainlink.feed.proxy.xrp_usd }} | | YFI to USD | {{ networks.moonriver.chainlink.feed.proxy.yfi_usd }} | === "Moonbase Alpha" | Base/Quote | Data Feed Contract (Proxy Address) | |:------------:|:------------------------------------------------------:| | AAVE to USD | {{ networks.moonbase.chainlink.feed.proxy.aave_usd }} | | ALGO to USD | {{ networks.moonbase.chainlink.feed.proxy.algo_usd }} | | AVAX to USD | {{ networks.moonbase.chainlink.feed.proxy.avax_usd }} | | BAND to USD | {{ networks.moonbase.chainlink.feed.proxy.band_usd }} | | BNB to USD | {{ networks.moonbase.chainlink.feed.proxy.bnb_usd }} | | BTC to USD | {{ networks.moonbase.chainlink.feed.proxy.btc_usd }} | | COMP to USD | {{ networks.moonbase.chainlink.feed.proxy.comp_usd }} | | CRV to USD | {{ networks.moonbase.chainlink.feed.proxy.crv_usd }} | | CVX to USD | {{ networks.moonbase.chainlink.feed.proxy.cvx_usd }} | | DAI to USD | {{ networks.moonbase.chainlink.feed.proxy.dai_usd }} | | DOT to USD | {{ networks.moonbase.chainlink.feed.proxy.dot_usd }} | | ETH to USD | {{ networks.moonbase.chainlink.feed.proxy.eth_usd }} | | FRAX to USD | {{ networks.moonbase.chainlink.feed.proxy.frax_usd }} | | FTM to USD | {{ networks.moonbase.chainlink.feed.proxy.ftm_usd }} | | GLMR to USD | {{ networks.moonbase.chainlink.feed.proxy.glmr_usd }} | | KSM to USD | {{ networks.moonbase.chainlink.feed.proxy.ksm_usd }} | | LINK to USD | {{ networks.moonbase.chainlink.feed.proxy.link_usd }} | | MKR to USD | {{ networks.moonbase.chainlink.feed.proxy.mkr_usd }} | | OP to USD | {{ networks.moonbase.chainlink.feed.proxy.op_usd }} | | stETH to USD | {{ networks.moonbase.chainlink.feed.proxy.steth_usd }} | | SUSHI to USD | {{ networks.moonbase.chainlink.feed.proxy.sushi_usd }} | | UNI to USD | {{ networks.moonbase.chainlink.feed.proxy.uni_usd }} | | USDC to USD | {{ networks.moonbase.chainlink.feed.proxy.usdc_usd }} | | USDT to USD | {{ networks.moonbase.chainlink.feed.proxy.usdt_usd }} | | YFI to USD | {{ networks.moonbase.chainlink.feed.proxy.yfi_usd }} | For example, you can use the aggregator interface to fetch the price feed of `BTC to USD` using [Remix](https://remix.ethereum.org){target=\_blank}. If you need help loading a contract into Remix, check out the [Using Remix](/builders/ethereum/dev-env/remix/){target=\_blank} page of the documentation site. You will need to connect your MetaMask account to Remix, so make sure you have MetaMask installed and are connected to the correct network. To get help setting up MetaMask, check out the [Interacting with Moonbeam Using MetaMask](/tokens/connect/metamask/#install-the-metamask-extension){target=\_blank} guide. After creating the file and compiling the contract, you will need to follow these steps: 1. Head to the **Deploy and Run Transactions** tab 2. Set the **ENVIRONMENT** to **Injected Web3** 3. If your MetaMask is already connected it will appear in the **ACCOUNT** selector. Otherwise, you will be prompted by MetaMask to select and connect your account(s) 4. Select the `AggregatorV3Interface` contract from the **CONTRACT** dropdown 5. Enter the Data Feed contract address corresponding to `BTC to USD` in the **At Address** field and click the **At Address** button: === "Moonbeam" ```text {{ networks.moonbeam.chainlink.feed.proxy.btc_usd }} ``` === "Moonriver" ```text {{ networks.moonriver.chainlink.feed.proxy.btc_usd }} ``` === "Moonbase Alpha" ```text {{ networks.moonbase.chainlink.feed.proxy.btc_usd }} ``` ![Load the Chainlink Price Feed Aggregator Interface on Moonriver](/images/builders/integrations/oracles/chainlink/chainlink-2.webp) This will create an instance of the aggregator interface that you can interact with and it will appear under the **Deployed Contracts** section in Remix. To get the latest price data you can follow these steps: 1. Expand the `AggregatorV3Interface` contract to reveal the available functions 2. Click `latestRoundData()` to query the data of the corresponding price feed, in this case BTC to USD ![Interact with the Chainlink Price Feed Aggregator Interface on Moonriver](/images/builders/integrations/oracles/chainlink/chainlink-3.webp) Note that to obtain the real price, you must account for the decimals of the price feed, available with the `decimals()` method. If there is any specific pair you want to be included, feel free to reach out through [Discord](https://discord.com/invite/PfpUATX){target=\_blank}. ## Basic Request Model {: #basic-request-model } Before going into fetching the data itself, it is important to understand the basics of the "basic request model." The generic flow for requesting and receiving data from a Chainlink oracle is as follows: 1. A client contract creates and makes a request for data to a Chainlink oracle 2. The request is sent through the `transferAndCall` function of the LINK token contract, which is an [ERC-677](https://github.com/ethereum/EIPs/issues/677){target=\_blank} compliant token, that allows tokens to be transferred and relays the request to the oracle contract 3. Once the token is transferred the LINK contract calls the oracle contract's `onTokenTransfer` function 4. The oracle contract is owned by the oracle node operators and is responsible for handling on-chain requests made through the LINK token. Once the request is received by the oracle contract an event is emitted to the node which acts upon it 5. After the request has been fulfilled by the oracle node, the node uses the `fulfillOracleRequest` function of the oracle contract to return the result to the client via the callback function defined in the original request ![Basic Request Diagram](/images/builders/integrations/oracles/chainlink/chainlink-basic-request.webp) When a request for data is created through the client contract, the following parameters need to be passed in to ensure the transaction will go through and the correct information will be returned: - **Oracle address** - address of the contract deployed by the oracle node - **Job ID** - the task to be executed. An oracle node has a set of job IDs, where each job corresponds to a task that can be requested by a user, for example, fetching a price feed - **Payment** - payment in LINK tokens that the oracle will receive for fulfiling the request ### Fetching Data {: #fetching-data } There are a few ways you can get started fetching data from an oracle on Moonbeam: - You can use the pre-deployed client contract, LINK token contract, and oracle contract that rely on the oracle node being run by Moonbeam - You can create your own custom client contract instead of the pre-deployed client contract to be used with the Moonbeam oracle node - You can create your own custom contracts and run your own oracle node The pre-deployed contracts and oracle node run by Moonbeam support a limited set of job IDs that can be used to fetch price data for various asset pairs. If you need additional data, please refer to the [Create Custom Contracts using your own Oracle Node](#create-custom-contracts-using-your-own-oracle-node) section below to learn how to get started. It's also important to note that the client contract must have a LINK tokens balance to be able to pay for requests. For the pre-deployed setup, the LINK value has been set to zero. If you deploy your own setup, you can also set the LINK value to zero in your `ChainlinkClient.sol` contract, and you can choose to deploy your own LINK token contract or use the pre-deployed one. ### Use Pre-deployed Contracts {: #use-pre-deployed-contracts } If you want to skip the hurdles of deploying all contracts, setting up your oracle node, creating job IDs, and so on, you can use a custom client contract that has already been deployed to Moonbase Alpha. The contract makes all requests to an oracle contract that has also already been deployed, with a zero LINK token payment. These requests are fulfilled by an oracle node that is run by the Moonbeam team. The client contract deployed on Moonbase Alpha is as follows: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.6.6; import "https://github.com/smartcontractkit/chainlink/blob/v1.13.3/contracts/src/v0.6/ChainlinkClient.sol"; /** * @title Client based in ChainlinkClient * @notice End users can deploy this contract to request the Prices from an Oracle */ contract Client is ChainlinkClient { // Stores the answer from the Chainlink oracle uint256 public currentPrice; address public owner; // Deploy with the address of the LINK token constructor(address _link) public { // Set the address for the LINK token for the network setChainlinkToken(_link); owner = msg.sender; } // Creates Chainlink Request function requestPrice(address _oracle, string memory _jobId, uint256 _payment) public onlyOwner { // newRequest takes a JobID, a callback address, and callback function as input Chainlink.Request memory req = buildChainlinkRequest(stringToBytes32(_jobId), address(this), this.fulfill.selector); // Sends the request with the amount of payment specified to the oracle sendChainlinkRequestTo(_oracle, req, _payment); } // Callback function called by the Oracle when it has resolved the request function fulfill(bytes32 _requestId, uint256 _price) public recordChainlinkFulfillment(_requestId) { currentPrice = _price; } // Allows the owner to cancel an unfulfilled request function cancelRequest( bytes32 _requestId, uint256 _payment, bytes4 _callbackFunctionId, uint256 _expiration ) public { cancelChainlinkRequest(_requestId, _payment, _callbackFunctionId, _expiration); } // Allows the owner to withdraw the LINK tokens in the contract to the address calling this function function withdrawLink() public onlyOwner { LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress()); require(link.transfer(msg.sender, link.balanceOf(address(this))), "Unable to transfer"); } // Decodes an input string in a bytes32 word function stringToBytes32(string memory _source) private pure returns (bytes32 result) { bytes memory emptyStringTest = bytes(_source); if (emptyStringTest.length == 0) { return 0x0; } assembly { // solhint-disable-line no-inline-assembly result := mload(add(_source, 32)) } return result; } // Reverts if the sender is not the owner of the contract modifier onlyOwner() { require(msg.sender == owner); _; } } ``` The core functions of the contract are as follows: - **`constructor`** - runs when the contract is deployed. It sets the address of the LINK token and the owner of the contract - **`requestPrice`** - needs the oracle contract address, the job ID, and the payment (in LINK) tokens to the fulfiller of the request. Builds the new request that is sent using the `sendChainlinkRequestTo` function from the `ChainlinkClient.sol` import - **`fulfill`** - callback used by the oracle node to fulfill the request by storing the queried information in the contract Note that the client contract must have a LINK tokens balance to be able to pay for this request. However, in this instance, the LINK value has been set to zero. The client contract is deployed at `{{ networks.moonbase.chainlink.client_contract }}`. You can try interacting with the client contract by using following interface contract: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.6.6; /** * @title Simple Interface to interact with Universal Client Contract * @notice Client Address {{ networks.moonbase.chainlink.client_contract }} */ interface ChainlinkInterface { /** * @notice Creates a Chainlink request with the job specification ID, * @notice and sends it to the Oracle. * @notice _oracle The address of the Oracle contract fixed top * @notice _payment For this example the PAYMENT is set to zero * @param _jobId The job spec ID that we want to call in string format */ function requestPrice(string calldata _jobId) external; function currentPrice() external view returns (uint); } ``` This provides two functions: - `requestPrice()` - only needs the job ID of the data you want to query. This function starts the chain of events explained before. - `currentPrice()` is a view function that returns the latest price stored in the contract Currently, the oracle node has a set of Job IDs for different price data for the following pairs: | Base/Quote | Job ID Reference | |:------------:|:-------------------------------------------------:| | AAVE to USD | {{ networks.moonbase.chainlink.basic.aave_usd }} | | ALGO to USD | {{ networks.moonbase.chainlink.basic.algo_usd }} | | AVAX to USD | {{ networks.moonbase.chainlink.basic.avax_usd }} | | BAND to USD | {{ networks.moonbase.chainlink.basic.band_usd }} | | BNB to USD | {{ networks.moonbase.chainlink.basic.bnb_usd }} | | BTC to USD | {{ networks.moonbase.chainlink.basic.btc_usd }} | | COMP to USD | {{ networks.moonbase.chainlink.basic.comp_usd }} | | CRV to USD | {{ networks.moonbase.chainlink.basic.crv_usd }} | | CVX to USD | {{ networks.moonbase.chainlink.basic.cvx_usd }} | | DAI to USD | {{ networks.moonbase.chainlink.basic.dai_usd }} | | DOT to USD | {{ networks.moonbase.chainlink.basic.dot_usd }} | | ETH to USD | {{ networks.moonbase.chainlink.basic.eth_usd }} | | FRAX to USD | {{ networks.moonbase.chainlink.basic.frax_usd }} | | FTM to USD | {{ networks.moonbase.chainlink.basic.ftm_usd }} | | KSM to USD | {{ networks.moonbase.chainlink.basic.ksm_usd }} | | LINK to USD | {{ networks.moonbase.chainlink.basic.link_usd }} | | MKR to USD | {{ networks.moonbase.chainlink.basic.mkr_usd }} | | OP to USD | {{ networks.moonbase.chainlink.basic.op_usd }} | | stETH to USD | {{ networks.moonbase.chainlink.basic.steth_usd }} | | SUSHI to USD | {{ networks.moonbase.chainlink.basic.sushi_usd }} | | UNI to USD | {{ networks.moonbase.chainlink.basic.uni_usd }} | | USDC to USD | {{ networks.moonbase.chainlink.basic.usdc_usd }} | | USDT to USD | {{ networks.moonbase.chainlink.basic.usdt_usd }} | | YFI to USD | {{ networks.moonbase.chainlink.basic.yfi_usd }} | For this example, you can go ahead and use the interface contract with the `BTC to USD` job ID in [Remix](/builders/ethereum/dev-env/remix/){target=\_blank}. After creating the file and compiling the contract, you can take the following steps: 1. Head to the **Deploy and Run Transactions** tab 2. Make sure you have set the **ENVIRONMENT** to **Injected Web3**, and you have your MetaMask connected to Moonbase Alpha 3. Enter the client contract address, `{{ networks.moonbase.chainlink.client_contract }}`, and click on **At Address**. This will create an instance of the client contract that you can interact with 4. Under the **Deployed Contracts** section, use the `requestPrice()` function to query the data of the corresponding job ID 5. Confirm the transaction. You will have to wait until the whole request process that was previously explained occurs 6. You can then check the price using the view function, `currentPrice()` ![Chainlink Basic Request on Moonbase Alpha](/images/builders/integrations/oracles/chainlink/chainlink-1.webp) If there is any specific pair you want to be included, feel free to reach out to the Moonbeam team through [Discord](https://discord.com/invite/PfpUATX){target=\_blank}. ### Create a Custom Client Contract {: #create-a-custom-client-contract } If you want to run your own custom client contract but use the oracle node being run by Moonbeam, you can do so with the following information: | Contract Type | Address | |:---------------:|:-------------------------------------------------:| | Oracle Contract | {{ networks.moonbase.chainlink.oracle_contract }} | | LINK Token | {{ networks.moonbase.chainlink.link_contract }} | If you decide to go this route, please keep in mind that the oracle node only supports the job IDs listed in the previous section. You'll only be able to access the pricing data for the supported pairs. If you need more functionality or want to use another API, please check out the [Create Custom Contracts using your own Oracle Node](#create-custom-contracts-using-your-own-oracle-node) section. To build your own client contract using the `ChainlinkClient`, you'll need to start by importing the contract: ```solidity import "https://github.com/smartcontractkit/chainlink/blob/v1.13.3/contracts/src/v0.6/ChainlinkClient.sol"; ``` You can checkout out the [Chainlink documentation on ChainlinkClient API Reference](https://docs.chain.link/any-api/api-reference){target=\_blank} for more information. Keep in mind that the LINK token payment is set to zero. ### Create Custom Contracts using your own Oracle Node {: #create-custom-contracts-using-your-own-oracle-node } To get started with your own setup, including your own client contract, oracle contract, and oracle node, you'll need to start off running an oracle node. You can follow the [Run a Chainlink Oracle Node on Moonbeam](/node-operators/oracle-nodes/node-chainlink/){target=\_blank} guide to spin up your own oracle node. You'll also learn how to setup your oracle contract and create jobs. If you [created a job to be used with any API](/node-operators/oracle-nodes/node-chainlink/#using-any-api){target=\_blank}, you can then create a client contract that sets the API endpoint URL to perform the GET request on. Note that the client contract must have a LINK tokens balance to be able to pay for requests. Therefore, you will need to set the LINK value to zero in your `ChainlinkClient.sol` contract. You'll also need to make sure that your oracle node has a `MINIMUM_CONTRACT_PAYMENT` of `0`. You can verify that it has been set to zero by checking out the **Configuration** section of your node at `http://localhost:6688/config`. The following client contract is an example of how to use any API from within your client contract: ```solidity pragma solidity ^0.8.7; import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol"; contract Client is ChainlinkClient { using Chainlink for Chainlink.Request; address private oracle; bytes32 private jobId; uint256 private fee; uint256 public volume; /** This example uses the LINK token address on Moonbase Alpha. Make sure to update the oracle and jobId. */ constructor() { setChainlinkToken(address(0xa36085F69e2889c224210F603D836748e7dC0088)); oracle = INSERT_YOUR_ORACLE_NODE_ADDRESS; jobId = "INSERT_YOUR_JOB_ID"; fee = 0; } /** * Create a Chainlink request to retrieve API response, find the target * data, then multiply by 1000000000000000000 (to remove decimal places from data). */ function requestVolumeData() public returns (bytes32 requestId) { Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.fulfill.selector); // Set the URL to perform the GET request on request.add("get", "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD"); // Set the path to find the desired data in the API response, where the response format is: // {"RAW": // {"ETH": // {"USD": // { // "VOLUME24HOUR": xxx.xxx, // } // } // } // } request.add("path", "RAW.ETH.USD.VOLUME24HOUR"); // Multiply the result by 1000000000000000000 to remove decimals int timesAmount = 10**18; request.addInt("times", timesAmount); // Sends the request return sendChainlinkRequestTo(oracle, request, fee); } /** * Receive the response in the form of uint256 */ function fulfill(bytes32 _requestId, uint256 _volume) public recordChainlinkFulfillment(_requestId) { volume = _volume; } } ``` !!! note The above example uses the pre-deployed LINK token contract address. You also have the option of deploying your own LINK token contract and using that instead. Once you've deployed the contract on Remix, you can begin to request the volume data. After you make a request, After you make a request, you can check the job status under the **Jobs** section on your node at `http://localhost:6688/jobs`.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/oracles/dia/ --- BEGIN CONTENT --- --- title: DIA Oracle description: Learn how to request a dedicated DIA oracle for your dApp, enabling access to price data for 2500+ tokens, randomness, and more. categories: Oracle Nodes --- # Introduction to DIA Oracles ## Introduction {: #introduction } [DIA](https://www.diadata.org){target=\_blank} offers customizable oracles that are tailored to each dApp’s needs. Each oracle can be customized in several ways, including data sources, data cleansing filters, pricing and computational methodologies, update mechanisms, and more. This ensures that the data and oracle remain robust and resilient to market conditions and provide a global market price as well as specific individual or cross-chain market prices. By collecting billions of raw trades directly from over 90 sources, including CEXs, DEXs, and NFT marketplaces, DIA enables full transparency, customization, and control throughout the entire value stack. DIA's data and oracle suite comprise price feeds for 20,000+ assets, including cryptocurrencies, NFT collections, and liquid-staked tokens, as well as random number generation and other data feed types. You can visit DIA's documentation to learn how to [Request a Custom Oracle](https://www.diadata.org/docs/how-to-guides/request-a-custom-oracle#request-a-custom-oracle){target=\_blank}.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Token Price Feeds {: #token-price-feeds } DIA token price feeds provide smart contracts with real-time price information for [3,000+ cryptocurrencies](https://www.diadata.org/app/price){target=\_blank}, sourced transparently from [90+ trusted, high-volume DEXs and CEXs](https://www.diadata.org/app/source/defi){target=\_blank}. ### Moonbeam Demo Price Oracles {: #moonbeam-demo-price-oracles } DIA has deployed the following demo oracles for the Moonbeam community, which provide a limited selection of cryptocurrency price feeds with predefined configuration settings: | Network | Contract Address | |:--------------:|:------------------------------------------------------------------------------------------------------------------------------------------------:| | Moonbeam | [`0x1f1BAe8D7a2957CeF5ffA0d957cfEDd6828D728f`](https://moonscan.io/address/0x1f1BAe8D7a2957CeF5ffA0d957cfEDd6828D728f){target=\_blank} | | Moonriver | [`0x11f74b94afb5968119c98ea277a2b73208bb39ab`](https://moonriver.moonscan.io/address/0x11f74b94afb5968119c98ea277a2b73208bb39ab){target=\_blank} | | Moonbase Alpha | [`0xe23d8713aa3a0a2c102af772d2467064821b8d46`](https://moonbase.moonscan.io/address/0xe23d8713aa3a0a2c102af772d2467064821b8d46){target=\_blank} | The demo oracle contracts deployed to Moonbeam are the [DIA Key-Value Oracle Contract V2](https://www.diadata.org/docs/nexus/reference/smart-contracts/diaoraclev2.sol#diaoraclev2-sol){target=\_blank}. The contract is structured as follows: ```solidity pragma solidity 0.7.4; contract DIAOracleV2 { mapping (string => uint256) public values; address oracleUpdater; event OracleUpdate(string key, uint128 value, uint128 timestamp); event UpdaterAddressChange(address newUpdater); constructor() { oracleUpdater = msg.sender; } function setValue(string memory key, uint128 value, uint128 timestamp) public { require(msg.sender == oracleUpdater); uint256 cValue = (((uint256)(value)) << 128) + timestamp; values[key] = cValue; emit OracleUpdate(key, value, timestamp); } function getValue(string memory key) external view returns (uint128, uint128) { uint256 cValue = values[key]; uint128 timestamp = (uint128)(cValue % 2**128); uint128 value = (uint128)(cValue >> 128); return (value, timestamp); } function updateOracleUpdaterAddress(address newOracleUpdaterAddress) public { require(msg.sender == oracleUpdater); oracleUpdater = newOracleUpdaterAddress; emit UpdaterAddressChange(newOracleUpdaterAddress); } } ``` !!! note DIA demo oracles are not intended for use in production environments. Developers can request a dedicated, production-ready oracle with custom price feeds and configuration settings. To start the request process, you can check out the [Request a Custom Oracle](https://www.diadata.org/docs/how-to-guides/request-a-custom-oracle#request-a-custom-oracle){target=\_blank} documentation. #### Included Price Feeds {: #price-feeds } The price feeds included with the demo oracles are: - [DIA/USD](https://www.diadata.org/app/price/asset/Ethereum/0x84cA8bc7997272c7CfB4D0Cd3D55cd942B3c9419){target=\_blank} - [BTC/USD](https://www.diadata.org/app/price/asset/Bitcoin/0x0000000000000000000000000000000000000000){target=\_blank} - [USDC/USD](https://www.diadata.org/app/price/asset/Ethereum/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48){target=\_blank} ### How to Access DIA Oracles {: #how-to-access-dia-oracles } The steps for accessing a price value on DIA oracles are as follows: 1. Access your oracle smart contract on Moonbeam 2. Call `getValue(pair_name)` with `pair_name` being the full pair name, such as `BTC/USD`. You can use the **Read Contract** functionality under the **Contract** tab of the contract on Moonscan to execute this call The response contains two values: - The current asset price in USD with a fix-comma notation of 8 decimals - The UNIX timestamp of the last oracle update You can find DIA's oracle integration samples in Solidity and Vyper languages by visiting the [Fetch Price Data](https://www.diadata.org/docs/nexus/how-to-guides/fetch-price-data){target=\_blank} guide on DIA's documentation site. ### Supported Token API Endpoints {: #supported-token-api-endpoints } DIA also supports Rest and GraphQL endpoints to return cryptocurrency price data. You can [visit the DIA documentation](https://www.diadata.org/docs/reference/apis/token-prices){target=\_blank} to see all API endpoints. For example, you can use the following JavaScript scripts to access the [BTC/USD price feed](#price-feeds): === "Rest" ```js const axios = require('axios'); const options = { method: 'GET', url: 'https://api.diadata.org/v1/assetQuotation/Bitcoin/0x0000000000000000000000000000000000000000', headers: { 'Content-Type': 'application/json' }, }; axios .request(options) .then(function (response) { console.log(response.data); }) .catch(function (error) { console.error(error); }); ``` === "GraphQL" ```js const axios = require('axios'); const url = 'https://api.diadata.org/graphql/query'; const query = ` { GetFeed( Filter: "mair", BlockSizeSeconds: 480, BlockShiftSeconds: 480, StartTime: 1690449575, EndTime: 1690535975, FeedSelection: [ { Address: "0x0000000000000000000000000000000000000000", Blockchain:"Bitcoin", Exchangepairs:[], }, ], ) { Name Time Value Pools Pairs } }`; const data = { query: query, }; axios .post(url, data) .then((response) => { console.log(response.data); }) .catch((error) => { console.error('Request failed:', error.message); }); ``` You can refer to DIA's documentation on [Rest API endpoints](https://www.diadata.org/docs/reference/apis/token-prices/api-endpoints){target=\_blank} and the [GraphQL Endpoint](https://www.diadata.org/docs/reference/apis/token-prices/graphql){target=\_blank} for information on the parameters and return data. ## NFT Floor Price Feeds {: #nft-floor-price-feeds } DIA NFT floor price feeds provide smart contracts with real-time price information for [18,000+ NFT collections](https://www.diadata.org/nft-api-oracle/){target=\_blank}, sourced on-chain with 100% transparency from [multiple cross-chain NFT marketplaces](https://www.diadata.org/app/source/nft){target=\_blank}. Please refer to DIA's documentation to find out how you can [request a custom NFT oracle](https://www.diadata.org/docs/request-a-custom-oracle#forum-request){target=\_blank} for NFTs on Moonbeam. ## Random Number Generation {: #random-number-generation } [DIA xRandom](https://www.diadata.org/docs/nexus/data-products/randomness#randomness){target=\_blank} provides smart contracts with unpredictable and unbiased random numbers, facilitating the development of on-chain use cases such as lotteries, prediction markets, NFT launches, and more. DIA leverages the Drand public randomness beacon, and updates its oracle with round numbers, randomness and a signature. Drand runs distributed nodes to produce their randomness beacon. Drand uses [Pedersen's DKG (Distributed Key Generation) protocol](https://docs.drand.love/docs/cryptography/#distributed-key-generation-dkg){target=\_blank} to create collective private and public keys. Participants in their League of Entropy then generate randomness in rounds and broadcast it together with its signature. To learn more about Drand’s randomness beacon, watch the [On-Chain Randomness Oracle | DIA Developer Tutorial](https://youtu.be/7HALDJr8V3g){target=\_blank} and read [Drand’s documentation](https://docs.drand.love/#how-drand-works){target=\_blank}. ### Moonbeam Demo Randomness Oracle {: #moonbeam-demo-randomness-oracle } DIA has deployed a demo oracle on Moonbase Alpha, which can be accessed at the following address: ```text 0x48d351ab7f8646239bbade95c3cc6de3ef4a6cec ``` The DIA randomness smart contract is structured as follows: ```solidity pragma solidity ^0.8.0; contract DIARandomOracle { struct Random { string randomness; string signature; string previousSignature; } mapping(uint256 => Random) public values; uint256 public lastRound = 0; address public oracleUpdater; event OracleUpdate(string key, uint128 value, uint128 timestamp); event UpdaterAddressChange(address newUpdater); constructor() { oracleUpdater = msg.sender; } function setRandomValue( uint256 _round, string memory _randomness, string memory _signature, string memory _previousSignature ) public { require(msg.sender == oracleUpdater, "not a updater"); require(lastRound < _round, "old round"); lastRound = _round; values[_round] = Random(_randomness, _signature, _previousSignature); } function getValue(uint256 _round) external view returns (Random memory) { return values[_round]; } function updateOracleUpdaterAddress(address newOracleUpdaterAddress) public { require(msg.sender == oracleUpdater, "not a updater"); oracleUpdater = newOracleUpdaterAddress; emit UpdaterAddressChange(newOracleUpdaterAddress); } function getRandomValueFromRound(uint256 _round) external view returns (string memory) { return values[_round].randomness; } function getRandomValueFromRoundWithSignature(uint256 _round) external view returns (Random memory) { return values[_round]; } function getLastRound() public view returns (uint256) { return lastRound; } } ``` !!! note DIA demo oracles are not intended for use in production environments. Developers can request a dedicated, production-ready randomness oracle. To start the request process, you can contact the [integrations team](https://t.me/DIABDteam){target=\_blank} on Telegram. ### How to Use the DIA Randomness Oracle {: #how-to-use-the-dia-randomness-oracle } The steps for accessing a published random value are as follows: 1. Access your randomness oracle smart contract on Moonbeam 2. Call `getLastRound()`to obtain the ID of the latest published round. You can use the **Read Contract** functionality under the **Contract** tab of the contract on Moonscan to execute this call 3. Call `getRandomValueFromRound(uint256 _round)` using the obtained round ID. Again, you can use Moonscan to quickly execute this call The response contains the randomness value. The signature can also be requested by calling `getRandomValueFromRoundWithSignature(uint256 _round)`, which returns a tuple containing the randomness value, the signature, and the previous signature. To learn how to deploy a randomness-consuming contract on Moonbeam, please refer to the [Deploying a Randomness Consuming Smart Contract on EVM chains with DIA xRandom Oracle](https://youtu.be/BzN-tBgW-xs){target=\_blank} video tutorial. ## Resources {: #resources } - [Twitter](https://twitter.com/DIAdata_org){target=\_blank} - [Discord](https://discord.com/invite/ZvGjVY5uvs){target=\_blank} - [Website](https://www.diadata.org/){target=\_blank} - [Docs](https://www.diadata.org/docs/home){target=\_blank} - [Explore data](https://www.diadata.org/app){target=\_blank}
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/oracles/ --- BEGIN CONTENT --- --- title: Use an Oracle in your DApp description: Check out some of the supported oracles and learn how to add an oracle to your DApp to request off-chain data for smart contracts on Moonbeam-based networks. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/oracles/razor-network/ --- BEGIN CONTENT --- --- title: Razor Network Oracle description: How to request data from a Razor Network Oracle in your Moonbeam Ethereum DApp using smart contracts. categories: Oracle Nodes --- # Razor Network Oracle ## Introduction {: #introduction } Developers can now fetch prices from Razor Network’s oracle using a Bridge contract deployed on the Moonbase Alpha TestNet. This Bridge acts as middleware, and events emitted by it are fetched by the Razor Network's oracle infrastructure, sending prices to the Bridge contract. To access these price feeds, you need to interact with the Bridge contract address, which can be found in the following table: | Network | Contract Address | |:--------------:|:------------------------------------------:| | Moonbase Alpha | 0x53f7660Ea48289B5DA42f1d79Eb9d4F5eB83D3BE |
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Jobs {: #jobs } Each data-feed has a Job ID attached to it. For example: | Job ID | Underlying Price [USD] | |:------:|:----------------------:| | 1 | ETH | | 2 | BTC | | 3 | Microsoft Stocks | You can check Job IDs for each data-feed on the [Razor Network Explorer](https://razorscan.io/#/custom){target=\_blank}. Price feeds are updated every 5 minutes. More information can be found in [Razor's documentation website](https://docs.razor.network){target=\_blank}. ## Get Data From Bridge Contract {: #get-data-from-bridge-contract } Contracts can query on-chain data such as token prices, from Razor Network's oracle by implementing the interface of the Bridge contract, which exposes the `getResult` and `getJob` functions. ```solidity pragma solidity 0.6.11; interface Razor { function getResult(uint256 id) external view returns (uint256); function getJob(uint256 id) external view returns(string memory url, string memory selector, string memory name, bool repeat, uint256 result); } ``` The first function, `getResult`, takes the Job ID associated with the data-feed and fetches the price. For example, if you pass in `1`, you will receive the price of the data-feed related to the Job ID. The second function, `getJob`, takes the Job ID associated with the data-feed and fetches the general information regarding the data-feed, such as the name of the data-feed, the price, and the URL being used to fetch the prices. ### Example Contract {: #example-contract } There is a predeployed bridge contract in the Moonbase Alpha TestNet (at address `{{ networks.moonbase.razor.bridge_address }}`) so you can quickly check the information fed from Razor Network's oracle. The only requirement is the Bridge interface, which defines `getResult` structure and makes the functions available to the contract for queries. You can use the following `Demo` contract. It provides various functions: - **fetchPrice** - a _view_ function that queries a single Job ID. For example, to fetch the price of `ETH` in `USD`, you will need to send the Job ID `1` - **fetchMultiPrices** - a _view_ function that queries multiple Job IDs. For example, to fetch the price of `ETH` and `BTC` in `USD`, you will need to send the Job IDs `[1,2]` - **savePrice** - a _public_ function that queries a single Job ID. This sends a transaction and modifies the `price` variable stored in the contract. - **saveMultiPrices** - a _public_ function that queries multiple Job IDs. For example, to fetch the price of `ETH` and `BTC` in `USD`, you will need to send the Job IDs `[1,2]`. This sends a transaction and modifies the `pricesArr` array stored in the contract, which will hold the price of each pair in the same order as specified in the input ```solidity pragma solidity 0.6.11; interface Razor { function getResult(uint256 id) external view returns (uint256); function getJob(uint256 id) external view returns(string memory url, string memory selector, string memory name, bool repeat, uint256 result); } contract Demo { // Interface Razor internal razor; // Variables uint256 public price; uint256[] public pricesArr; constructor(address _bridgeAddress) public { razor = Razor(_bridgeAddress); // Bridge Contract Address // Moonbase Alpha {{ networks.moonbase.razor.bridge_address }} } function fetchPrice(uint256 _jobID) public view returns (uint256){ return razor.getResult(_jobID); } function fetchMultiPrices(uint256[] memory jobs) external view returns(uint256[] memory){ uint256[] memory prices = new uint256[](jobs.length); for(uint256 i=0;i The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/oracles/supra/ --- BEGIN CONTENT --- --- title: Supra Oracles description: Supra's Pull Oracle provides low-latency, on-demand price feed updates for a variety of use cases. Learn how to integrate Supra's oracle on Moonbeam. categories: Oracle Nodes --- # Supra Oracles ## Introduction {: #introduction } [Supra](https://supra.com){target=\_blank} is a novel, high-throughput oracle and intralayer: a vertically integrated toolkit of cross-chain solutions (data oracles, asset bridge, automation network, and more) that interlink all blockchains, public (L1s and L2s) or private (enterprises), including Moonbeam. Supra provides decentralized oracle price feeds that can be used for on-chain and off-chain use cases such as spot and perpetual DEXes, lending protocols, and payment protocols. This page provides everything you need to know to get started with Supra on Moonbeam.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## How to use Supra's Price Feeds {: #price-feeds } Supra uses a pull model as a customized approach that publishes price data upon request. It combines Web2 and Web3 methods to achieve low latency when sending data from Supra to destination chains. The process involves the following steps: 1. Web2 methods are used to retrieve price data from Supra 2. Smart contracts are utilized for cryptographically verifying and writing the latest price data on-chain, where it lives on immutable ledgers, using [Supra's Pull Oracle V1](https://docs.supra.com/oracles/data-feeds/pull-oracle){target=\_blank} 3. Once the data has been written on-chain, the most recently published price feed data will be available in Supra's Storage contract The addresses for Supra's contracts on Moonbeam are as follows: === "Moonbeam" | Contract | Address | |:-----------:|:-----------------------------------------------------------------------------------------------------------------------------------:| | Pull Oracle | [{{ networks.moonbeam.supra.pull_oracle }}](https://moonscan.io/address/{{ networks.moonbeam.supra.pull_oracle }}){target=\_blank} | | Storage | [{{ networks.moonbeam.supra.storage }}](https://moonscan.io/address/{{ networks.moonbeam.supra.storage }}){target=\_blank} | === "Moonbase Alpha" | Contract | Address | |:-----------:|:--------------------------------------------------------------------------------------------------------------------------------------------:| | Pull Oracle | [{{ networks.moonbase.supra.pull_oracle }}](https://moonbase.moonscan.io/address/{{ networks.moonbase.supra.pull_oracle }}){target=\_blank} | | Storage | [{{ networks.moonbase.supra.storage }}](https://moonbase.moonscan.io/address/{{ networks.moonbase.supra.storage }}){target=\_blank} | !!! note Moonriver is not supported at this time. ### List of Available Price Feeds {: #list-of-available-price-feeds } To view a complete list of the available data pairs provided by Supra, please check out their [data feeds catalog](https://docs.supra.com/oracles/data-feeds/data-feeds-index) on their documentation site. To interact with any of these data pairs, you'll need to take note of the pair's **Pair ID**. ### Try It Out {: #try-it-out } Try out a basic example of how to fetch price data using Supra's pull model with step-by-step instructions in the [Fetching Price Data with Supra Oracles](/tutorials/integrations/supra/){target=\_blank} tutorial. You'll learn how to tackle each of the three steps mentioned in the [previous section](#price-feeds). ## Connect with Supra {: #connect-with-supra } Still looking for answers? Supra's got them! Check out all the ways you can reach the Supra team: - Visit [Supra's websites at supraoracles.com](https://supra.com){target=\_blank} - Read their [docs](https://docs.supra.com/oracles/overview){target=\_blank} - Chat with them on [Telegram](https://t.me/SupraOracles){target=\_blank} - Follow them on [Twitter](https://twitter.com/SupraOracles){target=\_blank} - Join their [Discord](https://discord.com/invite/supraoracles){target=\_blank} - Check out their [Youtube](https://www.youtube.com/SupraOfficial){target=\_blank}
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/wallets/ --- BEGIN CONTENT --- --- title: Add Wallet Integrations to DApps description: Learn how to add wallet integrations, such as MetaMask and WalletConnect, to your DApp on Moonbeam so users can automatically connect to their wallets. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/wallets/metamask/ --- BEGIN CONTENT --- --- title: Add MetaMask to a DApp description: This tutorial shows you how to integrate MetaMask into a DApp and automatically connect users to Moonbeam with the click of a button. categories: Tokens and Accounts --- # Integrate MetaMask into a DApp ## Introduction {: #introduction } With the release of MetaMask's [Custom Networks API](https://consensys.io/blog/connect-users-to-layer-2-networks-with-the-metamask-custom-networks-api){target=\_blank}, users can be prompted to add Moonbeam's Testnet, Moonbase Alpha. This section will take you through the process of adding a "Connect to Moonbase Alpha" button that will prompt users to connect their MetaMask account(s) to Moonbase Alpha. Your users will no longer need to know or worry about Moonbase Alpha's network configurations and adding a custom network to MetaMask. To interact with Moonbeam from your dApp, all users will need to do is click a few buttons to connect to Moonbase Alpha and get started. MetaMask injects a global Ethereum API into websites users visit at `window.ethereum`, which allows the websites to read and request the users' blockchain data. You'll be using the Ethereum provider to walk your users through the process of adding Moonbase Alpha as a custom network. In general, you will have to: - Check if the Ethereum provider exists and if it's MetaMask - Request the user's account address - Add Moonbase Alpha as a new chain This guide is divided into two sections. First, it'll cover adding a button that will be used to trigger MetaMask to pop up and connect to Moonbase Alpha. The second part of the guide will create the logic for connecting the user to MetaMask. This way when you click the button you can actually test the functionality as you go through the guide. ## Checking Prerequisites {: #checking-prerequisites } To add the Connect MetaMask button you'll need a JavaScript project and the MetaMask browser extension installed for local testing. It's recommended to use MetaMask's `detect-provider` utility package to detect the provider injected at `window.ethereum`. The package handles detecting the provider for the MetaMask extension and MetaMask Mobile. To install the package in your JavaScript project, run: ```bash npm install @metamask/detect-provider ``` ## Add a Button {: #add-a-button } You'll start off by adding a button that will be used to connect MetaMask to Moonbase Alpha. You want to start with the button so when you create the logic in the next step you can test the code as you make your way through the guide. The function you will create in the next section of the guide will be called `configureMoonbaseAlpha`. So the button on click should call `configureMoonbaseAlpha`. ```html ``` ## Add Logic {: #add-logic } Now that you have created the button, you need to add the `configureMoonbaseAlpha` function that will be used on click. 1. Detect the provider at `window.ethereum` and check if it's MetaMask. If you want a simple solution you can directly access `window.ethereum`. Or you can use MetaMask's `detect-provider` package and it will detect the provider for MetaMask extension and MetaMask Mobile for you ```javascript import detectEthereumProvider from '@metamask/detect-provider'; const configureMoonbaseAlpha = async () => { const provider = await detectEthereumProvider({ mustBeMetaMask: true }); if (provider) { // Logic will go here } else { console.error('Please install MetaMask'); } }; ``` 2. Request the user's accounts by calling the `eth_requestAccounts` method. This will prompt MetaMask to pop up and ask the user to select which accounts they would like to connect to. Behind the scenes, permissions are being checked by calling `wallet_requestPermissions`. Currently the only permissions are for `eth_accounts`. So you're ultimately verifying that you have access to the user's addresses returned from `eth_accounts`. If you're interested in learning more about the permissions system, check out [EIP-2255](https://eips.ethereum.org/EIPS/eip-2255){target=\_blank} ```javascript import detectEthereumProvider from '@metamask/detect-provider'; const configureMoonbaseAlpha = async () => { const provider = await detectEthereumProvider({ mustBeMetaMask: true }); if (provider) { try { await provider.request({ method: 'eth_requestAccounts' }); } catch (e) { console.error(e); } } else { console.error('Please install MetaMask'); } }; ``` ![Add accounts to MetaMask](/images/builders/integrations/wallets/metamask/metamask-1.webp) 3. Add Moonbase Alpha as a new chain by calling `wallet_addEthereumChain`. This will prompt the user to provide permission to add Moonbase Alpha as a custom network. Once the network has been successfully added, it will also prompt the user to then switch to Moonbase Alpha ```javascript import detectEthereumProvider from '@metamask/detect-provider'; const configureMoonbaseAlpha = async () => { const provider = await detectEthereumProvider({ mustBeMetaMask: true }); if (provider) { try { await provider.request({ method: 'eth_requestAccounts' }); await provider.request({ method: 'wallet_addEthereumChain', params: [ { // Moonbase Alpha's chainId is {{ networks.moonbase.chain_id }}, which is {{ networks.moonbase.hex_chain_id }} in hex chainId: '{{ networks.moonbase.hex_chain_id }}', chainName: 'Moonbase Alpha', nativeCurrency: { name: 'DEV', symbol: 'DEV', decimals: 18, }, rpcUrls: ['{{ networks.moonbase.rpc_url }}'], blockExplorerUrls: ['{{ networks.moonbase.block_explorer }}'], }, ], }); } catch (e) { console.error(e); } } else { console.error('Please install MetaMask'); } }; ``` ![Add and switch networks in MetaMask](/images/builders/integrations/wallets/metamask/metamask-2.webp) So, now you should have a button that, on click, walks users through the entire process of connecting their MetaMask accounts to Moonbase Alpha. ### Confirm Connection {: #confirm-connection } It's possible that you'll have logic that relies on knowing whether a user is connected to Moonbase Alpha or not. Perhaps you want to disable the button if the user is already connected. To confirm a user is connected to Moonbase Alpha, you can call `eth_chainId`, which will return the users current chain ID: ```javascript const chainId = await provider.request({ method: 'eth_chainId', }); // Moonbase Alpha's chainId is {{ networks.moonbase.chain_id }}, which is {{ networks.moonbase.hex_chain_id }} in hex if (chainId === '{{ networks.moonbase.hex_chain_id }}') { // At this point, you might want to disable the "Connect" button // or inform the user that they are already connected to the // Moonbase Alpha testnet } ``` ## Listen to Account Changes {: #listen-to-account-changes } To ensure that your project or dApp is staying up to date with the latest account information, you can add the `accountsChanged` event listener that MetaMask provides. MetaMask emits this event when the return value of `eth_accounts` changes. If an address is returned, it is your user's most recent account that provided access permissions. If no address is returned, that means the user has not provided any accounts with access permissions. ```javascript provider.on('accountsChanged', (accounts) => { if (accounts.length === 0) { // MetaMask is locked or the user doesn't have any connected accounts console.log('Please connect to MetaMask.'); } }); ``` ## Listen to Chain Changes {: #listen-to-chain-changes } To keep your project or dApp up to date with any changes to the connected chain, you'll want to subscribe to the `chainChanged` event. MetaMask emits this event every time the connected chain changes. ```javascript provider.on('chainChanged', () => { // MetaMask recommends reloading the page unless you have good reason not to window.location.reload(); }); ``` MetaMask recommends reloading the page whenever the chain changes, unless there is a good reason not to, as it's important to always be in sync with chain changes. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/wallets/particle-network/ --- BEGIN CONTENT --- --- title: Add Particle Network to a dApp description: Learn how to integrate Particle Network's Wallet-as-a-Service into a dApp built on Moonbeam to enable MPC-based onboarding and ERC-4337 AA interaction. categories: Tokens and Accounts --- # Particle Network Wallet Abstraction ## Introduction {: #introduction } [Particle Network](https://particle.network){target=\_blank} offers Wallet Abstraction services with an Account Abstraction stack, providing a suite of SDKs focused on reducing user onboarding friction. By embedding customizable Externally Owned Account (EOA) and [Account Abstraction (AA)](https://developers.particle.network/api-reference/aa/introduction#account-abstraction){target=\_blank} components, Particle allows quick 2-click onboarding via social logins like Google, email, and phone, as well as traditional Web3 methods. This approach removes the need for users to manage a conventional wallet, delivering a streamlined, application-specific experience for Web3 interactions. Particle Network supports Moonbeam, Moonriver, and the Moonbase Alpha TestNet with both standard EOA interactions and native [ERC-4337](https://eips.ethereum.org/EIPS/eip-4337){target=\_blank} `SimpleAccount` implementations, providing full-stack account abstraction. Key components of Particle Network's Moonbeam integration include: - **Particle Connect**: Particle's flagship Wallet-as-a-Service solution, offering embedded wallets powered by MPC-TSS for smooth, Web2-like onboarding and interactions, with Account Abstraction support integrated within a single SDK - **Particle Network Modular [AA Stack](https://developers.particle.network/landing/realized-vision){target=\_blank}**: Beyond the default EOA-based interactions, Particle also offers a modular AA stack for ERC-4337 account abstraction on Moonbeam, allowing flexibility in the smart account, bundler, and paymaster configurations to suit AA-enabled applications ![Particle Network Smart WaaS map](/images/builders/integrations/wallets/particle/particle-1.webp) In this guide, you'll go through a step-by-step example of using Particle Connect on Moonbeam. ## Create an Application {: #create-an-application } To use Particle Connect on Moonbeam, you'll need to create an account on the [Particle Network dashboard](https://dashboard.particle.network){target=\_blank} and spin up an application 1. Navigate to the Particle Network dashboard, then sign up or log in ![Dashboard login](/images/builders/integrations/wallets/particle/particle-2.webp) 2. Once logged in, click **Add New Project** to create a new project ![Project creation](/images/builders/integrations/wallets/particle/particle-3.webp) 3. Enter the project name and click **Save** ![Application creation](/images/builders/integrations/wallets/particle/particle-4.webp) 4. From the project's dashboard, scroll down to the **Your Apps** section and create a new app by selecting **iOS**, **Android**, or **Web** and providing the requested information ![Application creation](/images/builders/integrations/wallets/particle/particle-5.webp) 5. Finally, copy the **Project ID**, **Client Key**, and **App ID** ![Application dashboard](/images/builders/integrations/wallets/particle/particle-6.webp) ## Install Dependencies {: #install-dependencies } To integrate Particle Connect into your Moonbeam application, you'll need only a few dependencies. Particle Connect offers built-in Account Abstraction (AA) support; however, in this example, we'll install the Particle AA SDK to utilize EIP-1193 providers, such as ethers. ```bash yarn add @particle-network/connectkit viem@^2 @particle-network/aa ethers ``` > Note that this tutorial is based on a [Next.js app](https://nextjs.org/docs/app/getting-started/installation){target=\_blank} with TypeScript and Tailwind CSS. ## Configure Particle Connect {: #configure-particle-network } We’ll configure and initialize Particle Connect (Particle's flagship authentication SDK). Begin by creating a new file called `ConnectKit.tsx` in your project’s root directory, where we’ll set up the `ParticleConnectKit` component as the primary interface for configuration. Before proceeding, head back to the [Particle dashboard](https://dashboard.particle.network){target=\_blank} and retrieve the following API keys: - **`projectId`** – your project’s unique ID - **`clientKey`** – your client-specific key - **`appId`** – your application ID These keys are essential as they connect your Particle Connect instance with the Particle dashboard, enabling features like no-code customization, user activity tracking, and API request authentication. Place the API keys in a `.env` file in the following format: ```shell NEXT_PUBLIC_PROJECT_ID='INSERT_PROJECT_ID' NEXT_PUBLIC_CLIENT_KEY='INSERT_CLIENT_KEY' NEXT_PUBLIC_APP_ID='INSERT_APP_ID' ``` This setup ensures that your API keys are securely accessible to the Next.js application while protecting them from unauthorized access. Here’s the code to add to your `ConnectKit.tsx` file: ```js "use client"; import React from "react"; import { ConnectKitProvider, createConfig } from "@particle-network/connectkit"; import { authWalletConnectors } from "@particle-network/connectkit/auth"; import { moonbeam } from "@particle-network/connectkit/chains"; import { wallet, EntryPosition } from "@particle-network/connectkit/wallet"; import { aa } from "@particle-network/connectkit/aa"; const config = createConfig({ projectId: process.env.NEXT_PUBLIC_PROJECT_ID!, clientKey: process.env.NEXT_PUBLIC_CLIENT_KEY!, appId: process.env.NEXT_PUBLIC_APP_ID!, walletConnectors: [authWalletConnectors({})], plugins: [ wallet({ entryPosition: EntryPosition.BR, // Positions the modal button at the bottom right on login visible: true, // Determines if the wallet modal is displayed }), aa({ name: "SIMPLE", version: "2.0.0", }), ], chains: [moonbeam], }); export const ParticleConnectkit = ({ children }: React.PropsWithChildren) => { return {children}; }; ``` This setup initializes `ParticleConnectKit`, a wrapper for the configured `ConnectKitProvider` instance, using your project keys. It also defines essential SDK settings, such as supported chains (e.g., Moonbeam), wallet positioning and visibility options, and a `SIMPLE` smart account instance. For further customization options, refer to the [Particle Connect documentation](https://developers.particle.network/api-reference/connect/desktop/web#configuration){target=\_blank}. At this point, you've signed up and created an application, installed all required dependencies, and configured `ParticleConnectKit` and `SmartAccount,` if applicable. ## Integrate the `ParticleConnectKit` Component in Your App {: #integrate-particleconnectkit } After completing the configuration, wrap your application with the `ParticleConnectKit` component to enable global access to the Particle Connect SDK. Update your `layout.tsx` file in `src` as shown below: ```js import { ParticleConnectkit } from "@/ConnectKit"; import type { Metadata } from "next"; import { Inter } from "next/font/google"; import "./globals.css"; const inter = Inter({ subsets: ["latin"] }); export const metadata: Metadata = { title: "Particle Connectkit App", description: "Generated by create next app", }; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( {children} ); } ``` Wrapping your application in `ParticleConnectKit` provides global access to the SDK, making features like social logins and wallet generation available throughout your app. This setup in `layout.tsx` ensures all components can access Particle Connect’s capabilities. ### Connecting Wallet With the configured `layout.tsx` file, the next step is to add a central **Connect Wallet** button for user connectivity. You can achieve this by importing `ConnectButton` from `@particle-network/connectkit`. Once the user logs in, the `ConnectButton` transforms into an embedded widget. ```js "use client"; import { ConnectButton, useAccount } from "@particle-network/connectkit"; const HomePage = () => { const { address, isConnected, chainId } = useAccount(); return (
{isConnected && ( <>

Address: {address}

Chain ID: {chainId}

)}
); }; export default HomePage; ``` ### Sending transactions with an EIP-1193 provider Using Particle Connect alongside the Particle AA SDK enables you to work with an EIP-1193 provider like ethers. This approach is beneficial because you're likely already familiar with these providers or if you integrate Particle Connect into an existing application. To set this up, wrap the smart account provided by Particle Connect with an instance of ethers to create a `customProvider.` You can use ethers as usual from there, with the smart account as the underlying transaction signer. ```js import {useSmartAccount } from "@particle-network/connectkit"; import { AAWrapProvider, SendTransactionMode } from "@particle-network/aa"; const smartAccount = useSmartAccount(); // Init custom provider with gasless transaction mode const customProvider = smartAccount ? new ethers.BrowserProvider( new AAWrapProvider( smartAccount, SendTransactionMode.Gasless ) as Eip1193Provider, "any" ) : null; /** * Sends a transaction using the ethers.js library. * This transaction is gasless since the customProvider is initialized as gasless */ const executeTxEthers = async () => { if (!customProvider) return; const signer = await customProvider.getSigner(); const tx = { to: recipientAddress, value: parseEther("0.01").toString(), }; const txResponse = await signer.sendTransaction(tx); const txReceipt = await txResponse.wait(); console.log(txReceipt?.hash) }; ``` ## Example of Utilization {: #example-of-utilization } With those above established, Particle Connect can be used similarly, as shown in the example application below. Specifically, this application creates a smart account on Moonbeam MainNet through social login, then uses it to send a gasless transaction of 0.001 GLMR with the ethers provider. ```js "use client"; import React, { useEffect, useState } from "react"; // Particle imports import { ConnectButton, useAccount, usePublicClient, useSmartAccount, } from "@particle-network/connectkit"; // Eip1193 and AA Provider import { AAWrapProvider, SendTransactionMode } from "@particle-network/aa"; // Only needed with Eip1193 provider import { ethers, type Eip1193Provider } from "ethers"; import { formatEther, parseEther } from "viem"; export default function Home() { const { isConnected, chain } = useAccount(); const publicClient = usePublicClient(); const smartAccount = useSmartAccount(); const [userAddress, setUserAddress] = useState(""); const [balance, setBalance] = useState(null); const [recipientAddress, setRecipientAddress] = useState(""); const [transactionHash, setTransactionHash] = useState(null); // Init custom provider with gasless transaction mode const customProvider = smartAccount ? new ethers.BrowserProvider( new AAWrapProvider( smartAccount, SendTransactionMode.Gasless ) as Eip1193Provider, "any" ) : null; /** * Fetches the balance of a given address. * @param {string} address - The address to fetch the balance for. */ const fetchBalance = async (address: string) => { try { const balanceResponse = await publicClient?.getBalance({ address: address as `0x${string}`, }); if (balanceResponse) { const balanceInEther = formatEther(balanceResponse).toString(); setBalance(balanceInEther); } else { setBalance("0.0"); } } catch (error) { console.error("Error fetching balance:", error); setBalance("0.0"); } }; /** * Loads the user's account data, including address and balance. */ useEffect(() => { const loadAccountData = async () => { if (isConnected && smartAccount) { try { const address = await smartAccount.getAddress(); setUserAddress(address); await fetchBalance(address); } catch (error) { console.error("Error loading account data:", error); } } }; loadAccountData(); }, [isConnected, smartAccount]); /** * Sends a transaction using the ethers.js library. * This transaction is gasless since the customProvider is initialized as gasless */ const executeTxEthers = async () => { if (!customProvider) return; const signer = await customProvider.getSigner(); try { const tx = { to: recipientAddress, value: parseEther("0.01").toString(), }; const txResponse = await signer.sendTransaction(tx); const txReceipt = await txResponse.wait(); setTransactionHash(txReceipt?.hash || null); } catch (error) { console.error("Failed to send transaction using ethers.js:", error); } }; return (
{isConnected && ( <>

Address: {userAddress || "Loading..."}

Balance: {balance || "Loading..."} {chain?.nativeCurrency.symbol}

setRecipientAddress(e.target.value)} className="mt-4 p-3 w-full rounded border border-gray-700 bg-gray-900 text-white focus:outline-none" /> {transactionHash && (

Transaction Hash: {transactionHash}

)}
)}
); } ``` That concludes the brief introduction to Particle's Smart Wallet-as-a-Service stack and how to get started with Particle on Moonbeam. For more information, you can check out [Particle Network's documentation](https://developers.particle.network/landing/introduction){target=\_blank}. Find the repository with the complete code implementation on the [Particle Network GitHub](https://github.com/Particle-Network/connect-moonbeam-tutorial){target=\_blank}.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/wallets/rainbowkit/ --- BEGIN CONTENT --- --- title: Add RainbowKit to a DApp description: Learn how to integrate RainbowKit into a dApp to allow users to connect their mobile wallets to Moonbeam, Moonriver, or Moonbase Alpha networks. categories: Tokens and Accounts --- # Integrate RainbowKit into a DApp ## Introduction {: #introduction } [RainbowKit](https://rainbowkit.com/docs/introduction){target=\_blank} is a React library that adds wallet connection capabilities to a dApp. It supports numerous wallets and enables features such as switching connection chains, ENS address resolution, and balance display out-of-the-box. RainbowKit offers customization options for all EVM-compatible chains, making it possible to easily connect mobile wallets to your Moonbeam dApps. RainbowKit bundles together multiple tools to simplify adding wallet connection to your dApp: - [Wagmi](https://wagmi.sh/){target=\_blank} - a React Hooks library for interacting with Ethereum accounts, wallets, contracts, transactions, signing, ENS, and more - [viem](https://viem.sh/){target=\_blank} - TypeScript interface which provides low-level stateless primitives for interacting with Ethereum - [WalletConnect](https://walletconnect.com/){target=\_blank} - adds encrypted connections and enhanced UX experiences like connecting a mobile wallet by scanning a QR code - [TanStack Query](https://tanstack.com/query/latest/docs/framework/react/overview){target=\_blank} - helps manage and update server state within the application This guide takes you through adding RainbowKit to a dApp using the CLI, adding support for Moonbeam networks, and some options for further customizing your integration. ## Quick Start {: #quick-start } If you are starting a new project, RainbowKit can scaffold a project from the CLI, combining RainbowKit and Wagmi in a [Next.js](https://nextjs.org/docs){target=\_blank} application. Use your package manager of choice to run the CLI command and start your project: === "npm" ```bash npm init @rainbow-me/rainbowkit@latest ``` === "pnpm" ```bash pnpm create @rainbow-me/rainbowkit@latest ``` === "yarn" ```bash yarn create @rainbow-me/rainbowkit ``` The script will prompt you for a project name, generate a new directory with the boilerplate starter code, and install all required dependencies.
npm init @rainbow-me/rainbowkit@latest 🌈 Welcome to RainbowKit! rainbow-demo 🚀 Creating a new RainbowKit app in /Users/dawnkelly/Documents/papermoon_builds/RainbowKit/add-rainbow-kit/rainbow-demo 📦 Installing dependencies with npm. This could take a while. 📚 Initializing git repository 🌈 Done! Thanks for using RainbowKit 🙏 👉 To get started, run cd rainbow-demo and then npm run dev
You can now navigate to the project directory, start the development server, and navigate to `http://localhost:3000` to view your project locally: === "npm" ```bash cd INSERT_PROJECT_NAME npm run dev ``` === "pnpm" ```bash cd INSERT_PROJECT_NAME pnpm run dev ``` === "yarn" ```bash cd INSERT_PROJECT_NAME yarn dev ``` Your starting screen should look like this: ![Scaffolded RainbowKit project landing page](/images/builders/integrations/wallets/rainbowkit/rainbowkit-1.webp) Open the project in your code editor and take a look at the directory and file structure, making note of the `wagmi.ts` file. This file is where you can customize which chains to include in the list of networks users can connect to through your dApp. Moonbeam, Moonriver, and Moonbase Alpha are not on the list of default supported networks. You can customize your dApp's supported networks in the `wagmi.ts` file by updating the chain entrypoints imported from `wagmi/chains` and passed to the `chains` property when `config` is defined. Wagmi uses [chain definitions](https://wagmi.sh/core/api/chains#available-chains) established by viem, primarily the chain name. The `wagmi/chains` names for Moonbeam networks are as follows: === "Moonbeam" ```js moonbeam ``` === "Moonriver" ```js moonriver ``` === "Moonbase Alpha" ```js moonbaseAlpha ``` To add support for Moonbeam networks, update `wagmi.ts` as follows. You will learn how to generate the `projectId` value in the next section. ```js title="src/wagmi.ts" import '@rainbow-me/rainbowkit/styles.css'; import { getDefaultConfig, RainbowKitProvider } from '@rainbow-me/rainbowkit'; import { WagmiProvider } from 'wagmi'; import { moonbeam, moonriver, moonbaseAlpha } from 'wagmi/chains'; import { QueryClientProvider, QueryClient } from '@tanstack/react-query'; export const config = getDefaultConfig({ appName: 'My Moonbeam App', projectId: 'process.env.NEXT_PUBLIC_PROJECT_ID', chains: [moonbeam, moonriver, moonbaseAlpha], ssr: true, }); ``` ## Manual Setup If you want to add RainbowKit to an existing React application, you can complete a manual setup. The following sections will guide you through using the manual setup to install and import needed dependencies, configure chain connections to support Moonbeam networks, and make RainbowKit functionality available to users of your dApp. You will also learn how to specify which chain the **Connect Wallet** button should connect to by default and how to customize the RainbowKit theme to fit your project. ### Checking Prerequisites {: #checking-prerequisites } The following guide assumes you have: - An existing dApp built with [React](https://react.dev/){target=\_blank} and you want to use the manual setup to connect to a mobile wallet via RainbowKit - The [RainbowKit examples repository](https://github.com/rainbow-me/rainbowkit/tree/main/examples){target=\_blank} includes templates for multiple React frameworks - To follow this guide, visit [Next.js](https://nextjs.org/docs){target=\_blank} and follow the **Automatic Installation** instructions, selecting Typescript and the App Router options during setup - A mobile wallet which supports Moonbeam out of the box or allows for adding custom networks - A WalletConnect `projectId` - every dApp relying on WalletConnect is required to have an associated `projectId`. It is free to create an account, and you can instantly generate an ID To obtain a WalletConnect `projectId`: 1. Visit [WalletConnect Cloud](https://cloud.walletconnect.com/){target=\_blank} 2. On the **Projects** page, select **Create** 3. Add your project information (you can leave **Homepage URL** blank if you have not deployed your dApp) 4. Select the **AppKit** SDK 5. Select your coding environment or platform (select React for this guide) 6. Locate your `projectId` in the left menu. You can also find it in the **Get started** code snippet of the WalletConnect Quickstart ### Getting Started {: #getting-started } Ensure you are in the root directory for your project, then install RainbowKit and its peer dependencies: === "npm" ```bash npm install @rainbow-me/rainbowkit wagmi viem@2.x @tanstack/react-query ``` === "pnpm" ```bash pnpm install @rainbow-me/rainbowkit wagmi viem@2.x @tanstack/react-query ``` === "yarn" ```bash yarn add @rainbow-me/rainbowkit wagmi viem@2.x @tanstack/react-query ``` Next, start the development server to create a local dApp instance: === "npm" ```bash npm run dev ``` === "pnpm" ```bash pnpm run dev ``` === "yarn" ```bash yarn dev ``` If you navigate to `http://localhost:3000`, you should see the starter Next.js application in your browser. To test the RainbowKit connection, you will use the MetaMask mobile app. To follow this guide, you must have established a connection to the Moonbase Alpha TestNet on the MetaMask mobile app. You can connect your MetaMask mobile wallet to the Moonbase Alpha TestNet in a couple of ways. You can manually add the Moonbase Alpha TestNet configurations from the **Networks** section of the **Settings** menu. Or you can also open up the **Browser** from MetaMask mobile and navigate to the [Moonbeam documentation site (docs.moonbeam.network)](/){target=\_blank}, click on **Connect MetaMask** at the top of the page, and select **Moonbase Alpha** from the menu. Follow the prompts to automatically add Moonbase Alpha as a custom network. Next, safely add your `projectId` to your application: 1. Create a `.env.local` file in the root directory of your project ```bash touch .env.local ``` 2. Add your `projectId` to this file ```text title=".env.local" NEXT_PUBLIC_PROJECT_ID='INSERT_PROJECT_ID' ``` 3. Locate your `.gitignore` file in this same directory and ensure `.env*.local` is included in the list of files to ignore. This will prevent committing your `projectId` to GitHub In the next section, you will use this stored `projectId` when setting up the `wagmi` config. ### Connect DApp to MetaMask Mobile {: #connect-dapp-to-metamask-mobile } In the next sections, you will complete the steps needed to use RainbowKit to connect your dApp to MetaMask's mobile wallet: 1. Import RainbowKit, Wagmi, and TanStack Query 2. Setup configuration for Wagmi 3. Wrap your application with providers 4. Add the connect button ### Import RainbowKit, Wagmi, and TanStack Query Ensure you are still in your project's root directory, then create a new file called `wagmi.ts`. This file will contain the imports and configuration needed to connect your dApp to mobile wallets and interact with blockchains. ```bash touch wagmi.ts ``` === "Moonbeam" ```js moonbeam ``` === "Moonriver" ```js moonriver ``` === "Moonbase Alpha" ```js moonbaseAlpha ``` Add the `wagmi/chains` import with `moonbeam`, `moonriver`, and `moonbaseAlpha` as the supported chains. ```ts title="wagmi.ts" import '@rainbow-me/rainbowkit/styles.css'; import { getDefaultConfig, RainbowKitProvider } from '@rainbow-me/rainbowkit'; import { WagmiProvider } from 'wagmi'; import { moonbeam, moonriver, moonbaseAlpha } from 'wagmi/chains'; import { QueryClientProvider, QueryClient } from '@tanstack/react-query'; export const config = getDefaultConfig({ appName: 'My Moonbeam App', projectId: 'process.env.NEXT_PUBLIC_PROJECT_ID', chains: [moonbeam, moonriver, moonbaseAlpha], ssr: true, }); ``` Now, setup the `config` to include Moonbeam networks by ensuring the `chains` array matches the list of chains in the `import` statement. Finally, update the `projectId` value to use the one stored in your `.env.local` file. ```ts title="wagmi.ts" export const config = getDefaultConfig({ appName: 'My Moonbeam App', projectId: 'process.env.NEXT_PUBLIC_PROJECT_ID', chains: [moonbeam, moonriver, moonbaseAlpha], ssr: true, }); ``` ### Wrap Your Application with Providers With the configuration in place, the next step is to wrap your application with the `RainbowKitProvider`, `WagmiProvider`, and `QueryClientProvider` to make them available throughout your dApp. In your terminal, navigate to the `app` directory in your project and create a file named `providers.tsx`: ```bash cd app && touch providers.tsx ``` Open `providers.tsx` and add the following code to define `Providers`: ```ts title="providers.tsx" 'use client'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { WagmiProvider } from 'wagmi'; import { RainbowKitProvider } from '@rainbow-me/rainbowkit'; import { config } from '../wagmi'; const queryClient = new QueryClient(); export function Providers({ children }: { children: React.ReactNode }) { return ( {children} ); } ``` Now locate the `layout.tsx` file inside the `app` directory and modify the code to import `Providers` and wrap the application: ```ts title="layout.tsx" import type { Metadata } from 'next'; import { Inter } from 'next/font/google'; import './globals.css'; import '@rainbow-me/rainbowkit/styles.css'; import { Providers } from './providers'; const inter = Inter({ subsets: ['latin'] }); export const metadata: Metadata = { title: 'My Moonbeam dApp', description: 'Generated by create next app', }; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( {children} ); } ``` Wrapping the application in the providers makes the functionalities of RainbowKit, Wagmi, and TanStack Query available throughout your dApp. This setup gives you the flexibility to add a wallet connection button anywhere in your project. ### Add the Connect Button RainbowKit offers a `ConnectButton` component, which renders the **Connect** and **Disconnect** buttons and UI elements for switching chains. This example imports the `ConnectButton` into the existing `page.tsx` file for simplicity, but you may want to add it to an element like a **Header** or **Navbar** so it appears at the top of each page. Update the code in `page.tsx` as follows: ```ts title="page.tsx" import Image from 'next/image'; import styles from './page.module.css'; import { ConnectButton } from '@rainbow-me/rainbowkit'; export default function Home() { return (
); } ``` If you haven't already, start the development server and spin up a local version of your dApp. Your home page should now include a visible **Connect Wallet** button. Click the button to test the connection. You should now see the RainbowKit modal with options to get or connect a wallet. Select **MetaMask** and follow the prompts to connect your wallet. The current configuration defaults to connecting to Moonbeam and displaying the current network, native token balance, an ENS or fallback avatar, and the connected wallet address. Select the arrow next to **Moonbeam** to open the **Switch Networks** modal. Select **Moonbase Alpha** and sign the MetaMask transaction to authorize switching networks. You should now see **Moonbase Alpha** listed as the connected network with your DEV token balance, avatar, and account number displayed. ## Customize Rainbow Kit Not only does RainbowKit abstract away the complexities of managing wallet connections, but the library offers several options for customizing UI and functionality to meet the needs of your dApp. You can find a complete list of customization options in the RainbowKit [documentation](https://rainbowkit.com/docs/introduction){target=\_blank}. This section covers customizing the **Connect Wallet** button to connect initially to Moonbase Alpha and render it in a custom color. ### Set Custom Initial Chain RainbowKit will connect by default to the first chain supplied to Wagmi in the config. If you compare the order of chains listed in `wagmi.ts` to those on the **Switch Networks** modal, you will see they are the same. If you wanted to always connect to the TestNet first, a simple fix would be to move `moonbaseAlpha` to the top of the chain list. However, assuming this default behavior will never change is not the most reliable option. Instead, you can use the `initialChain` prop that is part of the `RainbowKitProvider` element to define which chain the wallet should initially connect to when the user selects **Connect Wallet**. Open your `providers.tsx` file and update the code to configure the `initialChain` prop. You can pass either a chain ID or chain name from the [Wagmi Chains list](https://wagmi.sh/core/api/chains){target=\_blank}. ### Define Custom Theme Colors RainbowKit offers three built-in theme functions: `lightTheme`, `darkTheme`, and `midnightTheme`. These theme functions return a theme object, which you can pass into the `RainbowKitProvider` prop `theme` to set custom colors, border radius, font stack, and overlay blur. Update `providers.tsx` with the following code. Be sure to add `darkTheme` to the `@rainbow-me/rainbowkit`import statement to allow your changes to render correctly. After customizing the initial chain and theme, your `providers.tsx` file should look like the following: ```js title="providers.tsx" 'use client'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { WagmiProvider } from 'wagmi'; import { RainbowKitProvider, darkTheme } from '@rainbow-me/rainbowkit'; import { config } from '../wagmi'; import { moonbaseAlpha } from 'viem/chains'; const queryClient = new QueryClient(); export function Providers({ children }: { children: React.ReactNode }) { return ( {children} ); } ``` ## Handle Disconnections You can now disconnect MetaMask from your dApp and then reconnect to test your customizations. There are two options for completing this step. ### Disconnect from DApp {: #disconnect-from-dapp } RainbowKit includes a **Disconnect** button out of the box. To open the modal, select the arrow next to your account number. Click the **Disconnect** button. You should now see **Connect Wallet**; your account information should no longer be visible. ![Built in Disconnect button](/images/builders/integrations/wallets/rainbowkit/rainbowkit-2.webp) ### Disconnect from MetaMask Mobile {: #disconnect-from-metamask-mobile } Some users prefer to disconnect from their mobile wallet rather than use a button within a dApp. To use this method: 1. Select the MetaMask extension in your browser to open the modal 2. Select the three dots in the upper right corner of the MetaMask modal 3. Select **Connected sites** 4. Review the list of sites connected to your wallet 5. Select **Disconnect** for each site you want to disconnect ## Final Result {: #final-result } The **Connect Wallet** button on your home page should now render in the color you entered for `accentColor` when customizing the theme. When you click **Connect Wallet**, you will see the same accent color in use. Select MetaMask and sign the transaction to authorize the connection. You should now see **Moonbase Alpha** as the connected network and your DEV token balance for the account balance without manually switching networks. ![Theme customization on the user modal](/images/builders/integrations/wallets/rainbowkit/rainbowkit-3.webp) This guide includes only a few of the customization options available through RainbowKit. You can learn more about the capabilities and options of this library by visiting [RainbowKit Docs](https://rainbowkit.com/docs/introduction){target=\_blank}. You can view the complete example code in the [rainbow-manual-build-demo repository](https://github.com/papermoonio/rainbowkit-manual-build-demo){target=\_blank}
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/integrations/wallets/walletconnect/ --- BEGIN CONTENT --- --- title: Add WalletConnect to a DApp description: Learn how to integrate WalletConnect into a DApp built on any of the Moonbeam networks, specifically so users can connect with their mobile wallets. categories: Tokens and Accounts --- # Integrate WalletConnect into a DApp ## Introduction {: #introduction } [WalletConnect](https://walletconnect.com){target=\_blank} is an open protocol to communicate securely between wallets and DApps. WalletConnect establishes a remote connection between a DApp and mobile wallet by using a bridge server to relay payloads. The connection is initiated via a QR code displayed in a DApp, which will need to be scanned and approved by a mobile wallet. When a connection is established, the payloads between the DApp and wallet are encrypted through a shared key. ![WalletConnect flow](/images/builders/integrations/wallets/walletconnect/walletconnect-1.webp) WalletConnect can also be used to establish a connection between a DApp and a desktop wallet. However, this guide will only cover a mobile wallet connection. In this guide, you'll learn how to integrate WalletConnect into a simple DApp built on the Moonbase Alpha TestNet. The guide will be divided into a few different sections. The first section will cover connecting your DApp to MetaMask mobile. After the connection has been established, the guide will cover disconnections. This way, when you are testing your DApp you will be able to connect and then disconnect so you don't end up with a bunch of unnecessary WalletConnect sessions lingering in MetaMask mobile. Afterwards you will learn how to display network and account details when connected, and send transactions from your DApp to MetaMask mobile for confirmation. This guide is an adaptation of the [WalletConnect Example Dapp](https://example.walletconnect.org){target=\_blank} ([source code](https://github.com/WalletConnect/walletconnect-example-dapp){target=\_blank}). To view the end result, you can check out the [Moonbeam WalletConnect Demo app](https://moonbeam-walletconnect-demo.netlify.app){target=\_blank} ([source code](https://github.com/papermoonio/moonbeam-walletconnect-demo){target=\_blank}). ## Quick Start {: #quick-start } If you already have a DApp with WalletConnect support, and just want to add Moonbeam support, you can use the following network configurations: === "Moonbeam" ```js { name: "Moonbeam", short_name: "moonbeam", chain: "Moonbeam", network: "mainnet", chain_id: {{ networks.moonbeam.chain_id }}, network_id: {{ networks.moonbeam.chain_id }}, rpc_url: "{{ networks.moonbeam.public_rpc_url }}", native_currency: { symbol: "GLMR", name: "Glimmer", decimals: "18", contractAddress: "", balance: "", }, }, ``` === "Moonriver" ```js { name: "Moonriver", short_name: "moonriver", chain: "Moonriver", network: "mainnet", chain_id: {{ networks.moonriver.chain_id }}, network_id: {{ networks.moonriver.chain_id }}, rpc_url: "{{ networks.moonriver.public_rpc_url }}", native_currency: { symbol: "MOVR", name: "Moonriver", decimals: "18", contractAddress: "", balance: "", }, }, ``` === "Moonbase Alpha" ```js { name: "Moonbase Alpha", short_name: "moonbase", chain: "Moonbase", network: "testnet", chain_id: {{ networks.moonbase.chain_id }}, network_id: {{ networks.moonbase.chain_id }}, rpc_url: "{{ networks.moonbase.rpc_url }}", native_currency: { symbol: "DEV", name: "DEV", decimals: "18", contractAddress: "", balance: "", }, }, ``` ## Checking Prerequisites {: #checking-prerequisites } Throughout this guide, you'll use a simple front-end dApp built with [React](https://react.dev){target=\_blank} to connect to a mobile wallet via WalletConnect. So, you will need a React project and the MetaMask mobile app installed for testing purposes. A template has been created that includes the required packages, some basic styling, and placeholders where logic and UI elements must be added. However, if you would like to use your own dApp, you'll need to install the following required dependencies: ```bash npm install ethers @walletconnect/client @walletconnect/qrcode-modal ``` This guide will use MetaMask mobile for testing purposes. To install MetaMask mobile, you can go to [metamask.io/download/](https://metamask.io/download){target=\_blank} and switch to either the **iOS** or **Android** tab. Lastly, you will need to have an account funded with DEV tokens, so that you can test out sending a transaction. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank}. ## Getting Started {: #getting-started } To get started quickly with the Moonbeam WalletConnect template, which provides everything you need to dive right in, you'll need to take the following steps: 1. Clone the [walletconnect-template GitHub repository](https://github.com/papermoonio/moonbeam-walletconnect-template){target=\_blank} 2. Run `npm install` to install the required dependencies 3. Run `npm start` to spin up a local instance of the DApp To test the WalletConnect connection, you can use the MetaMask mobile app. For the purposes of this guide, you will need to already be connected to the Moonbase Alpha TestNet on the MetaMask mobile app. Later on in the guide, you will learn how to check if the connected network is a supported network, and if not display an error that will suggest users to switch to a network that is supported. There are a couple of ways you can connect your MetaMask mobile wallet to the Moonbase Alpha TestNet. You can manually add the Moonbase Alpha TestNet configurations from the **Networks** section of the **Settings** menu. Or you can also open up the **Browser** from MetaMask mobile and navigate to [docs.moonbeam.network](/){target=\_blank}, click on **Connect MetaMask** at the top of the page, and select **Moonbase Alpha** from the menu. This will prompt you to automatically add Moonbase Alpha as a custom network and saves you from inputting the network configurations manually. ## Connect DApp to MetaMask Mobile {: #connect-dapp-to-metamask-mobile } In this section, you will learn how to make a connection between your DApp and MetaMask mobile. WalletConnect establishes a remote connection between a DApp and mobile wallet by using a bridge server to relay payloads. The connection is initiated via a QR code displayed in the DApp, which will need to be scanned and approved by the mobile wallet. To get started, you can open up the [`App.js` file of the template](https://github.com/papermoonio/moonbeam-walletconnect-template/blob/main/src/App.js){target=\_blank} and the first changes will be made within the `connect` function. This function will handle the connection logic by creating a new instance of the WalletConnect connector. You'll notice that the `setFetching` state hook is already in place. This will be used to set the `fetching` state variable to `true` while the connection is being established. In general the `connect` function will: 1. Create the WalletConnect Connector and pass in the URL for the bridge server and the WalletConnect QR code modal 2. Use the `setConnector` state hook to update the `connector` state variable 3. Check if the connection has been established, and if not create a new session request ```js const connect = async () => { setFetching(true); // 1. Create connector const connector = new WalletConnect({ bridge: 'https://bridge.walletconnect.org', qrcodeModal: QRCodeModal, }); // 2. Update the connector state setConnector(connector); // 3. If not connected, create a new session if (!connector.connected) { await connector.createSession(); } }; ``` Now that you have the `connect` function setup, you can create a **Connect Wallet** button that will call it `onClick`. You can replace the `{/* buttons and network details will go here */}` comment in the [template](https://github.com/papermoonio/moonbeam-walletconnect-template/blob/main/src/App.js#L124){target=\_blank} with the following button: ```js ``` To test out the code so far, if you haven't already you can run `npm start` to spin up a local instance of your DApp. Then click on **Connect Wallet**. The WalletConnect QR code modal will pop-up. ![Scan QR code from DApp](/images/builders/integrations/wallets/walletconnect/walletconnect-2.webp) To establish the connection from MetaMask mobile, you can: 1. Click on the scan icon in the top right corner and scan the QR code 2. A window will pop-up at the bottom of the screen and prompt you to connect to the DApp. Click **Connect** 3. If you were able to successfully connect, you will see a pop-up in MetaMask that says **Connected to Moonbeam WalletConnect Demo App** ![Connect WalletConnect on MetaMask mobile](/images/builders/integrations/wallets/walletconnect/walletconnect-3.webp) Currently, your DApp will still show the **Connect Wallet** button, so the next step will be to display a **Disconnect** button when connected instead. ## Handle Disconnections When you're developing your DApp and the WalletConnect integration, it is important to handle disconnections so that you can properly test the flow of the integration. You also don't want to end up with a bunch of lingering WalletConnect sessions within MetaMask mobile. If at any time, you need to manually end a session, you can do so from MetaMask mobile by naivgating to **Settings** and take the following steps: 1. Select **Experimental** 2. Under **WalletConnect Sessions**, tap on **View Sessions** 3. To remove a specific session, you can hold down on the session 4. A pop-up will appear at the bottom of the screen where you can then tap **End**. ![End WalletConnect Session on MetaMask mobile](/images/builders/integrations/wallets/walletconnect/walletconnect-4.webp) Although this is important for development, this way of disconnecting a session can also be done by a user. The next couple of sections will cover the logic for how to handle disconnections from your DApp and from MetaMask mobile. ### Disconnect from DApp {: #disconnect-from-dapp } To make it easy for users, your DApp should have a **Disconnect** button that will end the active session on their mobile wallet. First you can create the logic and then you can create the button. Upon disconnecting, you will need to reset the state of your DApp back to the initial state. To reset the state, you can create a `resetApp` function that uses the state hooks. ```js const resetApp = () => { setConnector(null); setFetching(false); }; ``` In addition to resetting the state of the DApp, you will also need to kill the session using the `connector` and the WalletConnect `killSession` function. Since all of this functionality should happen when the user clicks on the **Disconnect** button, you can create a single `killSession` function to handle the reset and the disconnection. ```js const killSession = () => { // Make sure the connector exists before trying to kill the session if (connector) { connector.killSession(); } resetApp(); }; ``` Now that you have all of the logic required to handle the disconnection, you will need the **Disconnect** button that `onClick` will call the `killSession` function. Since you only want to display the **Disconnect** button once a user is connected, you can use [conditional rendering](https://react.dev/learn/conditional-rendering){target=\_blank}. Conditional rendering allows you to check against certain variables and if a condition applies you can render one element or another. In this case, if you are not fetching the initial connection and the connector exists, you can render the **Disconnect** button, otherwise render the **Connect Wallet** button. You can replace the existing ` ); } ``` If you go to test the disconnection logic and nothing happens when you click **Connect Wallet**, make sure you have manually ended any preexisting sessions from MetaMask mobile. If you're still running into problems, do a hard refresh on your browser. Now when a user clicks on **Disconnect** the DApp will be reset, the connection will be disconnected on the user's mobile wallet, and the **Connect Wallet** button will be displayed again. ### Disconnect from MetaMask Mobile {: #disconnect-from-metamask-mobile } As previously mentioned, a user can also disconnect and end the session from within their mobile wallet. If this happens, WalletConnect emits a `disconnect` event that the DApp will need to listen for. Upon receiving the `disconnect` event, the state will need to be reset back to the initial state. In this scenario, there is no reason to use `killSession` to end the session on the mobile wallet as the user has already ended the session on their mobile wallet. You'll notice that in the template, the `disconnect` event is listened for within the [React Effect Hook](https://react.dev/learn/synchronizing-with-effects){target=\_blank}. The effect hook lets you perform side effects in function components such as fetching data and setting up a subscription. In the `disconnect` event callback, you can add the `resetApp` function so that whenever a `disconnect` event is emitted, you reset the state of your DApp. ```js connector.on('disconnect', async (error) => { if (error) { // Handle errors as you see fit console.error(error); } resetApp(); }); ``` So far you've setup the minimum logic required for connecting and disconnecting your DApp and the MetaMask mobile app. When the connection has been established, a **Disconnect** button is now displayed. In the next section, you'll expand on what is displayed when connected to include account and network details. ## Check Network Support & Display Results {: #check-network-support-display-result } With the basics of connecting and disconnecting out of the way, you can expand on what is displayed in the DApp when a user is connected. The first thing you'll want to do is check if the network they are on is supported and if not display a message that requests them to switch the network. The template comes with a list of supported networks, you can find it under [`src/helpers/networks.js`](https://github.com/papermoonio/moonbeam-walletconnect-template/blob/main/src/helpers/networks.js){target=\_blank}. For the purposes of this guide, Moonbase Alpha is the only one that you'll be testing but you can feel free to uncomment the Moonbeam and Moonriver network configurations and add additional networks as needed. You can add the logic to check if the connected network is supported to the `onConnect` function. The `onConnect` function is called anytime a `connect` event is emitted. If the user is connected to a supported network, you can display network details such as the chain ID, network name, and more. You can add the following state variables and hooks: ```js const [account, setAccount] = useState(null); const [chainId, setChainId] = useState(null); const [supported, setSupported] = useState(false); const [network, setNetwork] = useState(null); const [symbol, setSymbol] = useState(null); ``` Make sure that you also add these state hooks in the `resetApp` function, so that all of the state variables can be reset to their initial state. You'll notice that the `onConnect` function already accepts two parameters: the connected chain ID and account. You can set the state variables for the `chainId` and `account` then check to see if the network is supported. You'll use the chain ID to see if the network exists in the list of supported networks. If it does, you can use the `setSupported` state hook to set the state to `true`, and if not set it to `false`. ```js const onConnect = async (chainId, connectedAccount) => { setAccount(connectedAccount); setChainId(chainId); // get chain data const networkData = SUPPORTED_NETWORKS.filter( (chain) => chain.chain_id === chainId )[0]; if (!networkData) { setSupported(false); } else { setSupported(true); // set additional network data here } }; ``` If the network does exist in the list of supported networks, you can then save additional network name and symbol. The symbol will be used later on to display the connected account's balance. You can replace the `// set additional network data here` comment with the following: ```js setNetwork(networkData.name); setSymbol(networkData.native_currency.symbol); ``` You will also need to update the `useEffect` dependency array to include the `chainId` and `account` state variables so that it re-renders with any changes to either variable. ```js useEffect(() => { ... }, [connector, chainId, account]); ``` Then to render these state variables on the page, you can include additional UI elements alongside the **Disconnect** button. Again, you can use conditional rendering to display specific details or an error message if the network is supported or not. ```js { connector && !fetching ? ( Connected Account: {account} Chain ID: {chainId} {supported ? ( <> Network: {network} ) : ( Network not supported. Please disconnect, switch networks, and connect again. )} Disconnect ) : ( ); } ``` You can adapt the above code snippet as needed to provide better error handling. ## Refresh Data {: #refresh-data } While you're developing the DApp, you'll want to handle page refreshes and update the data as needed based on the WalletConnect connection. Otherwise, you might find yourself manually disconnecting from MetaMask mobile more often then not. The template already has a `refreshData` function, it just needs to be called under certain circumstances. If the `connector` exists and is connected, but the `chainId` or `account` doesn't you should call the `refreshData` function and use the `connector` configurations to update state and re-render the variables on the page. You can replace the `// check state variables here & if needed refresh the app` [comment](https://github.com/papermoonio/moonbeam-walletconnect-template/blob/main/src/App.js#L84){target=\_blank} with the following: ```js // If any of these variables do not exist and the connector is connected, refresh the data if ((!chainId || !account) && connector.connected) { refreshData(); } ``` You can test this logic out by refreshing the page after establishing a connection. Instead of defaulting to the **Connect Wallet** button, you'll see that the account and network details, and the **Disconnect** button are displayed. ## Add Account Balance {: #add-account-balance } Depending on your needs, you might want to show the connected account's balance for the connected network. To do so, you can use [Ethers](https://docs.ethers.org/v6){target=\_blank} to create a provider which can then be used to fetch the balance of the connected account. You can start by adding another state variable for `balance`. ```js const [balance, setBalance] = useState(null); ``` Make sure that you add this state hook in the `resetApp` function, and use it to reset the balance variable to its initial state. For simplicity, you can add the logic for fetching the account balance and saving it to state directly in the `onConnect` function. You will need to: 1. Create an Ethers provider by passing in the network's RPC url, chain ID, and name 2. Use the provider to call `getBalance`, which will return the balance as a `BigNumber` 3. Convert the `BigNumber` representation of the balance to a string representation of the balance in Ether 4. Use the `setBalance` state hook to save the balance to state ```js const onConnect = async (chainId, address) => { setAccount(address); const networkData = SUPPORTED_NETWORKS.filter( (network) => network.chain_id === chainId )[0]; if (!networkData) { setSupported(false); } else { setSupported(true); setNetwork(networkData.name); setSymbol(networkData.native_currency.symbol); setChainId(chainId); // 1. Create an Ethers provider const provider = new ethers.JsonRpcProvider(networkData.rpc_url, { chainId, name: networkData.name, }); // 2. Get the account balance const balance = await provider.getBalance(address); // 3. Format the balance const formattedBalance = ethers.formatEther(balance); // 4. Save the balance to state setBalance(formattedBalance); } }; ``` You will need to add the `balance` state variable to the `useEffect` dependency array alongside the `connector`, `chainId`, and `account` variables. You can also use the `balance` state variable to refresh the data on the page. ```js // If any of these variables do not exist and the connector is connected, refresh the data if ((!chainId || !account || !balance) && connector.connected) { refreshData(); } ``` Finally, you can display the account balance if the user is connected to a supported network. You can use the `symbol` state variable that was created earlier on in the guide to show the balance in **DEV** for Moonbase Alpha. ```js { supported ? ( <> Network: {network} Balance: {balance} {symbol} ) : ( Network not supported. Please disconnect, switch networks, and connect again. ); } ``` This example can be adapted to retrieve other data from Ethers as needed. ## Send a Transaction {: #send-a-transaction } To truly take advantage of the value that WalletConnect provides, you can send a transaction which will be initiated from within your DApp and then confirmed and signed from MetaMask mobile. To get started, you will need to update the `sendTransaction` function that has already been created in the template. The function will use the WalletConnect `connector` to send a transaction. For example purposes, you can send 2 DEV tokens on Moonbase Alpha to your own account. ```js const sendTransaction = async () => { try { await connector.sendTransaction({ from: account, to: account, value: '0x1BC16D674EC80000', }); } catch (e) { // Handle the error as you see fit console.error(e); } }; ``` To initiate the transaction from the DApp, you will need to create a button, that `onClick` calls the `sendTransaction` function. This should only be done if the connected network is a supported network. ```js { supported ? ( <> Network: {network} Balance: {balance} {symbol} Send Transaction ) : ( Network not supported. Please disconnect, switch networks, and connect again. ); } ``` When you click on **Send Transaction**, a pop-up will appear in MetaMask mobile with the transaction details: 1. To sign and send the transaction, you can click on **Confirm** 2. If successful you should see a notification in the MetaMask mobile app ![Send Transaction](/images/builders/integrations/wallets/walletconnect/walletconnect-5.webp) You can also confirm the transaction went through by searching for your account in a block explorer such as [Moonscan](https://moonbase.moonscan.io){target=\_blank}. ## Final Result {: #final-result } ![DApp Final Result](/images/builders/integrations/wallets/walletconnect/walletconnect-6.webp) To review the code for this tutorial in one place, you can check out the [moonbeam-walletconnect-demo GitHub repository](https://github.com/papermoonio/moonbeam-walletconnect-demo){target=\_blank}. To see all of the code in action, you can check out the deployed [Moonbeam WalletConnect Demo App](https://moonbeam-walletconnect-demo.netlify.app){target=\_blank}. ## Additional Considerations {: #additional-considerations } This guide covers the basics for setting up a WalletConnect connection, but there are many ways in which you can improve the experience for your users or yourself as you develop the integration. You might want to consider adding in support for the following items: - Adding a loader for when your transaction is waiting to be confirmed or a message that informs your users to check their mobile wallet and confirm the transaction from there - Adding notifications on your DApp for the status of sent transactions - Adding appropriate error handling - Adding in logic to automatically update your users balances --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/ --- BEGIN CONTENT --- --- title: Interoperability description: Learn about interoperability on Moonbeam by diving into how cross-consensus messaging (XCM) works and exploring available cross-chain protocols. dropdown_description: GMP protocols for cross-chain development template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/mrl/ --- BEGIN CONTENT --- --- title: Moonbeam Routed Liquidity description: Learn how to receive Moonbeam Routed Liquidity after establishing a cross-chain integration with a Moonbeam-based network. categories: XCM --- # Moonbeam Routed Liquidity ## Introduction {: #introduction } Moonbeam Routed Liquidity (MRL) refers to a use case in which liquidity in any blockchain ecosystem that Moonbeam is connected to can be routed to Polkadot parachains. This is possible because of multiple components that work together: - **General Message Passing (GMP)** - technology connecting multiple blockchains, including Moonbeam. With it, developers can pass messages with arbitrary data, and tokens can be sent across non-parachain blockchains through [chain-agnostic GMP protocols](/builders/interoperability/protocols/){target=\_blank} - [**Cross-Consensus Message Passing (XCM)**](/builders/interoperability/xcm/overview/){target=\_blank} - Polkadot's flavor of GMP. Main technology driving cross-chain interactions between Polkadot and its parachains, including Moonbeam - **XCM-Enabled ERC-20s** - also referred to as [local XC-20s](/builders/interoperability/xcm/xc20/overview/#local-xc20s){target=\_blank}, are all of the ERC-20 tokens that exist on Moonbeam's EVM that are XCM-enabled out of the box - [**GMP Precompile**](/builders/ethereum/precompiles/interoperability/gmp/){target=\_blank} - a [precompiled contract](/builders/ethereum/precompiles/overview/){target=\_blank} that acts as an interface between a message passed from [Wormhole GMP protocol](/builders/interoperability/protocols/wormhole/){target=\_blank} and XCM These components are combined to offer seamless liquidity routing into parachains through Moonbeam. Liquidity can be routed to parachains using either the [GMP Precompile](/builders/ethereum/precompiles/interoperability/gmp/){target=\_blank} or traditional smart contracts that interact with XCM-related precompiles, like the [X-Tokens](/builders/interoperability/xcm/xc20/send-xc20s/xtokens-precompile/){target=\_blank} Precompile. GMP protocols typically move assets in a lock/mint or burn/mint fashion. This liquidity exists on Moonbeam normally as ERC-20 tokens. All ERC-20s on Moonbeam are now XCM-enabled, meaning they can now exist as XC-20s in any other parachain, as long as they are registered on the other parachain. XCM-enabled ERC-20s are referred to as [local XC-20s](/builders/interoperability/xcm/xc20/overview/#local-xc20s){target=\_blank} on Moonbeam. MRL is currently available through Wormhole-connected chains, but nothing stops a parachain team from implementing a similar pathway through a different GMP provider. This guide will primarily cover the process of integrating with Wormhole's SDKs and interfaces so that your parachain can access liquidity from non-parachain blockchains through Moonbeam. It will also cover the requirements to get started and the tokens available through Wormhole. ## Prerequisites {: #prerequisites } To begin an MRL integration with your parachain, you will first need to: - [Establish a cross-chain integration with Moonbeam via HRMP channels](/builders/interoperability/xcm/xc-registration/xc-integration/){target=\_blank} so assets can be sent from Moonbeam to your parachain - [Register Moonbeam’s asset on your parachain](/builders/interoperability/xcm/xc-registration/assets/#register-moonbeam-native-assets){target=\_blank}. This is required due to a temporary drawback of pallets that send XCM messages for asset transfer, making Moonbeam’s native gas asset the only asset that can be used as a cross-chain fee on the way back - [Register the local XC-20 token(s) you want routed to your parachain](/builders/interoperability/xcm/xc-registration/assets/#register-local-xc20){target=\_blank} - Allow these local XC-20 token(s) to be used for XCM fees - Allow users to send the `Transact` XCM instruction (via `polkadotXcm.Send` or with the [XCM Transactor Pallet](/builders/interoperability/xcm/remote-execution/substrate-calls/xcm-transactor-pallet/#xcm-transactor-pallet-interface){target=\_blank}), which enables remote EVM calls, allowing accounts on a remote parachain to interact with the bridging smart contracts on Moonbeam ## MRL Through Wormhole {: #mrl-through-wormhole } While MRL intends to encompass many different GMP providers, Wormhole is the first built for the public.After you have completed all of the [prerequisites](#prerequisites), to receive liquidity through Wormhole, you'll need to: - Notify the Moonbeam team of your desire to integrate into the MRL program so that we can help you with the technical implementation - Connect with the Wormhole team and other MRL-dependent frontends to finalize technical details and sync announcements. They will likely need the following information: - Parachain ID - The account type that your parachain uses (i.e., AccountId32 or AccountKey20) - The addresses and names of the tokens that you have registered - An endpoint that a [Wormhole Connect](https://wormhole.com/products/connect){target=\_blank} frontend can use - Why do you want your parachain to be connected through Wormhole Connect? ### Send Tokens Through Wormhole to a Parachain {: #sending-tokens-through-wormhole } MRL provides a one-click solution that allows you to define a multilocation as the final destination for your assets arriving from any Wormhole chain with a [Wormhole Connect integration](https://wormhole.com/products/connect){target=\_blank}. To send tokens through Wormhole and MRL, user interfaces will use a mixture of the [Wormhole TokenBridge](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/interfaces/ITokenBridge.sol){target=\_blank} and [Moonbeam’s GMP Precompile](/builders/ethereum/precompiles/interoperability/gmp/){target=\_blank}. Users transferring liquidity will invoke the `transferTokensWithPayload` method on the origin chain's deployment of the Wormhole TokenBridge smart contract, which implements the `ITokenBridge.sol` interface to send tokens to the GMP Precompile. This function requires a bytes payload, formatted as a SCALE-encoded multilocation object wrapped within another precompile-specific versioned type. To learn how to build this payload, please refer to the [Building the Payload for Wormhole](/builders/ethereum/precompiles/interoperability/gmp/#building-the-payload-for-wormhole){target=\_blank} section of the GMP Precompile documentation. Wormhole relies on a set of distributed nodes that monitor the state on several blockchains. In Wormhole, these nodes are referred to as [Guardians](https://wormhole.com/docs/protocol/infrastructure/guardians/){target=\_blank}. The Guardian's role is to observe messages and sign the corresponding payloads. If 2/3rds of Wormhole's signing Guardians validate a particular message, the message becomes approved and can be received on other chains. The Guardian signatures and the message form a proof called a [Verified Action Approval (VAA)](https://wormhole.com/docs/protocol/infrastructure/vaas/){target=\_blank}. These VAAs are delivered to their destinations by [relayers](https://wormhole.com/docs/protocol/infrastructure/relayer/){target=\_blank} within the Wormhole network. On the destination chain, the VAA is used to perform an action. In this case, the VAA is passed into the `wormholeTransferERC20` function of the GMP Precompile, which processes the VAA through the Wormhole bridge contract (which mints the tokens) and relays the tokens to a parachain using XCM messages. Please note that as a parachain integrating MRL, you will likely not need to implement or use the GMP Precompile. A relayer's only job is to pass the transactions approved by Wormhole Guardians to the destination chain. MRL is supported by some relayers already, but anyone can run one. Furthermore, users can manually execute their transaction in the destination chain when bridging through Wormhole and avoid relayers altogether. ![Transferring wormhole MRL](/images/builders/interoperability/mrl/mrl-1.webp) ### Send Tokens From a Parachain Back Through Wormhole {: #sending-tokens-back-through-wormhole } To send tokens from a parachain back through Wormhole to a destination chain, a user must send a transaction, preferably using the `utility.batchAll` extrinsic, which will batch a token transfer and a remote execution action into a single transaction. For example, a batch with a `xTokens.transferMultiassets` call and a `polkadotXcm.send` call with the `Transact` instruction. The reason for batching is to offer a one-click solution. Nevertheless, for now, the user must also own xcGLMR (representation of GLMR) on the parachain. There are two main reasons as to why: - Local XC-20s (XCM-enabled ERC-20s) can't be used to pay for XCM execution on Moonbeam. This was a design decision, as it was preferred to treat them as ERC-20s and utilize the native `transfer` function of the ERC-20 interface. Consequently, XCM instructions handling the XC-20s are only limited to moving funds from one account to another and don't understand the Holding Register that is inherent to the XCM flow - Currently, XCM-related pallets limit XCM messages' ability to send tokens with different reserve chains. Consequently, you can't send an XC-20 and set the fee token to be the native parachain token Note that as of late 2024, the X-Tokens precompile now uses the Polkadot XCM pallet under the hood, replacing the X-Tokens pallet. Parachains using a different pallet must implement their own solution to transfer reserve and non-reserve assets in a single message. As an example, a brief overview of the entire process of sending MRL tokens from a parachain back through Wormhole to a destination chain is as follows: 1. Send a batch transaction using the `batchAll` extrinsic of the [Utility Pallet](/builders/substrate/interfaces/utility/utility/){target=\_blank} that contains the following two calls: - **`xTokens.transferMultiassets`** - sends xcGLMR and the local XC-20 to the user’s [Computed Origin account](#calculate-computed-origin-account). The Computed Origin account is a keyless account on Moonbeam that an account on another parachain has control of via XCM - **`polkadotXcm.send`** - with the `Transact` instruction. Sends a [remote EVM call via XCM](/builders/interoperability/xcm/remote-execution/remote-evm-calls/){target=\_blank} to the Batch Precompile on Moonbeam, which batches the following two calls into a single remote EVM transaction using the `ethereumXcm.transact` extrinsic: - **`approve`** (of the local XC-20 contract) - approves the Wormhole relayer to transfer the local XC-20 - **`transferTokensWithRelay`** (of the relayer contract) - calls the `transferTokensWithPayload` function of the Wormhole TokenBridge smart contract on Moonbeam to transfer the tokens cross-chain, which broadcasts the message for the Wormhole Guardians to pick up 2. The Guardian Network will pick up on the Wormhole transaction and sign it 3. A Wormhole relayer will relay the tokens to the destination chain and destination account ![Transferring Wormhole MRL out](/images/builders/interoperability/mrl/mrl-2.webp) Now that you have a general idea of the game plan, you can begin implementing it. The example in this guide will show you how to transfer assets from a parachain to Moonbase Alpha and back through Wormhole to the destination chain, but this guide can be adapted for Moonbeam. #### Calculate the Computed Origin Account {: #calculate-computed-origin-account } To send tokens back through Wormhole, you'll need to calculate the user's Computed Origin account (previously referred to as a multilocation-derivative account) on Moonbeam. This can be done off-chain using the [`calculate-multilocation-derivative-account.ts` script](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/calculate-multilocation-derivative-account.ts){target=\_blank} from the [xcm-tools repository](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank}. For more details, you can refer to the [Computed Origins](/builders/interoperability/xcm/remote-execution/computed-origins/){target=\_blank} guide. Alternatively, the `multilocationToAddress` function of the [XCM Utilities Precompile](/builders/interoperability/xcm/xcm-utils/){target=\_blank} can also be used. #### Create a Project {: #create-a-project } You'll need to create a new project directory for the files you'll be building in this guide. Take the following steps to set up your project: 1. Create a new directory and change into the directory ```bash mkdir wormhole-mrl-demo && cd wormhole-mrl-demo ``` 2. Create a `package.json` file: ```bash npm init -y ``` 3. Install packages that you'll need to build the remote EVM calls and the XCM extrinsics ```bash npm i @polkadot/api ethers ``` 4. Create the files that you'll need for this guide: - `build-transfer-multiassets-call.js` - for creating the `xTokens.transferMultiassets` extrinsic that transfers assets cross-chain. This contains the logic for the first call of the batch transaction - `build-remote-calldata.js` - for creating the encoded calldata that approves the Wormhole relayer to transfer the local XC-20 and initiates the transfer via the Wormhole TokenBridge contract. This is required for the second call of the batch transaction - `build-remote-evm-call.js` - to create the `polkadotXcm.send` extrinsic that executes the remote EVM call. This contains the logic for the second call of the batch transaction - `send-batch-transaction.js` - for assembling and sending the batch transaction for the asset transfer and the remote EVM call ```bash touch build-transfer-multiassets.js build-remote-calldata.js \ build-remote-evm-call.js send-batch-transaction.js ``` 5. Create a directory and files for the ABIs of each of the contracts you'll be working within this guide: ```bash mkdir abi && touch abi/ERC20.js abi/TokenRelayer.js abi/Batch.js ``` ??? code "ERC-20 Interface ABI" ```js title="ERC20.js" export default [ { anonymous: false, inputs: [ { indexed: true, internalType: 'address', name: 'owner', type: 'address', }, { indexed: true, internalType: 'address', name: 'spender', type: 'address', }, { indexed: false, internalType: 'uint256', name: 'value', type: 'uint256', }, ], name: 'Approval', type: 'event', }, { anonymous: false, inputs: [ { indexed: true, internalType: 'address', name: 'from', type: 'address', }, { indexed: true, internalType: 'address', name: 'to', type: 'address', }, { indexed: false, internalType: 'uint256', name: 'value', type: 'uint256', }, ], name: 'Transfer', type: 'event', }, { inputs: [ { internalType: 'address', name: 'owner', type: 'address', }, { internalType: 'address', name: 'spender', type: 'address', }, ], name: 'allowance', outputs: [ { internalType: 'uint256', name: '', type: 'uint256', }, ], stateMutability: 'view', type: 'function', }, { inputs: [ { internalType: 'address', name: 'spender', type: 'address', }, { internalType: 'uint256', name: 'amount', type: 'uint256', }, ], name: 'approve', outputs: [ { internalType: 'bool', name: '', type: 'bool', }, ], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ { internalType: 'address', name: 'account', type: 'address', }, ], name: 'balanceOf', outputs: [ { internalType: 'uint256', name: '', type: 'uint256', }, ], stateMutability: 'view', type: 'function', }, { inputs: [], name: 'totalSupply', outputs: [ { internalType: 'uint256', name: '', type: 'uint256', }, ], stateMutability: 'view', type: 'function', }, { inputs: [ { internalType: 'address', name: 'to', type: 'address', }, { internalType: 'uint256', name: 'amount', type: 'uint256', }, ], name: 'transfer', outputs: [ { internalType: 'bool', name: '', type: 'bool', }, ], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ { internalType: 'address', name: 'from', type: 'address', }, { internalType: 'address', name: 'to', type: 'address', }, { internalType: 'uint256', name: 'amount', type: 'uint256', }, ], name: 'transferFrom', outputs: [ { internalType: 'bool', name: '', type: 'bool', }, ], stateMutability: 'nonpayable', type: 'function', }, ]; ``` ??? code "TokenBridge Relayer ABI" ```js title="TokenRelayer.js" export default [ { inputs: [ { internalType: 'uint16', name: 'targetChainId', type: 'uint16', }, { internalType: 'address', name: 'token', type: 'address', }, { internalType: 'uint8', name: 'decimals', type: 'uint8', }, ], name: 'calculateRelayerFee', outputs: [ { internalType: 'uint256', name: 'feeInTokenDenomination', type: 'uint256', }, ], stateMutability: 'view', type: 'function', }, { inputs: [ { internalType: 'address', name: 'token', type: 'address', }, { internalType: 'uint256', name: 'amount', type: 'uint256', }, { internalType: 'uint256', name: 'toNativeTokenAmount', type: 'uint256', }, { internalType: 'uint16', name: 'targetChain', type: 'uint16', }, { internalType: 'bytes32', name: 'targetRecipient', type: 'bytes32', }, { internalType: 'uint32', name: 'batchId', type: 'uint32', }, ], name: 'transferTokensWithRelay', outputs: [ { internalType: 'uint64', name: 'messageSequence', type: 'uint64', }, ], stateMutability: 'payable', type: 'function', }, { inputs: [ { internalType: 'uint256', name: 'toNativeTokenAmount', type: 'uint256', }, { internalType: 'uint16', name: 'targetChain', type: 'uint16', }, { internalType: 'bytes32', name: 'targetRecipient', type: 'bytes32', }, { internalType: 'uint32', name: 'batchId', type: 'uint32', }, ], name: 'wrapAndTransferEthWithRelay', outputs: [ { internalType: 'uint64', name: 'messageSequence', type: 'uint64', }, ], stateMutability: 'payable', type: 'function', }, ]; ``` ??? code "Batch Precompile ABI" ```js title="Batch.js" export default [ { anonymous: false, inputs: [ { indexed: false, internalType: 'uint256', name: 'index', type: 'uint256', }, ], name: 'SubcallFailed', type: 'event', }, { anonymous: false, inputs: [ { indexed: false, internalType: 'uint256', name: 'index', type: 'uint256', }, ], name: 'SubcallSucceeded', type: 'event', }, { inputs: [ { internalType: 'address[]', name: 'to', type: 'address[]', }, { internalType: 'uint256[]', name: 'value', type: 'uint256[]', }, { internalType: 'bytes[]', name: 'callData', type: 'bytes[]', }, { internalType: 'uint64[]', name: 'gasLimit', type: 'uint64[]', }, ], name: 'batchAll', outputs: [], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ { internalType: 'address[]', name: 'to', type: 'address[]', }, { internalType: 'uint256[]', name: 'value', type: 'uint256[]', }, { internalType: 'bytes[]', name: 'callData', type: 'bytes[]', }, { internalType: 'uint64[]', name: 'gasLimit', type: 'uint64[]', }, ], name: 'batchSome', outputs: [], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ { internalType: 'address[]', name: 'to', type: 'address[]', }, { internalType: 'uint256[]', name: 'value', type: 'uint256[]', }, { internalType: 'bytes[]', name: 'callData', type: 'bytes[]', }, { internalType: 'uint64[]', name: 'gasLimit', type: 'uint64[]', }, ], name: 'batchSomeUntilFailure', outputs: [], stateMutability: 'nonpayable', type: 'function', }, ]; ``` #### Build the Transfer Multiassets Extrinsic {: #build-transfer-multiassets } You can begin to tackle the `xTokens.transferMultiassets` extrinsic, which accepts four parameters: - `assets` - defines the multilocation and amount of xcDEV (xcGLMR for Moonbeam) and the local XC-20 to send to Moonbase Alpha, with the xcDEV positioned as the first asset and the local XC-20 as the second - `feeItem` - set to the index of the xcDEV asset, which in this case is `0`, so that DEV is used to pay for the execution fees in Moonbase Alpha - `dest` - a multilocation that defines the Computed Origin account that you calculated in the previous section on Moonbase Alpha - `destWeightLimit` - the weight to be purchased to pay for XCM execution on the destination chain You can find more information on each parameter in the [X-Tokens Precompile page](/builders/interoperability/xcm/xc20/send-xc20s/xtokens-precompile/#xtokens-solidity-interface){target=\_blank} documentation. In the `build-transfer-multiassets-call.js` file, you'll build the `xTokens.transferMultiassets` extrinsic and export it. ```js title="build-transfer-multiassets-call.js" import { ApiPromise, WsProvider } from '@polkadot/api'; // Input data const originChainProviderWsURL = 'INSERT_ORIGIN_CHAIN_WSS_URL'; const computedOriginAccount = 'INSERT_COMPUTED_ORIGIN_ADDRESS'; const localXC20Address = 'INSERT_LOCAL_XC20_ADDRESS'; const transferAmount = 'INSERT_AMOUNT_TO_TRANSFER'; // Transfer multiassets parameters const assets = { V4: [ { // xcDEV id: { parents: 1, interior: { X2: [ { Parachain: 1000 }, // Parachain ID { PalletInstance: 3 }, // Index of the Balances Pallet ], }, }, fun: { Fungible: '100000000000000000', // 0.1 DEV as an estimation for XCM and EVM transaction fee }, }, { // Local XC-20 token id: { parents: 1, interior: { X3: [ { Parachain: 1000 }, // Parachain ID { PalletInstance: 48 }, // Index of the ERC-20 XCM Bridge Pallet { AccountKey20: { key: localXC20Address, }, }, ], }, }, fun: { Fungible: transferAmount, }, }, ], }; const feeItem = 0; const destination = { V4: { parents: 1, interior: { X2: [ { Parachain: 1000 }, { AccountKey20: { key: computedOriginAccount } }, ], }, }, }; const weightLimit = 'Unlimited'; export const getTransferMultiassetsCall = async () => { // Create origin chain API provider const originChainProvider = new WsProvider(originChainProviderWsURL); const originChainAPI = await ApiPromise.create({ provider: originChainProvider, }); // Create the transferMultiasset extrinsic const transferMultiassets = originChainAPI.tx.xTokens.transferMultiassets( assets, feeItem, destination, weightLimit ); originChainAPI.disconnect(); return transferMultiassets; }; ``` To modify the code for Moonbeam, you'll use the following configurations: | Parameter | Value | |:------------------------------:|:-----:| | Parachain ID | 2004 | | Balances Pallet Index | 10 | | ERC-20 XCM Bridge Pallet Index | 110 | #### Build the Remote EVM Call {: #build-the-remote-evm-call } To generate the second call of the batch transaction, the `polkadotXcm.send` extrinsic, you'll need to create the EVM transaction and then assemble the XCM instructions that execute said EVM transaction. For now, you'll focus on generating the calldata for the EVM transaction. For this, you'll construct a transaction that interacts with the [Batch Precompile](/builders/ethereum/precompiles/ux/batch/){target=\_blank} so that two transactions can happen in one. This is helpful because this EVM transaction has to approve both a Wormhole relayer to relay the local XC-20 token and the relay action itself. To create the batch transaction and wrap it in a remote EVM call to be executed on Moonbeam, you'll need to take the following steps: 1. Create contract instances of the local XC-20, [the Wormhole relayer](https://github.com/wormhole-foundation/example-token-bridge-relayer/blob/main/evm/src/token-bridge-relayer/TokenBridgeRelayer.sol){target=\_blank}, and the [Batch Precompile](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/batch/Batch.sol){target=\_blank}. For this, you'll need the ABI for each contract and the address of a Wormhole relayer. You can use the [xLabs relayer](https://xlabs.xyz/){target=\_blank}: === "Moonbeam" ```text 0xcafd2f0a35a4459fa40c0517e17e6fa2939441ca ``` === "Moonbase Alpha" ```text 0x9563a59c15842a6f322b10f69d1dd88b41f2e97b ``` 2. Use Ether's `encodeFunctionData` function to get the encoded call data for the two calls in the batch transaction: the `approve` transaction and the `transferTokensWithRelay` transaction 3. Combine the two transactions into a batch transaction and use Ether's `encodeFunctionData` to get the encoded call data for the batch transaction 4. Use the encoded call data for the batch transaction to create the remote EVM call via the `ethereumXcm.transact` extrinsic, which accepts the `xcmTransaction` as the parameter. For more information, please refer to the [Remote EVM Calls documentation](/builders/interoperability/xcm/remote-execution/remote-evm-calls/#ethereum-xcm-pallet-interface){target=\_blank} In the `build-remote-calldata.js` file, add the following code: ```js title="build-remote-calldata.js" import { ApiPromise, WsProvider } from '@polkadot/api'; import { ethers } from 'ethers'; import batchABI from './abi/Batch.js'; import erc20ABI from './abi/ERC20.js'; import tokenRelayerABI from './abi/TokenRelayer.js'; const localXC20Address = 'INSERT_LOCAL_XC20_ADDRESS'; const transferAmount = 'INSERT_AMOUNT_TO_TRANSFER'; const xLabsRelayer = '0x9563a59c15842a6f322b10f69d1dd88b41f2e97b'; const destinationChainId = 'INSERT_DESTINATION_CHAIN_ID'; const computedOriginAccount = 'INSERT_COMPUTED_ORIGIN_ADDRESS'; // The recipient address on the destination chain needs to be formatted in 32 bytes // You'll pad the address to the left with zeroes. Add the destination address below // without the 0x const destinationAddress = '0x000000000000000000000000' + 'INSERT_DESTINATION_ADDRESS'; // Create contract instances const batchInterface = new ethers.Interface(batchABI); const localXC20Interface = new ethers.Interface(erc20ABI); const tokenRelayer = new ethers.Contract( xLabsRelayer, tokenRelayerABI, new ethers.JsonRpcProvider('https://rpc.api.moonbase.moonbeam.network') ); // Get the encoded calldata for the approve transaction const approve = localXC20Interface.encodeFunctionData('approve', [ xLabsRelayer, // Spender transferAmount, // Amount ]); // Get the encoded calldata for the transferTokensWithRelay transaction. // Use wrapAndTransferEthWithRelay if the token is GLMR const transferTokensWithRelay = tokenRelayer.interface.encodeFunctionData( 'transferTokensWithRelay', [ localXC20Address, // Token transferAmount, // Amount to be transferred 0, // Amount to swap into native assets on the target chain destinationChainId, // Target chain ID, like Ethereum MainNet or Fantom destinationAddress, // Target recipient address 0, // Batch ID for Wormhole message batching ] ); const encodedBatchAllCall = batchInterface.encodeFunctionData('batchAll', [ [localXC20Address, xLabsRelayer], // Addresses to call [0, 0], // Value to send for each call [approve, transferTokensWithRelay], // Call data for each call [], // Gas limit for each call ]); export const getTransactCall = async () => { // Create Moonbeam API provider const moonbeamProvider = new WsProvider( 'wss://wss.api.moonbase.moonbeam.network' ); const moonbeamAPI = await ApiPromise.create({ provider: moonbeamProvider }); // Create the extrinsic for the remote EVM call const transact = moonbeamAPI.tx.ethereumXcm.transact({ V2: { gasLimit: 350000n, action: { Call: '0x0000000000000000000000000000000000000808', }, value: 0n, input: encodedBatchAllCall, }, }); const txWeight = (await transact.paymentInfo(computedOriginAccount)).weight; moonbeamAPI.disconnect(); return { transact, txWeight }; }; ``` #### Build the XCM Message for the Remote EVM Call {: #build-xcm-message-for-remote-evm-call } Next, you'll need to create the extrinsic to send the remote EVM call to Moonbeam. To do so, you'll want to send an XCM message such that the [`Transact`](/builders/interoperability/xcm/core-concepts/instructions/#transact){target=\_blank} XCM instruction gets successfully executed. The most common method to do this is through `polkadotXcm.send` with the [`WithdrawAsset`](/builders/interoperability/xcm/core-concepts/instructions/#withdraw-asset){target=\_blank}, [`BuyExecution`](/builders/interoperability/xcm/core-concepts/instructions/#buy-execution){target=\_blank}, and [`Transact`](/builders/interoperability/xcm/core-concepts/instructions/#transact){target=\_blank} instructions. [`RefundSurplus`](/builders/interoperability/xcm/core-concepts/instructions/#refund-surplus){target=\_blank} and [`DepositAsset`](/builders/interoperability/xcm/core-concepts/instructions/#deposit-asset){target=\_blank} can also be used to ensure no assets get trapped, but they are technically optional. In the `build-remote-evm-call.js` file, add the following code: ```js title="build-remote-evm-call.js" import { ApiPromise, WsProvider } from '@polkadot/api'; import { getTransactCall } from './build-batch-evm-call.js'; const originChainProviderWsURL = 'INSERT_ORIGIN_CHAIN_WSS_URL'; const computedOriginAccount = 'INSERT_COMPUTED_ORIGIN_ADDRESS'; export const getPolkadotXcmCall = async () => { // Create origin chain API provider const originChainProvider = new WsProvider(originChainProviderWsURL); const originChainAPI = await ApiPromise.create({ provider: originChainProvider, }); // Get the weight required to execute the Transact calldata const { transact, txWeight } = await getTransactCall(); // Create the extrinsic for the remote EVM call const sendXcm = originChainAPI.tx.polkadotXcm.send( { V4: { parents: 1, interior: { X1: [{ Parachain: 1000 }] } } }, { V4: [ { // Withdraw DEV asset (0.06) from the target account WithdrawAsset: [ { id: { parents: 0, interior: { X1: [{ PalletInstance: 3 }] }, }, fun: { Fungible: 60000000000000000n }, }, ], }, { // Buy execution with the DEV asset BuyExecution: { fees: { id: { parents: 0, interior: { X1: [{ PalletInstance: 3 }] }, }, fun: { Fungible: 60000000000000000n }, }, weightLimit: 'Unlimited', }, }, { Transact: { originKind: 'SovereignAccount', requireWeightAtMost: { refTime: txWeight.refTime, proofSize: txWeight.proofSize, }, call: { encoded: transact.method.toHex(), }, }, }, { RefundSurplus: {}, }, { DepositAsset: { // Note that this must be AllCounted and not All, since All has too high of a gas requirement assets: { Wild: { AllCounted: 1 } }, beneficiary: { parents: 0, interior: { X1: [{ AccountKey20: { key: computedOriginAccount } }], }, }, }, }, ], } ); return sendXcm; }; ``` #### Build the Batch Extrinsic {: #build-batch-extrinsic } To ensure that both the `xTokens.transferMultiassets` and the `polkadotXcm.send` transactions are sent together, you can batch them together using `utility.batchAll`. This helps ensure that the asset transfer happens before the EVM transaction, which is a necessary distinction. Unfortunately, this is subject to change with future XCM updates. In the `send-batch-transaction.js` file, add the following code: ```js title="send-batch-transaction.js" import { ApiPromise, WsProvider, Keyring } from '@polkadot/api'; import { cryptoWaitReady } from '@polkadot/util-crypto'; import { getTransferMultiassetsCall } from './build-transfer-multiassets-call.js'; import { getPolkadotXcmCall } from './build-remote-evm-call.js'; const originChainProviderWsURL = 'INSERT_ORIGIN_CHAIN_WSS_URL'; const sendBatchTransaction = async () => { // Create origin chain API provider const originChainProvider = new WsProvider(originChainProviderWsURL); const originChainAPI = await ApiPromise.create({ provider: originChainProvider, }); // Create the batch transaction const batchTransaction = originChainAPI.tx.utility.batchAll([ await getTransferMultiassetsCall(), await getPolkadotXcmCall(), ]); // Create a keyring instance to sign the transaction await cryptoWaitReady(); const keyring = new Keyring({ type: 'ethereum' }); const account = keyring.addFromUri(privateKey); // Send the batch transaction const transaction = await batchTransaction.signAndSend(account, ({ status }) => { if (status.isInBlock) console.log(`Transaction sent!`); }); originChainAPI.disconnect(); return transaction; }; sendBatchTransaction(); ``` If you want to see an example project that fully implements this, an example is available in a [GitHub repository](https://github.com/jboetticher/mrl-mono){target=\_blank}. It's important to note that not every parachain will have X-Tokens and the other pallets implemented in a way that will allow this path. Substrate-based chains are very flexible, to the point where a standard doesn't exist. If you believe your parachain does not support this path, please provide an alternative solution in the [Moonbeam forum](https://forum.moonbeam.network){target=\_blank} and to the Wormhole team. ### Tokens Available Through Wormhole {: #tokens-available-through-wormhole } While Wormhole has the technical capability to bridge any token across chains, relayers will not support every token for fees. The ERC-20 assets that can be bridged through Wormhole's MRL solution depend on the tokens the [xLabs relayer](https://xlabs.xyz){target=\_blank} takes in. The tokens that are available to Moonbeam and Moonbase Alpha are listed in the table below: === "Moonbeam" | Token Name | Symbol | Decimals | Address | |:-----------------:|:------:|:--------:|:------------------------------------------:| | Wrapped AVAX | wAVAX | 18 | 0xd4937A95BeC789CC1AE1640714C61c160279B22F | | Wrapped Bitcoin | wBTC | 8 | 0xE57eBd2d67B462E9926e04a8e33f01cD0D64346D | | Wrapped BNB | wBNB | 18 | 0xE3b841C3f96e647E6dc01b468d6D0AD3562a9eeb | | Celo Native Asset | CELO | 18 | 0xc1a792041985F65c17Eb65E66E254DC879CF380b | | Dai Stablecoin | DAI | 18 | 0x06e605775296e851FF43b4dAa541Bb0984E9D6fD | | Wrapped Ethereum | wETH | 18 | 0xab3f0245B83feB11d15AAffeFD7AD465a59817eD | | Wrapped Fantom | wFTM | 18 | 0x609AedD990bf45926bca9E4eE988b4Fb98587D3A | | Wrapped GLMR | wGLMR | 18 | 0xAcc15dC74880C9944775448304B263D191c6077F | | Wrapped Matic | wMATIC | 18 | 0x82DbDa803bb52434B1f4F41A6F0Acb1242A7dFa3 | | Wrapped SOL | SOL | 9 | 0x99Fec54a5Ad36D50A4Bba3a41CAB983a5BB86A7d | | Sui | SUI | 9 | 0x484eCCE6775143D3335Ed2C7bCB22151C53B9F49 | | Tether USD | USDT | 6 | 0xc30E9cA94CF52f3Bf5692aaCF81353a27052c46f | | USDC (Wormhole) | USDC | 6 | 0x931715FEE2d06333043d11F658C8CE934aC61D0c | === "Moonbase Alpha" | Token Name | Symbol | Decimals | Address | |:------------------------:|:------:|:--------:|:------------------------------------------:| | Wrapped Avax | wAVAX | 18 | 0x2E8afeCC19842229358f3650cc3F091908dcbaB4 | | Wrapped BNB | wBNB | 18 | 0x6097E80331B0c6aF4F74D7F2363E70Cb2Fd078A5 | | Celo Native Asset | CELO | 18 | 0x3406a9b09adf0cb36DC04c1523C4b294C6b79513 | | Dai Stablecoin | DAI | 18 | 0xc31EC0108D8e886be58808B4C2C53f8365f1885D | | Wrapped Ether | wETH | 18 | 0xD909178CC99d318e4D46e7E66a972955859670E1 | | Wrapped Ether (Wormhole) | wETH | 18 | 0xd27d8883E31FAA11B2613b14BE83ad8951C8783C | | Wrapped Fantom | wFTM | 18 | 0x566c1cebc6A4AFa1C122E039C4BEBe77043148Ee | | Wrapped Matic | wMATIC | 18 | 0xD2888f015BcB76CE3d27b6024cdEFA16836d0dbb | | Sui | SUI | 9 | 0x2ed4B5B1071A3C676664E9085C0e3826542C1b27 | | USDC | USDC | 6 | 0x6533CE14804D113b1F494dC56c5D60A43cb5C3b5 | Please take the time to verify that these assets are still Wormhole assets on Moonbeam by using the [Wormhole asset verifier](https://portalbridge.com/#/token-origin-verifier){target=\_blank}.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/protocols/axelar/ --- BEGIN CONTENT --- --- title: Cross-Chain Via Axelar description: Learn about Axelar, a GMP protocol for cross-chain asset transfers, and how to get started building cross-chain applications with Axelar on Moonbeam. categories: GMP Providers --- # Axelar Network ## Introduction {: #introduction } [Axelar](https://www.axelar.network){target=\_blank} delivers secure cross-chain communication for Web3. Axelar's infrastructure enables dApp users to interact with any asset or application, on any connected chain, with one click. Powered by a permissionless Proof-of-Stake validator set, Axelar network allows dApps to pass arbitrary messages across chains using Turing-complete calls. Axelar is a full-stack transport layer that supports asset transfer, [General Message Passing](https://docs.axelar.dev/dev/general-message-passing/overview){target=\_blank} and composability of programs. It securely connects all blockchain ecosystems, applications, assets and users to deliver Web3 interoperability. Axelar is composed of a decentralized network of validators, secure gateway contracts, uniform translation, routing architecture, and a suite of protocols and application programming interfaces (APIs). Take a look at the [Tech Stack Diagram](https://www.axelar.network/blog/an-introduction-to-the-axelar-network){target=\_blank} for more details. ![Axelar Technology Stack diagram](/images/builders/interoperability/protocols/axelar/axelar-1.webp) The Axelar APIs provide a rich suite for developing Web3 applications, ensuring that developers have the tools they need for building. With these tools and APIs, developers can use the Axelar network and its APIs to write dApps that can be easily deployed across all Axelar-connected ecosystems.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Getting Started {: #getting-started } There are a couple of resources to get you started building cross-chain applications with Axelar: - **[Developer documentation](https://docs.axelar.dev/dev/intro){target=\_blank}** - for technical guides - **[Satellite](https://satellite.money){target=\_blank}** - a bridging UI used to transfer assets across chains There is also a block explorer available to track your cross-chain transfers and more: - **[Axelarscan for MainNet](https://axelarscan.io){target=\_blank}** - **[Axelarscan for TestNet](https://testnet.axelarscan.io){target=\_blank}** ## Contracts {: #contracts } See the list of Axelar contracts deployed to Moonbeam, and the networks connected to Moonbeam through Axelar. - **MainNet Contracts** - [Moonbeam](https://docs.axelar.dev/dev/reference/mainnet-contract-addresses){target=\_blank} - **TestNet Contracts** - [Moonbase Alpha](https://docs.axelar.dev/dev/reference/testnet-contract-addresses){target=\_blank}
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/protocols/hyperlane/ --- BEGIN CONTENT --- --- title: Cross-Chain Via Hyperlane description: Learn about Hyperlane, a GMP protocol for cross-chain asset transfers, and how to get started building cross-chain applications with Hyperlane on Moonbeam. categories: GMP Providers --- # Hyperlane Protocol ## Introduction {: #introduction } [Hyperlane](https://hyperlane.xyz/){target=\_blank} is a security-modular cross-chain communication protocol for Web3. Hyperlane enables dApp users to interact with any asset or application, on any connected chain, with one click. It supports general asset transfer as well as custom cross-chain messaging. Using [Interchain Security Modules (ISMs)](https://docs.hyperlane.xyz/docs/protocol/ISM/modular-security){target=\_blank}, Hyperlane allows developers to configure the method by which messages are sent and validated across chains. Hyperlane is composed of validators, relayers, and watchtowers. [Validators](https://v2.hyperlane.xyz/docs/protocol/agents/validators){target=\_blank} will watch for and confirm cross-chain messages. [Relayers](https://v2.hyperlane.xyz/docs/protocol/agents/relayer){target=\_blank} spend the gas to send messages across chains. [Watchtowers](https://v2.hyperlane.xyz/docs/protocol/agents/processor){target=\_blank} perform checks to ensure that validators are good-faith actors, securing the protocol. Take a look at the tech stack diagram and their [protocol documentation](https://docs.hyperlane.xyz/docs/protocol/protocol-overview){target=\_blank} for more details. ![Hyperlane Technology Stack diagram](/images/builders/interoperability/protocols/hyperlane/hyperlane-1.webp) The Hyperlane APIs provide a rich suite for developing Web3 applications, ensuring that developers have the tools they need for building. With these tools and APIs, developers can use the Hyperlane protocol and its APIs to write dApps that can be easily deployed across all Hyperlane-connected ecosystems.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Getting Started {: #getting-started } There are a couple of resources to get you started building cross-chain applications with Hyperlane: - **[Developer documentation](https://v2.hyperlane.xyz/docs/build-with-hyperlane/guides){target=\_blank}** - for technical guides - **[Hyperlane Explorer](https://explorer.hyperlane.xyz){target=\_blank}** - to track cross-chain transfers ## Contracts {: #contracts } See the list of Hyperlane contracts deployed to Moonbeam, and the networks connected to Moonbeam through Hyperlane. - [MainNet and TestNet Contracts](https://v2.hyperlane.xyz/docs/resources/addresses/permissionless){target=\_blank}
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/protocols/ --- BEGIN CONTENT --- --- title: Cross-Chain Protocols description: Learn about the cross-chain protocols you can use to transfer assets and remotely call contracts on any connected blockchain. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/protocols/layerzero/ --- BEGIN CONTENT --- --- title: Cross-Chain Via LayerZero description: Learn about LayerZero, a GMP protocol for cross-chain asset transfers, and how to get started building cross-chain applications with LayerZero on Moonbeam. categories: GMP Providers --- # LayerZero Protocol ## Introduction {: #introduction } [LayerZero](https://layerzero.network){target=\_blank} delivers secure omnichain interoperability for Web3. It consists of an Oracle actor and a Relayer actor that work separately to provide secure messages from one chain to another. LayerZero's infrastructure enables dApp users to interact with any asset or application, on any connected chain, with one click. LayerZero is a transport layer that enables asset transfer with low-level communication primitives. DApps that utilize LayerZero are known as User Applications, whose messages are relayed across chains by a Relayer, and whose messages are verified on the destination chain by an Oracle's block headers. Take a look at the tech stack diagram below and their [conceptual documentation](https://docs.layerzero.network/v2/home/v2-overview){target=\_blank} for more details. ![LayerZero Technology Stack diagram](/images/builders/interoperability/protocols/layerzero/layerzero-1.webp) The LayerZero APIs provide a rich suite for developing Web3 applications, ensuring that developers have the tools they need for building. With these tools and APIs, developers can use the LayerZero protocol and its APIs to write dApps that can be easily deployed across all LayerZero-connected ecosystems.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Getting Started {: #getting-started } There are a couple of resources to get you started building cross-chain applications with LayerZero: - **[Developer documentation](https://docs.layerzero.network/v2){target=\_blank}** - for technical guides - **[Stargate](https://stargate.finance){target=\_blank}** - a bridging UI that uses LayerZero, built by the Stargate team ## Contracts {: #contracts } See the list of LayerZero contracts deployed to Moonbeam, and the networks connected to Moonbeam through LayerZero. - **MainNet Contracts** - [Moonbeam](https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts#moonbeam){target=\_blank} - **TestNet Contracts** - [Moonbase Alpha](https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts#moonbase){target=\_blank}
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/protocols/wormhole/ --- BEGIN CONTENT --- --- title: Cross-Chain via Wormhole description: Learn how to bridge assets, set up a relayer, and other ways you can connect your Moonbeam DApp to assets and functions on multiple blockchains using Wormhole. categories: GMP Providers --- # Wormhole Network ## Introduction [Wormhole](https://wormhole.com){target=\_blank} is a protocol that validates and secures cross-chain communication for Web3, through messages known as verifiable action approvals (VAAs). Wormhole's infrastructure enables dApp users to interact with any asset or application, on any connected chain, with one click. Powered by a multi-signature schemed protocol and 19 signing [Guardians](https://wormhole.com/docs/protocol/infrastructure/guardians/){target=\_blank}, Wormhole allows dApps to pass arbitrary messages across chains. Wormhole consists of multiple modular swap-in components that can be leveraged independently and supports an increasing number of composable applications built by numerous teams. Building xDapps on top of their protocol allows for quick cross-chain asset transfers and cross-chain logic to deliver maximal Web3 interoperability. Wormhole's architecture includes a signing Guardian network, bridging smart contracts, and relayers. Take a look at the tech stack diagram for more details. ![Wormhole Technology Stack diagram](/images/builders/interoperability/protocols/wormhole/wormhole-1.webp)
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Getting Started {: #getting-started } There are a couple of resources to get you started building cross-chain applications with Wormhole: - **[Developer documentation](https://wormhole.com/docs/){target=\_blank}** - for technical guides - **[Portal](https://portalbridge.com/#/transfer){target=\_blank}** - a bridging UI used to transfer assets across chains ## Contracts {: #contracts } See the list of Wormhole contracts deployed to Moonbeam, and the networks connected to Moonbeam through Wormhole. - **MainNet Contracts** - [Moonbeam](https://wormhole.com/docs/products/reference/supported-networks/#moonbeam){target=\_blank} ## Setting up a Specialized Relayer With the Relayer Engine {: #setting-up-a-specialized-relayer-with-the-relayer-engine } In this section, you will deploy a basic Wormhole connected smart contract and spin up a specialized relayer to send messages across chains. First, some context. VAAs, or verifiable action approvals, are Wormhole’s version of validated cross-chain messages. If 13 out of Wormhole's 19 signing Guardians validate a particular message, the message becomes approved and can be received on other chains. Adjacent to the guardian network (which act as the validators of Wormhole’s protocol) are the network spies. They don’t do any validation work. Instead, they watch the guardian network and act as an interface to allow users and applications to see what VAAs have been approved. The relayer’s role is to pay for the destination chain’s execution, and in many protocols, in turn a relayer is paid by the user. Wormhole does not have general relayers available yet, so Wormhole’s architecture requires dApp developers to create and maintain their own specialized relayers (instead of having a relayer that can execute for many different smart contracts). A developer would have to design their own system if they wished to have the contract caller pay for gas on the destination chain. This might seem like a greater amount of work, but it allows for more fine-tuning of how messages are handled. For example, a relayer could send the same message to multiple chains at the same time, known as multicasting. ### Checking Prerequisites {: #checking-prerequisites } To follow along with this tutorial, you will need to have: - [MetaMask installed and connected to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank} - [Docker installed](https://docs.docker.com/get-started/get-docker/){target=\_blank} - Have an account be funded with `DEV` tokens. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} - Have the same account be funded with native currency from a Wormhole connected EVM of your choice. Faucets [are in the table below](#deploying-the-wormhole-contract-with-remix-on-moonbase-alpha) ### Deploying the Wormhole Contract with Remix on Moonbase Alpha {:deploying-the-wormhole-contract-with-remix-on-moonbase-alpha} To send a cross-chain message, in this guide, you will need to deploy and use a smart contract. Every chain connected to Wormhole will have some sort of implementation of the [Wormhole core bridge](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\_blank}, whose purpose is to publish and verify VAAs. Each implementation of the core bridge contract (one per chain) is watched by every guardian in the guardian network, which is how they know when to start validating a message. Unlike other cross-chain protocols, Wormhole doesn’t provide a parent smart contract to inherit from for users to build off of. This is because Wormhole’s first chain, Solana, doesn’t have typical inheritance in their smart contracts like Solidity provides. To keep the design experience similar on each chain, Wormhole has their Solidity developers interact directly with the Wormhole core bridge smart contract on EVM chains. The [smart contract](https://github.com/jboetticher/relayer-engine-docs-example/blob/main/SimpleGeneralMessage.sol){target=\_blank} that you will be deploying today is stored in a Git repository that is forked from Wormhole’s relayer engine repository. It sends a string from one chain to another, and stores strings when received through Wormhole's protocol. To deploy the script, either copy and paste the contract into Remix or open up this [Remix gist link](https://remix.ethereum.org/?gist=6aac8f954e245d6394f685af5d404b4b){target=\_blank}. First things first, the code in this smart contract is simplified in certain areas (like security). When writing a smart contract for production, review the [Wormhole documentation](https://wormhole.com/docs/){target=\_blank} for a better understanding of standards. To be clear, **do not use the following smart contract in production**. 1. Go to the **Solidity Compiler** tab 2. Press the **Compile** button 3. Then, go to the **Deploy & Run Transactions** tab of Remix 4. Set the environment to **Injected Web3**. This will use MetaMask as the Web3 provider. Ensure that your MetaMask is connected to the Moonbase Alpha network ![Set up smart contract deployment](/images/builders/interoperability/protocols/wormhole/wormhole-2.webp) To deploy on each chain, you will need the local instance of the Wormhole core bridge and the chain ID of the chain mentioned. All of this data has been provided for a select few TestNets in the table below. You can find other networks’ endpoints on Wormhole’s [supported networks documentation](https://wormhole.com/docs/products/reference/supported-networks/){target=\_blank}. Keep in mind that you should only use EVMs for this demonstration, since the smart contract and relayer designed for this demonstration only supports EVMs. | Network & Faucet | Core Bridge Address | Wormhole Chain ID | |:--------------------------------------------------------------------:|:------------------------------------------:|:-----------------:| | [Polygon Mumbai](https://faucet.polygon.technology){target=\_blank} | 0x0CBE91CF822c73C2315FB05100C2F714765d5c20 | 5 | | [Avalanche Fuji](https://faucet.avax.network){target=\_blank} | 0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C | 6 | | [Fantom TestNet](https://faucet.fantom.network){target=\_blank} | 0x1BB3B4119b7BA9dfad76B0545fb3F531383c3bB7 | 10 | | [Sepolia](https://www.sepoliafaucet.io){target=\_blank} | 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78 | 10002 | | [Moonbase Alpha](https://faucet.moonbeam.network){target=\_blank} | 0xa5B7D85a8f27dd7907dc8FdC21FA5657D5E2F901 | 16 | 1. Ensure that the contract chosen is **SimpleGeneralMessage** 2. Open up the deploy menu with the arrow button 3. Input the relevant chain ID in the **_CHAINID** input 4. Input the relevant core bridge address in the **WORMHOLE_CORE_BRIDGE_ADDRESS** input 5. Press the **transact** button to start a deployment transaction 6. Press the **Confirm** button in MetaMask to deploy Once the contract has been deployed on Moonbase Alpha make sure to copy down its address and repeat the process with one of any of the other [EVM TestNets](https://wormhole.com/docs/products/reference/supported-networks/){target=\_blank} that are connected to Wormhole so that you can send a message across chains. Remember that you will have to change your network in MetaMask to deploy to the right network. ### Whitelisting Moonbase Alpha’s Connected Contract {:whitelisting-moonbase-alpha-connected-contract} At this point, you should have the same smart contracts deployed twice. One on Moonbase Alpha, and another on another EVM chain. Wormhole recommends including a whitelisting system in their connected contracts, which you will have to use in `SimpleGeneralMessage` before attempting to send a cross-chain message. To add a whitelisted contract, you must invoke the `addTrustedAddress(bytes32 sender, uint16 _chainId)` function, which requires a *bytes32* formatted address and a chain ID. You can find the chain ID in the [table above](#deploying-the-wormhole-contract-with-remix-on-moonbase-alpha) and on [Wormhole’s documentation](https://wormhole.com/docs/products/reference/supported-networks/){target=\_blank}. ```solidity function addTrustedAddress(bytes32 sender, uint16 _chainId) external { myTrustedContracts[sender][_chainId] = true; } ``` Note that the `sender` parameter is a `bytes32` type instead of an `address` type. Wormhole’s VAAs provide emitter (origin) addresses in the form of `bytes32`, so they are stored and checked as `bytes32`. To convert an `address` type to `bytes32`, you will need to pad an additional 24 zeros. This is because an `address` value is 20 bytes, less than the 32 for `bytes32`. Every byte has 2 hexadecimal characters, so: ```text zeros to add = (32 bytes - 20 bytes) * 2 hexadecimal characters zeros to add = 24 ``` For example, if your connected contract’s address was `0xaf108eF646c8214c9DD9C13CBC5fadf964Bbe293`, you would input the following into Remix: ```text 0x000000000000000000000000af108ef646c8214c9dd9c13cbc5fadf964bbe293 ``` Now use Remix to ensure that your two connected contracts trust each other. You will have to do this on both contracts that you have deployed if you intend to send messages back and forth. To switch between contracts on different chains, connect to the destination network through MetaMask. 1. Make sure that you are in the **Injected** **Provider** environment 2. Ensure that you are on the right account 3. Also check that the contract is still **SimpleGeneralMessage** 4. Finally, take the address of the destination contract, and paste it into the **At Address** input ![At address](/images/builders/interoperability/protocols/wormhole/wormhole-3.webp) To add trusted remote addresses: 1. Find the **addTrustedAddress** function within the deployed contract and open it 2. When you are on Moonbase Alpha, set the **sender** as the properly formatted (padded with 24 zeros) address of the contract you deployed on the other EVM TestNet 3. Set the **_chainId** as the Wormhole chain ID of the chain that the other contract is deployed on. Afterwards, transact and confirm in MetaMask When you are on the alternate EVM TestNet, set the **sender** as the properly formatted (padded with 24 zeros) address of the contract you deployed on Moonbase Alpha. Set the **_chainId** as Moonbase Alpha’s Wormhole chain ID (16). Finally, transact and confirm in MetaMask. ![Add trusted address](/images/builders/interoperability/protocols/wormhole/wormhole-4.webp) In this section you should have sent two transactions on two chains to whitelist addresses in both contracts. Afterwards, you should be allowed to send messages between the connected contracts. ### Running a Wormhole Guardian Network Spy {: #running-wormhole-guardian-spy } Now you will run a TestNet relayer for Wormhole! This walkthrough is based off of Wormhole’s [relayer-engine](https://github.com/wormhole-foundation/relayer-engine){target=\_blank} GitHub repository, which as of time of writing, is on commit [`cc0aad4`](https://github.com/wormhole-foundation/relayer-engine/commit/cc0aad43787a87ecd9f0d9893d8ccf92901d7adb){target=\_blank}. It’s in relatively active development, which can cause great changes in the structure of the folders. Clone the [fork of the relayer-engine](https://github.com/jboetticher/relayer-engine-docs-example){target=\_blank} that has been prepared specifically for interacting with `SimpleGeneralMessage`. [Docker](https://docs.docker.com/get-started/get-docker/){target=\_blank} and [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\_blank} are required to run this relayer, so be sure to install them to your device. First things first: the setup. Use the npm package manager to install dependencies (like ethers and the relayer engine itself) using the command line. ```bash npm install cd plugins/simplegeneralmessage_plugin npm install ``` Once that’s finished, take a look around at the different folders. There are three folders: `src`, `relay-engine-config`, and `plugins`. The `src` folder contains the script that acts as the starting point for the entire application, so it includes setup. The `relay-engine-config` include JSON configuration files that are specific to the `SimpleGeneralMessage` smart contract. The `plugins` folder contains the plugin that has logic pertaining to relaying for the `SimpleGeneralMessage` smart contract. Before going into detail about how to run anything or how any of the plugin scripts work, you need to understand the different components of the relayer and what the relayer does. The relayer filters and receives VAAs from the guardian network and does "something" with it. In this case, the relayer will filter messages approved by the Guardians that originate from your deployed connected contracts, then parse the VAA, then determine its destination, and finally attempt to execute a function called `processMyMessage(bytes32 VAA)` at the destination. It is important to understand that other relayers from other actors can receive this VAA and that other relayers can execute any VAA in any way they see fit. From a technical standpoint, the implementation of this relayer has four parts. 1. A non-validating spy node that watches the Wormhole guardian network for all VAAs 2. A component known as a listener, which receives the output of the spy node, filters out which ones are relevant to the relayer, and packages them into workflow objects 3. A Redis database that stores the workflow objects that the listener outputs 4. A component known as an executor, which pops workflows off the database and processes them in some way (in this case, sends a transaction on the destination chain) Starting from scratch, this can be a lot. Fortunately, Wormhole provides a `relayer-engine` package to help with the setup. It’s best to tackle the configuration and setup of these four components in order, so start with the spy node. The spy node uses Docker, so ensure that Docker is active before attempting to start the node. The command to start the Docker container is long, so to simplify things, it has been added as an npm script to the repository's parent directory. Just run: ```bash npm run testnet-spy ``` First, you should see a few logs from the startup of the Docker container. Then, a lot of logs should be spamming the console. These are all the VAAs that are going through the Wormhole TestNet, and there are a lot! Don’t worry, you won’t have to decipher any of these logs: the code can do that for you. Leave this running in the background and get another terminal instance to move on to the next step.
npm run testnet-spy @wormhole-foundation/example-relayer-project@0.0.1 testnet-spy docker run --platform=linux/amd64 -p 7073:7073 --entrypoint /guardiand ghcr.io/wormhole-foundation/guardiand:latest spy --nodeKey /node.key --spyRPC "[::]:7073" --network /wormhole/testnet/2/1 --bootstrap /dns4/t-guardian-01.testnet.xlabs.xyz/udp/8999/quic/p2p/12D3KooWCW3LGUtkCVkHZmVSZHzL3C4WRKWfqAiJPz1NR7dT9Bxh INFO wormhole-spy spy/spy.go:322 status server listening on [::]:6060 INFO wormhole-spy spy/spy.go:270 spy server listening {"addr": "[::]:7073"} INFO wormhole-spy common/nodekey.go:16 No node key found, generating a new one... {"path": "/node.key"} INFO wormhole-spy.supervisor supervisor/supervisor_processor.go:41 supervisor processor started INFO wormhole-spy spy/spy.go:413 Started internal services INFO wormhole-spy.root.p2p p2p/p2p.go:276 Connecting to bootstrap peers {"bootstrap_peers": "/dns4/t-guardian-01.testnet.xlabs.xyz/udp/8999/quic-v1/p2p/12D3KooWCW3LGUtkCVkHZmVSZHzL3C4WRKWfqAiJPz1NR7dT9Bxh"} INFO wormhole-spy.root.p2p p2p/p2p.go:345 Subscribing pubsub topic {"topic": "/wormhole/testnet/2/1/broadcast"} INFO dht/RtRefreshManager rtrefresh/rt_refresh_manager.go:322 starting refreshing cpl 0 with key CIQAAAAEGIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA (routing table size was 0) INFO wormhole-spy.root.p2p p2p/p2p.go:387 Connected to bootstrap peers {"num": 1} INFO wormhole-spy.root.p2p p2p/p2p.go:389 Node has been started {"peer_id": "12D3KooWJmUftCbuZH9rAF6Zzq9dhDhQ5yQrdwEVhiY8PXN3KtTG", "addrs": "[/ip4/127.0.0.1/udp/8999/quic-v1 /ip4/172.17.0.2/udp/8999/quic-v1 /ip6/::1/udp/8999/quic-v1]"} 2024-08-01T23:03:51.193Z INFO wormhole-spy spy/spy.go:371 Received signed VAA {"vaa": "AQAAAAABAICa9rr2B5VTAg6tcYu/5DCkzbKVC5xG2CT0EZ681BP0Mxmb9RwTvSENT7Cr1GZ8LRmXbW7W0kZVELN+hhAh5boAZqwUVgAAAAAAGuEB+u2sWFHjK5sjtflBGowrrEquPtTde4Ed0acupKpxAAAAAASqMYIBQVVXVgAAAAAACT4b8wAAJxCYq1BJcB42Joc35zEoMLG3u4ARJg=="}
### Setting up the Listener Component {:setting-up-the-listener-component} Now to break down the custom code and configurable component of the relayer. The listener component, aptly named, listens to the spy node for relevant messages. To define what the relevant messages are, you must edit a config file. In `plugins/simplegeneralmessage_plugin/config/devnet.json`, there exists an array named `spyServiceFilters`. Each object within this array whitelists a contract’s VAAs as relevant to the relayer. The object contains a `chainId` (a Wormhole chain ID) and an `emitterAddress`. For example, in the image below, the first object will watch for VAAs sent by `0x428097dCddCB00Ab65e63AB9bc56Bb48d106ECBE` on Moonbase Alpha (Wormhole chain ID is 16). Be sure to edit the `spyServiceFilters` array so that the relayer listens to the two contracts that you deployed. ```json "spyServiceFilters": [ { "chainId": 16, "emitterAddress": "0x428097dCddCB00Ab65e63AB9bc56Bb48d106ECBE" }, { "chainId": 10, "emitterAddress": "0x5017Fd40aeA8Ab94693bE41b3bE4e90F45860bA4" } ] ``` In the `simplegeneralmessage_plugin` folder, open up `src/plugin.ts`. This file contains plugin code for both the listener and executor components of the relayer, but the comments should make it obvious which functions are relevant to which component. Snippets of the file are shown below and you should be following along, but in case you aren’t, the entire file can be accessed in [its GitHub repository](https://github.com/jboetticher/relayer-engine-docs-example/blob/main/plugins/simplegeneralmessage_plugin/src/plugin.ts){target=\_blank}. Look at the `getFilters()` function below. Notice something familiar? The `spyServiceFilters` object is injected into the plugin class that `getFilters()` is part of. Note that no filtering is being done, this is only the preparation of the filters. The actual filtering of VAAs occurs within the `relayer-engine` package, which uses this `getFilters()` function to understand what to filter. If a developer wanted to add additional logic to the filters, they could here, but for your purposes, simply listing some hard-coded addresses is fine. ```ts // How the relayer injects the VAA filters. // This is the default implementation provided by the dummy plugin. getFilters(): ContractFilter[] { if (this.pluginConfig.spyServiceFilters) { return this.pluginConfig.spyServiceFilters; } this.logger.error('Contract filters not specified in config'); throw new Error('Contract filters not specified in config'); } ``` After filtering, the listener needs to write to the Redis database with workflow data in the `consumeEvent(vaa, stagingArea)` function below. A workflow is just data that the executor needs from the listener to do a proper execution with. In this case, the only information that is being added to the workflow is the time at which the VAA was received and the parsed data in the VAA itself. If a developer wanted to add more relevant information to the workflow, they could do so in the `workflowData` object. The `nextStagingArea` object is a way for consumed events (filtered VAAs) to affect each other. For example, if a developer wanted to package two VAAs together into one workflow, they wouldn’t return a `workflowData` every time. ```ts // Receives VAAs and returns workflows. async consumeEvent( vaa: ParsedVaaWithBytes, stagingArea: StagingAreaKeyLock, ): Promise< | { workflowData: WorkflowPayload; workflowOptions?: WorkflowOptions; } | undefined > { this.logger.debug(`VAA hash: ${vaa.hash.toString('base64')}`); return { workflowData: { vaa: vaa.bytes.toString('base64'), }, }; } ``` That’s all that’s necessary for the listener component. Fortunately, most of the code is hidden from the user within the `relayer-engine` package. If you recall the list of components, the third is the Redis database component. Most of the code that has to do with the database is hidden from the user, since the `relayer-engine` package will write & read from it, then inject any relevant data back into the plugin code. To run the Redis database, simply run the following command in the parent directory: ```bash npm run redis ``` ### Setting up the Executor Component {: #setting-up-the-executor-component} Finally, you must handle the executor component. Recall that the executor component takes workflow data from the Redis database and does some sort of execution action with that data. For most relayers, this execution will involve an on-chain transaction, since a relayer acts as a trustless oracle for VAAs. The `relayer-engine` package helps handle the wallets for the plugin. Currently, the package only supports Solana and EVM wallets, but with further development more chains will be supported. But it’s not impossible to integrate NEAR or Algorand into the relayer, since you would just have to write your own wallet handling system in addition to the one already provided by the package. To work with the built-in wallet handling system provided by the package, open the file at `relayer-engine-config/executor.json.example`. This example script is provided to show you how to format your private keys (the current key is provided by Wormhole). Rename the example file to `executor.json`. In the `privateKeys` object of `executor.json`, replace the content of each array with your private key. The account of the private key entries will be the one that pays for execution fees in the relayer’s executor component. Please manage your keys with care, as exposing them can result in loss of funds. While `executor.json` is ignored by git in this repository, please be sure that the wallet you are using for TestNet has no MainNet funds just to be safe. ```json { "privateKeys": { "16": [ "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d" ], "2": [ "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d" ], "5": [ "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d" ], "6": [ "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d" ], "10": [ "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d" ], } } ``` Remove any entries from the `privateKeys` object if their key belongs to a chain that you are not using. If you are using a chain that wasn’t listed in the EVM TestNet table above, you will have to add your own array. The key for this array should be the Wormhole chain ID of the other EVM that you chose to deploy on before. For example, if you deployed on the Fantom TestNet, you would add the following object, since the Wormhole chain ID of the Fantom TestNet is `10`. ```json "10": [ "INSERT_YOUR_PRIVATE_KEY" ] ``` Now that the wallets are sorted out for the executor, look at the code of the executor itself, which is in the `plugins/simplegeneralmessage_plugin/src/plugin.ts` file. If you haven’t been following along, the entire file can be accessed in [its GitHub repository](https://github.com/jboetticher/relayer-engine-docs-example/blob/main/plugins/simplegeneralmessage_plugin/src/plugin.ts){target=\_blank}. The `handleWorkflow(workflow, providers, execute)` function is where all of the logic is, though there are some helper functions underneath it. This is the function that the `relayer-engine` package invokes when there is a workflow in the Redis database that’s to be used. Notice the three parameters that are injected into the function: `workflow`, `providers`, and `execute`. - The `workflow` object provides the data that was stored in the database during the listener component’s execution of the `consumeEvent(vaa, stagingArea)` function. In this case, only the VAA and time it was received was stored in the database, which are stored in the local `payload` variable - The `providers` object injects Ethers and other chains’ providers, which might be helpful for querying on-chain data or doing other blockchain related actions. As mentioned before, the only providers that are currently supported by the package are Solana and EVMs. The `providers` object isn’t used in this implementation - The `execute` object currently has two functions in it: `onEVM(options)` and `onSolana(options)`. These functions require a Wormhole chain ID and a callback function that has a wallet object injected into it. The wallet included is based off of the private key that was configured in the `executor.json` file The first substantial thing this function does is parse the workflow object, then parse its VAA with some helper functions. Afterwards, it takes the parsed VAA payload, converts it into a hexadecimal format, and uses the Ethers utility to ABI-decode the payload into its separate values that were defined way-back-when in the smart contract. With the data that was decoded by Ethers, it’s possible to figure out to which contract and which chain the payload is being sent to, since that data was packaged into the message. The function checks if the specified destination chain ID belongs to an EVM, and will execute using the `execute.onEVM(options)` function mentioned before. Otherwise, it logs an error since this system doesn’t expect to interact with non-EVM chains for simplicity. ```ts // Consumes a workflow for execution async handleWorkflow( workflow: Workflow, providers: Providers, execute: ActionExecutor ): Promise { this.logger.info(`Workflow ${workflow.id} received...`); const { vaa } = this.parseWorkflowPayload(workflow); const parsed = wh.parseVaa(vaa); this.logger.info(`Parsed VAA. seq: ${parsed.sequence}`); // Here we are parsing the payload so that we can send it to the right recipient const hexPayload = parsed.payload.toString('hex'); let [recipient, destID, sender, message] = ethers.utils.defaultAbiCoder.decode( ['bytes32', 'uint16', 'bytes32', 'string'], '0x' + hexPayload ); recipient = this.formatAddress(recipient); sender = this.formatAddress(sender); const destChainID = destID as ChainId; this.logger.info( `VAA: ${sender} sent "${message}" to ${recipient} on chain ${destID}.` ); // Execution logic if (wh.isEVMChain(destChainID)) { // This is where you do all of the EVM execution. // Add your own private wallet for the executor to inject in // relayer-engine-config/executor.json await execute.onEVM({ chainId: destChainID, f: async (wallet, chainId) => { const contract = new ethers.Contract(recipient, abi, wallet.wallet); const result = await contract.processMyMessage(vaa); this.logger.info(result); }, }); } else { // The relayer plugin has a built-in Solana wallet handler, which you could use // here. NEAR & Algorand are supported by Wormhole, but they're not supported by // the relayer plugin. If you want to interact with NEAR or Algorand you'd have // to make your own wallet management system, that's all this.logger.error( 'Requested chainID is not an EVM chain, which is currently unsupported.' ); } }; ``` In the callback function, it creates a [contract object](https://docs.ethers.org/v6/api/contract/#Contract){target=\_blank} with the Ethers package. The ABI that it imports is exported from the `SimpleGeneralMessage` contract’s compilation, so this code is assuming that the recipient of the message specified in the VAA is or inherits from a `SimpleGeneralMessage` contract. Then, the code attempts to execute the `processMyMessage(bytes32 VAA)` function with the VAA, which was previously defined as the function that messages are relayed to. Recall that this function name was arbitrarily chosen for the smart contract because the relayer could specify any function to call. That freedom is expressed in the ability for a developer to change this relayer’s code! ```ts await execute.onEVM({ chainId: destChainID, f: async (wallet, chainId) => { const contract = new ethers.Contract(recipient, abi, wallet.wallet); const result = await contract.processMyMessage(vaa); this.logger.info(result); }, }); ``` The final piece is to check `relayer-engine-config/common.json`. This config file controls the execution of the entire relayer. Ensure that the TestNet EVMs that you are using are listed within the `supportedChains` object of this file. The plugin will not run properly if it’s not listed. If a chain that you are using is not listed, you will have to import the data from [Wormhole’s developer documentation](https://wormhole.com/docs/products/reference/supported-networks/){target=\_blank} into the config file in a format like below. There are also additional configurations for the relayer. For example, the `mode` string is set to `"BOTH"` to ensure that both the listener and executor plugins are used, but a developer could decide to run only one if they wanted. Additionally, there are multiple log levels to specify, such as `"error"` for just error messages. For this demo, however, just leave the configuration settings as is. ```json "mode": "BOTH", "logLevel": "debug", ... { "chainId": 16, "chainName": "Moonbase Alpha", "nodeUrl": "https://rpc.api.moonbase.moonbeam.network", "bridgeAddress": "0xa5B7D85a8f27dd7907dc8FdC21FA5657D5E2F901", "tokenBridgeAddress": "0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96" }, ``` That’s it for the configuration! Now to run it. In your terminal instance (one that isn’t running the spy node), navigate to the parent folder. Run the following command: ```bash npm run start ``` You should see something similar to the logs below in the console.
warn | GlobalStorage: You are starting a relayer without a namespace, which could cause issues if you run multiple relayers using the same Redis instance info | main: Running as both executor and listener debug | executorHarness: Finished gathering worker infos. info | Fantom Testnet-0-worker: Spawned info | Moonbase Alpha-0-worker: Spawned info | listenerHarness: Initializing spy listener... info | spyEventSource: Initializing spy listener for plugin SimpleGeneralMessagePlugin... debug | missedVaaFetching: Grouping emitter keys from plugins... debug | listenerHarness: End of listener harness run function warn | koa deprecated Support for generators will be removed in v3. See the documentation for examples of how to convert old middleware https://github.com/koajs/koa/blob/master/docs/migration.md node_modules/relayer-engine/relayer-engine/lib/index.js:138:9 info | spyEventSource: SimpleGeneralMessagePlugin subscribing to spy with raw filters: [{"chainId":2,"emitterAddress":"0xfB7327Fe26aD52b693E38232E5D97F4892623075"},{"chainId":5,"emitterAddress":"0xfB7327Fe26aD52b693E38232E5D97F4892623075"},{"chainId":6,"emitterAddress":"0xfB7327Fe26aD52b693E38232E5D97F4892623075"},{"chainId":16,"emitterAddress":"0x428097dCddCB00Ab65e63AB9bc56Bb48d106ECBE"},{"chainId":10,"emitterAddress":"0x5017Fd40aeA8Ab94693bE41b3bE4e90F45860bA4"}] debug | spyEventSource: SimpleGeneralMessagePlugin using transformed filters: [{"emitterFilter":{"chainId":2,"emitterAddress":"000000000000000000000000fb7327fe26ad52b693e38232e5d97f4892623075"}},{"emitterFilter":{"chainId":5,"emitterAddress":"000000000000000000000000fb7327fe26ad52b693e38232e5d97f4892623075"}},{"emitterFilter":{"chainId":6,"emitterAddress":"000000000000000000000000fb7327fe26ad52b693e38232e5d97f4892623075"}},{"emitterFilter":{"chainId":16,"emitterAddress":"000000000000000000000000428097dcddcb00ab65e63ab9bc56bb48d106ecbe"}},{"emitterFilter":{"chainId":10,"emitterAddress":"0000000000000000000000005017fd40aea8ab94693be41b3be4e90f45860ba4"}}] debug | missedVaaFetching: Starting nextVaaFetchingWorker... debug | missedVaaFetching: Pessimistically fetching next vaa for all emitters registered by plugins info | spyEventSource: connected to spy service, listening for transfer signed VAAs info | MetricsServer: Prometheus metrics running on port 3001 info | ApiServer: Api running on port 3000 debug | missedVaaFetching: nextVaaFetchingWorker loop completed, sleeping 300000000 ms...
### Sending a Cross-Chain Message from Moonbase with Wormhole {: #send-message-from-moonbase } Now, to send a cross-chain message, you just need to call the `sendMessage(string memory message, address destAddress, uint16 destChainId)` function. Use the Remix interface. This example is going to send a cross-chain message to the Fantom TestNet, but you can substitute the `destChainId` for whichever EVM you desire. Check the following things: 1. The environment is **Injected Provider** on network 1287 (Moonbase Alpha) 2. You have substantial funds in your wallet from [the faucet](https://faucet.moonbeam.network){target=\_blank} to cover the transaction gas cost on both the origin and destination chains 3. Put a short message of your choice in the **message** input of the **sendMessage** section (in this case, "this is a message") 4. Put the address of your instance of SimpleGeneralMessage on destination chain in the **destAddress** input 5. Put the destination chain’s Wormhole chain ID in the **destChainId** input of the **sendMessage** section 6. Once this is all done, transact the execution and confirm it in MetaMask ![Send a transaction](/images/builders/interoperability/protocols/wormhole/wormhole-5.webp) After a few seconds to a minute, cross-chain messages should be properly relayed through the relayer that you are hosting on your local machine.
debug | spyEventSource: 7iWtnE4whSBtCxmUA87FUQkCLhy92gHW/qIg6/vTMNM= debug | spyEventSource: 10 info | missedVaafetching: Fetching missed vas for 10: 0000000000000000000000001fd6d0beaf150526a6e48dbde8484a73a280a45, from 1 to 2 debug | SimpleGeneralMessagePlugin: VAA hash: 7iWtnE4whSBtCmUA87FUQkCLhy92gHW/qIg6/VTMNM= info | leventHarness: Received workflow data from plugin SimpleGeneralMessagePlugin, adding workflow. debug | GlobalStorage: Updating emitter record last seen sequence. debug | GlobalStorage: Found emitterRecord debug | executorHarness: New workflow found info | executorHarness: Starting workflow. info | SimpleGeneralMessagePlugin: Workflow 10/0000000000000000000000001d6d0beaf150526a648dbde8484a73a280a45/2/ee25 a received. info | SimpleGeneralMessagePlugin: Parsed VAA. seq: 2 info | SimpleGeneralMessagePlugin: VAA: 0x0394c0edf cca370b20622721985b577850b@eb75 sent "this is a message" to exa8add 09e4fcf1b5edc588c54bee137cb35e61f5b on chain 16. debug | GlobalStorage: Updated emitter record. Key SimpleGeneralMessagePlugin:10:0000000000000000000000001d6d0beaf150 52f6a648dbde8484a73a280a45, {"lastSeenSequence":2,"time":"2023-03-14T21:38:11.780Z"} info | Moonbase Alpha-0-worker: Relaying action for plugin SimpleGeneralMessagePlugin, debug | executorHarness: No new workflows found. info | SimpleGeneralMessagePlugin: [object Object] info | Moonbase Alpha-0-worker: Action SimpleGeneralMessagePlugin completed info | executorHarness: Finished executing workflow.
## Moonbeam Routed Liquidity Integration {: #moonbeam-routed-liquidity-integration } Wormhole will provide liquidity to parachains through the Moonbeam Routed Liquidity (MRL) program. This program allows one-click transfers of liquidity from Wormhole connected chains into parachain wallets by sending liquidity through Moonbeam networks. [MRL](/builders/interoperability/mrl/){target=\_blank} utilizes the [GMP Precompile](/builders/ethereum/precompiles/interoperability/gmp/){target=\_blank}, whose documentation explains how cross-chain messages should be constructed to properly use the precompile.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/core-concepts/ --- BEGIN CONTENT --- --- title: Core Concepts in XCM description: Discover some of the fundamental components involved in constructing cross-chain messages, such as XCM instructions and multilocations. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/core-concepts/instructions/ --- BEGIN CONTENT --- --- title: XCM Instructions description: When XCM instructions are combined, they form an XCM message that performs a cross-chain action. Take a look at some of the most common instructions. categories: XCM, Basics --- # XCM Instructions ## Introduction {: #introduction } XCM messages contain a series of [actions and instructions](https://github.com/paritytech/xcm-format#5-the-xcvm-instruction-set){target=\_blank} that are executed by the Cross-Consensus Virtual Machine (XCVM). An action (for example, transferring a token from one blockchain to another) consists of instructions that the XCVM partly executes in the origin and destination chains. For example, an XCM message that transfers DOT from Polkadot to Moonbeam will include the following XCM instructions (in that order), some of which are executed on Polkadot and some of which are executed on Moonbeam: 1. [TransferReserveAsset](#transfer-reserve-asset) — executed in Polkadot 2. [ReserveAssetDeposited](#reserve-asset-deposited) — executed in Moonbeam 3. [ClearOrigin](#clear-origin) — executed in Moonbeam 4. [BuyExecution](#buy-execution) — executed in Moonbeam 5. [DepositAsset](#deposit-asset) — executed in Moonbeam Building the instructions for an XCM message from scratch is not an easy task. Consequently, there are wrapper functions and pallets that developers can leverage to use XCM features. The [Polkadot XCM](/builders/interoperability/xcm/xc20/send-xc20s/xcm-pallet/){target=\_blank} and [XCM Transactor](/builders/interoperability/xcm/remote-execution/substrate-calls/xcm-transactor-pallet/){target=\_blank} Pallets provide functions with a predefined set of XCM instructions to either send [XC-20s](/builders/interoperability/xcm/xc20/overview/){target=\_blank} or remotely execute on other chains via XCM. If you're interested in experimenting with different combinations of instructions, you can [use the Polkadot XCM Pallet to execute and send custom XCM messages](/builders/interoperability/xcm/send-execute-xcm/){target=\_blank}. This guide provides an overview of some of the most commonly used XCM instructions, including those in the above example. ## Buy Execution {: #buy-execution } The [`BuyExecution`](https://github.com/paritytech/xcm-format#buyexecution){target=\_blank} instruction typically gets executed in the target chain. It takes assets from the holding register, a temporary position in the Cross-Consensus Virtual Machine (XCVM), to pay for execution fees. The target chain determines the fees to pay. ## Clear Origin {: #clear-origin } The [`ClearOrigin`](https://github.com/paritytech/xcm-format#clearorigin){target=\_blank} instruction gets executed in the target chain. It clears the origin of the XCM author, thereby ensuring that later XCM instructions cannot command the authority of the author. ## Deposit Asset {: #deposit-asset } The [`DepositAsset`](https://github.com/paritytech/xcm-format#depositasset){target=\_blank} instruction gets executed in the target chain. It removes the assets from the holding register, a temporary position in the Cross-Consensus Virtual Machine (XCVM), and sends them to a destination account on the target chain. ## Descend Origin {: #descend-origin } The [`DescendOrigin`](https://github.com/paritytech/xcm-format#descendorigin){target=\_blank} instruction gets executed in the target chain. It mutates the origin on the target chain to match the origin on the source chain, ensuring execution on the target chain occurs on behalf of the same entity initiating the XCM message on the source chain. ## Initiate Reserve Withdraw {: #initiate-reserve-withdraw } The [`InitiateReserveWithdraw`](https://github.com/paritytech/xcm-format#initiatereservewithdraw){target=\_blank} instruction gets executed in the source chain. It removes the assets from the holding register, a temporary position in the Cross-Consensus Virtual Machine (XCVM), (essentially burning them), and sends an XCM message to the reserve chain starting with the `WithdrawAsset` instruction. ## Refund Surplus {: #refund-surplus } The [`RefundSurplus`](https://github.com/paritytech/xcm-format#refundsurplus){target=\_blank} instruction typically gets executed in the target chain after the XCM is processed. This instruction will take any leftover assets from the `BuyExecution` instruction and put the assets into the holding register, a temporary position in the Cross-Consensus Virtual Machine (XCVM). ## Reserve Asset Deposited {: #reserve-asset-deposited } The [`ReserveAssetDeposited`](https://github.com/paritytech/xcm-format#reserveassetdeposited-){target=\_blank} instruction gets executed in the target chain. It takes a representation of the assets received in the Sovereign account and places them into the holding register, a temporary position in the Cross-Consensus Virtual Machine (XCVM). ## Set Appendix {: #set-appendix } The [`SetAppendix`](https://github.com/paritytech/xcm-format#setappendix){target=\_blank} instruction gets executed in the target chain. It sets the appendix register, which holds code that should be run after the current execution is finished. ## Transfer Reserve Asset {: #transfer-reserve-asset } The [`TransferReserveAsset`](https://github.com/paritytech/xcm-format#transferreserveasset){target=\_blank} instruction gets executed in the reserve chain. It moves assets from the origin account and deposits them into a destination account on the target chain. It then sends an XCM message to the target chain with the `ReserveAssetDeposited` instruction, followed by the XCM instructions that are to be executed. ## Transact {: #transact } The [`Transact`](https://github.com/paritytech/xcm-format#transact){target=\_blank} instruction gets executed in the target chain. It dispatches encoded call data from a given origin, allowing for the execution of specific operations or functions on the target chain. ## Withdraw Asset {: #withdraw-asset } The [`WithdrawAsset`](https://github.com/paritytech/xcm-format#withdrawasset){target=\_blank} instruction can be executed in either the source or target chain. It removes assets and places them into the holding register, a temporary position in the Cross-Consensus Virtual Machine (XCVM). --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/core-concepts/multilocations/ --- BEGIN CONTENT --- --- title: XCM Multilocations description: Learn everything there is to know about multilocations, their role in XCM, and how to format a multilocation to target a specific point in the ecosystem. categories: XCM --- # Multilocations ## Introduction {: #introduction } A multilocation defines a specific point in the entire relay chain/parachain ecosystem relative to a given origin. It can be used to target a specific parachain, asset, account, or even a pallet inside a parachain. Multilocations follow a hierarchical structure, in which some locations are encapsulated within others. For example, a relay chain encapsulates all of the parachains that are connected to it. Similarly, a parachain encapsulates all of the pallets, accounts, and assets that exist within it. ![Hierarchy of multilocations](/images/builders/interoperability/xcm/core-concepts/multilocations/multilocations-1.webp) ## Defining a Multilocation {: #defining-a-multilocation } A multilocation contains two parameters: - `parents` - refers to how many "hops" up into a parent blockchain you need to take from a given origin. From the perspective of a parachain within the relay chain ecosystem, there can only be one parent, so the value for `parents` can only ever be `0` to represent the parachain or `1` to represent the relay chain. When defining universal locations that consider other consensus systems like Ethereum, `parents` can have higher values - `interior` - refers to how many fields you need to define the target point. From the relay chain, you can drill down to target a specific parachain, or account, asset, or pallet on that parachain. Since this downward movement can be more complex, [Junctions](#junctions) are used to represent the steps needed to reach the target location and are defined by `XN`, where `N` is the number of Junctions required. If no Junctions are required to define the target point, its value would be `Here` as opposed to `X1` For example, if you are targeting the relay chain specifically, you'll use `Here` since you aren't defining an account on the relay chain, a parachain, or a specific point within a parachain. On the flip side, if you're targeting an account on the relay chain, or a parachain, or a specific point within a parachain, you'll use one or more Junctions, as needed. ### Junctions {: #junctions } A Junction can be any of the following: - `Parachain` - describes a parachain using the parachain's ID ```js { Parachain: INSERT_PARACHAIN_ID } ``` - `AccountId32` - describes a 32-byte Substrate-style account. Accepts an optional `network` parameter, which can be one of the following: `Any`, `Named`, `Polkadot`, or `Kusama` ```js { AccountId32: { id: INSERT_ADDRESS, network: INSERT_NETWORK } } ``` - `AccountIndex64` - describes a 64-bit (8-byte) index for an account. Accepts an optional `network` parameter, which can be one of the following: `Any`, `Named`, `Polkadot`, or `Kusama` ```js { AccountIndex64: { index: INSERT_ACCOUNT_INDEX, network: INSERT_NETWORK } } ``` - `AccountKey20` - describes a 20-byte Ethereum-style account, as is used in Moonbeam. Accepts an optional `network` parameter, which can be one of the following: `Any`, `Named`, `Polkadot`, or `Kusama` ```js { AccountKey20: { key: INSERT_ADDRESS, network: INSERT_NETWORK } } ``` - `PalletInstance` - describes the index of a pallet on the target chain ```js { PalletInstance: INSERT_PALLET_INSTANCE_INDEX } ``` - `GeneralIndex` - describes a nondescript index that can be used to target data stored in a key-value format ```js { GeneralIndex: INSERT_GENERAL_INDEX } ``` - `GeneralKey` - describes a nondescript key that can be used to target more complex data structures. This requires you to specify the `data` and the `length` of the data ```js { GeneralKey: { length: INSERT_LENGTH_OF_DATA, data: [INSERT_DATA] } } ``` - `OnlyChild` - describes the child of a location if there is only a one-to-one relation between the parent and child. This is currently not used except as a fallback when deriving context - `Plurality` - describes multiple elements that meet specific conditions or share common characteristics. This requires you to specify the [Body ID](https://github.com/paritytech/polkadot-sdk/blob/{{ polkadot_sdk }}/polkadot/xcm/src/v3/junction.rs#L150-L176){target=\_blank} and the [Body Part](https://github.com/paritytech/polkadot-sdk/blob/{{ polkadot_sdk }}/polkadot/xcm/src/v3/junction.rs#L222-L251){target=\_blank} that the Junction represents ```js { Plurality: { id: INSERT_BODY_ID, part: INSERT_BODY_PART } } ``` When using Junctions, you'll use `XN`, where `N` is the number of Junctions required to reach the target location. For example, if you're targeting an account on Moonbeam from a parachain, `parents` needs to be set to `1`, and you'll need to define two Junctions, the `Parachain` and the `AccountKey20`, so you'll use `X2`, which is an array that will contain each Junction: ```js { parents: 1, interior: { X2: [ { Parachain: 2004 }, { AccountKey20: { key: 'INSERT_MOONBEAM_ADDRESS' } }, ], }, }; ``` ## Example Multilocations {: #example-multilocations } ### Target Moonbeam from Another Parachain {: #target-moonbeam-from-parachain } To target a Moonbeam-based chain from another parachain, you would use the following multilocation: === "Moonbeam" ```js { parents: 1, interior: { X1: [{ Parachain: 2004 }], }, }; ``` === "Moonriver" ```js { parents: 1, interior: { X1: [{ Parachain: 2023 }], }, }; ``` === "Moonbase Alpha" ```js { parents: 1, interior: { X1: [{ Parachain: 1000 }], }, }; ``` ### Target an Account on Moonbeam from Another Parachain {: #target-account-moonbeam-from-parachain } To target a specific account on a Moonbeam-based chain from another parachain, you would use the following multilocation: === "Moonbeam" ```js { parents: 1, interior: { X2: [ { Parachain: 2004 }, { AccountKey20: { key: 'INSERT_MOONBEAM_ADDRESS' } }, ], }, }; ``` === "Moonriver" ```js { parents: 1, interior: { X2: [ { Parachain: 2023 }, { AccountKey20: { key: 'INSERT_MOONBEAM_ADDRESS' } }, ], }, }; ``` === "Moonbase Alpha" ```js { parents: 1, interior: { X2: [ { Parachain: 1000 }, { AccountKey20: { key: 'INSERT_MOONBEAM_ADDRESS' } }, ], }, }; ``` ### Target Moonbeam's Native Asset from Another Parachain {: #target-moonbeam-native-asset-from-parachain } To target the native asset of a Moonbeam-based chain from another parachain, you would use the following multilocation: === "Moonbeam" ```js { parents: 1, interior: { X2: [ { Parachain: 2004 }, { PalletInstance: 10 }, // Index of the Balances Pallet on Moonbeam ], }, }; ``` === "Moonriver" ```js { parents: 1, interior: { X2: [ { Parachain: 2023 }, { PalletInstance: 10 }, // Index of the Balances Pallet on Moonriver ], }, }; ``` === "Moonbase Alpha" ```js { parents: 1, interior: { X2: [ { Parachain: 1000 }, { PalletInstance: 3 }, // Index of the Balances Pallet on Moonbase Alpha ], }, }; ``` ### Target Moonbeam from the Relay Chain {: #target-moonbeam-from-relay } To target a Moonbeam-based chain from the relay chain, you would use the following multilocation: === "Moonbeam" ```js { parents: 0, interior: { X1: [{ Parachain: 2004 }], }, }; ``` === "Moonriver" ```js { parents: 0, interior: { X1: [{ Parachain: 2023 }], }, }; ``` === "Moonbase Alpha" ```js { parents: 0, interior: { X1: [{ Parachain: 1000 }], }, }; ``` ### Target the Relay Chain from Moonbeam {: #target-relay-from-moonbeam } To target the relay chain from a Moonbeam-based chain, you would use the following multilocation: === "Moonbeam" ```js { parents: 1, interior: Here, }; ``` === "Moonriver" ```js { parents: 1, interior: Here, }; ``` === "Moonbase Alpha" ```js { parents: 1, interior: Here, }; ``` ### Target an Account on the Relay Chain from Moonbeam {: #target-account-relay-from-moonbeam } To target a specific account on the relay chain, you would use the following multilocation: === "Moonbeam" ```js { parents: 1, interior: { X1: { AccountId32: { id: INSERT_RELAY_ADDRESS } } }, }; ``` === "Moonriver" ```js { parents: 1, interior: { X1: { AccountId32: { id: INSERT_RELAY_ADDRESS } } }, }; ``` === "Moonbase Alpha" ```js { parents: 1, interior: { X1: { AccountId32: { id: INSERT_RELAY_ADDRESS } } }, }; ``` ### Target Another Parachain from Moonbeam {: #target-parachain-from-moonbeam } To target another parachain (for example, a parachain that has an ID of 1234) from Moonbeam, you would use the following multilocation: === "Moonbeam" ```js { parents: 1, interior: { X1: [{ Parachain: 1234 }], }, }; ``` === "Moonriver" ```js { parents: 1, interior: { X1: [{ Parachain: 1234 }], }, }; ``` === "Moonbase Alpha" ```js { parents: 1, interior: { X1: [{ Parachain: 1234 }], }, }; ``` ### Location to Account API {: #location-to-account-api } The Location to Account API is an easy way to convert a multilocation into an `AccountID20` address. The Location to Account API can be accessed from the [Runtime Calls](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbeam.network#/runtime){target=\_blank} tab of the **Developer** section of Polkadot.js Apps. The `convertLocation` method of the Location to Account API takes a multilocation as a parameter and returns an `AccountID20` address. ```javascript // Query the locationToAccountApi using convertLocation method const result = await api.call.locationToAccountApi.convertLocation(multilocation); console.log('Conversion result:', result.toHuman()); ``` You can view the complete script below. ??? code "View the complete script" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Construct API provider const wsProvider = new WsProvider('INSERT_WSS_ENDPOINT'); const api = await ApiPromise.create({ provider: wsProvider }); // Define the multilocation parameter const multilocation = { V4: { parents: 1, interior: 'Here', }, }; // Query the locationToAccountApi using convertLocation method const result = await api.call.locationToAccountApi.convertLocation(multilocation); console.log('Conversion result:', result.toHuman()); // Disconnect the API await api.disconnect(); }; main().catch(console.error); ``` The method will return the `AccountID20` address corresponding to the provided multilocation as follows: ```bash Conversion result: { Ok: '0x506172656E740000000000000000000000000000' } ``` --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/core-concepts/sovereign-accounts/ --- BEGIN CONTENT --- --- title: Sovereign Accounts and Reserve-Backed Transfers description: Discover how sovereign accounts work on Moonbeam, how to calculate them, and their role in cross-chain asset transfers. categories: XCM --- # Overview of Sovereign Accounts ## Introduction {: #introduction } In Polkadot-based ecosystems, a sovereign account is a unique, keyless account controlled by a blockchain’s runtime through XCM rather than an individual or organization. These accounts are used to store assets when transferring tokens cross-chain. For example, if you send a reserve tokens transfer from a parachain to Moonbeam, the originating parachain locks those tokens in Moonbeam’s sovereign account on the source chain, while a wrapped representation of those tokens is minted on Moonbeam. Sovereign accounts play a central role in [reserve-backed transfers](https://wiki.polkadot.network/learn/learn-xcm-usecases/#reserve-asset-transfer){target=\_blank}, where one chain (the “reserve”) holds the real assets and other chains hold derivative tokens. When tokens move across chains, the reserve (or origin) chain locks or unlocks the underlying asset, and derivative tokens are minted or burned on the destination chain. ## Calculating a Parachain Sovereign Account {: #calculating-sovereign } You can calculate a parachain’s sovereign account on a given relay chain using the [xcm-tools](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank} repository. This is especially useful when you need to verify where underlying tokens are locked or to fund a parachain’s sovereign account directly. 1. Clone or navigate to the [xcm-tools repository](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank} 2. Use the `calculate-sovereign-account` script, specifying the **Parachain ID** with the `--p` flag and the relay chain with the `--r` flag (default is `polkadot`; other accepted values are `kusama` or `moonbase`) The parachain ID you need can be found on the respective relay chain’s [Polkadot.js Apps **Parachains** page](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frelay.api.moonbase.moonbeam.network#/parachains){target=\_blank}. The **Parachains** page can be accessed under the **Network** dropdown. For example, to calculate the sovereign account address for parachain `1000` on the Moonbase Alpha testnet: ```bash yarn calculate-sovereign-account --p 1000 --r moonbase ``` Running the script will generate output like the following:
yarn calculate-sovereign-account --p 1000 --r moonbase yarn run v1.22.22 $ ts-node 'scripts/calculate-sovereign-account.ts' --p 1000 --r moonbase Sovereign Account Address on Relay: 0x70617261e8030000000000000000000000000000000000000000000000000000 Sovereign Account Address on other Parachains (Generic): 0x7369626ce8030000000000000000000000000000000000000000000000000000 Sovereign Account Address on Moonbase Alpha: 0x7369626ce8030000000000000000000000000000
The relay address is how the Polkadot or Kusama relay chain references the sovereign account. Generic parachain address is typically used for referencing this parachain’s sovereign account from other parachains. The Moonbase Alpha address is the corresponding sovereign account in the H160 EVM address format used by Moonbase Alpha. ## Learn More {: #learn-more } Sovereign accounts form the backbone of reserve-backed transfers, enabling safe custody of assets for minting wrapped tokens across Polkadot’s ecosystem. By combining sovereign accounts with the XCM framework, parachains can interoperate seamlessly—locking and unlocking assets in a transparent, trust-minimized way. For more information about how sovereign accounts facilitate cross-chain transfers with XCM, be sure to check out the [Send XC-20s section](/builders/interoperability/xcm/xc20/send-xc20s/overview/){target=\_blank}. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/core-concepts/weights-fees/ --- BEGIN CONTENT --- --- title: XCM Execution Fees description: Learn about the XCM instructions involved in handling XCM execution fee payments and how to calculate fees on Polkadot, Kusama, and Moonbeam-based networks. categories: XCM --- # XCM Fees on Moonbeam ## Introduction {: #introduction} XCM aims to be a language that communicates ideas between consensus systems. Sending an XCM message consists of a series of instructions that are executed in both the origin and the destination chains. The combination of XCM instructions results in actions such as token transfers. In order to process and execute each XCM instruction, there are typically associated fees that must be paid. However, XCM is designed to be general, extensible, and efficient so that it remains valuable and future-proof throughout a growing ecosystem. As such, the generality applies to concepts including payments of fees for XCM execution. In Ethereum, fees are baked into the transaction protocol, whereas in the Polkadot ecosystem, each chain has the flexibility to define how XCM fees are handled. This guide will cover aspects of fee payment, such as who is responsible for paying XCM execution fees, how it is paid for, and how the fees are calculated on Moonbeam. !!! note **The following information is provided for general information purposes only.** The weight and extrinsic base cost might have changed since the time of writing. Please ensure you check the actual values, and never use the following information for production apps. ## Payment of Fees {: #payment-of-fees } Generally speaking, the fee payment process can be described as follows: 1. Some assets need to be provided 2. The exchange of assets for computing time (or weight) must be negotiated 3. The XCM operations will be performed as instructed, with the provided weight limit or funds available for execution Each chain can configure what happens with the XCM fees and in which tokens they can be paid (either the native reserve token or an external one). For example: - **Polkadot and Kusama** - the fees are paid in DOT or KSM (respectively) and given to the validator of the block - **Moonbeam and Moonriver** - the XCM execution fees can be paid in the reserve asset (GLMR or MOVR, respectively), but also in assets originated in other chains if they are registered as an [XCM execution asset](/builders/interoperability/xcm/xc-registration/assets/){target=\_blank}. When XCM execution (token transfers or remote execution) is paid in the native chain reserve asset (GLMR or MOVR), {{ networks.moonbeam.treasury.tx_fees_burned }}% is burned. When XCM execution is paid in a foreign asset, the fee is sent to the Treasury Consider the following scenario: Alice has some DOT on Polkadot, and she wants to transfer it to Alith on Moonbeam. She sends an XCM message with a set of XCM instructions that will retrieve a given amount of DOT from her account on Polkadot and mint them as xcDOT into Alith's account. Part of the instructions are executed on Polkadot, and the other part is executed on Moonbeam. How does Alice pay Moonbeam to execute these instructions and fulfill her request? Her request is fulfilled through a series of XCM instructions that are included in the XCM message, which enables her to buy execution time minus any related XCM execution fees. The execution time is used to issue and transfer xcDOT, a representation of DOT on Moonbeam. This means that when Alice sends some DOT to Alith's account on Moonbeam, she'll receive a 1:1 representation of her DOT as xcDOT minus any XCM execution fees. Note that in this scenario, XCM execution fees are paid in xcDOT and sent to the treasury. The exact process for Alice's transfer is as follows: 1. Assets are sent to an account on Polkadot that is owned by Moonbeam, known as the Sovereign account. After the assets are received, an XCM message is sent to Moonbeam 2. The XCM message in Moonbeam will: 1. Mint the corresponding asset representation 2. Buy the corresponding execution time 3. Use that execution time to deposit the representation (minus fees) to the destination account ### XCM Instructions {: #xcm-instructions } An XCM message is comprised of a series of XCM instructions. As a result, different combinations of XCM instructions result in different actions. For example, to move DOT to Moonbeam, the following XCM instructions are used: When DOT is transferred from Polkadot to Moonbeam, the following XCM instructions are executed in sequence: 1. [`TransferReserveAsset`](/builders/interoperability/xcm/core-concepts/instructions/#transfer-reserve-asset){target=_blank} - executes on Polkadot, moving the DOT from the sender and depositing it into Moonbeam’s Sovereign account on Polkadot 2. [`ReserveAssetDeposited`](/builders/interoperability/xcm/core-concepts/instructions/#reserve-asset-deposited){target=_blank} - executes on Moonbeam, minting the corresponding ERC-20 representation of DOT (xcDOT) on Moonbeam 3. [`ClearOrigin`](/builders/interoperability/xcm/core-concepts/instructions/#clear-origin){target=_blank} - executes on Moonbeam, clearing any origin data—previously set to Polkadot’s Sovereign account 4. [`BuyExecution`](/builders/interoperability/xcm/core-concepts/instructions/#buy-execution){target=_blank} - executes on Moonbeam, determining the execution fees. Here, a portion of the newly minted xcDOT is used to pay the cost of XCM 5. [`DepositAsset`](/builders/interoperability/xcm/core-concepts/instructions/#deposit-asset){target=_blank} - executes on Moonbeam, delivering the xcDOT to the intended recipient’s account on Moonbeam To check how the instructions for an XCM message are built to transfer self-reserve assets to a target chain, such as DOT to Moonbeam, you can refer to the [X-Tokens Open Runtime Module Library](https://github.com/moonbeam-foundation/open-runtime-module-library/blob/master/xtokens/src/lib.rs){target=\_blank} repository (as an example). You'll want to take a look at the [`transfer_self_reserve_asset`](https://github.com/moonbeam-foundation/open-runtime-module-library/blob/master/xtokens/src/lib.rs#L699){target=\_blank} function. You'll notice it calls `TransferReserveAsset` and passes in `assets`, `dest`, and `xcm` as parameters. In particular, the `xcm` parameter includes the `BuyExecution` and `DepositAsset` instructions. If you then head over to the Polkadot GitHub repository, you can find the [`TransferReserveAsset` instruction](https://github.com/paritytech/polkadot-sdk/blob/{{ polkadot_sdk }}/polkadot/xcm/xcm-executor/src/lib.rs#L671){target=\_blank}. The XCM message is constructed by combining the `ReserveAssetDeposited` and `ClearOrigin` instructions with the `xcm` parameter, which as mentioned includes the `BuyExecution` and `DepositAsset` instructions. In scenarios where you want to move an asset back to its reserve chain, such as sending xcDOT from Moonbeam to Polkadot, Moonbeam uses the following set of XCM instructions: 1. [`WithdrawAsset`](/builders/interoperability/xcm/core-concepts/instructions/#withdraw-asset){target=_blank} – executes on Moonbeam, taking the specified token (xcDOT) from the sender 2. [`InitiateReserveWithdraw`](/builders/interoperability/xcm/core-concepts/instructions/#initiate-reserve-withdraw){target=_blank} – executes on Moonbeam, which, burns the token on Moonbeam (removing the wrapped representation), and sends an XCM message to Polkadot, indicating the tokens should be released there 3. [`WithdrawAsset`](/builders/interoperability/xcm/core-concepts/instructions/#withdraw-asset){target=_blank} – executes on Polkadot, removing the tokens from Moonbeam’s Sovereign account on Polkadot 4. [`ClearOrigin`](/builders/interoperability/xcm/core-concepts/instructions/#clear-origin){target=_blank} – gets executed on Polkadot. Clears any origin data (e.g., the Sovereign account on Moonbeam) 5. [`BuyExecution`](/builders/interoperability/xcm/core-concepts/instructions/#buy-execution){target=_blank} – Polkadot determines the execution fees and uses part of the DOT being transferred to pay for them 6. [`DepositAsset`](/builders/interoperability/xcm/core-concepts/instructions/#deposit-asset){target=_blank} – finally, the native DOT tokens are deposited into the specified Polkadot account To check how the instructions for an XCM message are built to transfer reserve assets to a target chain, such as xcDOT to Polkadot, you can refer to the [X-Tokens Open Runtime Module Library](https://github.com/moonbeam-foundation/open-runtime-module-library/tree/master/xtokens){target=\_blank} repository. You'll want to take a look at the [`transfer_to_reserve`](https://github.com/moonbeam-foundation/open-runtime-module-library/blob/master/xtokens/src/lib.rs#L719){target=\_blank} function. You'll notice that it calls `WithdrawAsset`, then `InitiateReserveWithdraw` and passes in `assets`, `dest`, and `xcm` as parameters. In particular, the `xcm` parameter includes the `BuyExecution` and `DepositAsset` instructions. If you then head over to the Polkadot GitHub repository, you can find the [`InitiateReserveWithdraw` instruction](https://github.com/paritytech/polkadot-sdk/blob/{{polkadot_sdk}}/polkadot/xcm/xcm-executor/src/lib.rs#L903){target=\_blank}. The XCM message is constructed by combining the `WithdrawAsset` and `ClearOrigin` instructions with the `xcm` parameter, which as mentioned includes the `BuyExecution` and `DepositAsset` instructions. ## Relay Chain XCM Fee Calculation {: #rel-chain-xcm-fee-calc } Substrate has introduced a weight system that determines how heavy or, in other words, how expensive from a computational cost perspective an extrinsic is. One unit of weight is defined as one picosecond of execution time. When it comes to paying fees, users will pay a transaction fee based on the weight of the call that is being made, in addition to factors such as network congestion. The following sections will break down how to calculate XCM fees for Polkadot and Kusama. It's important to note that Kusama, in particular, uses benchmarked data to determine the total weight costs for XCM instructions and that some XCM instructions might include database reads and writes, which add weight to the call. There are two databases available in Polkadot and Kusama: RocksDB (which is the default) and ParityDB, both of which have their own associated weight costs for each network. ### Polkadot {: #polkadot } The total weight costs on Polkadot take into consideration database reads and writes in addition to the weight required for a given instruction. Polkadot uses benchmarked weights for instructions, and database read-and-write operations. The breakdown of weight costs for the database operations can be found on the respective repository files for [RocksDB (default)](https://github.com/polkadot-fellows/runtimes/blob/{{ networks.polkadot.spec_version }}/relay/polkadot/constants/src/weights/rocksdb_weights.rs){target=\_blank} and [ParityDB](https://github.com/polkadot-fellows/runtimes/blob/{{ networks.polkadot.spec_version }}/relay/polkadot/constants/src/weights/paritydb_weights.rs){target=\_blank}. Now that you are aware of the weight costs for database reads and writes on Polkadot, you can calculate the weight cost for a given instruction using the base weight for instructions. On Polkadot, the benchmarked base weights are broken up into two categories: fungible and generic. Fungible weights are for XCM instructions that involve moving assets, and generic weights are for everything else. You can view the current weights for [fungible assets](https://github.com/polkadot-fellows/runtimes/blob/{{ networks.polkadot.spec_version }}/relay/polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs#L46){target=\_blank} and [generic assets](https://github.com/polkadot-fellows/runtimes/blob/{{networks.polkadot.spec_version}}/relay/polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs#L46){target=\_blank} directly in the Polkadot Runtime code. With the instruction weight cost established, you can calculate the cost of each instruction in DOT. In Polkadot, the [`ExtrinsicBaseWeight`](https://github.com/polkadot-fellows/runtimes/blob/{{ networks.polkadot.spec_version }}/relay/polkadot/constants/src/weights/extrinsic_weights.rs#L56){target=\_blank} is set to `{{ networks.polkadot.extrinsic_base_weight.display }}` which is [mapped to 1/10th](https://github.com/polkadot-fellows/runtimes/blob/{{ networks.polkadot.spec_version }}/relay/polkadot/constants/src/lib.rs#L92){target=\_blank} of a cent. Where 1 cent is `10^10 / 100`. Therefore, to calculate the cost of executing an XCM instruction, you can use the following formula: ```text XCM-DOT-Cost = XCMInstrWeight * DOTWeightToFeeCoefficient ``` Where `DOTWeightToFeeCoefficient` is a constant (map to 1 cent), and can be calculated as: ```text DOTWeightToFeeCoefficient = 10^10 / ( 10 * 100 * DOTExtrinsicBaseWeight ) ``` Now, you can begin to calculate the final fee in DOT, using `DOTWeightToFeeCoefficient` as a constant and `TotalWeight` as the variable: ```text XCM-Planck-DOT-Cost = TotalWeight * DOTWeightToFeeCoefficient XCM-DOT-Cost = XCM-Planck-DOT-Cost / DOTDecimalConversion ``` ### Kusama {: #kusama } The total weight costs on Kusama take into consideration database reads and writes in addition to the weight required for a given instruction. The breakdown of weight costs for the database operations can be found on the respective repository files for [RocksDB (default)](https://github.com/polkadot-fellows/runtimes/blob/{{ networks.kusama.spec_version }}/relay/kusama/constants/src/weights/rocksdb_weights.rs){target=\_blank} and [ParityDB](https://github.com/polkadot-fellows/runtimes/blob/{{ networks.kusama.spec_version }}/relay/kusama/constants/src/weights/paritydb_weights.rs){target=\_blank}. On Kusama, the benchmarked base weights are broken up into two categories: fungible and generic. Fungible weights are for XCM instructions that involve moving assets, and generic weights are for everything else. You can view the current weights for [fungible assets](https://github.com/polkadot-fellows/runtimes/blob/{{ networks.kusama.spec_version }}/relay/kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs#L46){target=\_blank} and [generic assets](https://github.com/polkadot-fellows/runtimes/blob/{{networks.kusama.spec_version}}/relay/kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs#L46){target=\_blank} directly in the Kusama Runtime code. With the instruction weight cost established, you can calculate the cost of the instruction in KSM with the [`ExtrinsicBaseWeight`](https://github.com/polkadot-fellows/runtimes/blob/{{networks.kusama.spec_version}}/relay/kusama/constants/src/weights/extrinsic_weights.rs#L56){target=\_blank} and the [weight fee mapping](https://github.com/polkadot-fellows/runtimes/blob/{{networks.kusama.spec_version}}/relay/kusama/constants/src/lib.rs#L90){target=\_blank}. To calculate the cost of executing an XCM instruction, you can use the following formula: ```text XCM-KSM-Cost = XCMInstrWeight * KSMWeightToFeeCoefficient ``` Where `KSMWeightToFeeCoefficient` is a constant (map to 1 cent), and can be calculated as: ```text KSMWeightToFeeCoefficient = 10^12 / ( 10 * 3000 * KSMExtrinsicBaseWeight ) ``` Now, you can begin to calculate the final fee in KSM, using `KSMWeightToFeeCoefficient` as a constant and `TotalWeight` as the variable: ```text XCM-Planck-KSM-Cost = TotalWeight * KSMWeightToFeeCoefficient XCM-KSM-Cost = XCM-Planck-KSM-Cost / KSMDecimalConversion ``` ## Moonbeam-based Networks XCM Fee Calculation {: #moonbeam-xcm-fee-calc } Substrate has introduced a weight system that determines how heavy or, in other words, how expensive an extrinsic is from a computational cost perspective. One unit of weight is defined as one picosecond of execution time. When it comes to paying fees, users will pay a transaction fee based on the weight of the call being made, and each parachain can decide how to convert weight to fee. For example, this may account for additional costs related to transaction size and storage. For all Moonbeam-based networks, the generic XCM instructions are benchmarked, while the fungible XCM instructions still use a fixed amount of weight per instruction. Consequently, the total weight cost of the benchmarked XCM instructions considers the number of database reads and writes in addition to the weight required for a given instruction. The Polkadot SDK has a breakdown of the relevant [RocksDB database weights](https://github.com/paritytech/polkadot-sdk/blob/{{polkadot_sdk}}/substrate/frame/support/src/weights/rocksdb_weights.rs#L27-L28){target=\_blank}. Now you can calculate the weight cost for both fungible and generic XCM instructions using the base weight for instruction and the extra database reads and writes if applicable. For example, the `WithdrawAsset` instruction is part of the fungible XCM instructions. Therefore, it is not benchmarked, and the total weight cost of the [`WithdrawAsset` instruction](https://github.com/moonbeam-foundation/moonbeam/blob/{{ networks.moonbeam.spec_version }}/pallets/moonbeam-xcm-benchmarks/src/weights/fungible.rs#L36){target=\_blank} is `{{ xcm.fungible_weights.display }}`, except for when transferring local XC-20s. The total weight cost for the `WithdrawAsset` instruction for local XC-20s is based on converting Ethereum gas to Substrate weight. The `BuyExecution` instruction is generic and therefore has a predefined benchmarked weight. You can view its current base weight in the [Moonbeam runtime source code](https://github.com/moonbeam-foundation/moonbeam/blob/{{ networks.moonbeam.spec_version }}/pallets/moonbeam-xcm-benchmarks/src/weights/generic.rs#L132-L133){target=\_blank}. In addition to the base weight, the instruction performs four database reads, which are added to calculate the total weight. You can find all the weight values for all the XCM instructions in the following table, which apply to all Moonbeam-based networks: | Benchmarked Instructions | Non-Benchmarked Instructions | |:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| | [Generic XCM Instructions](https://github.com/moonbeam-foundation/moonbeam/blob/{{ networks.moonbeam.spec_version }}/pallets/moonbeam-xcm-benchmarks/src/weights/generic.rs#L97){target=\_blank} | [Fungible XCM Instructions](https://github.com/moonbeam-foundation/moonbeam/blob/{{ networks.moonbeam.spec_version }}/pallets/moonbeam-xcm-benchmarks/src/weights/fungible.rs#L29){target=\_blank} | The following sections will break down how to calculate XCM fees for Moonbeam-based networks. There are two main scenarios: - Fees paid in the reserve token (native tokens like GLMR, MOVR, or DEV) - Fees paid in external assets (XC-20s) ### Fee Calculation for Reserve Assets {: #moonbeam-reserve-assets } For each XCM instruction, the weight units are converted to balance units as part of the fee calculation. The amount of Wei per weight unit for each of the Moonbeam-based networks is as follows: | Moonbeam | Moonriver | Moonbase Alpha | |:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| | [{{ networks.moonbeam.xcm.instructions.wei_per_weight.display }}](https://github.com/moonbeam-foundation/moonbeam/blob/{{networks.moonbeam.spec_version}}/runtime/moonbeam/src/lib.rs#L160){target=\_blank} | [{{ networks.moonriver.xcm.instructions.wei_per_weight.display }}](https://github.com/moonbeam-foundation/moonbeam/blob/{{networks.moonriver.spec_version}}/runtime/moonriver/src/lib.rs#L168){target=\_blank} | [{{ networks.moonbase.xcm.instructions.wei_per_weight.display }}](https://github.com/moonbeam-foundation/moonbeam/blob/{{networks.moonbase.spec_version}}/runtime/moonbase/src/lib.rs#L169){target=\_blank} | This means that on Moonbeam, for example, the formula to calculate the cost of one XCM instruction in the reserve asset is as follows: ```text XCM-Wei-Cost = XCMInstrWeight * WeiPerWeight XCM-GLMR-Cost = XCM-Wei-Cost / 10^18 ``` Therefore, the actual calculation for fungible instructions, for example, is: ```text XCM-Wei-Cost = {{ xcm.fungible_weights.numbers_only }} * {{ networks.moonbeam.xcm.instructions.wei_per_weight.numbers_only }} XCM-GLMR-Cost = {{ networks.moonbeam.xcm.transfer_glmr.wei_cost }} / 10^18 ``` The total cost is `{{ networks.moonbeam.xcm.transfer_glmr.glmr_cost }} GLMR` for an XCM instruction on Moonbeam. ### Fee Calculation for External Assets {: #fee-calc-external-assets } Moonbeam charges fees for external assets based on the weight of the call. Weight is a struct that contains two fields, `refTime` and `proofSize`. `refTime` refers to the amount of computational time that can be used for execution. `proofSize` refers to the size of the PoV (Proof of Validity) of the Moonbeam block that gets submitted to the Polkadot Relay Chain for validation. Since both `refTime` and `proofSize` are integral components of determining a weight, it is impossible to obtain an accurate weight value with just one of these values. You can query the `refTime` and `proofSize` of an XCM instruction with the [`queryXcmWeight` method of the `xcmPaymentApi`](#query-xcm-weight). You can do this [programmatically](#query-xcm-weight) or by visiting the [Runtime Calls tab of Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fmoonbeam.api.onfinality.io%2Fpublic-ws#/runtime){target=\_blank}. The `queryXcmWeight` method takes an XCM version and instruction has a parameter and returns the corresponding `refTime` and `proofSize` values. #### Weight to Gas Mapping {: #weight-to-gas-mapping } For calls that are derived from EVM operations, such as the `DepositAsset` instruction which relies on the EVM operation `MintInto`, you can calculate their respective weight values by multiplying the gas limit by weight multipliers. For `refTime`, you'll need to multiply the gas limit by `{{ xcm.generic_weights.weight_per_gas.numbers_only }}` and for `proofSize` you'll need to multiply the gas limit by `{{ xcm.generic_weights.proof_size.weight_per_gas }}`. A chart is included below for convenience. | Weight Type | Multiplier Value | |:-----------:|:---------------------------------------------------:| | Ref Time | {{ xcm.generic_weights.weight_per_gas.display }} | | Proof Size | {{ xcm.generic_weights.proof_size.weight_per_gas }} | To determine the total weight for Alice's transfer of DOT to Moonbeam, you'll need the weight for each of the four XCM instructions required for the transfer. Note that while the first three instructions have specific `refTime` and `proofSize` values corresponding to these instructions that can be retrieved via [`queryXcmWeight` method of the `xcmPaymentApi`](#query-xcm-weight), `DepositAsset` relies on the EVM operation [`MintInto`](https://github.com/moonbeam-foundation/moonbeam/blob/{{ networks.moonbeam.spec_version }}/pallets/moonbeam-foreign-assets/src/evm.rs#L40){target=\_blank} and a `WeightPerGas` conversion of `{{ xcm.generic_weights.weight_per_gas.display }}` per gas. The `refTime` of `DepositAsset` can thus be calculated as: ```text {{ xcm.generic_weights.ref_time.mint_into_gas.numbers_only }} gas * {{ xcm.generic_weights.weight_per_gas.numbers_only }} weight per gas = {{ xcm.generic_weights.ref_time.deposit_asset.numbers_only }} ``` And the `proofSize` of `DepositAsset` can be calculated as: ```text {{ xcm.generic_weights.ref_time.mint_into_gas.numbers_only }} gas * {{ xcm.generic_weights.proof_size.weight_per_gas }} weight per gas = {{ xcm.generic_weights.proof_size.deposit_asset.numbers_only }} ``` ### Weight to Asset Fee Conversion {: #weight-to-asset-fee-conversion} Once you have the sum of the `refTime` and `proofSize` values, you can easily retrieve the required commensurate fee amount. The [`queryWeightToAssetFee` method of the `xcmPaymentApi`](#weight-to-asset-fee-conversion) takes a `refTime`, `proofSize`, and asset multilocation as parameters and returns the commensurate fee. By providing the amounts obtained above of `{{ networks.moonbeam.xcm.transfer_dot.total_weight.display }}` `refTime` and `{{ xcm.generic_weights.proof_size.transfer_dot_total.display }}` `proofSize`, and the asset multilocation for DOT, we get a fee amount of `88,920,522` Plank, which is the smallest unit in Polkadot. We can convert this to DOT by dividing by `10^10` which gets us a DOT fee amount of `{{ networks.moonbeam.xcm.transfer_dot.xcdot_cost }}` DOT. ## XCM Payment API Expanded Examples {: #xcm-payment-api-exanded-examples } The XCM Payment API methods provide various helpful ways to calculate fees, evaluate acceptable fee payment currencies, and more. Remember that in addition to accessing this via API, you can also interact with the XCM Payment API via the [Runtime Calls tab of Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fmoonbeam.api.onfinality.io%2Fpublic-ws#/runtime){target=\_blank}. ### Query Acceptable Fee Payment Assets {: #query-acceptable-fee-payment-assets } This function takes the XCM Version as a parameter and returns a list of acceptable fee assets in multilocation form. ```javascript const allowedAssets = await api.call.xcmPaymentApi.queryAcceptablePaymentAssets(3); console.log(allowedAssets); ``` ??? code "View the complete script" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Construct API provider const wsProvider = new WsProvider('INSERT_WSS_ENDPOINT'); const api = await ApiPromise.create({ provider: wsProvider }); const allowedAssets = await api.call.xcmPaymentApi.queryAcceptablePaymentAssets(4); console.log(allowedAssets); // Disconnect the API await api.disconnect(); }; main(); ``` ### Weight to Asset Fee Conversion {: #weight-to-asset-fee-conversion } This method converts a weight into a fee for the specified asset. It takes as parameters a weight and an asset multilocation and returns the respective fee amount. ```javascript const fee = await api.call.xcmPaymentApi.queryWeightToAssetFee( { refTime: 10_000_000_000n, proofSize: 0n, }, { V3: { Concrete: { parents: 1, interior: 'Here' }, }, } ); console.log(fee); ``` ??? code "View the complete script" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Construct API provider const wsProvider = new WsProvider('INSERT_WSS_ENDPOINT'); const api = await ApiPromise.create({ provider: wsProvider }); const fee = await api.call.xcmPaymentApi.queryWeightToAssetFee( { refTime: 10_000_000_000n, proofSize: 0n, }, { V3: { Concrete: { parents: 1, interior: 'Here' }, }, } ); console.log(fee); // Disconnect the API await api.disconnect(); }; main(); ``` ### Query XCM Weight {: #query-xcm-weight} This method takes an XCM message as a parameter and returns the weight of the message. ```javascript const message = { V3: [instr1, instr2] }; const theWeight = await api.call.xcmPaymentApi.queryXcmWeight(message); console.log(theWeight); ``` ??? code "View the complete script" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Construct API provider const wsProvider = new WsProvider('INSERT_WSS_ENDPOINT'); const api = await ApiPromise.create({ provider: wsProvider }); const amountToSend = BigInt(1 * 10 ** 12); // Sending 1 token (assuming 12 decimal places) const assetMultiLocation = { parents: 0, interior: { X1: { PalletInstance: 3 } }, }; // The asset's location (adjust PalletInstance as needed) const recipientAccount = '0x1234567890abcdef1234567890abcdef12345678'; // The recipient's account on the destination chain // 2. XCM Destination (e.g., Parachain ID 2000) const dest = { V3: { parents: 1, interior: { X1: { Parachain: 2000 } } } }; // 3. XCM Instruction 1: Withdraw the asset from the sender const instr1 = { WithdrawAsset: [ { id: { Concrete: assetMultiLocation }, fun: { Fungible: amountToSend }, }, ], }; // 4. XCM Instruction 2: Deposit the asset into the recipient's account on the destination chain const instr2 = { DepositAsset: { assets: { Wild: 'All' }, // Sending all withdrawn assets (in this case, 1 token) beneficiary: { parents: 0, interior: { X1: { AccountKey20: { key: recipientAccount } } }, }, }, }; // 5. Build the XCM Message const message = { V3: [instr1, instr2] }; const theWeight = await api.call.xcmPaymentApi.queryXcmWeight(message); console.log(theWeight); // Disconnect the API await api.disconnect(); }; main(); ``` --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/ --- BEGIN CONTENT --- --- title: Cross-Chain Communication description: An overview of how cross-consensus messaging (XCM) works and how you can leverage XCM to transfer assets to and from Moonbeam. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/overview/ --- BEGIN CONTENT --- --- title: Cross-Consensus Messaging (XCM) description: An overview of how cross-consensus messaging (XCM) works and how developers can leverage Polkadot/Kusama XCM to gain access to new assets. categories: Basics, XCM --- # Cross-Consensus Messaging (XCM) ## Introduction {: #introduction } [Polkadot's architecture](https://wiki.polkadot.network/learn/learn-architecture/){target=\_blank} allows parachains to natively interoperate with each other, enabling cross-blockchain transfers of any type of data or asset. To do so, a [Cross-Consensus Message (XCM)](https://wiki.polkadot.network/learn/learn-xcm/){target=\_blank} format defines a language around how the message transfer between two interoperating blockchains should be performed. XCM is not specific to Polkadot, as it aims to be a generic and extensible language between different consensus systems. This page is a brief introduction and overview of XCM and other related elements. More information can be found in [Polkadot's Wiki](https://wiki.polkadot.network/learn/learn-xcm/){target=\_blank}. If you want to jump to more XCM-related content, feel free to check out the following pages: - [**Core XCM Concepts**](/builders/interoperability/xcm/core-concepts/){target=\_blank} - learn topics related to [XCM Instructions](/builders/interoperability/xcm/core-concepts/instructions/){target=\_blank}, [Multilocations](/builders/interoperability/xcm/core-concepts/multilocations/){target=\_blank}, and [XCM Fees](/builders/interoperability/xcm/core-concepts/weights-fees/){target=\_blank} - [**XC Registration**](/builders/interoperability/xcm/xc-registration/){target=\_blank} - go through the process of [Opening an XCM Channel with Moonbeam](/builders/interoperability/xcm/xc-registration/xc-integration/){target=\_blank} and how to [Register Polkadot Native Assets as XC-20s](/builders/interoperability/xcm/xc-registration/assets/){target=\_blank} - [**XC-20s**](/builders/interoperability/xcm/xc20/){target=\_blank} - read an [Overview](/builders/interoperability/xcm/xc20/overview/){target=\_blank} of this Moonbeam-only asset class and learn how to [Interact with XC-20s](/builders/interoperability/xcm/xc20/interact/){target=\_blank} and how to [Send them via XCM](/builders/interoperability/xcm/xc20/send-xc20s/){target=\_blank} - [**Remote Execution via XCM**](/builders/interoperability/xcm/remote-execution/){target=\_blank} - grasp all concepts related to remote execution via XCM, starting with a [High-Level Overview](/builders/interoperability/xcm/remote-execution/overview/){target=\_blank}, then [Computed Origins](/builders/interoperability/xcm/remote-execution/computed-origins/){target=\_blank} and wrapping up with [Remote Calls via XCM](/builders/interoperability/xcm/remote-execution/substrate-calls/){target=\_blank} and [Remote EVM Calls via XCM](/builders/interoperability/xcm/remote-execution/remote-evm-calls/){target=\_blank} - [**XCM SDK**](https://moonbeam-foundation.github.io/xcm-sdk/latest/){target=\_blank} - learn how to [Use Moonbeam's XCM SDK](https://moonbeam-foundation.github.io/xcm-sdk/latest/example-usage/xcm/){target=\_blank} - **XCM Debugging and Tools** - learn how to test some XCM scenarios by [Sending and Executing Generic XCM Messages](/builders/interoperability/xcm/send-execute-xcm/){target=\_blank}, or how to use the [XCM Utilities Precompile](/builders/interoperability/xcm/xcm-utils/){target=\_blank} to access XCM_related utility functions directly within the EVM ## General XCM Definitions {: #general-xcm-definitions } - **XCM** — stands for Cross-Consensus Message. It is a general way for consensus systems to communicate with each other - **VMP** — stands for Vertical Message Passing, one of the transport methods for XCMs. It allows parachains to exchange messages with the relay chain. *UMP* (Upward Message Passing) enables parachains to send messages to their relay chain, while *DMP* (Downward Message Passing) enables the relay chain to pass messages down to one of their parachains - **XCMP** — stands for Cross-Consensus Message Passing, one of the transport methods for XCMs. It allows parachains to exchange messages with other parachains on the same relay chain - **HRMP** — stands for Horizontal Relay-routed Message Passing, a stop-gap protocol while a full XCMP implementation is launched. It has the same interface as XCMP, but messages are stored on the relay chain - **Sovereign account** — an account each chain in the ecosystem has, one for the relay chain and the other for other parachains. It is calculated as the `blake2` hash of a specific word and parachain ID concatenated (`blake2(para+ParachainID)` for the Sovereign account in the relay chain, and `blake2(sibl+ParachainID)` for the Sovereign account in other parachains), truncating the hash to the correct length. The account is owned by root and can only be used through SUDO (if available) or [governance (referenda)](/learn/features/governance/){target=\_blank}. The Sovereign account typically signs XCM messages in other chains in the ecosystem - **Multilocation** — a way to specify a point in the entire relay chain/parachain ecosystem relative to a given origin. For example, it can be used to specify a specific parachain, asset, account, or even a pallet inside a parachain. In general terms, a multilocation is defined with a `parents` and an `interior`: - `parents` - refers to how many "hops" into a parent blockchain you need to take from a given origin - `interior` - refers to how many fields you need to define the target point. For example, to target a parachain with ID `1000` from another parachain, the multilocation would be `{ "parents": 1, "interior": { "X1": [{ "Parachain": 1000 }]}}` ## Cross-Chain Transport Protocols via XCM {: #xcm-transport-protocols } XCM implements two cross-consensus or transport protocols for acting on XCM messages between its constituent parachains, Moonbeam being one of them: - **Vertical Message Passing (VMP)** — once a project is onboarded as a parachain, it automatically has a bi-directional communication channel with the relay chain. Therefore, there is no need for chain registration. VMP is divided into two kinds of message-passing transport protocols: * **Upward Message Passing (UMP)** — allows parachains to send messages to their relay chain, for example, from Moonbeam to Polkadot * **Downward Message Passing (DMP)** — allows the relay chain to pass messages down to one of their parachains, for example, from Polkadot to Moonbeam - **Cross-Chain Message Passing (XCMP)** — allows two parachains to exchange messages as long as they are connected to the same relay chain. Cross-chain transactions are resolved using a simple queuing mechanism based on a Merkle tree to ensure fidelity. Collators exchange messages between parachains, while the relay chain validators will verify that the message transmission happened !!! note Currently, while XCMP is being developed, a stop-gap protocol is implemented called Horizontal Relay-routed Message Passing (HRMP), in which the messages are stored in and read from the relay chain. This will be deprecated in the future for the full XCMP implementation. ![Vertical Message Passing and Cross-chain Message Passing Overview](/images/builders/interoperability/xcm/overview/overview-1.webp) ## Establishing Cross-Chain Communication {: #channel-registration } Before two chains can start communicating, a messaging channel must be opened. Channels are unidirectional, meaning that a channel from chain A to chain B will only pass messages from A to B. Therefore, two channels must be opened to send messages back and forth. A channel for XCMs between the relay chain and parachain is automatically opened when a connection is established. However, when parachain A wants to open a communication channel with parachain B, parachain A must send an open channel extrinsic to its network. This extrinsic is an XCM as well! Even though parachain A has expressed its intentions of opening an XCM channel with parachain B, the latter has not signaled to the relay chain its intentions to receive messages from parachain A. Therefore, to have an established channel, parachain B must send an extrinsic (an XCM) to the relay chain. The accepting channel extrinsic is similar to the previous one. However, the encoded call data only includes the new method (accept channel) and the parachain ID of the sender (parachain A in this example). Once both parachains have agreed, the channel is opened within the following epoch. To learn more about the channel registration process, please refer to the [How to Establish an XC Integration with Moonbeam](/builders/interoperability/xcm/xc-registration/xc-integration/){target=\_blank} guide. ![XCM Channel Registration Overview](/images/builders/interoperability/xcm/overview/overview-2.webp) Once the channel is established, cross-chain messages can be sent between parachains. For asset transfers, assets need to be registered before being transferred through XCMs, either by being baked into the runtime as a constant or through a pallet. Moonbeam relies on a Substrate pallet to handle asset registration without the need for runtime upgrades, making the process a lot simpler. To learn how to register an asset on Moonbeam and the information necessary to add Moonbeam assets to another chain, please refer to the [How to Register Cross-Chain Assets](/builders/interoperability/xcm/xc-registration/assets/){target=\_blank} guide. ## XCM on Moonbeam {: #moonbeam-and-xcm } As Moonbeam is a parachain within the Polkadot ecosystems, one of the most direct implementations of XCM is to enable asset transfer from Polkadot and other parachains from/to Moonbeam. This allows users to bring their tokens to Moonbeam and all its dApps. To this end, Moonbeam has introduced [XC-20s](/builders/interoperability/xcm/xc20/overview/){target=\_blank}, which expand on Moonbeam's unique Ethereum compatibility features. XC-20s allow Polkadot native assets to be represented via a standard [ERC-20 interface](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/assets-erc20/ERC20.sol){target=\_blank} through a precompiled contract. When these assets are registered on Moonbeam, they can be set as XCM execution fee assets. Consequently, when a user transfers such an asset to Moonbeam, a small part of the amount will be used to cover the XCM execution fees. In addition, ERC-20s that are deployed to Moonbeam can be sent to other chains in the Polkadot ecosystem via XCM. Consequently, from a developer's perspective, XC-20s are ERC-20 tokens with the added benefit of being an XCM cross-chain asset, and dApps can easily support them through a familiar ERC-20 interface. ![Moonbeam XC-20 XCM Integration With Polkadot](/images/builders/interoperability/xcm/overview/overview-3.webp) To send XC-20s across the Polkadot ecosystem from Moonbeam, developers need to use the [Polkadot XCM Pallet](/builders/interoperability/xcm/xc20/send-xc20s/xcm-pallet/){target=\_blank} for transfers via the Substrate API and the [X-Tokens Precompile](/builders/interoperability/xcm/xc20/send-xc20s/xtokens-precompile/){target=\_blank} or the [XCM Precompile](/builders/interoperability/xcm/xc20/send-xc20s/eth-api/){target=\_blank} for transfers via the Ethereum API. Another unique feature of Moonbeam is the ability to initiate XCM actions from EVM smart contracts or to call its EVM through XCM messages via remote execution. This unlocks a new set of possibilities, where contracts on Moonbeam can access parachain-specific functionalities via XCM, or other parachain ecosystems can use EVM smart contracts on Moonbeam to expand their functions. The following sections provide a high-level overview of the main use cases mentioned before. ### XCM Transfers between Moonbeam & Polkadot {: #transfers-moonbeam-polkadot } As Moonbeam is a parachain within the Polkadot ecosystem, a straightforward implementation of XCM + VMP is DOT transfers from/to Polkadot/Moonbeam. To this end, DOT was registered as [_xcDOT_](https://moonscan.io/token/0xffffffff1fcacbd218edc0eba20fc2308c778080){target=\_blank} on Moonbeam. Alice (Polkadot) wants to transfer a certain amount of DOT from Polkadot to her account on Moonbeam, named Alith. Therefore, she initiates an XCM that expresses her intentions. For such transfers, Moonbeam owns a Sovereign account on Polkadot. Consequently, the XCM message execution on Polkadot will transfer the amount of DOT to Moonbeam's Sovereign account on Polkadot. Once the assets are deposited, the second part of the message is sent to Moonbeam. Moonbeam will locally execute the action the XCM message is programmed to do. In this case, it is to mint and transfer the same amount of _xcDOT_ to the account defined by Alice, which in this case is Alith. The fee to execute the XCM in the target parachain is paid in the asset being transferred (_xcDOT_ for this example). ![Transfers from the Relay Chain to Moonbeam](/images/builders/interoperability/xcm/overview/overview-4.webp) Note the following: - The Alice and Alith accounts can be different. For example, Polkadot's accounts are SR25519 (or ED25519), while Moonbeam's are ECDSA (Ethereum-styled) accounts. They can also have different owners - There is a certain degree of trust where one chain relies on the other to execute its part of the XCM message. This is programmed at a runtime level so that it can be easily verified - For this example, _xcDOT_ is a wrapped representation of the original DOT being held in Moonbeam's Sovereign account on Polkadot. _xcDOT_ can be transferred within Moonbeam at any time, and they can be redeemed for DOT on a 1:1 basis as well (minus some fees) Alith deposited her _xcDOT_ in a liquidity pool. Next, Charleth acquires some _xcDOT_ by swapping against that liquidity pool, and he wants to transfer some _xcDOT_ to Charley's Polkadot account. Therefore, he initiates an XCM that expresses his intentions. Consequently, the XCM message execution on Moonbeam will burn the number of _xcDOT_. Once the assets are burned, the second part of the message is sent to Polkadot. Polkadot will execute the action the XCM message is programmed to do locally. In this case, it is to transfer the same amount of _xcDOT_ burned from the Moonbeam Sovereign account to the account defined by Charleth, which in this case is Charley. ![Transfers Back from Moonbeam to the Relay Chain](/images/builders/interoperability/xcm/overview/overview-5.webp) ### XCM Transfers between Moonbeam & Other Parachains {: #transfers-moonbeam-other-parachains } Since Moonbeam is a parachain within the Polkadot ecosystem, a straightforward implementation of XCM and XCMP asset transfers from and to Moonbeam and other parachains. This section gives a high-level overview of the main differences compared to XCMs from Polkadot/Moonbeam. The first requirement is that a bidirectional channel between the parachains must exist, and the asset being transferred must be registered in the target parachain. Only when both conditions are met can XCMs be sent between parachains. Then, when Alith (Moonbeam) transfers a certain amount of GLMR from Moonbeam to another account (Alice) in a target parachain, tokens are sent to a Sovereign Account owned by that target parachain on Moonbeam. As the XCM message is executed in the target parachain, it is expected that this will mint and transfer the same amount of _xcGLMR_ (cross-chain GLMR) to the account defined by Alith, which in this case is Alice. The fee to execute the XCM in the target parachain is paid in the transferred asset (_xcGLMR_ for this example). ![Transfers from Moonbeam to another Parachain](/images/builders/interoperability/xcm/overview/overview-6.webp) As explained in the previous section, the process is similar for _xcGLMR_ to move back to Moonbeam. First, the XCM message execution burns the number of _xcGLMR_ returned to Moonbeam. Once burned, the remnant part of the message is sent to Moonbeam via the relay chain. Moonbeam will locally execute the XCM message's and transfer GLMR (the same amount of burned _xcGLMR_) from the target parachain Sovereign account to the specified address. ### Remote Execution between Other Chains & Moonbeam {: #execution-chains-moonbeam } As mentioned before, XCM also enables remote execution from/to Moonbeam to other chains in the Polkadot ecosystem. Similarly to the other use cases, it is necessary for XCM-specific channels to be established before remote execution can happen between the chains. Channels are general-purpose, so they can be used for both asset transfers and remote execution. Another important component is the asset for which the remote execution fees are paid. On Moonbeam, when an XC-20 is registered, it can be set as an XCM execution fee asset. Consequently, when transferring that XC-20 to Moonbeam, the XCM execution fee is deducted from the amount being transferred. For remote execution, users can include a small amount of tokens in the XCM message to cover XCM execution fees. Alice (Polkadot) wants to perform a certain remote action through a smart contract on Moonbeam. Therefore, she initiates an XCM that expresses her intentions; she must have previously funded the XCM execution account she owns on Moonbeam with either GLMR or _xcDOT_. Moonbeam will locally execute the action the XCM message is programmed to do. In this case, it is to withdraw the asset decided by Alice for the XCM execution fee and buy some execution time on Moonbeam to execute the smart contract call on Moonbeam's EVM. You can read more about the flow in detail on the [Remote Execution](/builders/interoperability/xcm/remote-execution/overview/){target=\_blank} page. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/remote-execution/computed-origins/ --- BEGIN CONTENT --- --- title: Computed Origin Accounts description: Learn about Computed Origin accounts, which can be used to execute remote cross-chain calls through a simple transaction, and how to calculate these accounts. categories: XCM Remote Execution --- # Computed Origin Accounts ## Introduction {: #introduction } The Computed Origin, previously referred to as the multilocation-derivative account, is an account computed when executing remote calls via XCM. Computed origins are keyless (the private key is unknown). Consequently, Computed Origins can only be accessed through XCM extrinsics from the origin account. In other words, the origin account is the only account that can initiate transactions on your Computed Origin account, and if you lose access to your origin account, you’ll also lose access to your Computed Origin account. The Computed Origin is calculated from the origin that is being used to execute the XCM in the destination chain. By default, this is the Sovereign account of the source chain in the destination chain. This origin can be mutated by the [`DescendOrigin`](/builders/interoperability/xcm/core-concepts/instructions/#descend-origin){target=\_blank} XCM instruction. However, the destination chain can decide whether or not to use the newly mutated origin for the execution of the XCM. On Moonbeam, the Computed Origin account is used to execute the XCM. Moonbeam-based networks follow [the Computed Origins standard set by Polkadot](https://github.com/paritytech/polkadot-sdk/blob/{{ polkadot_sdk }}/polkadot/xcm/xcm-builder/src/location_conversion.rs){target=\_blank}, that is, through a `blake2` hash of a data structure that depends on the origin of the XCM message. However, because Moonbeam uses Ethereum-styled accounts, Computed Origins are truncated to 20 bytes. ## The Origin Conversion {: #origin-conversion } The [origin conversion](https://github.com/paritytech/polkadot-sdk/blob/{{ polkadot_sdk }}/polkadot/xcm/xcm-executor/src/lib.rs#L719){target=\_blank} for a remote call happens when the `Transact` instruction gets executed. The new origin on the target chain is the one that pays for the fees for XCM execution on the target chain. For example, from the relay chain, the [`DescendOrigin`](/builders/interoperability/xcm/core-concepts/instructions/#descend-origin){target=\_blank} instruction is natively injected by the [XCM Pallet](https://github.com/paritytech/polkadot-sdk/blob/{{ polkadot_sdk }}/polkadot/xcm/pallet-xcm/src/lib.rs){target=\_blank}. In the case of Moonbase Alpha's relay chain (based on Westend), it has the following format (a multilocation junction): ```js { DescendOrigin: { X1: { AccountId32: { network: { westend: null }, id: decodedAddress, }, }, }, } ``` Where the `decodedAddress` corresponds to the address of the account who signed the transaction on the relay chain (in a decoded 32-byte format). You can make sure that your address is properly decoded by using the following snippet, which will decode an address if needed and ignore it if not: ```js import { decodeAddress } from '@polkadot/util-crypto'; const decodedAddress = decodeAddress('INSERT_ADDRESS'); ``` When the XCM instruction gets executed in Moonbeam (Moonbase Alpha in this example), the origin will have mutated to the following multilocation: ```js { DescendOrigin: { parents: 1, interior: { X1: { AccountId32: { network: { westend: null }, id: decodedAddress, }, }, }, }, } ``` ## How to Calculate the Computed Origin {: #calculate-computed-origin } You can easily calculate the Computed Origin account through the `calculate-multilocation-derivative-account` or the `calculate-remote-origin` script in the [xcm-tools](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank} repository. The script accepts the following inputs: - `--ws-provider` or `-w` - corresponds to the endpoint to use to fetch the Computed Origin. This should be the endpoint for the target chain - `--address` or `--a` - specifies the source chain address that is sending the XCM message - `--para-id` or `--p` - (optional) specifies the parachain ID of the origin chain of the XCM message. It is optional, as the XCM message might come from the relay chain (no parachain ID). Or parachains can act as relay chains for other parachains - `--parents` - (optional) corresponds to the parents value of the source chain in relation to the target chain. If you're calculating the Computed Origin account for an account on the relay chain, this value would be `1`. If left out, the parents value defaults to `0` To use the script, you can take the following steps: 1. Clone the [xcm-tools](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank} repo 2. Run `yarn` to install the necessary packages 3. Run the script ```bash yarn calculate-multilocation-derivative-account \ --ws-provider INSERT_RPC_ENDPOINT \ --address INSERT_ORIGIN_ACCOUNT \ --para-id INSERT_ORIGIN_PARACHAIN_ID_IF_APPLIES \ --parents INSERT_PARENTS_VALUE_IF_APPLIES ``` You can also calculate the Computed Origin account using the `multilocationToAddress` function of the [XCM Utilities Precompile](/builders/interoperability/xcm/xcm-utils/){target=\_blank}. ### Calculate the Computed Origin on a Moonbeam-based Network {: #calculate-the-computed-origin-on-moonbeam } For example, to calculate the Computed Origin on Moonbase Alpha for Alice's relay chain account, which is `5DV1dYwnQ27gKCKwhikaw1rz1bYdvZZUuFkuduB4hEK3FgDT`, you would use the following command to run the script: ```bash yarn calculate-multilocation-derivative-account \ --ws-provider wss://wss.api.moonbase.moonbeam.network \ --address 5DV1dYwnQ27gKCKwhikaw1rz1bYdvZZUuFkuduB4hEK3FgDT \ --parents 1 ``` !!! note For Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. The returned output includes the following values: | Name | Value | |:-------------------------------------------:|:---------------------------------------------------------------------------------------------------------------------------------------------------------:| | Origin Chain Encoded Address | `5DV1dYwnQ27gKCKwhikaw1rz1bYdvZZUuFkuduB4hEK3FgDT` | | Origin Chain Decoded Address | `0x3ec5f48ad0567c752275d87787954fef72f557b8bfa5eefc88665fa0beb89a56` | | Multilocation Received in Destination Chain | `{"parents":1,"interior":{"x1":{"accountId32":{"network": {"westend":null},"id":"0xdd2399f3b5ca0fc584c4637283cda4d73f6f87c0afb2e78fdbbbf4ce26c2556c"}}}}` | | Computed Origin Account (32 bytes) | `0xdd2399f3b5ca0fc584c4637283cda4d73f6f87c0afb2e78fdbbbf4ce26c2556c` | | Computed Origin Account (20 bytes) | `0xdd2399f3b5ca0fc584c4637283cda4d73f6f87c0` | Consequently, for this example, Alice's Computed Origin account on Moonbase Alpha is `0xdd2399f3b5ca0fc584c4637283cda4d73f6f87c0`. Note that Alice is the only person who can access this account through a remote transact from the relay chain, as she is the owner of its private keys and the Computed Origin account is keyless. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/remote-execution/ --- BEGIN CONTENT --- --- title: Cross-Chain Remote Execution description: Learn about the basics of remote execution and how to perform remote cross-chain execution on other chains in the ecosystem and remote EVM calls on Moonbeam. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/remote-execution/overview/ --- BEGIN CONTENT --- --- title: Remote Execution Overview description: Learn the basics of remote execution via XCM messages, which allow users to execute actions on other blockchains using accounts they control remotely via XCM. categories: XCM Remote Execution, Basics --- # Remote Execution via XCM ## Introduction {: #introduction } The [Cross-Consensus Message (XCM)](https://wiki.polkadot.network/learn/learn-xcm/){target=\_blank} format defines how messages can be sent between interoperable blockchains. This format opens the door to sending an XCM message that executes an arbitrary set of bytes in a Moonbeam-based network, the relay chain, or other parachains in the Polkadot/Kusama ecosystems. Remote execution via XCM opens a new set of possibilities for cross-chain interactions, from chains executing actions on other chains to users performing remote actions without switching chains. This page covers the fundamentals of XCM remote execution. If you want to learn how to perform remote execution via XCM, please refer to the [Remote Execution via the Substrate API](/builders/interoperability/xcm/remote-execution/substrate-calls/xcm-transactor-pallet/){target=\_blank} or the [Remote Execution via the Ethereum API](/builders/interoperability/xcm/xc20/send-xc20s/xtokens-precompile/){target=\_blank} guides. ## Execution Origin {: #execution-origin } Generally speaking, all transactions have an origin, which is where a call comes from. Ethereum transactions have only one origin type, the `msg.sender`, which is the account that initiated the transaction. Substrate-based transactions are more complex, as they can have different origins with different privilege levels. This is similar to having an EVM smart contract call with a specific `require` statement in which the call must come from an allowed address. In contrast, these privilege levels are programmed in the Substrate-based runtime itself. Origins are super important across different components of the Substrate runtime and, hence, the Moonbeam runtime. For example, they define the authority level they inherit in the [on-chain governance implementation](/learn/features/governance/){target=\_blank}. During the execution of an XCM message, the origin defines the context in which the XCM is being executed. By default, the XCM is executed by the source chain's Sovereign account in the destination chain. This Polkadot-specific property of having remote origins that are calculated when executing XCM is known as [Computed Origins](/builders/interoperability/xcm/remote-execution/computed-origins/){target=\_blank} (formerly known as Multilocation Derivative Accounts). Depending on the destination chain's configuration, including the `DescendOrigin` XCM instruction can mutate the origin from which the XCM message is executed. This property is significant for remote XCM execution, as the action being executed considers the context of the newly mutated origin and not the source chain's Sovereign account. ## XCM Instructions for Remote Execution {: #xcm-instructions-remote-execution } The core XCM instructions required to perform remote execution on Moonbeam (as an example) via XCM are the following: - [`DescendOrigin`](/builders/interoperability/xcm/core-concepts/instructions/#descend-origin){target=\_blank} - (optional) gets executed in Moonbeam. Mutates the origin to create a new Computed Origin that represents a keyless account controlled via XCM by the sender in the source chain - [`WithdrawAsset`](/builders/interoperability/xcm/core-concepts/instructions/#withdraw-asset){target=\_blank} - gets executed in Moonbeam. Takes funds from the Computed Origin - [`BuyExecution`](/builders/interoperability/xcm/core-concepts/instructions/#buy-execution){target=\_blank} - gets executed in Moonbeam. Uses the funds taken by the previous XCM instruction to pay for the XCM execution, including the remote call - [`Transact`](/builders/interoperability/xcm/core-concepts/instructions/#transact){target=\_blank} - gets executed in Moonbeam. Executes the arbitrary bytes provided in the XCM instruction The XCM instructions detailed above can be complemented by other XCM instructions to handle certain scenarios, like failure on execution, more accurately. One example is the inclusion of [`SetAppendix`](/builders/interoperability/xcm/core-concepts/instructions/#set-appendix){target=\_blank}, [`RefundSurplus`](/builders/interoperability/xcm/core-concepts/instructions/#refund-surplus){target=\_blank}, and [`Deposit`](/builders/interoperability/xcm/core-concepts/instructions/#deposit-asset){target=\_blank}. ## General Remote Execution via XCM Flow {: #general-remote-execution-via-xcm-flow } A user initiates a transaction in the source chain through a pallet that builds the XCM with at least the [required XCM instructions for remote execution](#xcm-instructions-remote-execution). The transaction is executed in the source chain, which sends an XCM message with the given instructions to the destination chain. The XCM message arrives at the destination chain, which executes it. It is executed with the source chain's Sovereign account as a Computed Origin by default. One example that uses this type of origin is when chains open or accept an HRMP channel on the relay chain. If the XCM message included a [`DescendOrigin`](/builders/interoperability/xcm/core-concepts/instructions/#descend-origin){target=\_blank} instruction, the destination chain may mutate the origin to calculate a new Computed Origin (as is the case with Moonbeam-based networks). Next, [`WithdrawAsset`](/builders/interoperability/xcm/core-concepts/instructions/#withdraw-asset){target=\_blank} takes funds from the Computed Origin (either a Sovereign account or mutated), which are then used to pay for the XCM execution through the [`BuyExecution`](/builders/interoperability/xcm/core-concepts/instructions/#buy-execution){target=\_blank} XCM instruction. Note that on both instructions, you need to specify which asset you want to use. In addition, you must include the bytes to be executed in the amount of execution to buy. Lastly, [`Transact`](/builders/interoperability/xcm/core-concepts/instructions/#transact){target=\_blank} executes an arbitrary set of bytes that correspond to a pallet and function in the destination chain. You have to specify the type of origin to use (typically `SovereignAccount`) and the weight required to execute the bytes (similar to gas in the Ethereum realm). ![Diagram of the XCM instructions executed on the destination chain for remote execution.](/images/builders/interoperability/xcm/remote-execution/overview/overview-1.webp) --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/remote-execution/remote-evm-calls/ --- BEGIN CONTENT --- --- title: Remote EVM Calls Through XCM description: How to do remote calls to smart contracts on Moonbeam EVM through XCM from any Polkadot parachain that has an XCM channel established with Moonbeam. categories: XCM Remote Execution, Ethereum Toolkit --- # Remote EVM Calls Through XCM ## Introduction {: #introduction} The [XCM Transactor Pallet](/builders/interoperability/xcm/remote-execution/substrate-calls/xcm-transactor-pallet/){target=\_blank} provides a simple interface to perform remote cross-chain calls through XCM. However, this does not consider the possibility of doing remote calls to Moonbeam's EVM, only to Substrate-specific pallets (functionalities). Moonbeam's EVM is only accessible through the [Ethereum Pallet](https://github.com/polkadot-evm/frontier/tree/master/frame/ethereum){target=\_blank}. Among many other things, this pallet handles certain validations of transactions before getting them into the transaction pool. Then, it performs another validation step before inserting a transaction from the pool into a block. Lastly, it provides the interface through a `transact` function to execute a validated transaction. All these steps follow the same behavior as an Ethereum transaction in terms of structure and signature scheme. However, calling the [Ethereum Pallet](https://github.com/polkadot-evm/frontier/tree/master/frame/ethereum){target=\_blank} directly through an XCM [`Transact`](https://github.com/paritytech/xcm-format#transact){target=\_blank} is not feasible. Mainly because the dispatcher account for the remote EVM call (referred to as `msg.sender` in Ethereum) does not sign the XCM transaction on the Moonbeam side. The XCM extrinsic is signed in the origin chain, and the XCM executor dispatches the call, through the [`Transact`](https://github.com/paritytech/xcm-format#transact){target=\_blank} instruction, from a known caller linked to the sender in the origin chain. In this context, the Ethereum Pallet will not be able to verify the signature and, ultimately, validate the transaction. To this end, the [Ethereum XCM Pallet](https://github.com/moonbeam-foundation/moonbeam/tree/master/pallets/ethereum-xcm){target=\_blank} was introduced. It acts as a middleware between the XCM [`Transact`](https://github.com/paritytech/xcm-format#transact){target=\_blank} instruction and the [Ethereum Pallet](https://github.com/polkadot-evm/frontier/tree/master/frame/ethereum){target=\_blank}, as special considerations need to be made when performing EVM calls remotely through XCM. The pallet performs the necessary checks and validates the transaction. Next, the pallet calls the Ethereum Pallet to dispatch the transaction to the EVM. Due to how the EVM is accessed, there are some differences between regular and remote EVM calls. The happy path for both regular and remote EVM calls through XCM is portrayed in the following diagram: ![Happy path for regular and remote EVM calls through XCM](/images/builders/interoperability/xcm/remote-execution/remote-evm-calls/xcmevm-1.webp) This guide will go through the differences between regular and remote EVM calls. In addition, it will show you how to perform remote EVM calls through the extrinsic exposed by the [Ethereum XCM pallet](https://github.com/moonbeam-foundation/moonbeam/tree/master/pallets/ethereum-xcm){target=\_blank}. !!! note Remote EVM calls are done through the [XCM Transactor Pallet](/builders/interoperability/xcm/remote-execution/substrate-calls/xcm-transactor-pallet/){target=\_blank}. Therefore, it is recommended to get familiar with XCM Transactor concepts before trying to perform remote EVM calls through XCM. **Note that remote calls to Moonbeam's EVM through XCM are still being actively developed**. In addition, **developers must understand that sending incorrect XCM messages can result in the loss of funds.** Consequently, it is essential to test XCM features on a TestNet before moving to a production environment. ## Differences between Regular and Remote EVM Calls through XCM {: #differences-regular-remote-evm} As explained in the [introduction](#introduction), the paths that regular and remote EVM calls take to get to the EVM are quite different. The main reason behind this difference is the dispatcher of the transaction. A regular EVM call has an apparent sender who signs the Ethereum transaction with its private key. The signature, of ECDSA type, can be verified with the signed message and the `r-s` values that are produced by the signing algorithm. Ethereum signatures use an additional variable called `v`, which is the recovery identifier. With remote EVM calls, the signer signs an XCM transaction in another chain. Moonbeam receives that XCM message, which follows the conventional remote execution via XCM form: - [`DescendOrigin`](/builders/interoperability/xcm/core-concepts/instructions/#descend-origin){target=\_blank} (optional) - [`WithdrawAsset`](/builders/interoperability/xcm/core-concepts/instructions/#withdraw-asset){target=\_blank} - [`BuyExecution`](/builders/interoperability/xcm/core-concepts/instructions/#buy-execution){target=\_blank} - [`Transact`](/builders/interoperability/xcm/core-concepts/instructions/#transact){target=\_blank} XCM execution happens through a [Computed Origin account mechanism](/builders/interoperability/xcm/remote-execution/computed-origins/){target=\_blank}, which by default uses the source chain's Sovereign account in the destination chain. If `DescendOrigin` is included, Moonbeam will mutate the origin of the XCM call to a keyless account that a user from the source chain can control remotely via XCM. The remote EVM call is dispatched from that keyless account (or a related [proxy](/tokens/manage/proxy-accounts/){target=\_blank}). Therefore, because the transaction is not signed, it does not have the real `v-r-s` values of the signature, but `0x1` instead. Since remote EVM calls do not have the actual `v-r-s` values of the signature, there could be collision problems with the EVM transaction hash, as it is calculated as the keccak256 hash of the signed transaction blob. In consequence, if two accounts with the same nonce submit the same transaction object, they will end up with the same EVM transaction hash. Therefore, all remote EVM transactions use a global nonce that is attached to the [Ethereum XCM Pallet](https://github.com/moonbeam-foundation/moonbeam/tree/master/pallets/ethereum-xcm){target=\_blank}. Another significant difference is in terms of the gas price. The fee for remote EVM calls is charged at an XCM execution level. Consequently, the gas price at an EVM level is zero, and the EVM will not charge for the execution itself. This can also be seen in the receipt of a remote EVM call transaction. Accordingly, the XCM message must be configured so that the `BuyExecution` buys enough weight to cover the gas cost. The last difference is in terms of the gas limit. Ethereum uses a gas-metered system to moderate the amount of execution that can be done in a block. On the contrary, Moonbeam uses a [weight-based system](https://docs.polkadot.com/polkadot-protocol/parachain-basics/blocks-transactions-fees/fees/){target=\_blank} in which each call is characterized by the time it takes to execute in a block. Each unit of weight corresponds to one picosecond of execution time. As of runtime 2900, the configuration of the XCM queue suggests that XCM messages should be executable within the following weight units: === "Moonbeam" ```text 125,000,000,000 (0.125 seconds of block execution time) ``` === "Moonriver" ```text 500,000,000,000 (0.5 seconds of block execution time) ``` === "Moonbase Alpha" ```text 500,000,000,000 (0.5 seconds of block execution time) ``` !!! note Prior to runtime 2900, the weight limit of XCM messages across all networks was `20,000,000,000` weight units (this is, `0.02` seconds of block execution time). Suppose the XCM message can't be executed due to the lack of execution time in a given block, and the weight requirement exceeds the above limits. In that case, the XCM message will be marked as `overweight` and only be executable through democracy. The maximum weight limit per XCM message constrains the gas limit available for remote EVM calls through XCM. For all Moonbeam-based networks, there is a ratio of [`25,000` units of gas per unit of weight](https://github.com/moonbeam-foundation/moonbeam/blob/{{ networks.moonbase.spec_version }}/runtime/moonbase/src/lib.rs#L417){target=\_blank} ([`WEIGHT_REF_TIME_PER_SECOND`](https://paritytech.github.io/substrate/master/frame_support/weights/constants/constant.WEIGHT_REF_TIME_PER_SECOND.html){target=\_blank} / [`GAS_PER_SECOND`](https://github.com/moonbeam-foundation/moonbeam/blob/{{ networks.moonbase.spec_version }}/runtime/moonbase/src/lib.rs#L413){target=\_blank}). Considering that you need some XCM message weight to execute the XCM instructions, a remote EVM call might consume 2,000,000,000 units. The following equation can be used to determine the maximum gas units for a remote EVM call: ```text Maximum Gas Units = (Maximum Weight Units - Remote EVM Weight Units) / 25,000 ``` Therefore, the maximum gas limit you can provide for a remote EVM call can be calculated: === "Moonbeam" ```text Maximum Gas Units = (125,000,000,000 - 2,000,000,000) / 25,000 Maximum Gas Units = 4,920,000 ``` === "Moonriver" ```text Maximum Gas Units = (500,000,000,000 - 2,000,000,000) / 25,000 Maximum Gas Units = 19,920,000 ``` === "Moonbase Alpha" ```text Maximum Gas Units = (500,000,000,000 - 2,000,000,000) / 25,000 Maximum Gas Units = 19,920,000 ``` !!! note These values are subject to change in the future. In summary, these are the main differences between regular and remote EVM calls: - Remote EVM calls use a global nonce (owned by the [Ethereum XCM Pallet](https://github.com/moonbeam-foundation/moonbeam/tree/master/pallets/ethereum-xcm){target=\_blank}) instead of a nonce per account - The `v-r-s` values of the signature for remote EVM calls are `0x1`. The sender can't be retrieved from the signature through standard methods (for example, through [ECRECOVER](/builders/ethereum/precompiles/utility/eth-mainnet/#verify-signatures-with-ecrecover){target=\_blank}). Nevertheless, the `from` is included in both the transaction receipt and when getting the transaction by hash (using the Ethereum JSON-RPC) - The gas price for all remote EVM calls is zero. The EVM execution is charged at an XCM execution level and not at an EVM level - The current maximum gas limit you can set for a remote EVM call is different, as outlined above ## Ethereum XCM Pallet Interface {: #ethereum-xcm-pallet-interface} ### Extrinsics {: #extrinsics } The Ethereum XCM Pallet provides the following extrinsics (functions) that can be called by the `Transact` instruction to access Moonbeam's EVM through XCM: ???+ function "**transact**(xcmTransaction) — function to remotely call the EVM through XCM. Only callable through the execution of an XCM message" === "Parameters" - `xcmTransaction` - the Ethereum transaction details of the call that will be dispatched. The `xcmTransaction` structure, which is versioned, contains the following: - `gasLimit` - the gas limit for the Ethereum transaction - `action` - the action to be executed, which provides two options: `Call` and `Create`. The current implementation of the [Ethereum XCM Pallet](https://github.com/moonbeam-foundation/moonbeam/tree/master/pallets/ethereum-xcm){target=\_blank} does not support the `CREATE` operation. Therefore, you can't deploy a smart contract through remote EVM calls. For `Call`, you'll need to specify the contract address you're interacting with - `value` - the amount of native tokens to send - `input` - the encoded call data of the contract interaction === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const xcmTransaction = { V2: { gasLimit: INSERT_GAS_LIMIT, action: { Call: 'INSERT_CONTRACT_ADDRESS_TO_CALL' }, value: INSERT_VALUE, input: 'INSERT_CONTRACT_CALL_DATA', }, }; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.ethereumXcm.transact(xcmTransaction); }; main(); ``` !!! note In the following sections, you'll learn exactly how to get the Ethereum transaction call data and build an XCM message using this extrinsic. ??? function "**transactThroughProxy**(transactAs, xcmTransaction) — function to remotely call the EVM through XCM and be dispatched from a given account with known keys (the `msg.sender`)" === "Parameters" - `xcmTransaction` - the Ethereum transaction details of the call that will be dispatched. The `xcmTransaction` structure, which is versioned, contains the following: - `gasLimit` - the gas limit for the Ethereum transaction - `action` - the action to be executed, which provides two options: `Call` and `Create`. The current implementation of the [Ethereum XCM Pallet](https://github.com/moonbeam-foundation/moonbeam/tree/master/pallets/ethereum-xcm){target=\_blank} does not support the `CREATE` operation. Therefore, you can't deploy a smart contract through remote EVM calls. For `Call`, you'll need to specify the contract address you're interacting with - `value` - the amount of native tokens to send - `input` - the encoded call data of the contract interaction - `xcmTransactAs` - the account from which the remote EVM call will be dispatched (the `msg.sender`). This account needs to have set the Computed Origin account as a [proxy](/tokens/manage/proxy-accounts/){target=\_blank} of type `any` on Moonbeam, or the remote EVM call will fail. Transaction fees are still paid by the Computed Origin account === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const xcmTransaction = { V2: { gasLimit: INSERT_GAS_LIMIT, action: { Call: 'INSERT_CONTRACT_ADDRESS_TO_CALL' }, value: INSERT_VALUE, input: 'INSERT_CONTRACT_CALL_DATA', }, }; const xcmTransactAs = 'INSERT_COMPUTED_ORIGIN_PROXY_ADDRESS'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.ethereumXcm.transactThroughProxy( xcmTransaction, xcmTransactAs ); }; main(); ``` ## Building a Remote EVM Call Through XCM {: #build-remote-evm-call-xcm} This guide covers building an XCM message for remote EVM calls using the [XCM Pallet](https://github.com/paritytech/polkadot-sdk/blob/{{ polkadot_sdk }}/polkadot/xcm/pallet-xcm/src/lib.rs){target=\_blank} from the relay chain to Moonbase Alpha. More specifically, it will use the `transact` function. The steps to use the `transactThroughProxy` function are identical. However, you'll need to provide the `transactAs` account and ensure that this account has set the Computed Origin account as a proxy of type `any` on Moonbase Alpha. !!! note When using `transactThroughProxy`, the EVM call is dispatched by the `transactAs` account you provide, acting as the `msg.sender`, as long as this account has set the Computed Origin account as a proxy of type `any` in the Moonbeam-based network you are using. However, transaction fees are still paid by the Computed Origin account, so you need to ensure it has enough funds to cover them. The process for building and performing the remote execution can be summarized as follows: 1. Calculate the call data for the EVM call that will be performed on Moonbase Alpha 2. Use the EVM call data to generate the call data for the `transact` extrinsic of the Ethereum XCM Pallet on Moonbase Alpha 3. Build the XCM message on the relay chain, which will include the `WithdrawAsset`, `BuyExecution`, and `Transact` instructions. In the `Transact` instruction, you'll use the Ethereum XCM `transact` call data 4. Using Alice's account on the relay chain, you'll send the XCM message via the `send` extrinsic of the XCM Pallet 5. Alice's Computed Origin account on Moonbase Alpha will dispatch the EVM call data ### Checking Prerequisites {: #ethereumxcm-check-prerequisites} To be able to send the call from the relay chain, you need the following: - An [account](https://polkadot.js.org/apps/?rpc=wss://relay.api.moonbase.moonbeam.network#/accounts){target=\_blank} on the relay chain with funds (UNIT) to pay for the transaction fees. You can acquire some xcUNIT by swapping for DEV tokens (Moonbase Alpha's native token) on [Moonbeam-Swap](https://moonbeam-swap.netlify.app){target=\_blank}, a demo Uniswap-V2 clone on Moonbase Alpha, and then [send them to the relay chain](/builders/interoperability/xcm/xc20/send-xc20s/xtokens-precompile/){target=\_blank}. Additionally, you can [contact us on Discord](https://discord.com/invite/PfpUATX){target=\_blank} to get some UNIT tokens directly - The address of your Computed Origin account. Please refer to the [Computed Origin](/builders/interoperability/xcm/remote-execution/computed-origins/){target=\_blank} guide to learn how to calculate your Computed Origin address - To fund your Computed Origin account. The account must have enough DEV tokens (or GLMR/MOVR for Moonbeam/Moonriver) to cover the cost of the XCM execution of the remote EVM call. Note that this is the account from which the remote EVM call will be dispatched (the `msg.sender`). Consequently, the account must satisfy whatever conditions are required for the EVM call to be executed correctly. For example, hold any relevant ERC-20 token if you are doing an ERC-20 transfer !!! note Suppose you are using the `transactThroughProxy` function. In that case, the `transactAs` account must satisfy whatever conditions are required for the EVM call to be executed correctly, as it acts as the `msg.sender`. However, the Computed Origin account is the one that needs to hold the DEV tokens (or GLMR/MOVR for Moonbeam/Moonriver) to cover the cost of the XCM execution of the remote EVM call. ### Ethereum XCM Transact Call Data {: #ethereumxcm-transact-data } Before you send the XCM message from the relay chain to Moonbase Alpha, you need to get the encoded call data that will be dispatched through the execution of the [`Transact`](https://github.com/paritytech/xcm-format#transact){target=\_blank} XCM instruction. In this example, you'll be interacting with the `transact` function of the [Ethereum XCM Pallet](https://github.com/moonbeam-foundation/moonbeam/tree/master/pallets/ethereum-xcm), which accepts an `xcmTransaction` as a parameter. The `xcmTransaction` parameter requires you to define the `gasLimit`, `action`, `value`, and `input`. For the action to be executed, you'll be performing a contract interaction with a simple [incrementer contract](https://moonbase.moonscan.io/address/0xa72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8#code){target=\_blank}, which is located at `0xa72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8`. You'll be calling the `increment` function, which has no input argument and will increase the value of the `number` by one. It will also store the block's timestamp in which the function is executed to the `timestamp` variable. The encoded call data for the `increment` function is `0xd09de08a`, which is the function selector and is the first eight hexadecimal characters (or 4 bytes) of the keccak256 hash of `increment()`. If you choose to interact with a function that has input parameters, they also need to be encoded. The easiest way to get the encoded call data is to emulate a transaction either in [Remix](/builders/ethereum/dev-env/remix/#interacting-with-a-moonbeam-based-erc-20-from-metamask){target=\_blank} or [Moonscan](https://moonbase.moonscan.io/address/0xa72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8#code){target=\_blank}. Then, in Metamask, check the **HEX DATA: 4 BYTES** selector under the **HEX** tab to get the call data. You don't need to sign the transaction. Now that you have the encoded contract interaction data, you can determine the gas limit for this call using the [`eth_estimateGas` JSON-RPC method](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_estimategas){target=\_blank}. For this example, you can set the gas limit to `155000`. For the value, you can set it to `0` since this particular interaction does not need DEV (or GLMR/MOVR for Moonbeam/Moonriver). For an interaction that requires DEV, you'll need to modify this value accordingly. Now that you have all of the components required for the `xcmTransaction` parameter, you can build it: ```js const xcmTransaction = { V2: { gasLimit: 155000, action: { Call: '0xa72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8' }, value: 0, input: '0xd09de08a', }, }; ``` Next, you can write the script to get the encoded call data for the transaction. You'll take the following steps: 1. Provide the input data for the call. This includes: - The Moonbase Alpha endpoint URL to create the provider - The value for the `xcmTransaction` parameter of the `transact` function 2. Create the [Polkadot.js API](/builders/substrate/libraries/polkadot-js-api/){target=\_blank} provider 3. Craft the `ethereumXcm.transact` extrinsic with the `xcmTransaction` value 4. Get the encoded call data for the extrinsic. You don't need to sign and send the transaction ```js import { ApiPromise, WsProvider } from '@polkadot/api'; // Version 10.13.1 // 1. Input data const providerWsURL = 'wss://wss.api.moonbase.moonbeam.network'; const xcmTransaction = { V2: { gasLimit: 155000, action: { Call: '0xa72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8' }, value: 0, input: '0xd09de08a', }, }; const getEncodedCalldata = async () => { // 2. Create Substrate API Provider const substrateProvider = new WsProvider(providerWsURL); const api = await ApiPromise.create({ provider: substrateProvider }); // 3. Create the extrinsic const tx = api.tx.ethereumXcm.transact(xcmTransaction); // 4. Get the encoded call data const encodedCall = tx.method.toHex(); console.log(`Encoded Calldata: ${encodedCall}`); api.disconnect(); }; getEncodedCalldata(); ``` !!! note You can view an example of the output of the above script on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/extrinsics/decode/0x260001785d02000000000000000000000000000000000000000000000000000000000000a72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8000000000000000000000000000000000000000000000000000000000000000010d09de08a00){target=\_blank} using the following encoded call data: `0x260001785d02000000000000000000000000000000000000000000000000000000000000a72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8000000000000000000000000000000000000000000000000000000000000000010d09de08a00`. You'll use the encoded call data in the `Transact` instruction in the following section. ### Estimate Weight Required at Most {: #estimate-weight-required-at-most } When using the `Transact` instruction, you'll need to define the `requireWeightAtMost` field, which is the required weight for the transaction. This field accepts two arguments: the `refTime` and `proofSize`. The `refTime` is the amount of computational time that can be used for execution, and the `proofSize` is the amount of storage in bytes that can be used. To get an estimate for the `refTime` and `proofSize`, you can use the [`paymentInfo` method of the Polkadot.js API](/builders/substrate/libraries/polkadot-js-api/#fees){target=\_blank}. Since these weights are required for the `Transact` call data, you can extend the script from the previous section to add in the call to `paymentInfo`. The `paymentInfo` method accepts the same parameters you would normally pass to the `.signAndSend` method, which is the sending account and, optionally, some additional values such as a nonce or signer. To modify the encoded call data script, you'll need to add Alice's Computed Origin address and use it to call the `tx.paymentInfo` method. ???+ code "Modified script" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; // Version 10.13.1 // 1. Input data const providerWsURL = 'wss://wss.api.moonbase.moonbeam.network'; const xcmTransaction = { V2: { gasLimit: 155000, action: { Call: '0xa72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8' }, value: 0, input: '0xd09de08a', }, }; const getEncodedCalldata = async () => { // 2. Create Substrate API Provider const substrateProvider = new WsProvider(providerWsURL); const api = await ApiPromise.create({ provider: substrateProvider }); // 3. Create the extrinsic const tx = api.tx.ethereumXcm.transact(xcmTransaction); // 4. Estimate the required weight const alice = '0xdd2399f3b5ca0fc584c4637283cda4d73f6f87c0'; const info = await tx.paymentInfo(alice); console.log(`Required Weight: ${info.weight}`); api.disconnect(); }; getEncodedCalldata(); ``` The script, at the time of writing, returns an estimate of `3900000000` for `refTime` and `9687` for `proofSize`. ### Building the XCM for Remote XCM Execution {: #build-xcm-remote-evm} Now that you've generated the call data for the EVM call, you're going to use the XCM Pallet on the relay chain to perform the remote execution. To do so, you'll use the `send` function, which accepts two parameters: - `dest` - the XCM versioned multilocation representing a chain in the ecosystem where the XCM message is being sent to (the target chain) - `message` - the SCALE-encoded versioned XCM message to be executed You can start assembling these parameters by taking the following steps: 1. Build the multilocation of the destination, which is Moonbase Alpha: ```js const dest = { V4: { parents: 0, interior: { X1: [{ Parachain: 1000 }] } } }; ``` 2. Build the `WithdrawAsset` instruction, which will require you to define: - The multilocation of the DEV token on Moonbase Alpha - The amount of DEV tokens to withdraw ```js const instr1 = { WithdrawAsset: [ { id: { parents: 0, interior: { X1: [{ PalletInstance: 3 }] } }, fun: { Fungible: 10000000000000000n }, // 0.01 DEV }, ], }; ``` 3. Build the `BuyExecution` instruction, which will require you to define: - The multilocation of the DEV token on Moonbase Alpha - The amount of DEV tokens to buy for execution - The weight limit ```js const instr2 = { BuyExecution: [ { id: { parents: 0, interior: { X1: [{ PalletInstance: 3 }] } }, fun: { Fungible: 10000000000000000n }, // 0.01 DEV }, { Unlimited: null }, ], }; ``` 4. Build the `Transact` instruction, which will require you to define: - The origin kind - The required weight for the transaction, which you calculated in the [Estimate Weight Required at Most](#estimate-weight-required-at-most) section - The encoded call data, which you generated in the [Ethereum XCM Transact Call Data](#ethereumxcm-transact-data) section ```js const instr3 = { Transact: { originKind: 'SovereignAccount', requireWeightAtMost: { refTime: 3900000000n, proofSize: 9687n }, call: { encoded: '0x260001785d02000000000000000000000000000000000000000000000000000000000000a72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8000000000000000000000000000000000000000000000000000000000000000010d09de08a00', }, }, }; ``` 5. Combine the XCM instructions into a versioned XCM message: ```js const message = { V4: [instr1, instr2, instr3] }; ``` Now that you have the values for each of the parameters, you can write the script for the execution. You'll take the following steps: 1. Provide the input data for the call. This includes: - The relay chain endpoint URL to create the provider - The values for each of the parameters of the `send` function 2. Create a Keyring instance that will be used to send the transaction 3. Create the [Polkadot.js API](/builders/substrate/libraries/polkadot-js-api/){target=\_blank} provider 4. Craft the `xcmPallet.send` extrinsic with the `dest` and `message` values 5. Send the transaction using the `signAndSend` extrinsic and the Keyring instance you created in the second step !!! remember This is for demo purposes only. Never store your private key in a JavaScript file. ```js import { ApiPromise, WsProvider, Keyring } from '@polkadot/api'; // Version 10.13.1 import { cryptoWaitReady } from '@polkadot/util-crypto'; // 1. Input data const providerWsURL = 'wss://relay.api.moonbase.moonbeam.network'; const privateKey = 'INSERT_PRIVATE_KEY'; const dest = { V4: { parents: 0, interior: { X1: [{ Parachain: 1000 }] } } }; const instr1 = { WithdrawAsset: [ { id: { parents: 0, interior: { X1: [{ PalletInstance: 3 }] } }, fun: { Fungible: 10000000000000000n }, // 0.01 DEV }, ], }; const instr2 = { BuyExecution: [ { id: { parents: 0, interior: { X1: [{ PalletInstance: 3 }] } }, fun: { Fungible: 10000000000000000n }, // 0.01 DEV }, { Unlimited: null }, ], }; const instr3 = { Transact: { originKind: 'SovereignAccount', requireWeightAtMost: { refTime: 3900000000n, proofSize: 9687n }, call: { encoded: '0x260001785d02000000000000000000000000000000000000000000000000000000000000a72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8000000000000000000000000000000000000000000000000000000000000000010d09de08a00', }, }, }; const message = { V4: [instr1, instr2, instr3] }; const sendXcmMessage = async () => { // 2. Create Keyring instance await cryptoWaitReady(); const keyring = new Keyring({ type: 'sr25519' }); const alice = keyring.addFromUri(privateKey); // 3. Create Substrate API Provider const substrateProvider = new WsProvider(providerWsURL); const api = await ApiPromise.create({ provider: substrateProvider }); // 4. Create the extrinsic const tx = api.tx.xcmPallet.send(dest, message); // 5. Send the transaction const txHash = await tx.signAndSend(alice); console.log(`Submitted with hash ${txHash}`); api.disconnect(); }; sendXcmMessage(); ``` !!! note You can view an example of the output of the above script on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://relay.api.moonbase.moonbeam.network#/extrinsics/decode/0x630004000100a10f040c000400010403001300008a5d784563011300010403001300008a5d784563010006010300286bee007901260001581501000000000000000000000000000000000000000000000000000000000000a72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8000000000000000000000000000000000000000000000000000000000000000010d09de08a00){target=\_blank} using the following encoded call data: `0x630004000100a10f040c000400010403001300008a5d784563011300010403001300008a5d784563010006010300286bee007901260001581501000000000000000000000000000000000000000000000000000000000000a72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8000000000000000000000000000000000000000000000000000000000000000010d09de08a00`. Once the transaction is processed, you can check the relevant extrinsics and events in the [relay chain](https://polkadot.js.org/apps/?rpc=wss://relay.api.moonbase.moonbeam.network#/explorer/query/0x2a0e40a2e5261e792190826ce338ed513fe44dec16dd416a12f547d358773f98){target=\_blank} and [Moonbase Alpha](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/explorer/query/0x7570d6fa34b9dccd8b8839c2986260034eafef732bbc09f8ae5f857c28765145){target=\_blank}. In the relay chain, the extrinsic is `xcmPallet.send`, and the associated event is `xcmPallet.Sent` (among others related to the fee). In Moonbase Alpha, the XCM execution happens within the `parachainSystem.setValidationData` extrinsic, and there are multiple associated events that can be highlighted: - **parachainSystem.DownwardMessagesReceived** — event that signals that a message from the relay chain was received. With the current XCM implementation, messages from other parachains will show the same event - **balances.Withdraw** — event related to the withdrawing of tokens to pay for the execution of the call. Note that the `who` address is the Computed Origin account calculated before - **ethereum.Executed** — event associated with the execution of the remote EVM call. It provides the `from`, `to`, `transactionHash` (calculated with the non-standard signature and global pallet nonce), and the `exitReason`. Currently, some common EVM errors, like out of gas, will show `Reverted` in the exit reason - **polkadotXcm.AssetsTrapped** — event that is emitted when part of the tokens withdrawn from the account (for fees) are not used. Generally, when there are leftover tokens in the registry that are not allocated to an account. These tokens are temporarily burned and can be retrieved through a democracy proposal. A combination of both `RefundSurplus` and `DepositAsset` XCM instructions can prevent assets from getting trapped To verify that the remote EVM call through XCM was successful, you can head to the [contract's page in Moonscan](https://moonbase.moonscan.io/address/0xa72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8#readContract){target=\_blank} and verify the new value for the number and its timestamp. ## Remote EVM Call Transaction by Hash {: #remote-evm-call-txhash} As mentioned before, there are some [differences between regular and remote XCM EVM calls](#differences-regular-remote-evm). Some main differences can be seen when retrieving the transaction by its hash using the Ethereum JSON-RPC. To do so, you first need to retrieve the transaction hash you want to query. For this example, you can use the transaction hash from the [previous section](#build-remote-evm-call-xcm), which is [0x753588d6e59030eeffd31aabccdd0fb7c92db836fcaa8ad71512cf3a7d0cb97f](https://moonbase.moonscan.io/tx/0x753588d6e59030eeffd31aabccdd0fb7c92db836fcaa8ad71512cf3a7d0cb97f){target=\_blank}. Open the terminal, and execute the following command: ```sh curl --location --request POST 'https://rpc.api.moonbase.moonbeam.network' \ --header 'Content-Type: application/json' \ --data-raw '{ "jsonrpc":"2.0", "id":1, "method":"eth_getTransactionByHash", "params": ["0x753588d6e59030eeffd31aabccdd0fb7c92db836fcaa8ad71512cf3a7d0cb97f"] } ' ``` If the JSON-RPC request is sent correctly, the response should look like this: ```json { "jsonrpc": "2.0", "result": { "hash": "0x753588d6e59030eeffd31aabccdd0fb7c92db836fcaa8ad71512cf3a7d0cb97f", "nonce": "0x129", "blockHash": "0xeb8222567e434215f472f0c53f68a606c77ea8f475e5fbc3a5b715db6cce8887", "blockNumber": "0x46c268", "transactionIndex": "0x0", "from": "0xdd2399f3b5ca0fc584c4637283cda4d73f6f87c0", "to": "0xa72f549a1a12b9b49f30a7f3aeb1f4e96389c5d8", "value": "0x0", "gasPrice": "0x0", "maxFeePerGas": "0x0", "maxPriorityFeePerGas": "0x0", "gas": "0x25d78", "input": "0xd09de08a", "creates": null, "raw": "0x02eb820507820129808083025d7894a72f549a1a12b9b49f30a7f3aeb1f4e96389c5d88084d09de08ac0010101", "publicKey": "0x14745b9075ac0f0426c61c9a2895f130ea6f3b964e8f49cefdb4e2d248306f19396361d877f8b9ad60a94a5ec28325a1b9baa2ae59e7a9f6fe1731caec130ab4", "chainId": "0x507", "standardV": "0x1", "v": "0x1", "r": "0x1", "s": "0x1", "accessList": [], "type": "0x2" }, "id": 1 } ``` Note that the `v-r-s` values are set to `0x1`, and the gas price-related fields are set to `0x0`. In addition, the `nonce` field corresponds to a global nonce of the [Ethereum XCM Pallet](https://github.com/moonbeam-foundation/moonbeam/tree/master/pallets/ethereum-xcm){target=\_blank}, and not the transaction count of the dispatcher account. !!! note You might be able to find some transaction hash collisions in the Moonbase Alpha TestNet, as early versions of remote EVM calls through XCM did not use a global nonce of the [Ethereum XCM Pallet](https://github.com/moonbeam-foundation/moonbeam/tree/master/pallets/ethereum-xcm){target=\_blank}. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/remote-execution/substrate-calls/ --- BEGIN CONTENT --- --- title: Remote Substrate Calls description: Discover how to use the XCM Transactor Pallet and XCM Transactor Precompile to remotely call Substrate pallets on other chains in the ecosystem from Moonbeam. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/remote-execution/substrate-calls/xcm-transactor-pallet/ --- BEGIN CONTENT --- --- title: The XCM Transactor Pallet description: This guide provides an introduction to the XCM Transactor Pallet and explains how to send remote calls to another chain using some of the pallet's extrinsics. categories: XCM Remote Execution --- # Using the XCM Transactor Pallet for Remote Execution ## Introduction {: #introduction } XCM messages are comprised of a [series of instructions](/builders/interoperability/xcm/core-concepts/instructions/){target=\_blank} that are executed by the Cross-Consensus Virtual Machine (XCVM). Combinations of these instructions result in predetermined actions such as cross-chain token transfers and, more interestingly, remote cross-chain execution. Remote execution involves executing operations or actions on one blockchain from another blockchain while maintaining the integrity of the sender's identity and permissions. Typically, XCM messages are sent from the root origin (that is, SUDO or through governance), which is not ideal for projects that want to leverage remote cross-chain calls via a simple transaction. The [XCM Transactor Pallet](https://github.com/moonbeam-foundation/moonbeam/blob/master/pallets/xcm-transactor/src/lib.rs){target=\_blank} makes it easy to transact on a remote chain through either the [Sovereign account](/builders/interoperability/xcm/overview/#general-xcm-definitions){target=\_blank}, which should only be allowed through governance, or a [Computed Origin account](/builders/interoperability/xcm/remote-execution/computed-origins/){target=\_blank} via a simple transaction from the source chain. This guide will show you how to use the XCM Transactor Pallet to send XCM messages from a Moonbeam-based network to other chains in the ecosystem. In addition, you'll also learn how to use the XCM Transactor Precompile to perform the same actions via the Ethereum API. **Note that there are still limitations to what you can remotely execute through XCM messages**. **Developers must understand that sending incorrect XCM messages can result in the loss of funds.** Consequently, it is essential to test XCM features on a TestNet before moving to a production environment. ## XCM Transactor Pallet Interface {: #xcm-transactor-pallet-interface} ### Extrinsics {: #extrinsics } The XCM Transactor Pallet provides the following extrinsics (functions): ???+ function "**hrmpManage**(action, fee, weightInfo) - manages HRMP operations related to opening, accepting, and closing an HRMP channel" On Moonbeam or Moonriver, this function must be executed via governance through the General Admin or the Root Track. On Moonbase Alpha or a Moonbeam development node, this function can also be executed via sudo. === "Parameters" - `action` - the action to execute. Can be either `InitOpen`, `Accept`, `Close`, or `Cancel` - `fee` - the asset to be used for fees. This contains the `currency` and the `feeAmount`: - `currency` - defines how you are specifying the token to use to pay for the fees, which can be either of the following: - `AsCurrencyId` - the currency ID of the asset to use for the fees. The currency ID can be either: - `SelfReserve` - uses the native asset - `ForeignAsset` - uses an [external XC-20](/builders/interoperability/xcm/xc20/overview/#external-xc20s){target=\_blank}. It requires you to specify the asset ID of the XC-20 - `LocalAssetReserve` - *deprecated* - use [Local XC-20s](/builders/interoperability/xcm/xc20/overview/#local-xc20s){target=\_blank} instead via the `Erc20` currency type - `Erc20` - uses a [local XC-20](/builders/interoperability/xcm/xc20/overview/#local-xc20s){target=\_blank}. It requires you to specify the contract address of the local XC-20 - `AsMultiLocation` - the XCM versioned multilocation for the asset to use for the fees - `feeAmount` - (optional) the amount to use for fees - `weightInfo` - the weight information to be used. The `weightInfo` structure contains the following: - `transactRequiredWeightAtMost` — the weight required to perform the execution of the `Transact` call. The `transactRequiredWeightAtMost` structure contains the following: - `refTime` - the amount of computational time that can be used for execution - `proofSize` - the amount of storage in bytes that can be used - `overallWeight` — (optional) the total weight the extrinsic can use to execute all the XCM instructions, plus the weight of the `Transact` call (`transactRequiredWeightAtMost`). The `overallWeight` can be defined as either: - `Unlimited` - allows an unlimited amount of weight that can be purchased - `Limited` - limits the amount of weight that can be purchased by defining the following: - `refTime` - the amount of computational time that can be used for execution - `proofSize` - the amount of storage in bytes that can be used === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const action = 'InitOpen'; // Or 'Accept', 'Close', or 'Cancel' const fee = { currency: { AsCurrencyId: { ForeignAsset: INSERT_ASSET_ID }, }, feeAmount: INSERT_FEE_AMOUNT, }; const weightInfo = { transactRequiredWeightAtMost: { refTime: INSERT_REF_TIME, proofSize: INSERT_PROOF_SIZE, }, overallWeight: { Unlimited: null }, }; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.xcmTransactor.hrmpManage(action, fee, weightInfo); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); }; main(); ``` ??? function "**removeFeePerSecond**(assetLocation) — remove the fee per second information for a given asset in its reserve chain" On Moonbeam or Moonriver, this function must be executed via governance through the General Admin or the Root Track. On Moonbase Alpha or a Moonbeam development node, this function can also be executed via sudo. === "Parameters" - `assetLocation` - the XCM versioned multilocation of the asset to remove the fee per second information for === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const assetLocation = { V4: { parents: INSERT_PARENTS, interior: INSERT_INTERIOR, }, };; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.xcmTransactor.removeFeePerSecond(assetLocation); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); }; main(); ``` ??? function "**removeTransactInfo**(location) — remove the transact information for a given chain" On Moonbeam or Moonriver, this function must be executed via governance through the General Admin or the Root Track. On Moonbase Alpha or a Moonbeam development node, this function can also be executed via sudo. === "Parameters" - `location` - the XCM versioned multilocation of a given chain that you wish to remove the transact information for === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const assetLocation = { V4: { parents: INSERT_PARENTS, interior: INSERT_INTERIOR, }, };; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.xcmTransactor.removeTransactInfo(assetLocation); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); }; main(); ``` ??? function "**setFeePerSecond**(assetLocation, feePerSecond) — sets the fee per second for a given asset on its reserve chain. The fee per second information typically relates to the cost of executing XCM instructions" On Moonbeam or Moonriver, this function must be executed via governance through the General Admin or the Root Track. On Moonbase Alpha or a Moonbeam development node, this function can also be executed via sudo. === "Parameters" - `assetLocation` - the XCM versioned multilocation of the asset to remove the fee per second information for - `feePerSecond` - the number of token units per second of XCM execution that will be charged to the sender of the extrinsic when executing XCM instructions === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const assetLocation = { V4: { parents: INSERT_PARENTS, interior: INSERT_INTERIOR, }, }; const feePerSecond = INSERT_FEE_PER_SECOND; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.xcmTransactor.setFeePerSecond(assetLocation, feePerSecond); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); }; main(); ``` ??? function "**setTransactInfo**(location, transactExtraWeight, maxWeight) — sets the transact information for a given chain. The transact information typically includes details about the weight required for executing XCM instructions as well as the maximum weight allowed for remote XCM execution on the target chain" On Moonbeam or Moonriver, this function must be executed via governance through the General Admin or the Root Track. On Moonbase Alpha or a Moonbeam development node, this function can also be executed via sudo. === "Parameters" - `location` - the XCM versioned multilocation of a given chain that you wish to set the transact information for - `transactExtraWeight` — the weight to cover execution fees of the XCM instructions (`WithdrawAsset`, `BuyExecution`, and `Transact`), which is estimated to be at least 10% over what the remote XCM instructions execution uses. The `transactExtraWeight` structure contains the following: - `refTime` - the amount of computational time that can be used for execution - `proofSize` - the amount of storage in bytes that can be used - `maxWeight` — maximum weight units allowed for the remote XCM execution. The `maxWeight` structure also contains `refTime` and `proofSize` - `transactExtraWeightSigned` — (optional) the weight to cover execution fees of the XCM instructions (`DescendOrigin`, `WithdrawAsset`, `BuyExecution`, and `Transact`), which is estimated to be at least 10% over what the remote XCM instructions execution uses. The `transactExtraWeightSigned` structure also contains `refTime` and `proofSize` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const location = INSERT_MULTILOCATION; const transactExtraWeight = { refTime: INSERT_REF_TIME, proofSize: INSERT_PROOF_SIZE, }; const maxWeight = { refTime: INSERT_REF_TIME, proofSize: INSERT_PROOF_SIZE, }; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.xcmTransactor.setTransactInfo( location, transactExtraWeight, maxWeight ); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); }; main(); ``` ??? function "**transactThroughSigned**(destination, fee, call, weightInfo, refund) — sends an XCM message with instructions to remotely execute a call in the destination chain. The remote call will be signed and executed by a new account that the destination parachain must compute. Moonbeam-based networks follow [the Computed Origins standard set by Polkadot](https://github.com/paritytech/polkadot-sdk/blob/{{ polkadot_sdk }}/polkadot/xcm/xcm-builder/src/location_conversion.rs){target=\_blank}" === "Parameters" - `dest` - the XCM versioned multilocation for a chain in the ecosystem where the XCM message is being sent to (the target chain) - `fee` - the asset to be used for fees. This contains the `currency` and the `feeAmount`: - `currency` - defines how you are specifying the token to use to pay for the fees, which can be either of the following: - `AsCurrencyId` - the currency ID of the asset to use for the fees. The currency ID can be either: - `SelfReserve` - uses the native asset - `ForeignAsset` - uses an [external XC-20](/builders/interoperability/xcm/xc20/overview/#external-xc20s){target=\_blank}. It requires you to specify the asset ID of the XC-20 - `LocalAssetReserve` - *deprecated* - use [Local XC-20s](/builders/interoperability/xcm/xc20/overview/#local-xc20s){target=\_blank} instead via the `Erc20` currency type - `Erc20` - uses a [local XC-20](/builders/interoperability/xcm/xc20/overview/#local-xc20s){target=\_blank}. It requires you to specify the contract address of the local XC-20 - `AsMultiLocation` - the XCM versioned multilocation for the asset to use for the fees - `feeAmount` - (optional) the amount to use for fees - `call` - encoded call data of the call that will be executed in the target chain - `weightInfo` - the weight information to be used. The `weightInfo` structure contains the following: - `transactRequiredWeightAtMost` — the weight required to perform the execution of the `Transact` call. The `transactRequiredWeightAtMost` structure contains the following: - `refTime` - the amount of computational time that can be used for execution - `proofSize` - the amount of storage in bytes that can be used - `overallWeight` — (optional) the total weight the extrinsic can use to execute all the XCM instructions, plus the weight of the `Transact` call (`transactRequiredWeightAtMost`). The `overallWeight` can be defined as either: - `Unlimited` - allows an unlimited amount of weight that can be purchased - `Limited` - limits the amount of weight that can be purchased by defining the following: - `refTime` - the amount of computational time that can be used for execution - `proofSize` - the amount of storage in bytes that can be used - `refund` - a boolean indicating whether or not to add the `RefundSurplus` and `DepositAsset` instructions to the XCM message to refund any leftover fees === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const dest = { V4: { parents: INSERT_PARENTS, interior: INSERT_INTERIOR, }, }; const fee = { currency: { AsCurrencyId: { ForeignAsset: INSERT_ASSET_ID }, }, feeAmount: INSERT_FEE_AMOUNT, }; const call = 'INSERT_ENCODED_CALL_DATA'; const weightInfo = { transactRequiredWeightAtMost: { refTime: INSERT_REF_TIME, proofSize: INSERT_PROOF_SIZE, }, overallWeight: { Unlimited: null }, }; const refund = INSERT_BOOLEAN_FOR_REFUND; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.xcmTransactor.transactThroughSigned( dest, fee, call, weightInfo, refund ); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); }; main(); ``` !!! note In the following sections, you'll learn exactly how to retrieve all of the arguments needed to build and send an XCM message using this extrinsic. ??? function "**transactThroughSovereign**(dest, feePayer, fee, call, originKind, weightInfo, refund) — sends an XCM message with instructions to remotely execute a given call at the given destination. The remote call will be signed by the origin parachain Sovereign account (who pays the fees), but the transaction is dispatched from a given origin. The XCM Transactor Pallet calculates the fees for the remote execution and charges the given account the estimated amount in the corresponding [XC-20 token](/builders/interoperability/xcm/xc20/overview/){target=\_blank}" === "Parameters" - `dest` - the XCM versioned multilocation for a chain in the ecosystem where the XCM message is being sent to (the target chain) - `feePayer` - (optional) the address that will pay for the remote XCM execution in the corresponding [XC-20 token](/builders/interoperability/xcm/xc20/overview/){target=\_blank}. If you don't specify the `feePayer`, the XCM execution fees will be paid by the Sovereign account on the destination chain - `fee` - the asset to be used for fees. This contains the `currency` and the `feeAmount`: - `currency` - defines how you are specifying the token to use to pay for the fees, which can be either of the following: - `AsCurrencyId` - the currency ID of the asset to use for the fees. The currency ID can be either: - `SelfReserve` - uses the native asset - `ForeignAsset` - uses an [external XC-20](/builders/interoperability/xcm/xc20/overview/#external-xc20s){target=\_blank}. It requires you to specify the asset ID of the XC-20 - `LocalAssetReserve` - *deprecated* - use [Local XC-20s](/builders/interoperability/xcm/xc20/overview/#local-xc20s){target=\_blank} instead via the `Erc20` currency type - `Erc20` - uses a [local XC-20](/builders/interoperability/xcm/xc20/overview/#local-xc20s){target=\_blank}. It requires you to specify the contract address of the local XC-20 - `AsMultiLocation` - the XCM versioned multilocation for the asset to use for the fees - `feeAmount` - (optional) the amount to use for fees - `call` - encoded call data of the call that will be executed in the target chain - `originKind` — dispatcher of the remote call in the destination chain. There are [four types of dispatchers](https://github.com/paritytech/polkadot-sdk/blob/polkadot-stable2412/polkadot/xcm/src/v3/mod.rs#L421-L440){target=\_blank} available: `Native`, `SovereignAccount`, `Superuser`, or `Xcm` - `weightInfo` - the weight information to be used. The `weightInfo` structure contains the following: - `transactRequiredWeightAtMost` — the weight required to perform the execution of the `Transact` call. The `transactRequiredWeightAtMost` structure contains the following: - `refTime` - the amount of computational time that can be used for execution - `proofSize` - the amount of storage in bytes that can be used - `overallWeight` — (optional) the total weight the extrinsic can use to execute all the XCM instructions, plus the weight of the `Transact` call (`transactRequiredWeightAtMost`). The `overallWeight` can be defined as either: - `Unlimited` - allows an unlimited amount of weight that can be purchased - `Limited` - limits the amount of weight that can be purchased by defining the following: - `refTime` - the amount of computational time that can be used for execution - `proofSize` - the amount of storage in bytes that can be used - `refund` - a boolean indicating whether or not to add the `RefundSurplus` and `DepositAsset` instructions to the XCM message to refund any leftover fees === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const dest = { V4: { parents: INSERT_PARENTS, interior: INSERT_INTERIOR, }, }; const fee = { currency: { AsCurrencyId: { ForeignAsset: INSERT_ASSET_ID }, }, feeAmount: INSERT_FEE_AMOUNT, }; const feePayer = 'INSERT_ADDRESS_RESPONSIBLE_FOR_FEES'; const call = 'INSERT_ENCODED_CALL_DATA'; const originKind = 'INSERT_ORIGIN_KIND'; const weightInfo = { transactRequiredWeightAtMost: { refTime: INSERT_REF_TIME, proofSize: INSERT_PROOF_SIZE, }, overallWeight: { Unlimited: null }, }; const refund = INSERT_BOOLEAN_FOR_REFUND; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.xcmTransactor.transactThroughSovereign( dest, feePayer, fee, call, originKind, weightInfo, refund ); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); }; main(); ``` ### Storage Methods {: #storage-methods } The XCM Transactor Pallet includes the following read-only storage method: ???+ function "**destinationAssetFeePerSecond**(location) - returns the fee per second for a given asset" === "Parameters" - `location` - (optional) the XCM versioned multilocation for a specific destination asset === "Returns" A number representing the value for fee per second of the given asset. This value may be returned in a different format depending on the chain and how they store their data. You can use the `@polkadot/util` library for a variety of conversions, for example, to convert a hex value to a big integer using the `hexToBigInt` method. ```js // If using Polkadot.js API and calling toJSON() on the unwrapped value 10000000000000 ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const location = { parents: INSERT_PARENTS, interior: INSERT_INTERIOR, }; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const feePerSecond = await api.query.xcmTransactor.destinationAssetFeePerSecond(location); if (feePerSecond.isSome) { const data = feePerSecond.unwrap(); console.log(data.toJSON()); } }; main(); ``` ??? function "**palletVersion**() — returns current pallet version from storage" === "Parameters" None === "Returns" A number representing the current version of the pallet. ```js // If using Polkadot.js API and calling toJSON() on the unwrapped value 0 ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const palletVersion = await api.query.xcmTransactor.palletVersion(); }; main(); ``` ??? function "**transactInfoWithWeightLimit**(location) — returns the transact information for a given multilocation" === "Parameters" - `location` - (optional) the XCM versioned multilocation for a specific destination asset === "Returns" The transact information object. ```js // If using Polkadot.js API and calling toJSON() on the unwrapped value { transactExtraWeight: { refTime: 3000000000, proofSize: 131072 }, maxWeight: { refTime: 20000000000, proofSize: 131072 }, transactExtraWeightSigned: { refTime: 4000000000, proofSize: 131072 }, } ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const location = { parents: INSERT_PARENTS, interior: INSERT_INTERIOR, }; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const transactInfoWithWeightLimit = await api.query.xcmTransactor.transactInfoWithWeightLimit(location); if (transactInfoWithWeightLimit.isSome) { const data = transactInfoWithWeightLimit.unwrap(); console.log(data.toJSON()); } }; main(); ``` ### Pallet Constants {: #constants } The XCM Transactor Pallet includes the following read-only functions to obtain pallet constants: ???+ function "**baseXcmWeight**() - returns the base XCM weight required for execution, per XCM instruction" === "Returns" The base XCM weight object. ```js // If using Polkadot.js API and calling toJSON() on the unwrapped value { refTime: 200000000, proofSize: 0 } ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const baseXcmWeight = api.consts.xcmTransactor.baseXcmWeight; console.log(baseXcmWeight.toJSON()); }; main(); ``` ??? function "**selfLocation**() - returns the multilocation of the chain" === "Returns" The self-location multilocation object. ```js // If using Polkadot.js API and calling toJSON() on the unwrapped value { parents: 0, interior: { here: null } } ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const selfLocation = api.consts.xcmTransactor.selfLocation; console.log(selfLocation.toJSON()); }; main(); ``` ## XCM Instructions for Remote Execution {: #xcm-instructions-for-remote-execution } The relevant [XCM instructions](/builders/interoperability/xcm/core-concepts/instructions/){target=\_blank} to perform remote execution through XCM are, but are not limited to: - [`DescendOrigin`](/builders/interoperability/xcm/core-concepts/instructions/#descend-origin){target=\_blank} - gets executed in the target chain. It mutates the origin on the target chain to match the origin on the source chain, ensuring execution on the target chain occurs on behalf of the same entity initiating the XCM message on the source chain - [`WithdrawAsset`](/builders/interoperability/xcm/core-concepts/instructions/#withdraw-asset){target=\_blank} - gets executed in the target chain. Removes assets and places them into a holding register - [`BuyExecution`](/builders/interoperability/xcm/core-concepts/instructions/#buy-execution){target=\_blank} - gets executed in the target chain. Takes the assets from holding to pay for execution fees. The fees to pay are determined by the target chain - [`Transact`](/builders/interoperability/xcm/core-concepts/instructions/#transact){target=\_blank} - gets executed in the target chain. Dispatches encoded call data from a given origin, allowing for the execution of specific operations or functions ## Transact through a Computed Origin Account {: #xcmtransactor-transact-through-signed } This section covers building an XCM message for remote execution using the XCM Transactor Pallet, specifically with the `transactThroughSigned` function. This function uses a Computed Origin account on the destination chain to dispatch the remote call. The example in this section uses a destination parachain that is not publicly available, so you won't be able to follow along exactly. You can modify the example as needed for your own use case. !!! note You need to ensure that the call you are going to execute remotely is allowed in the destination chain! ### Checking Prerequisites {: #xcmtransactor-signed-check-prerequisites } To be able to send the extrinsics in this section, you need to have: - An account in the origin chain with [funds](/builders/get-started/networks/moonbase/#get-tokens){target=\_blank} - Funds in the Computed Origin account on the target chain. To learn how to calculate the address of the Computed Origin account, please refer to the [How to Calculate the Computed Origin](/builders/interoperability/xcm/remote-execution/computed-origins/){target=\_blank} documentation For this example, the following accounts will be used: - Alice's account in the origin parachain (Moonbase Alpha): `0x44236223aB4291b93EEd10E4B511B37a398DEE55` - Her Computed Origin address in the target parachain (Parachain 888): `0x5c27c4bb7047083420eddff9cddac4a0a120b45c` ### Building the XCM {: #xcm-transact-through-signed } Since you'll be interacting with the `transactThroughSigned` function of the XCM Transactor Pallet, you'll need to assemble the values for the `dest`, `fee`, `call`, `weightInfo`, and `refund` parameters. To do so, you can take the following steps: 1. Define the destination multilocation, which will target parachain 888 ```js const privateKey = 'INSERT_PRIVATE_KEY'; const dest = { V4: { parents: 1, interior: { X1: [{ Parachain: 888 }] }, }, ``` 2. Define the `fee` information, which will require you to define the currency and set the fee amount === "External XC-20s" ```js const fee = { currency: { AsCurrencyId: { ForeignAsset: 35487752324713722007834302681851459189n }, }, feeAmount: 50000000000000000n, }; ``` === "Local XC-20s" ```js const fee = { currency: { AsCurrencyId: { Erc20: { contractAddress: ERC_20_ADDRESS} }, }, feeAmount: 50000000000000000n, }; ``` 3. Define the `call` that will be executed in the destination chain, which is the encoded call data of the pallet, method, and input to be called. It can be constructed in [Polkadot.js Apps](https://polkadot.js.org/apps){target=\_blank} (which must be connected to the destination chain) or using the [Polkadot.js API](/builders/substrate/libraries/polkadot-js-api/){target=\_blank}. For this example, the inner call is a simple balance transfer of 1 token of the destination chain to Alice's account there ```js const call = '0x030044236223ab4291b93eed10e4b511b37a398dee5513000064a7b3b6e00d'; ``` 4. Set the `weightInfo`, which includes the weight specific to the inner call (`transactRequiredWeightAtMost`) and the optional overall weight of the transact plus XCM execution (`overallWeight`). For each parameter, you can follow these guidelines: - For `transactRequiredAtMost`, you can set `refTime` to `1000000000` weight units and `proofSize` to `40000` - For `overallWeight`, the value must be the total of `transactRequiredWeightAtMost` plus the weight needed to cover the execution costs for the XCM instructions in the destination chain. If you do not provide this value, the pallet will use the element in storage (if it exists) and add it to `transactRequiredWeightAtMost`. For this example, you can set the `overallWeight` to `Unlimited`, which removes the need to know how much weight the destination chain will require to execute the XCM ```js const weightInfo = { transactRequiredWeightAtMost: { refTime: 1000000000n, proofSize: 40000n }, overallWeight: { Unlimited: null }, }; ``` !!! note For accurate estimates of the `refTime` and `proofSize` figures for `transactRequiredAtMost`, you can use the [`paymentInfo` method of the Polkadot.js API](/builders/substrate/libraries/polkadot-js-api/#fees){target=\_blank}. 5. To refund any leftover XCM fees, you can set the `refund` value to `true`. Otherwise, set it to `false` ```js const refund = true; ``` ### Sending the XCM {: #sending-the-xcm } Now that you have the values for each of the parameters, you can write the script for the transaction. You'll take the following steps: 1. Provide the input data for the call. This includes: - The Moonbase Alpha endpoint URL to create the provider - The values for each of the parameters of the `transactThroughSigned` function 2. Create a Keyring instance that will be used to send the transaction 3. Create the [Polkadot.js API](/builders/substrate/libraries/polkadot-js-api/){target=\_blank} provider 4. Craft the `xcmTransactor.transactThroughSigned` extrinsic with the `dest`, `fee`, `call`, `weightInfo`, and `refund` values 5. Send the transaction using the `signAndSend` extrinsic and the Keyring instance you created in the second step !!! remember This is for demo purposes only. Never store your private key in a JavaScript file. ```js import { ApiPromise, WsProvider, Keyring } from '@polkadot/api'; // Version 10.13.1 import { cryptoWaitReady } from '@polkadot/util-crypto'; // 1. Provide input data const providerWsURL = 'wss://wss.api.moonbase.moonbeam.network'; const privateKey = 'INSERT_PRIVATE_KEY'; const dest = { V4: { parents: 1, interior: { X1: [{ Parachain: 888 }] }, }, }; const fee = { currency: { AsCurrencyId: { ForeignAsset: 35487752324713722007834302681851459189n }, }, feeAmount: 50000000000000000n, }; const call = '0x030044236223ab4291b93eed10e4b511b37a398dee5513000064a7b3b6e00d'; const weightInfo = { transactRequiredWeightAtMost: { refTime: 1000000000n, proofSize: 40000n }, overallWeight: { Unlimited: null }, }; const refund = true; const transactThroughSigned = async () => { // 2. Create Keyring instance await cryptoWaitReady(); const keyring = new Keyring({ type: 'ethereum' }); const alice = keyring.addFromUri(privateKey); // 3. Create Substrate API provider const substrateProvider = new WsProvider(providerWsURL); const api = await ApiPromise.create({ provider: substrateProvider }); // 4. Craft the extrinsic const tx = api.tx.xcmTransactor.transactThroughSigned( dest, fee, call, weightInfo, refund ); // 5. Send the transaction const txHash = await tx.signAndSend(alice); console.log(`Submitted with hash ${txHash}`); api.disconnect(); }; transactThroughSigned(); ``` !!! note You can view an example of the above script, which sends one token to Alice's Computed Origin account on parachain 888, on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/extrinsics/decode/0x210604010100e10d00017576e5e612ff054915d426c546b1b21a010000c52ebca2b10000000000000000007c030044236223ab4291b93eed10e4b511b37a398dee5513000064a7b3b6e00d02286bee02710200010001){target=\_blank} using the following encoded calldata: `0x210604010100e10d00017576e5e612ff054915d426c546b1b21a010000c52ebca2b10000000000000000007c030044236223ab4291b93eed10e4b511b37a398dee5513000064a7b3b6e00d02286bee02710200010001`. ### XCM Transact through Computed Origin Fees {: #transact-through-computed-origin-fees } When [transacting through the Computed Origin account](#xcmtransactor-transact-through-signed){target=\_blank}, the transaction fees are paid by the same account from which the call is dispatched, which is a Computed Origin account in the destination chain. Consequently, the Computed Origin account must hold the necessary funds to pay for the entire execution. Note that the destination token, for which fees are paid, does not need to be registered as an XC-20 in the origin chain. To estimate the amount of tokens Alice's Computed Origin account will need to execute the remote call, you need to check the transact information specific to the destination chain. You can use the following script to get the transact information for parachain 888: ```js import { ApiPromise, WsProvider } from '@polkadot/api'; // Version 10.13.1 const providerWsURL = 'wss://wss.api.moonbase.moonbeam.network'; const location = { parents: 1, interior: { X1: [{ Parachain: 888 }] } }; const main = async () => { const substrateProvider = new WsProvider(providerWsURL); const api = await ApiPromise.create({ provider: substrateProvider }); const transactInfoWithWeightLimit = await api.query.xcmTransactor.transactInfoWithWeightLimit(location); if (transactInfoWithWeightLimit.isSome) { const data = transactInfoWithWeightLimit.unwrap(); const transactExtraWeightSigned = data.toJSON().transactExtraWeightSigned.refTime; console.log(transactExtraWeightSigned); } api.disconnect(); }; main(); ``` The response shows that the `transactExtraWeightSigned` is `{{ networks.moonbase_beta.xcm_message.transact.weight.display }}`. This weight is needed to execute the four XCM instructions for this remote call in that specific destination chain. Next, you need to find out how much the destination chain charges per weight of XCM execution in reference to the asset's price. Previously, this was done by sourcing a units per second value. However, this method has been replaced by calculating a relative price. Relative price refers to how many units of the foreign asset correspond to one unit of the native token (GLMR or MOVR) from a value (i.e., price) perspective. For example, if the foreign asset is worth $5 and GLMR is worth $0.25, the relative price would be 0.05. However, we must scale the result to 18 decimals to correspond to the Wei units used. In this case, the relative price would be `50000000000000000`. You can calculate the relative price with a script in the [XCM Tools repo](https://github.com/Moonsong-Labs/xcm-tools?tab=readme-ov-file#calculate-relative-price){target=\_blank}. The script is also reproduced below: ??? code "Calculate Relative Price" ```typescript import axios from 'axios'; import chalk from 'chalk'; // CoinGecko IDs for the networks const NETWORK_IDS = { GLMR: 'moonbeam', MOVR: 'moonriver', }; async function calculateRelativePrice( assetPrice: number, network: 'GLMR' | 'MOVR' ): Promise { try { // Fetch the native token price from CoinGecko const response = await axios.get( `https://api.coingecko.com/api/v3/simple/price?ids=${NETWORK_IDS[network]}&vs_currencies=usd` ); const nativeTokenPrice = response.data[NETWORK_IDS[network]].usd; // Calculate relative price with 18 decimal places // Formula: (nativeTokenPrice / assetPrice) * 10^18 // This gives us how many units of the asset we need to equal 1 unit of native token const relativePrice = (nativeTokenPrice / assetPrice) * Math.pow(10, 18); // Return as string to preserve precision return relativePrice.toFixed(0); } catch (error) { if (error instanceof Error) { throw new Error(`Failed to calculate relative price: ${error.message}`); } throw error; } } function validateInput( price: string, network: string ): { assetPrice: number; network: 'GLMR' | 'MOVR' } { // Validate price const assetPrice = parseFloat(price); if (isNaN(assetPrice) || assetPrice <= 0) { throw new Error('Price must be a positive number'); } // Validate network const upperNetwork = network.toUpperCase() as 'GLMR' | 'MOVR'; if (!['GLMR', 'MOVR'].includes(upperNetwork)) { throw new Error('Network must be either GLMR or MOVR'); } return { assetPrice, network: upperNetwork }; } function printUsage() { console.log('\nUsage:'); console.log('npx ts-node relative-price-calculator.ts '); console.log('\nExample:'); console.log('npx ts-node relative-price-calculator.ts 0.25 GLMR'); console.log('\nParameters:'); console.log('price - The price of your asset in USD'); console.log('network - Either GLMR or MOVR'); } async function main() { try { // Get command line arguments const [, , price, network] = process.argv; // Check if help flag is passed if (price === '--help' || price === '-h') { printUsage(); return; } // Check if required arguments are provided if (!price || !network) { console.error('Error: Missing required arguments'); printUsage(); process.exit(1); } // Validate inputs const { assetPrice, network: validNetwork } = validateInput(price, network); console.log( `\nCalculating relative price for asset worth $${assetPrice} against ${validNetwork}...` ); const relativePrice = await calculateRelativePrice( assetPrice, validNetwork ); const nativeTokenPrice = ( await axios.get( `https://api.coingecko.com/api/v3/simple/price?ids=${NETWORK_IDS[validNetwork]}&vs_currencies=usd` ) ).data[NETWORK_IDS[validNetwork]].usd; const decimalRatio = nativeTokenPrice / assetPrice; console.log(`\nResults:`); console.log(`Asset Price: $${assetPrice}`); console.log(`Network: ${validNetwork}`); console.log(`Native Token Price (from CoinGecko): $${nativeTokenPrice}`); console.log(`\nRelative Price Analysis:`); console.log( `1 ${validNetwork} is equal to approximately ${decimalRatio.toFixed( 3 )} of your specified token.` ); console.log( `With 18 decimals, 1 ${validNetwork} or in WEI, 1000000000000000000 is equal to a relative price of ${relativePrice} units of your token` ); console.log(chalk.bold(`\nRelative Price: ${relativePrice}`)); console.log( `\nThe relative price you should specify in asset registration steps is ${relativePrice}\n` ); } catch (error) { console.error('\nError:', error instanceof Error ? error.message : error); process.exit(1); } } main(); ``` Note that the relative price value is related to the cost estimated in the [relay chain XCM fee calculation](/builders/interoperability/xcm/core-concepts/weights-fees/#polkadot){target=\_blank} section or to the one shown in the [units per weight](/builders/interoperability/xcm/core-concepts/weights-fees/#moonbeam-reserve-assets){target=\_blank} section if the target is another parachain. You'll need to find the correct value to ensure that the amount of tokens the Computed Origin account holds is correct. Calculating the associated XCM execution fee is as simple as multiplying the `transactExtraWeightSigned` times the `relativePrice` (for an estimation): ```text XCM-Wei-Token-Cost = transactExtraWeightSigned * relativePrice XCM-Token-Cost = XCM-Wei-Token-Cost / DecimalConversion ``` Therefore, the actual calculation for one XCM Transactor transact through derivative call is: ```text XCM-Wei-Token-Cost = {{ networks.moonbase_beta.xcm_message.transact.weight.numbers_only }} * {{ networks.moonbase.xcm.units_per_second.xcbetadev.transact_numbers_only }} XCM-Token-Cost = {{ networks.moonbase_beta.xcm_message.transact.wei_betadev_cost }} / 10^18 ``` The cost of transacting through a Computed Origin is `{{ networks.moonbase_beta.xcm_message.transact.betadev_cost }} TOKEN`. **Note that this does not include the cost of the call being remotely executed, only XCM execution fees.** --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/remote-execution/substrate-calls/xcm-transactor-precompile/ --- BEGIN CONTENT --- --- title: The XCM Transactor Precompile description: This guide describes the XCM Transactor Precompile and shows how to use some of its functions to send remote calls to other chains using Ethereum libraries. categories: XCM Remote Execution --- # Using the XCM Transactor Precompile for Remote Execution XCM messages are comprised of a [series of instructions](/builders/interoperability/xcm/core-concepts/instructions/){target=\_blank} that are executed by the Cross-Consensus Virtual Machine (XCVM). Combinations of these instructions result in predetermined actions such as cross-chain token transfers and, more interestingly, remote cross-chain execution. Remote execution involves executing operations or actions on one blockchain from another blockchain while maintaining the integrity of the sender's identity and permissions. Typically, XCM messages are sent from the root origin (that is, SUDO or through governance), which is not ideal for projects that want to leverage remote cross-chain calls via a simple transaction. The [XCM Transactor Pallet](https://github.com/moonbeam-foundation/moonbeam/blob/master/pallets/xcm-transactor/src/lib.rs){target=\_blank} makes it easy to transact on a remote chain through either the [Sovereign account](/builders/interoperability/xcm/overview/#general-xcm-definitions){target=\_blank}, which should only be allowed through governance, or a [Computed Origin account](/builders/interoperability/xcm/remote-execution/computed-origins/){target=\_blank} via a simple transaction from the source chain. However, the XCM Transactor Pallet is coded in Rust and is normally not accessible from the Ethereum API side of Moonbeam. As such, Moonbeam introduced the XCM Transactor Precompile, which is a Solidity interface that allows you to interact directly with the Substrate pallet using the Ethereum API. This guide will show you how to use the XCM Transactor Precompile to send XCM messages from a Moonbeam-based network to other chains in the ecosystem. **Note that there are still limitations to what you can remotely execute through XCM messages**. **Developers must understand that sending incorrect XCM messages can result in the loss of funds.** Consequently, it is essential to test XCM features on a TestNet before moving to a production environment. ## XCM Transactor Precompile Contract Address {: #precompile-address } There are several versions of the XCM Transactor Precompile. **V1 will be deprecated in the near future**, so all implementations must migrate to the newer interfaces. The XCM Transactor Precompiles are located at the following addresses: === "Moonbeam" | Version | Address | |:-------:|:----------------------------------------------------------------------:| | V1 |
```{{ networks.moonbeam.precompiles.xcm_transactor_v1 }}```
| | V2 |
```{{ networks.moonbeam.precompiles.xcm_transactor_v2 }}```
| | V3 |
```{{ networks.moonbeam.precompiles.xcm_transactor_v3 }}```
| === "Moonriver" | Version | Address | |:-------:|:-----------------------------------------------------------------------:| | V1 |
```{{ networks.moonriver.precompiles.xcm_transactor_v1 }}```
| | V2 |
```{{ networks.moonriver.precompiles.xcm_transactor_v2 }}```
| | V3 |
```{{ networks.moonriver.precompiles.xcm_transactor_v3 }}```
| === "Moonbase Alpha" | Version | Address | |:-------:|:----------------------------------------------------------------------:| | V1 |
```{{ networks.moonbase.precompiles.xcm_transactor_v1 }}```
| | V2 |
```{{ networks.moonbase.precompiles.xcm_transactor_v2 }}```
| | V3 |
```{{ networks.moonbase.precompiles.xcm_transactor_v3 }}```
| !!! note There can be some unintended consequences when using the precompiled contracts on Moonbeam. Please refer to the [Security Considerations](/learn/core-concepts/security/){target=\_blank} page for more information. ## The XCM Transactor Solidity Interface {: #xcmtrasactor-solidity-interface } The XCM Transactor Precompile is a Solidity interface through which developers can interact with the XCM Transactor Pallet using the Ethereum API. ??? code "XcmTransactorV1.sol" ```solidity // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.3; /// @dev The XcmTransactorV1 contract's address. address constant XCM_TRANSACTOR_V1_ADDRESS = 0x0000000000000000000000000000000000000806; /// @dev The XcmTransactorV1 contract's instance. XcmTransactorV1 constant XCM_TRANSACTOR_V1_CONTRACT = XcmTransactorV1( XCM_TRANSACTOR_V1_ADDRESS ); /// @author The Moonbeam Team /// @title Xcm Transactor Interface /// @dev The interface through which solidity contracts will interact with xcm transactor pallet /// @custom:address 0x0000000000000000000000000000000000000806 interface XcmTransactorV1 { // A multilocation is defined by its number of parents and the encoded junctions (interior) struct Multilocation { uint8 parents; bytes[] interior; } /// Get index of an account in xcm transactor /// @custom:selector 3fdc4f36 /// @param index The index of which we want to retrieve the account /// @return owner The owner of the derivative index /// function indexToAccount(uint16 index) external view returns (address owner); /// DEPRECATED, replaced by transactInfoWithSigned /// Get transact info of a multilocation /// @custom:selector d07d87c3 /// @param multilocation The location for which we want to know the transact info /// @return transactExtraWeight The extra weight involved in the XCM message of using derivative /// @return feePerSecond The amount of fee charged for a second of execution in the dest /// @return maxWeight Maximum allowed weight for a single message in dest /// function transactInfo(Multilocation memory multilocation) external view returns ( uint64 transactExtraWeight, uint256 feePerSecond, uint64 maxWeight ); /// Get transact info of a multilocation /// @custom:selector b689e20c /// @param multilocation The location for which we want to know the transact info /// @return transactExtraWeight The extra weight involved in the XCM message of using derivative /// @return transactExtraWeightSigned The extra weight involved in the XCM message of using signed /// @return maxWeight Maximum allowed weight for a single message in dest /// function transactInfoWithSigned(Multilocation memory multilocation) external view returns ( uint64 transactExtraWeight, uint64 transactExtraWeightSigned, uint64 maxWeight ); /// Get fee per second charged in its reserve chain for an asset /// @custom:selector 906c9990 /// @param multilocation The asset location for which we want to know the fee per second value /// @return feePerSecond The fee per second that the reserve chain charges for this asset /// function feePerSecond(Multilocation memory multilocation) external view returns (uint256 feePerSecond); /// Transact through XCM using fee based on its multilocation /// @custom:selector 94a63c54 /// @dev The token transfer burns/transfers the corresponding amount before sending /// @param transactor The transactor to be used /// @param index The index to be used /// @param feeAsset The asset in which we want to pay fees. /// It has to be a reserve of the destination chain /// @param weight The weight we want to buy in the destination chain /// @param innerCall The inner call to be executed in the destination chain function transactThroughDerivativeMultilocation( uint8 transactor, uint16 index, Multilocation memory feeAsset, uint64 weight, bytes memory innerCall ) external; /// Transact through XCM using fee based on its currencyId /// @custom:selector 02ae072d /// @dev The token transfer burns/transfers the corresponding amount before sending /// @param transactor The transactor to be used /// @param index The index to be used /// @param currencyId Address of the currencyId of the asset to be used for fees /// It has to be a reserve of the destination chain /// @param weight The weight we want to buy in the destination chain /// @param innerCall The inner call to be executed in the destination chain function transactThroughDerivative( uint8 transactor, uint16 index, address currencyId, uint64 weight, bytes memory innerCall ) external; /// Transact through XCM using fee based on its multilocation through signed origins /// @custom:selector 71d31587 /// @dev No token is burnt before sending the message. The caller must ensure the destination /// is able to understand the DescendOrigin message, and create a unique account from which /// dispatch the call /// @param dest The destination chain (as multilocation) where to send the message /// @param feeLocation The asset multilocation that indentifies the fee payment currency /// It has to be a reserve of the destination chain /// @param weight The weight we want to buy in the destination chain for the call to be made /// @param call The call to be executed in the destination chain function transactThroughSignedMultilocation( Multilocation memory dest, Multilocation memory feeLocation, uint64 weight, bytes memory call ) external; /// Transact through XCM using fee based on its erc20 address through signed origins /// @custom:selector 42ca339d /// @dev No token is burnt before sending the message. The caller must ensure the destination /// is able to understand the DescendOrigin message, and create a unique account from which /// dispatch the call /// @param dest The destination chain (as multilocation) where to send the message /// @param feeLocationAddress The ERC20 address of the token we want to use to pay for fees /// only callable if such an asset has been BRIDGED to our chain /// @param weight The weight we want to buy in the destination chain for the call to be made /// @param call The call to be executed in the destination chain function transactThroughSigned( Multilocation memory dest, address feeLocationAddress, uint64 weight, bytes memory call ) external; /// @dev Encode 'utility.as_derivative' relay call /// @custom:selector ff86378d /// @param transactor The transactor to be used /// @param index: The derivative index to use /// @param innerCall: The inner call to be executed from the derivated address /// @return result The bytes associated with the encoded call function encodeUtilityAsDerivative(uint8 transactor, uint16 index, bytes memory innerCall) external pure returns (bytes memory result); } ``` ??? code "XcmTransactorV2.sol" ```solidity // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; /// @dev The XcmTransactorV2 contract's address. address constant XCM_TRANSACTOR_V2_ADDRESS = 0x000000000000000000000000000000000000080D; /// @dev The XcmTransactorV2 contract's instance. XcmTransactorV2 constant XCM_TRANSACTOR_V2_CONTRACT = XcmTransactorV2( XCM_TRANSACTOR_V2_ADDRESS ); /// @author The Moonbeam Team /// @title Xcm Transactor Interface /// The interface through which solidity contracts will interact with xcm transactor pallet /// @custom:address 0x000000000000000000000000000000000000080D interface XcmTransactorV2 { // A multilocation is defined by its number of parents and the encoded junctions (interior) struct Multilocation { uint8 parents; bytes[] interior; } /// Get index of an account in xcm transactor /// @custom:selector 3fdc4f36 /// @param index The index of which we want to retrieve the account /// @return owner The owner of the derivative index /// function indexToAccount(uint16 index) external view returns (address owner); /// Get transact info of a multilocation /// @custom:selector b689e20c /// @param multilocation The location for which we want to know the transact info /// @return transactExtraWeight The extra weight involved in the XCM message of using derivative /// @return transactExtraWeightSigned The extra weight involved in the XCM message of using signed /// @return maxWeight Maximum allowed weight for a single message in dest /// function transactInfoWithSigned(Multilocation memory multilocation) external view returns ( uint64 transactExtraWeight, uint64 transactExtraWeightSigned, uint64 maxWeight ); /// Get fee per second charged in its reserve chain for an asset /// @custom:selector 906c9990 /// @param multilocation The asset location for which we want to know the fee per second value /// @return feePerSecond The fee per second that the reserve chain charges for this asset /// function feePerSecond(Multilocation memory multilocation) external view returns (uint256 feePerSecond); /// Transact through XCM using fee based on its multilocation /// @custom:selector fe430475 /// @dev The token transfer burns/transfers the corresponding amount before sending /// @param transactor The transactor to be used /// @param index The index to be used /// @param feeAsset The asset in which we want to pay fees. /// It has to be a reserve of the destination chain /// @param transactRequiredWeightAtMost The weight we want to buy in the destination chain /// @param innerCall The inner call to be executed in the destination chain /// @param feeAmount Amount to be used as fee. /// @param overallWeight Overall weight to be used for the xcm message. /// function transactThroughDerivativeMultilocation( uint8 transactor, uint16 index, Multilocation memory feeAsset, uint64 transactRequiredWeightAtMost, bytes memory innerCall, uint256 feeAmount, uint64 overallWeight ) external; /// Transact through XCM using fee based on its currency_id /// @custom:selector 185de2ae /// @dev The token transfer burns/transfers the corresponding amount before sending /// @param transactor The transactor to be used /// @param index The index to be used /// @param currencyId Address of the currencyId of the asset to be used for fees /// It has to be a reserve of the destination chain /// @param transactRequiredWeightAtMost The weight we want to buy in the destination chain /// @param innerCall The inner call to be executed in the destination chain /// @param feeAmount Amount to be used as fee. /// @param overallWeight Overall weight to be used for the xcm message. function transactThroughDerivative( uint8 transactor, uint16 index, address currencyId, uint64 transactRequiredWeightAtMost, bytes memory innerCall, uint256 feeAmount, uint64 overallWeight ) external; /// Transact through XCM using fee based on its multilocation through signed origins /// @custom:selector d7ab340c /// @dev No token is burnt before sending the message. The caller must ensure the destination /// is able to understand the DescendOrigin message, and create a unique account from which /// dispatch the call /// @param dest The destination chain (as multilocation) where to send the message /// @param feeLocation The asset multilocation that indentifies the fee payment currency /// It has to be a reserve of the destination chain /// @param transactRequiredWeightAtMost The weight we want to buy in the destination chain for the call to be made /// @param call The call to be executed in the destination chain /// @param feeAmount Amount to be used as fee. /// @param overallWeight Overall weight to be used for the xcm message. function transactThroughSignedMultilocation( Multilocation memory dest, Multilocation memory feeLocation, uint64 transactRequiredWeightAtMost, bytes memory call, uint256 feeAmount, uint64 overallWeight ) external; /// Transact through XCM using fee based on its erc20 address through signed origins /// @custom:selector b648f3fe /// @dev No token is burnt before sending the message. The caller must ensure the destination /// is able to understand the DescendOrigin message, and create a unique account from which /// dispatch the call /// @param dest The destination chain (as multilocation) where to send the message /// @param feeLocationAddress The ERC20 address of the token we want to use to pay for fees /// only callable if such an asset has been BRIDGED to our chain /// @param transactRequiredWeightAtMost The weight we want to buy in the destination chain for the call to be made /// @param call The call to be executed in the destination chain /// @param feeAmount Amount to be used as fee. /// @param overallWeight Overall weight to be used for the xcm message. function transactThroughSigned( Multilocation memory dest, address feeLocationAddress, uint64 transactRequiredWeightAtMost, bytes memory call, uint256 feeAmount, uint64 overallWeight ) external; /// @dev Encode 'utility.as_derivative' relay call /// @custom:selector ff86378d /// @param transactor The transactor to be used /// @param index: The derivative index to use /// @param innerCall: The inner call to be executed from the derivated address /// @return result The bytes associated with the encoded call function encodeUtilityAsDerivative(uint8 transactor, uint16 index, bytes memory innerCall) external pure returns (bytes memory result); } ``` ??? code "XcmTransactorV3.sol" ```solidity // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; /// @dev The XcmTransactorV3 contract's address. address constant XCM_TRANSACTOR_V3_ADDRESS = 0x0000000000000000000000000000000000000817; /// @dev The XcmTransactorV3 contract's instance. XcmTransactorV3 constant XCM_TRANSACTOR_V3_CONTRACT = XcmTransactorV3( XCM_TRANSACTOR_V3_ADDRESS ); /// @author The Moonbeam Team /// @title Xcm Transactor Interface /// The interface through which solidity contracts will interact with xcm transactor pallet /// @custom:address 0x0000000000000000000000000000000000000817 interface XcmTransactorV3 { // A multilocation is defined by its number of parents and the encoded junctions (interior) struct Multilocation { uint8 parents; bytes[] interior; } // Support for Weights V2 struct Weight { uint64 refTime; uint64 proofSize; } /// Get index of an account in xcm transactor /// @custom:selector 3fdc4f36 /// @param index The index of which we want to retrieve the account /// @return owner The owner of the derivative index /// function indexToAccount(uint16 index) external view returns (address owner); /// Get transact info of a multilocation /// @custom:selector b689e20c /// @param multilocation The location for which we want to know the transact info /// @return transactExtraWeight The extra weight involved in the XCM message of using derivative /// @return transactExtraWeightSigned The extra weight involved in the XCM message of using signed /// @return maxWeight Maximum allowed weight for a single message in dest /// function transactInfoWithSigned(Multilocation memory multilocation) external view returns ( Weight memory transactExtraWeight, Weight memory transactExtraWeightSigned, Weight memory maxWeight ); /// Get fee per second charged in its reserve chain for an asset /// @custom:selector 906c9990 /// @param multilocation The asset location for which we want to know the fee per second value /// @return feePerSecond The fee per second that the reserve chain charges for this asset /// function feePerSecond(Multilocation memory multilocation) external view returns (uint256 feePerSecond); /// Transact through XCM using fee based on its multilocation /// @custom:selector bdacc26b /// @dev The token transfer burns/transfers the corresponding amount before sending /// @param transactor The transactor to be used /// @param index The index to be used /// @param feeAsset The asset in which we want to pay fees. /// It has to be a reserve of the destination chain /// @param transactRequiredWeightAtMost The weight we want to buy in the destination chain /// @param innerCall The inner call to be executed in the destination chain /// @param feeAmount Amount to be used as fee. /// @param overallWeight Overall weight to be used for the xcm message. If uint64:MAX is passed /// through refTime field, Unlimited variant will be used. /// @param refund Indicates if RefundSurplus instruction will be appended function transactThroughDerivativeMultilocation( uint8 transactor, uint16 index, Multilocation memory feeAsset, Weight memory transactRequiredWeightAtMost, bytes memory innerCall, uint256 feeAmount, Weight memory overallWeight, bool refund ) external; /// Transact through XCM using fee based on its currency_id /// @custom:selector ca8c82d8 /// @dev The token transfer burns/transfers the corresponding amount before sending /// @param transactor The transactor to be used /// @param index The index to be used /// @param currencyId Address of the currencyId of the asset to be used for fees /// It has to be a reserve of the destination chain /// @param transactRequiredWeightAtMost The weight we want to buy in the destination chain /// @param innerCall The inner call to be executed in the destination chain /// @param feeAmount Amount to be used as fee. /// @param overallWeight Overall weight to be used for the xcm message. If uint64:MAX is passed /// through refTime field, Unlimited variant will be used. /// @param refund Indicates if RefundSurplus instruction will be appended function transactThroughDerivative( uint8 transactor, uint16 index, address currencyId, Weight memory transactRequiredWeightAtMost, bytes memory innerCall, uint256 feeAmount, Weight memory overallWeight, bool refund ) external; /// Transact through XCM using fee based on its multilocation through signed origins /// @custom:selector 27b1d492 /// @dev No token is burnt before sending the message. The caller must ensure the destination /// is able to understand the DescendOrigin message, and create a unique account from which /// dispatch the call /// @param dest The destination chain (as multilocation) where to send the message /// @param feeLocation The asset multilocation that indentifies the fee payment currency /// It has to be a reserve of the destination chain /// @param transactRequiredWeightAtMost The weight we want to buy in the destination chain for the call to be made /// @param call The call to be executed in the destination chain /// @param feeAmount Amount to be used as fee. /// @param overallWeight Overall weight to be used for the xcm message. If uint64:MAX is passed /// through refTime field, Unlimited variant will be used. /// @param refund Indicates if RefundSurplus instruction will be appended function transactThroughSignedMultilocation( Multilocation memory dest, Multilocation memory feeLocation, Weight memory transactRequiredWeightAtMost, bytes memory call, uint256 feeAmount, Weight memory overallWeight, bool refund ) external; /// Transact through XCM using fee based on its erc20 address through signed origins /// @custom:selector b18270cf /// @dev No token is burnt before sending the message. The caller must ensure the destination /// is able to understand the DescendOrigin message, and create a unique account from which /// dispatch the call /// @param dest The destination chain (as multilocation) where to send the message /// @param feeLocationAddress The ERC20 address of the token we want to use to pay for fees /// only callable if such an asset has been BRIDGED to our chain /// @param transactRequiredWeightAtMost The weight we want to buy in the destination chain for the call to be made /// @param call The call to be executed in the destination chain /// @param feeAmount Amount to be used as fee. /// @param overallWeight Overall weight to be used for the xcm message. If uint64:MAX is passed /// through refTime field, Unlimited variant will be used. /// @param refund Indicates if RefundSurplus instruction will be appended function transactThroughSigned( Multilocation memory dest, address feeLocationAddress, Weight memory transactRequiredWeightAtMost, bytes memory call, uint256 feeAmount, Weight memory overallWeight, bool refund ) external; /// @dev Encode 'utility.as_derivative' relay call /// @custom:selector ff86378d /// @param transactor The transactor to be used /// @param index: The derivative index to use /// @param innerCall: The inner call to be executed from the derivated address /// @return result The bytes associated with the encoded call function encodeUtilityAsDerivative(uint8 transactor, uint16 index, bytes memory innerCall) external pure returns (bytes memory result); } ``` !!! note The [XCM Transactor Precompile V1](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-transactor/src/v1/XcmTransactorV1.sol){target=\_blank} will be deprecated in the near future, so all implementations must migrate to the newer interfaces. The interface varies slightly from version to version. You can find an overview of each version's interface below. === "V2" The V2 interface includes the following functions: ??? function "**transactInfoWithSigned**(*Multilocation* *memory* multilocation) — read-only function that returns the transact information for a given chain" === "Parameters" - `multilocation` - the multilocation of the chain to get the transact information for === "Returns" The transact information for: - The three XCM instructions associated with the external call execution (`transactExtraWeight`) - The extra weight information associated with the `DescendOrigin` XCM instruction for the transact through signed extrinsic (`transactExtraWeightSigned`) - The maximum allowed weight for the message in the given chain ```js [ 173428000n, 0n, 20000000000n ] ``` ??? function "**feePerSecond**(*Multilocation* *memory* multilocation) — read-only function that returns units of tokens per second of the XCM execution that is charged as the XCM execution fee for a given asset. This is useful when, for a given chain, there are multiple assets that can be used for fee payment" === "Parameters" - `multilocation` - the multilocation of the asset to get the units per second value for === "Returns" The fee per second that the reserve chain charges for the given asset. ```js 13764626000000n ``` ??? function "**transactThroughSignedMultilocation**(*Multilocation* *memory* dest, *Multilocation* *memory* feeLocation, *uint64* transactRequiredWeightAtMost, *bytes* *memory* call, *uint256* feeAmount, *uint64* overallWeight) — sends an XCM message with instructions to remotely execute a call in the destination chain. The remote call will be signed and executed by a new account, called the [Computed Origin](/builders/interoperability/xcm/remote-execution/computed-origins/){target=\_blank} account, that the destination parachain must compute. Moonbeam-based networks follow [the Computed Origins standard set by Polkadot](https://github.com/paritytech/polkadot-sdk/blob/{{ polkadot_sdk }}/polkadot/xcm/xcm-builder/src/location_conversion.rs){target=\_blank}. You need to provide the asset multilocation of the token that is used for fee payment instead of the address of the XC-20 token" === "Parameters" - `dest` - the multilocation of a chain in the ecosystem where the XCM message is being sent to (the target chain). The multilocation must be formatted in a particular way, which is described in the [Building the Precompile Multilocation](#building-the-precompile-multilocation) section - `feeLocation` - the multilocation of the asset to use for fee payment. The multilocation must be formatted in a particular way, which is described in the [Building the Precompile Multilocation](#building-the-precompile-multilocation) section - `transactRequiredWeightAtMost` - the weight to buy in the destination chain for the execution of the call defined in the `Transact` instruction - `call` - the call to be executed in the destination chain, as defined in the `Transact` instruction - `feeAmount` - the amount to be used as a fee - `overallWeight` - the total weight the extrinsic can use to execute all the XCM instructions, plus the weight of the `Transact` call (`transactRequiredWeightAtMost`). The `overallWeight` structure also contains `refTime` and `proofSize`. If you pass in the maximum value for a uint64 for the `refTime`, you'll allow for an unlimited amount of weight to be purchased, which removes the need to know exactly how much weight the destination chain requires to execute the XCM ??? function "**transactThroughSigned**(*Multilocation* *memory* dest, *address* feeLocationAddress, *uint64* transactRequiredWeightAtMost, *bytes* *memory* call, *uint256* feeAmount, *uint64* overallWeight) — sends an XCM message with instructions to remotely execute a call in the destination chain. The remote call will be signed and executed by a new account, called the [Computed Origin](/builders/interoperability/xcm/remote-execution/computed-origins/){target=\_blank} account, that the destination parachain must compute. Moonbeam-based networks follow [the Computed Origins standard set by Polkadot](https://github.com/paritytech/polkadot-sdk/blob/{{ polkadot_sdk }}/polkadot/xcm/xcm-builder/src/location_conversion.rs){target=\_blank}. You need to provide the address of the XC-20 asset to be used for fee payment" === "Parameters" - `dest` - the multilocation of a chain in the ecosystem where the XCM message is being sent to (the target chain). The multilocation must be formatted in a particular way, which is described in the [Building the Precompile Multilocation](#building-the-precompile-multilocation) section - `feeLocationAddress` - the [XC-20 address](/builders/interoperability/xcm/xc20/overview/#current-xc20-assets){target=\_blank} of the asset to use for fee payment - `transactRequiredWeightAtMost` - the weight to buy in the destination chain for the execution of the call defined in the `Transact` instruction - `call` - the call to be executed in the destination chain, as defined in the `Transact` instruction - `feeAmount` - the amount to be used as a fee - `overallWeight` - the total weight the extrinsic can use to execute all the XCM instructions, plus the weight of the `Transact` call (`transactRequiredWeightAtMost`). The `overallWeight` structure also contains `refTime` and `proofSize`. If you pass in the maximum value for a uint64 for the `refTime`, you'll allow for an unlimited amount of weight to be purchased, which removes the need to know exactly how much weight the destination chain requires to execute the XCM === "V3" The V3 interface adds support for Weights V2, which updates the `Weight` type to represent proof size in addition to computational time. As such, this requires that `refTime` and `proofSize` be defined, where `refTime` is the amount of computational time that can be used for execution and `proofSize` is the amount of storage in bytes that can be used. The following struct was added to the XCM Transactor Precompile to support Weights V2: ```solidity struct Weight { uint64 refTime; uint65 proofSize; } ``` Additionally, support for the [`RefundSurplus`](/builders/interoperability/xcm/core-concepts/instructions/#refund-surplus){target=\_blank} and [`DepositAsset`](/builders/interoperability/xcm/core-concepts/instructions/#deposit-asset){target=\_blank} instructions was added. To append the `RefundSurplus` instruction to the XCM message, you can use the `refund` parameter, which will refund any leftover funds not used for the `Transact` if set to `true`. The V3 interface includes the following functions: ??? function "**transactInfoWithSigned**(*Multilocation* *memory* multilocation) — read-only function that returns the transact information for a given chain" === "Parameters" - `multilocation` - the multilocation of the chain to get the transact information for === "Returns" The transact information for: - The three XCM instructions associated with the external call execution (`transactExtraWeight`) - The extra weight information associated with the `DescendOrigin` XCM instruction for the transact through signed extrinsic (`transactExtraWeightSigned`) - The maximum allowed weight for the message in the given chain ```js [ 173428000n, 0n, 20000000000n ] ``` ??? function "**feePerSecond**(*Multilocation* *memory* multilocation) — read-only function that returns units of token per second of the XCM execution that is charged as the XCM execution fee for a given asset. This is useful when, for a given chain, there are multiple assets that can be used for fee payment" === "Parameters" - `multilocation` - the multilocation of the asset to get the units per second value for === "Returns" The fee per second that the reserve chain charges for the given asset. ```js 13764626000000n ``` ??? function "**transactThroughSignedMultilocation**(*Multilocation* *memory* dest, *Multilocation* *memory* feeLocation, *Weight* transactRequiredWeightAtMost, *bytes* *memory* call, *uint256* feeAmount, *Weight* overallWeight, *bool* refund) — sends an XCM message with instructions to remotely execute a call in the destination chain. The remote call will be signed and executed by a new account, called the [Computed Origin](/builders/interoperability/xcm/remote-execution/computed-origins/){target=\_blank} account, that the destination parachain must compute. Moonbeam-based networks follow [the Computed Origins standard set by Polkadot](https://github.com/paritytech/polkadot-sdk/blob/{{ polkadot_sdk }}/polkadot/xcm/xcm-builder/src/location_conversion.rs){target=\_blank}. You need to provide the asset multilocation of the token that is used for fee payment instead of the address of the XC-20 token" === "Parameters" - `dest` - the multilocation of a chain in the ecosystem where the XCM message is being sent to (the target chain). The multilocation must be formatted in a particular way, which is described in the [Building the Precompile Multilocation](#building-the-precompile-multilocation) section - `feeLocation` - the multilocation of the asset to use for fee payment. The multilocation must be formatted in a particular way, which is described in the [following section](#building-the-precompile-multilocation) - `transactRequiredWeightAtMost` - the weight to buy in the destination chain for the execution of the call defined in the `Transact` instruction. The `transactRequiredWeightAtMost` structure contains the following: - `refTime` - the amount of computational time that can be used for execution - `proofSize` - the amount of storage in bytes that can be used It should be formatted as follows: ```js [ INSERT_REF_TIME, INSERT_PROOF_SIZE ] ``` - `call` - the call to be executed in the destination chain, as defined in the `Transact` instruction - `feeAmount` - the amount to be used as a fee - `overallWeight` - the total weight the extrinsic can use to execute all the XCM instructions, plus the weight of the `Transact` call (`transactRequiredWeightAtMost`). The `overallWeight` structure also contains `refTime` and `proofSize`. If you pass in the maximum value for a uint64 for the `refTime`, you'll allow for an unlimited amount of weight to be purchased, which removes the need to know exactly how much weight the destination chain requires to execute the XCM - `refund` - a boolean indicating whether or not to add the `RefundSurplus` and `DepositAsset` instructions to the XCM message to refund any leftover fees ??? function "**transactThroughSigned**(*Multilocation* *memory* dest, *address* feeLocationAddress, *Weight* transactRequiredWeightAtMost, *bytes* *memory* call, *uint256* feeAmount, *Weight* overallWeight, *bool* refund) — sends an XCM message with instructions to remotely execute a call in the destination chain. The remote call will be signed and executed by a new account, called the [Computed Origin](/builders/interoperability/xcm/remote-execution/computed-origins/){target=\_blank} account, that the destination parachain must compute. Moonbeam-based networks follow [the Computed Origins standard set by Polkadot](https://github.com/paritytech/polkadot-sdk/blob/{{ polkadot_sdk }}/polkadot/xcm/xcm-builder/src/location_conversion.rs){target=\_blank}. You need to provide the address of the XC-20 asset to be used for fee payment" === "Parameters" - `dest` - the multilocation of a chain in the ecosystem where the XCM message is being sent to (the target chain). The multilocation must be formatted in a particular way, which is described in the [Building the Precompile Multilocation](#building-the-precompile-multilocation) section - `feeLocationAddress` - the [XC-20 address](/builders/interoperability/xcm/xc20/overview/#current-xc20-assets){target=\_blank} of the asset to use for fee payment - `transactRequiredWeightAtMost` - the weight to buy in the destination chain for the execution of the call defined in the `Transact` instruction. The `transactRequiredWeightAtMost` structure contains the following: - `refTime` - the amount of computational time that can be used for execution - `proofSize` - the amount of storage in bytes that can be used It should be formatted as follows: ```js [ INSERT_REF_TIME, INSERT_PROOF_SIZE ] ``` - `call` - the call to be executed in the destination chain, as defined in the `Transact` instruction - `feeAmount` - the amount to be used as a fee - `overallWeight` - the total weight the extrinsic can use to execute all the XCM instructions, plus the weight of the `Transact` call (`transactRequiredWeightAtMost`). The `overallWeight` structure also contains `refTime` and `proofSize`. If you pass in the maximum value for a uint64 for the `refTime`, you'll allow for an unlimited amount of weight to be purchased, which removes the need to know exactly how much weight the destination chain requires to execute the XCM - `refund` - a boolean indicating whether or not to add the `RefundSurplus` and `DepositAsset` instructions to the XCM message to refund any leftover fees ## XCM Instructions for Remote Execution {: #xcm-instructions-for-remote-execution } The relevant [XCM instructions](/builders/interoperability/xcm/core-concepts/instructions/){target=\_blank} to perform remote execution through XCM are, but are not limited to: - [`DescendOrigin`](/builders/interoperability/xcm/core-concepts/instructions/#descend-origin){target=\_blank} - gets executed in the target chain. It mutates the origin on the target chain to match the origin on the source chain, ensuring execution on the target chain occurs on behalf of the same entity initiating the XCM message on the source chain - [`WithdrawAsset`](/builders/interoperability/xcm/core-concepts/instructions/#withdraw-asset){target=\_blank} - gets executed in the target chain. Removes assets and places them into a holding register - [`BuyExecution`](/builders/interoperability/xcm/core-concepts/instructions/#buy-execution){target=\_blank} - gets executed in the target chain. Takes the assets from holding to pay for execution fees. The fees to pay are determined by the target chain - [`Transact`](/builders/interoperability/xcm/core-concepts/instructions/#transact){target=\_blank} - gets executed in the target chain. Dispatches encoded call data from a given origin, allowing for the execution of specific operations or functions ## Building the Precompile Multilocation {: #building-the-precompile-multilocation } In the XCM Transactor Precompile interface, the `Multilocation` structure is defined as follows: ```solidity struct Multilocation { uint8 parents; bytes[] interior; } ``` As with a standard [multilocation](/builders/interoperability/xcm/core-concepts/multilocations/){target=\_blank}, there are `parents` and `interior` elements. However, instead of defining the multilocation as an object, with Ethereum libraries, the struct is defined as an array, which contains a `uint8` for the `parents` as the first element and a bytes array for the `interior` as the second element. The normal values you would see for the `parents` element are: | Origin | Destination | Parents Value | |:-----------:|:-----------:|:-------------:| | Parachain A | Parachain A | 0 | | Parachain A | Relay Chain | 1 | | Parachain A | Parachain B | 1 | For the `interior` element, the number of fields you need to drill down to in the target chain to reach the exact location of the target, such as the specific asset or account, represents the size of the bytes array: | Array | Size | Interior Value | |:------------:|:----:|:--------------:| | [] | 0 | Here | | [XYZ] | 1 | X1 | | [XYZ, ABC] | 2 | X2 | | [XYZ, ... N] | N | XN | !!! note Interior value `Here` is often used for the relay chain (either as a destination or to target the relay chain asset). Each field required to reach the exact location of the target needs to be defined as a hex string. The first byte (2 hexadecimal characters) corresponds to the selector of the field. For example: | Byte Value | Selector | Data Type | |:----------:|:--------------:|-----------| | 0x00 | Parachain | bytes4 | | 0x01 | AccountId32 | bytes32 | | 0x02 | AccountIndex64 | u64 | | 0x03 | AccountKey20 | bytes20 | | 0x04 | PalletInstance | byte | | 0x05 | GeneralIndex | u128 | | 0x06 | GeneralKey | bytes[] | Next, depending on the selector and its data type, the following bytes correspond to the actual data being provided. Note that for `AccountId32`, `AccountIndex64`, and `AccountKey20`, the optional `network` field is appended at the end. For example: | Selector | Data Value | Represents | |:--------------:|:----------------------:|:----------------------------------:| | Parachain | "0x00+000007E7" | Parachain ID 2023 | | AccountId32 | "0x01+AccountId32+00" | AccountId32, Network(Option) Null | | AccountId32 | "0x01+AccountId32+03" | AccountId32, Network Polkadot | | AccountKey20 | "0x03+AccountKey20+00" | AccountKey20, Network(Option) Null | | PalletInstance | "0x04+03" | Pallet Instance 3 | !!! note The `interior` data usually needs to be wrapped around quotes, or you might get an `invalid tuple value` error. The following code snippet goes through some examples of `Multilocation` structures, as they would need to be fed into the XCM Transactor Precompile functions: ```js // Multilocation targeting the relay chain asset from a parachain [ 1, // parents = 1 [], // interior = here ] // Multilocation targeting Moonbase Alpha DEV token from another parachain [ 1, // parents = 1 [ // interior = X2 (the array has a length of 2) "0x00000003E8", // Parachain selector + Parachain ID 1000 (Moonbase Alpha) "0x0403", // Pallet Instance selector + Pallet Instance 3 (Balances Pallet) ], ] // Multilocation targeting aUSD asset on Acala [ 1, // parents = 1 [ // interior = X2 (the array has a length of 2) "0x00000007D0", // Parachain selector + Parachain ID 2000 (Acala) "0x060001", // General Key selector + Asset Key ], ] ``` ## Transact through a Computed Origin Account {: #xcmtransactor-transact-through-signed } This section covers building an XCM message for remote execution using the XCM Transactor Pallet, specifically with the `transactThroughSigned` function. This function uses a [Computed Origin](/builders/interoperability/xcm/remote-execution/computed-origins/){target=\_blank} account on the destination chain to dispatch the remote call. The example in this section uses a destination parachain that is not publicly available, so you won't be able to follow along exactly. You can modify the example as needed for your own use case. !!! note You need to ensure that the call you are going to execute remotely is allowed in the destination chain! ### Checking Prerequisites {: #xcmtransactor-signed-check-prerequisites } To be able to send the extrinsics in this section, you need to have: - An account in the origin chain with [funds](/builders/get-started/networks/moonbase/#get-tokens){target=\_blank} - Funds in the Computed Origin account on the target chain. To learn how to calculate the address of the Computed Origin account, please refer to the [How to Calculate the Computed Origin](/builders/interoperability/xcm/remote-execution/computed-origins/){target=\_blank} documentation For this example, the following accounts will be used: - Alice's account in the origin parachain (Moonbase Alpha): `0x44236223aB4291b93EEd10E4B511B37a398DEE55` - Her Computed Origin address in the target parachain (Parachain 888): `0x5c27c4bb7047083420eddff9cddac4a0a120b45c` ### Building the XCM {: #xcm-transact-through-signed } For this example, you'll interact with the `transactThroughSigned` function of the XCM Transactor Precompile V3. To use this function, you'll take these general steps: 1. Create a provider using a Moonbase Alpha RPC endpoint 2. Create a signer to send the transaction. This example uses a private key to create the signer and is for demo purposes only. **Never store your private key in a JavaScript file** 3. Create a contract instance of the XCM Transactor V3 Precompile using the address and ABI of the precompile ??? code "XCM Transactor V3 ABI" ```js [ { inputs: [ { internalType: 'uint8', name: 'transactor', type: 'uint8', }, { internalType: 'uint16', name: 'index', type: 'uint16', }, { internalType: 'bytes', name: 'innerCall', type: 'bytes', }, ], name: 'encodeUtilityAsDerivative', outputs: [ { internalType: 'bytes', name: 'result', type: 'bytes', }, ], stateMutability: 'pure', type: 'function', }, { inputs: [ { components: [ { internalType: 'uint8', name: 'parents', type: 'uint8', }, { internalType: 'bytes[]', name: 'interior', type: 'bytes[]', }, ], internalType: 'struct XcmTransactorV3.Multilocation', name: 'multilocation', type: 'tuple', }, ], name: 'feePerSecond', outputs: [ { internalType: 'uint256', name: 'feePerSecond', type: 'uint256', }, ], stateMutability: 'view', type: 'function', }, { inputs: [ { internalType: 'uint16', name: 'index', type: 'uint16', }, ], name: 'indexToAccount', outputs: [ { internalType: 'address', name: 'owner', type: 'address', }, ], stateMutability: 'view', type: 'function', }, { inputs: [ { components: [ { internalType: 'uint8', name: 'parents', type: 'uint8', }, { internalType: 'bytes[]', name: 'interior', type: 'bytes[]', }, ], internalType: 'struct XcmTransactorV3.Multilocation', name: 'multilocation', type: 'tuple', }, ], name: 'transactInfoWithSigned', outputs: [ { components: [ { internalType: 'uint64', name: 'refTime', type: 'uint64', }, { internalType: 'uint64', name: 'proofSize', type: 'uint64', }, ], internalType: 'struct XcmTransactorV3.Weight', name: 'transactExtraWeight', type: 'tuple', }, { components: [ { internalType: 'uint64', name: 'refTime', type: 'uint64', }, { internalType: 'uint64', name: 'proofSize', type: 'uint64', }, ], internalType: 'struct XcmTransactorV3.Weight', name: 'transactExtraWeightSigned', type: 'tuple', }, { components: [ { internalType: 'uint64', name: 'refTime', type: 'uint64', }, { internalType: 'uint64', name: 'proofSize', type: 'uint64', }, ], internalType: 'struct XcmTransactorV3.Weight', name: 'maxWeight', type: 'tuple', }, ], stateMutability: 'view', type: 'function', }, { inputs: [ { internalType: 'uint8', name: 'transactor', type: 'uint8', }, { internalType: 'uint16', name: 'index', type: 'uint16', }, { internalType: 'address', name: 'currencyId', type: 'address', }, { components: [ { internalType: 'uint64', name: 'refTime', type: 'uint64', }, { internalType: 'uint64', name: 'proofSize', type: 'uint64', }, ], internalType: 'struct XcmTransactorV3.Weight', name: 'transactRequiredWeightAtMost', type: 'tuple', }, { internalType: 'bytes', name: 'innerCall', type: 'bytes', }, { internalType: 'uint256', name: 'feeAmount', type: 'uint256', }, { components: [ { internalType: 'uint64', name: 'refTime', type: 'uint64', }, { internalType: 'uint64', name: 'proofSize', type: 'uint64', }, ], internalType: 'struct XcmTransactorV3.Weight', name: 'overallWeight', type: 'tuple', }, { internalType: 'bool', name: 'refund', type: 'bool', }, ], name: 'transactThroughDerivative', outputs: [], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ { internalType: 'uint8', name: 'transactor', type: 'uint8', }, { internalType: 'uint16', name: 'index', type: 'uint16', }, { components: [ { internalType: 'uint8', name: 'parents', type: 'uint8', }, { internalType: 'bytes[]', name: 'interior', type: 'bytes[]', }, ], internalType: 'struct XcmTransactorV3.Multilocation', name: 'feeAsset', type: 'tuple', }, { components: [ { internalType: 'uint64', name: 'refTime', type: 'uint64', }, { internalType: 'uint64', name: 'proofSize', type: 'uint64', }, ], internalType: 'struct XcmTransactorV3.Weight', name: 'transactRequiredWeightAtMost', type: 'tuple', }, { internalType: 'bytes', name: 'innerCall', type: 'bytes', }, { internalType: 'uint256', name: 'feeAmount', type: 'uint256', }, { components: [ { internalType: 'uint64', name: 'refTime', type: 'uint64', }, { internalType: 'uint64', name: 'proofSize', type: 'uint64', }, ], internalType: 'struct XcmTransactorV3.Weight', name: 'overallWeight', type: 'tuple', }, { internalType: 'bool', name: 'refund', type: 'bool', }, ], name: 'transactThroughDerivativeMultilocation', outputs: [], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ { components: [ { internalType: 'uint8', name: 'parents', type: 'uint8', }, { internalType: 'bytes[]', name: 'interior', type: 'bytes[]', }, ], internalType: 'struct XcmTransactorV3.Multilocation', name: 'dest', type: 'tuple', }, { internalType: 'address', name: 'feeLocationAddress', type: 'address', }, { components: [ { internalType: 'uint64', name: 'refTime', type: 'uint64', }, { internalType: 'uint64', name: 'proofSize', type: 'uint64', }, ], internalType: 'struct XcmTransactorV3.Weight', name: 'transactRequiredWeightAtMost', type: 'tuple', }, { internalType: 'bytes', name: 'call', type: 'bytes', }, { internalType: 'uint256', name: 'feeAmount', type: 'uint256', }, { components: [ { internalType: 'uint64', name: 'refTime', type: 'uint64', }, { internalType: 'uint64', name: 'proofSize', type: 'uint64', }, ], internalType: 'struct XcmTransactorV3.Weight', name: 'overallWeight', type: 'tuple', }, { internalType: 'bool', name: 'refund', type: 'bool', }, ], name: 'transactThroughSigned', outputs: [], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ { components: [ { internalType: 'uint8', name: 'parents', type: 'uint8', }, { internalType: 'bytes[]', name: 'interior', type: 'bytes[]', }, ], internalType: 'struct XcmTransactorV3.Multilocation', name: 'dest', type: 'tuple', }, { components: [ { internalType: 'uint8', name: 'parents', type: 'uint8', }, { internalType: 'bytes[]', name: 'interior', type: 'bytes[]', }, ], internalType: 'struct XcmTransactorV3.Multilocation', name: 'feeLocation', type: 'tuple', }, { components: [ { internalType: 'uint64', name: 'refTime', type: 'uint64', }, { internalType: 'uint64', name: 'proofSize', type: 'uint64', }, ], internalType: 'struct XcmTransactorV3.Weight', name: 'transactRequiredWeightAtMost', type: 'tuple', }, { internalType: 'bytes', name: 'call', type: 'bytes', }, { internalType: 'uint256', name: 'feeAmount', type: 'uint256', }, { components: [ { internalType: 'uint64', name: 'refTime', type: 'uint64', }, { internalType: 'uint64', name: 'proofSize', type: 'uint64', }, ], internalType: 'struct XcmTransactorV3.Weight', name: 'overallWeight', type: 'tuple', }, { internalType: 'bool', name: 'refund', type: 'bool', }, ], name: 'transactThroughSignedMultilocation', outputs: [], stateMutability: 'nonpayable', type: 'function', }, ]; ``` 4. Assemble the arguments for the `transactThroughSigned` function: - `dest` - the multilocation of the destination, which is parachain 888: ```js const dest = [ 1, // parents = 1 [ // interior = X1 (the array has a length of 1) '0x0000000378', // Parachain selector + Parachain ID 888 ], ]; ``` - `feeLocationAddress` - the address of the XC-20 to use for fees, which is parachain 888's native asset: ```js const feeLocationAddress = '0xFFFFFFFF1AB2B146C526D4154905FF12E6E57675'; ``` - `transactRequiredWeightAtMost` - the weight required to execute the call in the `Transact` instruction. You can get this information by using the [`paymentInfo` method of the Polkadot.js API](/builders/substrate/libraries/polkadot-js-api/#fees){target=\_blank} on the call ```js const transactRequiredWeightAtMost = [1000000000n, 5000n]; ``` - `call` - the encoded call data of the pallet, method, and input to be called. It can be constructed in [Polkadot.js Apps](https://polkadot.js.org/apps){target=\_blank} (which must be connected to the destination chain) or using the [Polkadot.js API](/builders/substrate/libraries/polkadot-js-api/){target=\_blank}. For this example, the inner call is a simple balance transfer of 1 token of the destination chain to Alice's account there: ```js const call = '0x030044236223ab4291b93eed10e4b511b37a398dee5513000064a7b3b6e00d'; ``` - `feeAmount` - the amount to use for fees ```js const feeAmount = 50000000000000000n; ``` - `overallWeight` - the weight specific to the inner call (`transactRequiredWeightAtMost`) plus the weight needed to cover the execution costs for the XCM instructions in the destination chain: `DescendOrigin`, `WithdrawAsset`, `BuyExecution`, and `Transact`. It's important to note that each chain defines its own weight requirements. To determine the weight required for each XCM instruction on a given chain, please refer to the chain's documentation or reach out to a member of their team. Alternatively, you can pass in the maximum value for a uint64 for the `refTime` (the first index of the array). This will be interpreted as using an unlimited amount of weight, which removes the need to know exactly how much weight the destination chain requires to execute the XCM ```js const overallWeight = [18446744073709551615n, 10000n]; ``` 5. Create the `transactThroughSigned` function, passing in the arguments 6. Sign and send the transaction === "Ethers.js" ```js import { ethers } from 'ethers'; // Import Ethers library const abi = INSERT_ABI; const privateKey = 'INSERT_PRIVATE_KEY'; // Create Ethers provider and signer const provider = new ethers.JsonRpcProvider( 'https://rpc.api.moonbase.moonbeam.network' ); const signer = new ethers.Wallet(privateKey, provider); // Create contract instance const xcmTransactorV3 = new ethers.Contract( '0x0000000000000000000000000000000000000817', abi, signer ); // Arguments for the transactThroughSigned function const dest = [ 1, // parents = 1 [ // interior = X1 (the array has a length of 1) '0x0000000378', // Parachain selector + Parachain ID 888 ], ]; const feeLocationAddress = '0xFFFFFFFF1AB2B146C526D4154905FF12E6E57675'; const transactRequiredWeightAtMost = [1000000000n, 5000n]; const call = '0x030044236223ab4291b93eed10e4b511b37a398dee5513000064a7b3b6e00d'; const feeAmount = 50000000000000000n; const overallWeight = [2000000000n, 10000n]; const refund = true; // Sends 1 token to Alice's account on parachain 888 async function transactThroughSigned() { // Creates, signs, and sends the transfer transaction const transaction = await xcmTransactorV3.transactThroughSigned( dest, feeLocationAddress, transactRequiredWeightAtMost, call, feeAmount, overallWeight, refund ); // Waits for the transaction to be included in a block await transaction.wait(); console.log(transaction); } transactThroughSigned(); ``` === "Web3.js" ```js import Web3 from 'web3'; // Import Web3 library const abi = INSERT_ABI; const privateKey = 'INSERT_PRIVATE_KEY'; // Create Web3 provider const web3 = new Web3('https://rpc.api.moonbase.moonbeam.network'); // Change to network of choice // Create contract instance const xcmTransactorV3 = new web3.eth.Contract( abi, '0x0000000000000000000000000000000000000817', { from: web3.eth.accounts.privateKeyToAccount(privateKey).address } // 'from' is necessary for gas estimation ); // Arguments for the transactThroughSigned function const dest = [ 1, // parents = 1 [ // interior = X1 (the array has a length of 1) '0x0000000378', // Parachain selector + Parachain ID 888 ], ]; const feeLocationAddress = '0xFFFFFFFF1AB2B146C526D4154905FF12E6E57675'; const transactRequiredWeightAtMost = [1000000000n, 5000n]; const call = '0x030044236223ab4291b93eed10e4b511b37a398dee5513000064a7b3b6e00d'; const feeAmount = 50000000000000000n; const overallWeight = [2000000000n, 10000n]; const refund = true; // Sends 1 token to Alice's account on parachain 888 async function transactThroughSigned() { // Create transaction const transferTx = xcmTransactorV3.methods.transactThroughSigned( dest, feeLocationAddress, transactRequiredWeightAtMost, call, feeAmount, overallWeight, refund ); // Sign transaction const signedTx = await web3.eth.accounts.signTransaction( { to: '0x000000000000000000000000000000000000080d', data: transferTx.encodeABI(), gas: await transferTx.estimateGas(), }, privateKey ); // Send signed transaction const sendTx = await web3.eth.sendSignedTransaction(signedTx.rawTransaction); console.log(sendTx); } transactThroughSigned(); ``` === "Web3.py" ```py from web3 import Web3 abi = "INSERT_ABI" # Paste or import the XCM Transactor V3 ABI private_key = "INSERT_PRIVATE_KEY" # This is for demo purposes, never store your private key in plain text address = "INSERT_ADDRESS" # The wallet address that corresponds to your private key # Create Web3 provider web3 = Web3(Web3.HTTPProvider("https://rpc.api.moonbase.moonbeam.network")) # Create contract instance xcm_transactor_v3 = web3.eth.contract( address="0x0000000000000000000000000000000000000817", abi=abi ) # Arguments for the transactThroughSigned function dest = [ 1, # parents = 1 [ # interior = X1 (the array has a length of 1) "0x0000000378", # Parachain selector + Parachain ID 888 ], ] feeLocationAddress = "0xFFFFFFFF1AB2B146C526D4154905FF12E6E57675" transactRequiredWeightAtMost = [1000000000, 5000] call = "0x030044236223ab4291b93eed10e4b511b37a398dee5513000064a7b3b6e00d" feeAmount = 50000000000000000 overallWeight = [2000000000, 10000] refund = True # Sends 1 xcUNIT to the relay chain using the transferMultiasset function def transact_through_signed(): # Create transaction transferTx = xcm_transactor_v3.functions.transactThroughSigned( dest, feeLocationAddress, transactRequiredWeightAtMost, call, feeAmount, overallWeight, refund, ).build_transaction( { "from": address, "nonce": web3.eth.get_transaction_count(address), } ) # Sign transaction signedTx = web3.eth.account.sign_transaction(transferTx, private_key) # Send tx and wait for receipt hash = web3.eth.send_raw_transaction(signedTx.rawTransaction) receipt = web3.eth.wait_for_transaction_receipt(hash) print(f"Tx successful with hash: { receipt.transactionHash.hex() }") transact_through_signed() ``` ### XCM Transact through Computed Origin Fees {: #transact-through-computed-origin-fees } When [transacting through the Computed Origin account](#xcmtransactor-transact-through-signed){target=\_blank}, the transaction fees are paid by the same account from which the call is dispatched, which is a Computed Origin account in the destination chain. Consequently, the Computed Origin account must hold the necessary funds to pay for the entire execution. Note that the destination token, for which fees are paid, does not need to be registered as an XC-20 in the origin chain. To estimate the amount of token Alice's Computed Origin account will need to have to execute the remote call, you need to check the transact information specific to the destination chain. You can use the following script to get the transact information for parachain 888: ```js import { ethers } from 'ethers'; // Import Ethers library const abi = INSERT_ABI; const privateKey = 'INSERT_PRIVATE_KEY'; // Create Ethers wallet & contract instance const provider = new ethers.JsonRpcProvider( 'https://rpc.api.moonbase.moonbeam.network' ); const signer = new ethers.Wallet(privateKey, provider); const xcmTransactorV3 = new ethers.Contract( '0x0000000000000000000000000000000000000817', abi, signer ); // Multilocation for parachain 888 const multilocation = [ 1, // parents = 1 [ // interior = X1 (the array has a length of 1) '0x0000000378', // Parachain selector + Parachain ID 888 ], ]; const main = async () => { const transactInfoWithSigned = await xcmTransactorV3.transactInfoWithSigned( multilocation ); console.log(transactInfoWithSigned); }; main(); ``` The response shows that the `transactExtraWeightSigned` is `{{ networks.moonbase_beta.xcm_message.transact.weight.display }}`. This weight is needed to execute the four XCM instructions for this remote call in that specific destination chain. Next, you need to find out how much the destination chain charges per weight of XCM execution in reference to the asset's price. Previously, this was done by sourcing a units per second value. However, this method has been replaced by calculating a relative price. Relative price refers to how many units of the foreign asset correspond to one unit of the native token (GLMR or MOVR) from a value (i.e., price) perspective. For example, if the foreign asset is worth $5 and GLMR is worth $0.25, the relative price would be 0.05. However, we must scale the result to 18 decimals to correspond to the Wei units used. In this case, the relative price would be `50000000000000000`. You can calculate the relative price with a script in the [XCM Tools repo](https://github.com/Moonsong-Labs/xcm-tools?tab=readme-ov-file#calculate-relative-price){target=\_blank}. The script is also reproduced below: ??? code "Calculate Relative Price" ```typescript import axios from 'axios'; import chalk from 'chalk'; // CoinGecko IDs for the networks const NETWORK_IDS = { GLMR: 'moonbeam', MOVR: 'moonriver', }; async function calculateRelativePrice( assetPrice: number, network: 'GLMR' | 'MOVR' ): Promise { try { // Fetch the native token price from CoinGecko const response = await axios.get( `https://api.coingecko.com/api/v3/simple/price?ids=${NETWORK_IDS[network]}&vs_currencies=usd` ); const nativeTokenPrice = response.data[NETWORK_IDS[network]].usd; // Calculate relative price with 18 decimal places // Formula: (nativeTokenPrice / assetPrice) * 10^18 // This gives us how many units of the asset we need to equal 1 unit of native token const relativePrice = (nativeTokenPrice / assetPrice) * Math.pow(10, 18); // Return as string to preserve precision return relativePrice.toFixed(0); } catch (error) { if (error instanceof Error) { throw new Error(`Failed to calculate relative price: ${error.message}`); } throw error; } } function validateInput( price: string, network: string ): { assetPrice: number; network: 'GLMR' | 'MOVR' } { // Validate price const assetPrice = parseFloat(price); if (isNaN(assetPrice) || assetPrice <= 0) { throw new Error('Price must be a positive number'); } // Validate network const upperNetwork = network.toUpperCase() as 'GLMR' | 'MOVR'; if (!['GLMR', 'MOVR'].includes(upperNetwork)) { throw new Error('Network must be either GLMR or MOVR'); } return { assetPrice, network: upperNetwork }; } function printUsage() { console.log('\nUsage:'); console.log('npx ts-node relative-price-calculator.ts '); console.log('\nExample:'); console.log('npx ts-node relative-price-calculator.ts 0.25 GLMR'); console.log('\nParameters:'); console.log('price - The price of your asset in USD'); console.log('network - Either GLMR or MOVR'); } async function main() { try { // Get command line arguments const [, , price, network] = process.argv; // Check if help flag is passed if (price === '--help' || price === '-h') { printUsage(); return; } // Check if required arguments are provided if (!price || !network) { console.error('Error: Missing required arguments'); printUsage(); process.exit(1); } // Validate inputs const { assetPrice, network: validNetwork } = validateInput(price, network); console.log( `\nCalculating relative price for asset worth $${assetPrice} against ${validNetwork}...` ); const relativePrice = await calculateRelativePrice( assetPrice, validNetwork ); const nativeTokenPrice = ( await axios.get( `https://api.coingecko.com/api/v3/simple/price?ids=${NETWORK_IDS[validNetwork]}&vs_currencies=usd` ) ).data[NETWORK_IDS[validNetwork]].usd; const decimalRatio = nativeTokenPrice / assetPrice; console.log(`\nResults:`); console.log(`Asset Price: $${assetPrice}`); console.log(`Network: ${validNetwork}`); console.log(`Native Token Price (from CoinGecko): $${nativeTokenPrice}`); console.log(`\nRelative Price Analysis:`); console.log( `1 ${validNetwork} is equal to approximately ${decimalRatio.toFixed( 3 )} of your specified token.` ); console.log( `With 18 decimals, 1 ${validNetwork} or in WEI, 1000000000000000000 is equal to a relative price of ${relativePrice} units of your token` ); console.log(chalk.bold(`\nRelative Price: ${relativePrice}`)); console.log( `\nThe relative price you should specify in asset registration steps is ${relativePrice}\n` ); } catch (error) { console.error('\nError:', error instanceof Error ? error.message : error); process.exit(1); } } main(); ``` Note that the relative price value is related to the cost estimated in the [relay chain XCM fee calculation](/builders/interoperability/xcm/core-concepts/weights-fees/#polkadot){target=\_blank} section or to the one shown in the [units per weight](/builders/interoperability/xcm/core-concepts/weights-fees/#moonbeam-reserve-assets){target=\_blank} section if the target is another parachain. You'll need to find the correct value to ensure that the amount of tokens the Computed Origin account holds is correct. Calculating the associated XCM execution fee is as simple as multiplying the `transactExtraWeightSigned` times the `relativePrice` (for an estimation): ```text XCM-Wei-Token-Cost = transactExtraWeightSigned * relativePrice XCM-Token-Cost = XCM-Wei-Token-Cost / DecimalConversion ``` Therefore, the actual calculation for one XCM Transactor transact through derivative call is: ```text XCM-Wei-Token-Cost = {{ networks.moonbase_beta.xcm_message.transact.weight.numbers_only }} * {{ networks.moonbase.xcm.units_per_second.xcbetadev.transact_numbers_only }} XCM-Token-Cost = {{ networks.moonbase_beta.xcm_message.transact.wei_betadev_cost }} / 10^18 ``` The cost of transacting through a Computed Origin is `{{ networks.moonbase_beta.xcm_message.transact.betadev_cost }} TOKEN`. **Note that this does not include the cost of the call being remotely executed, only XCM execution fees.** --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/send-execute-xcm/ --- BEGIN CONTENT --- --- title: Send, Execute and Test XCM Messages description: Build a custom XCM message, verify its construction and integrity using the XCM Dry Run API, and then execute it locally on Moonbeam to observe the results. categories: XCM --- # Send, Execute, and Test XCM Messages ## Introduction {: #introduction } XCM messages are comprised of a [series of instructions](/builders/interoperability/xcm/core-concepts/instructions/){target=\_blank} that are executed by the Cross-Consensus Virtual Machine (XCVM). Combinations of these instructions result in predetermined actions, such as cross-chain token transfers. You can create your own custom XCM messages by combining various XCM instructions. Pallets such as [Polkadot XCM](/builders/interoperability/xcm/xc20/send-xc20s/xcm-pallet/){target=\_blank} and [XCM Transactor](/builders/interoperability/xcm/remote-execution/substrate-calls/xcm-transactor-pallet/){target=\_blank} provide functions with a predefined set of XCM instructions to either send [XC-20s](/builders/interoperability/xcm/xc20/overview/){target=\_blank} or remotely execute on other chains via XCM. However, to get a better understanding of the results from combining different XCM instructions, you can build and execute custom XCM messages locally on Moonbeam (only available on Moonbase Alpha). You can also send custom XCM messages to another chain (which will start with the [`DescendOrigin`](https://github.com/paritytech/xcm-format#descendorigin){target=\_blank} instruction). Nevertheless, for the XCM message to be successfully executed, the target chain needs to be able to understand the instructions. To execute or send a custom XCM message, you can either use the [Polkadot XCM Pallet](#polkadot-xcm-pallet-interface) directly or through the Ethereum API with the [XCM Utilities Precompile](/builders/interoperability/xcm/xcm-utils/){target=\_blank}. In this guide, you'll learn how to use both methods to execute and send custom-built XCM messages locally on Moonbase Alpha. This guide assumes that you are familiar with general XCM concepts, such as [general XCM terminology](/builders/interoperability/xcm/overview/#general-xcm-definitions){target=\_blank} and [XCM instructions](/builders/interoperability/xcm/core-concepts/instructions/){target=\_blank}. For more information, you can check out the [XCM Overview](/builders/interoperability/xcm/overview/){target=\_blank} documentation. ## Polkadot XCM Pallet Interface {: #polkadot-xcm-pallet-interface } ### Extrinsics {: #extrinsics } The Polkadot XCM Pallet includes the following relevant extrinsics (functions): ???+ function "**execute**(message, maxWeight) — **supported on Moonbase Alpha only** - executes a custom XCM message on the source chain" === "Parameters" - `message` - the SCALE-encoded versioned XCM message to be executed - `maxWeight` - the maximum weight allowed to be consumed, which is defined by specifying the: - `refTime` - the amount of computational time that can be used for execution - `proofSize` - the amount of storage in bytes that can be used === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const message = { V4: [INSERT_XCM_INSTRUCTIONS] }; const maxWeight = { refTime: INSERT_REF_TIME, proofSize: INSERT_PROOF_SIZE }; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.polkadotXcm.execute(message, maxWeight); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); }; main(); ``` ???+ function "**send**(dest, message) — **supported on Moonbase Alpha only** - sends a custom XCM message to a destination chain. For the XCM message to be successfully executed, the target chain needs to be able to understand the instructions in the message" === "Parameters" - `dest` - the XCM versioned multilocation representing a chain in the ecosystem where the XCM message is being sent to (the target chain) - `message` - the SCALE-encoded versioned XCM message to be executed === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const dest = { V4: { parents: INSERT_PARENTS, interior: INSERT_INTERIOR } }; const message = { V4: [INSERT_XCM_INSTRUCTIONS] }; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.polkadotXcm.send(dest, message); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); }; main(); ``` ### Storage Methods {: #storage-methods } The Polkadot XCM Pallet includes the following relevant read-only storage methods: ???+ function "**assetTraps**(hash) — returns the existing number of times an asset has been trapped given a hash of the asset" === "Parameters" `hash` - (optional) the Blake2-256 hash of the [`Asset`](https://github.com/paritytech/xcm-format#6-universal-asset-identifiers){target=\_blank} === "Returns" The number of times an asset has been trapped. If the hash was omitted, it returns an array of all of the hashes and the number of times each asset has been trapped. ```js // If using Polkadot.js API and calling toJSON() on the value // If hash was provided: 10 // If hash was omitted: [ [ 0xf7d4341888be30c6a842a77c52617423e8109aa249e88779019cf731ed772fb7 ], 10 ], ... ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const trappedAssets = await api.query.polkadotXcm.assetTraps.entries(); trappedAssets.forEach( ([ { args: [hash], }, count ]) => { console.log( `Asset with hash ${hash.toJSON()} has been trapped ${count.toJSON()} times` ); } ); }; main(); ``` ??? function "**palletVersion**() — returns current pallet version from storage" === "Parameters" None === "Returns" A number representing the current version of the pallet. ```js // If using Polkadot.js API and calling toJSON() on the unwrapped value 0 ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const palletVersion = await api.query.polkadotXcm.palletVersion(); }; main(); ``` ## Checking Prerequisites {: #checking-prerequisites } To follow along with this guide, you will need the following: - Your account must be funded with DEV tokens. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} ## Execute an XCM Message Locally {: #execute-an-xcm-message-locally } This section of the guide covers the process of building a custom XCM message to be executed locally (i.e., in Moonbeam) via two different methods: the `execute` function of the Polkadot XCM Pallet and the `xcmExecute` function of the [XCM Utilities Precompile](/builders/interoperability/xcm/xcm-utils/){target=\_blank}. This functionality provides a playground for you to experiment with different XCM instructions and see firsthand the results of these experiments. This also comes in handy to determine the [fees](/builders/interoperability/xcm/core-concepts/weights-fees/){target=\_blank} associated with a given XCM message on Moonbeam. In the following example, you'll transfer DEV tokens from one account to another on Moonbase Alpha. To do so, you'll be building an XCM message that contains the following XCM instructions, which are executed locally (in this case, on Moonbase Alpha): - [`WithdrawAsset`](/builders/interoperability/xcm/core-concepts/instructions/#withdraw-asset){target=\_blank} - removes assets and places them into the holding register - [`DepositAsset`](/builders/interoperability/xcm/core-concepts/instructions/#deposit-asset){target=\_blank} - removes the assets from the holding register and deposits the equivalent assets to a beneficiary account !!! note Typically, when you send an XCM message cross-chain to a target chain, the [`BuyExecution` instruction](/builders/interoperability/xcm/core-concepts/instructions/#buy-execution){target=\_blank} is needed to pay for remote execution. However, for local execution, this instruction is not necessary as you are already getting charged via the extrinsic call. ### Execute an XCM Message with the Polkadot.js API {: #execute-an-xcm-message-with-polkadotjs-api } In this example, you'll execute a custom XCM message locally on Moonbase Alpha using the Polkadot.js API to interact directly with the Polkadot XCM Pallet. The `execute` function of the Polkadot XCM Pallet accepts two parameters: `message` and `maxWeight`. You can start assembling these parameters by taking the following steps: 1. Build the `WithdrawAsset` instruction, which will require you to define: - The multilocation of the DEV token on Moonbase Alpha - The amount of DEV tokens to transfer ```js const instr1 = { WithdrawAsset: [ { id: { parents: 0, interior: { X1: [{ PalletInstance: 3 }] } }, fun: { Fungible: 100000000000000000n }, // 0.1 DEV }, ], }; ``` 2. Build the `DepositAsset` instruction, which will require you to define: - The asset identifier for DEV tokens. You can use the [`WildAsset` format](https://github.com/paritytech/xcm-format/blob/master/README.md#6-universal-asset-identifiers){target=\_blank}, which allows for wildcard matching, to identify the asset - The multilocation of the beneficiary account on Moonbase Alpha ```js const instr2 = { DepositAsset: { assets: { Wild: { AllCounted: 1, }, }, beneficiary: { parents: 0, interior: { X1: [ { AccountKey20: { key: '0x3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0', }, }, ], }, }, }, }; ``` 3. Combine the XCM instructions into a versioned XCM message: ```js const message = { V4: [instr1, instr2] }; ``` 4. Specify the `maxWeight`, which includes a value for `refTime` and `proofSize` that you will need to define. You can get both of these values by providing the XCM message as a parameter to the `queryXcmWeight` method of the [`xcmPaymentApi` runtime call](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fmoonbeam-alpha.api.onfinality.io%2Fpublic-ws#/runtime){target=\_blank}. ```js const maxWeight = { refTime: 7250000000n, proofSize: 19374n }; ``` Now that you have the values for each of the parameters, you can write the script for the execution. You'll take the following steps: 1. Provide the input data for the call. This includes: - The Moonbase Alpha endpoint URL to create the provider - The values for each of the parameters of the `execute` function 2. Create a Keyring instance that will be used to send the transaction 3. Create the [Polkadot.js API](/builders/substrate/libraries/polkadot-js-api/){target=\_blank} provider 4. Craft the `polkadotXcm.execute` extrinsic with the `message` and `maxWeight` 5. Send the transaction using the `signAndSend` extrinsic and the Keyring instance you created in the second step !!! remember This is for demo purposes only. Never store your private key in a JavaScript file. ```js import { ApiPromise, WsProvider, Keyring } from '@polkadot/api'; // Version 10.13.1 import { cryptoWaitReady } from '@polkadot/util-crypto'; // 1. Provide input data const providerWsURL = 'wss://wss.api.moonbase.moonbeam.network'; const privateKey = 'INSERT_PRIVATE_KEY'; const instr1 = { WithdrawAsset: [ { id: { parents: 0, interior: { X1: [{ PalletInstance: 3 }] } }, fun: { Fungible: 100000000000000000n }, // 0.1 DEV }, ], }; const instr2 = { DepositAsset: { assets: { Wild: { AllCounted: 1, }, }, beneficiary: { parents: 0, interior: { X1: [ { AccountKey20: { key: '0x3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0', }, }, ], }, }, }, }; const message = { V4: [instr1, instr2] }; const maxWeight = { refTime: 7250000000n, proofSize: 19374n }; const executeXcmMessage = async () => { // 2. Create Keyring instance await cryptoWaitReady(); const keyring = new Keyring({ type: 'ethereum' }); const alice = keyring.addFromUri(privateKey); // 3. Create Substrate API provider const substrateProvider = new WsProvider(providerWsURL); const api = await ApiPromise.create({ provider: substrateProvider }); // 4. Craft the extrinsic const tx = api.tx.polkadotXcm.execute(message, maxWeight); // 5. Send the transaction const txHash = await tx.signAndSend(alice); console.log(`Submitted with hash ${txHash}`); api.disconnect(); }; executeXcmMessage(); ``` !!! note You can view an example of the above script, which sends 1 DEV to Bob's account on Moonbase Alpha, on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/extrinsics/decode/0x1c030408000400010403001300008a5d784563010d010204000103003cd0a705a2dc65e5b1e1205896baa2be8a07c6e007803822b001ba2e0100){target=\_blank} using the following encoded calldata: `0x1c030408000400010403001300008a5d784563010d010204000103003cd0a705a2dc65e5b1e1205896baa2be8a07c6e007803822b001ba2e0100`. Once the transaction is processed, the 0.1 DEV tokens should be withdrawn from Alice's account along with the associated XCM fees, and the destination account should have received 0.1 DEV tokens in their account. A `polkadotXcm.Attempted` event will be emitted with the outcome. ## Test an XCM Message with the Dry Run API {: #test-an-xcm-message-with-the-dry-run-api } The XCM Dry Run API is an easy and convenient way to test the integrity of your XCM message without incurring any transaction fees. The XCM Dry Run API can be accessed from the [Runtime Calls](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbeam.network#/runtime){target=\_blank} tab of the **Developer** section of Polkadot.js Apps. ### Dry Run Call API Method {: #dry-run-call-api-method } This method takes as a parameter the origin and the call data and returns an execution result, actual weight, and event data. ```javascript const testAccount = api.createType( 'AccountId20', '0x88bcE0b038eFFa09e58fE6d24fDe4b5Af21aa798' ); const callData = '0x1c030408000400010403001300008a5d784563010d010204000103003cd0a705a2dc65e5b1e1205896baa2be8a07c6e007803822b001ba2e0100'; const callDataU8a = hexToU8a(callData); const result = await api.call.dryRunApi.dryRunCall( { system: { Signed: testAccount } }, callDataU8a ); ``` ??? code "View the complete script" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { hexToU8a } from '@polkadot/util'; const main = async () => { try { // Construct API provider const wsProvider = new WsProvider('INSERT_WSS_ENDPOINT'); const api = await ApiPromise.create({ provider: wsProvider }); console.log('Connected to the API. Preparing dry run call...'); // Create a test account (you should replace this with an actual account) const testAccount = api.createType( 'AccountId20', '0x88bcE0b038eFFa09e58fE6d24fDe4b5Af21aa798' ); // The call data (replace with your actual call data) const callData = '0x1c030408000400010403001300008a5d784563010d010204000103003cd0a705a2dc65e5b1e1205896baa2be8a07c6e007803822b001ba2e0100'; // Your hex-encoded call data // Convert hex to Uint8Array const callDataU8a = hexToU8a(callData); // Perform the dry run call const result = await api.call.dryRunApi.dryRunCall( { system: { Signed: testAccount } }, // origin callDataU8a // call ); console.log( 'Dry run XCM result:', JSON.stringify(result.toJSON(), null, 2) ); // Disconnect the API await api.disconnect(); console.log('Disconnected from the API.'); } catch (error) { console.error('An error occurred:', error); } }; main().catch(console.error); ``` Upon calling the XCM Dry Run API, the method will tell you whether the call would be successful and returns the event data that would be emitted if the call were actually submitted on chain. You can view the initial output of the `dryRunCall` below. ??? code "View the complete output" ```json Dry run XCM result: { "ok": { "executionResult": { "ok": { "actualWeight": { "refTime": 7301615000, "proofSize": 20928 }, "paysFee": "Yes" } }, "emittedEvents": [ { "index": "0x030b", "data": [ "0x88bcE0b038eFFa09e58fE6d24fDe4b5Af21aa798", "0x0000000000000000016345785d8a0000" ] }, { "index": "0x0300", "data": [ "0x3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0", "0x0000000000000000016345785d8a0000" ] }, { "index": "0x030a", "data": [ "0x3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0", "0x0000000000000000016345785d8a0000" ] }, { "index": "0x1c00", "data": [ { "complete": { "used": { "refTime": 7250000000, "proofSize": 19374 } } } ] } ], "localXcm": { "v4": [ { "withdrawAsset": [ { "id": { "parents": 0, "interior": { "x1": [ { "palletInstance": 3 } ] } }, "fun": { "fungible": "0x0000000000000000016345785d8a0000" } } ] }, { "depositAsset": { "assets": { "wild": { "allCounted": 1 } }, "beneficiary": { "parents": 0, "interior": { "x1": [ { "accountKey20": { "network": null, "key": "0x3cd0a705a2dc65e5b1e1205896baa2be8a07c6e0" } } ] } } } } ] } // Additional events returned here // Omitted for clarity ``` ### Dry Run XCM API Method {: #dry-run-xcm-api-method } The `dryRunXCM` method of the XCM Dry Run API takes a full XCM message as a parameter instead of an encoded call, as well as the origin of the message. `dryRunXCM` takes as a parameter the origin and the XCM message and returns an execution result, actual weight, and event data. ```javascript // Define the origin const origin = { V4: { parents: 1, interior: 'Here' } }; const message = []; // Insert XCM Message Here // Perform the dry run XCM call const result = await api.call.dryRunApi.dryRunXcm(origin, message); ``` ??? code "View the complete script" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { hexToU8a } from '@polkadot/util'; const main = async () => { try { // Construct API provider const wsProvider = new WsProvider('INSERT_WSS_ENDPOINT'); const api = await ApiPromise.create({ provider: wsProvider }); console.log('Connected to the API. Preparing dry run XCM call...'); // Define the origin const origin = { V4: { parents: 1, interior: 'Here' } }; const amountToSend = 1000000000000; const message = { V4: [ { WithdrawAsset: [ { id: { parents: 1, interior: 'Here' }, fun: { Fungible: amountToSend }, }, ], }, { BuyExecution: { fees: { id: { parents: 1, interior: 'Here' }, fun: { Fungible: amountToSend }, }, weightLimit: { Unlimited: null }, }, }, { DepositAsset: { assets: { Wild: { AllOf: { id: { parents: 1, interior: 'Here' } } } }, maxAssets: 1, beneficiary: { parents: 0, interior: { X1: [ { AccountKey20: { network: null, key: hexToU8a('0x3B939FeaD1557C741Ff06492FD0127bd287A421e') } } ] } } } } ], }; // Perform the dry run XCM call const result = await api.call.dryRunApi.dryRunXcm(origin, message); console.log( 'Dry run XCM result:', JSON.stringify(result.toJSON(), null, 2) ); await api.disconnect(); console.log('Disconnected from the API.'); } catch (error) { console.error('An error occurred:', error); } }; main().catch(console.error); ``` Upon calling the XCM Dry Run API, the method will tell you whether the call would be successful and returns the event data that would be emitted if the XCM were to be actually submitted on chain. You can view the initial output of the `dryRunXCM` below. ??? code "View the complete output" ```json Dry run XCM result: { "ok": { "executionResult": { "complete": { "used": { "refTime": 76473048000, "proofSize": 222483 } } }, "emittedEvents": [ { "index": "0x1d03", "data": [ "0x1fcacbd218edc0eba20fc2308c778080", "0x506172656E740000000000000000000000000000", 1000000000000 ] }, { "index": "0x1d01", "data": [ "0x1fcacbd218edc0eba20fc2308c778080", "0x3B939FeaD1557C741Ff06492FD0127bd287A421e", 959944978002 ] }, { "index": "0x1d01", "data": [ "0x1fcacbd218edc0eba20fc2308c778080", "0x6d6F646c70632f74727372790000000000000000", 40055021998 ] } ], // Additional events returned here // Omitted for clarity ``` ## Execute an XCM Message with the XCM Utilities Precompile {: #execute-xcm-utils-precompile } In this section, you'll use the `xcmExecute` function of the [XCM Utilities Precompile](/builders/interoperability/xcm/xcm-utils/){target=\_blank}, which is only supported on Moonbase Alpha, to execute an XCM message locally. The XCM Utilities Precompile is located at the following address: ```text {{ networks.moonbase.precompiles.xcm_utils }} ``` Under the hood, the `xcmExecute` function of the XCM Utilities Precompile calls the `execute` function of the Polkadot XCM Pallet, which is a Substrate pallet that is coded in Rust. The benefit of using the XCM Utilities Precompile to call `xcmExecute` is that you can do so via the Ethereum API and use [Ethereum libraries](/builders/ethereum/libraries/){target=\_blank} like [Ethers.js](/builders/ethereum/libraries/ethersjs/){target=\_blank}. The `xcmExecute` function accepts two parameters: the SCALE encoded versioned XCM message to be executed and the maximum weight to be consumed. First, you'll learn how to generate the encoded calldata, and then you'll learn how to use the encoded calldata to interact with the XCM Utilities Precompile. ### Generate the Encoded Calldata of an XCM Message {: #generate-encoded-calldata } To get the encoded calldata of the XCM message, you can create a script similar to the one you created in the [Execute an XCM Message with the Polkadot.js API](#execute-an-xcm-message-with-polkadotjs-api) section. Instead of building the message and sending the transaction, you'll build the message to get the encoded calldata. You'll take the following steps: 1. Provide the input data for the call. This includes: - The Moonbase Alpha endpoint URL to create the provider - The values for each of the parameters of the `execute` function as defined in the [Execute an XCM Message with the Polkadot.js API](#execute-an-xcm-message-with-polkadotjs-api) section 2. Create the [Polkadot.js API](/builders/substrate/libraries/polkadot-js-api/){target=\_blank} provider 3. Craft the `polkadotXcm.execute` extrinsic with the `message` and `maxWeight` 4. Use the transaction to get the encoded calldata The entire script is as follows: ```js import { ApiPromise, WsProvider } from '@polkadot/api'; // Version 10.13.1 // 1. Provide input data const moonbeamAccount = 'INSERT_ADDRESS'; const providerWsURL = 'wss://wss.api.moonbase.moonbeam.network'; const instr1 = { WithdrawAsset: [ { id: { parents: 0, interior: { X1: [{ PalletInstance: 3 }] } }, fun: { Fungible: 100000000000000000n }, }, ], }; const instr2 = { DepositAsset: { assets: { Wild: { AllCounted: 1 } }, beneficiary: { parents: 0, interior: { X1: [ { AccountKey20: { key: moonbeamAccount, }, }, ], }, }, }, }; const message = { V4: [instr1, instr2] }; const maxWeight = { refTime: 7250000000n, proofSize: 19374n }; const getEncodedXcmMessage = async () => { // 2. Create Substrate API provider const substrateProvider = new WsProvider(providerWsURL); const api = await ApiPromise.create({ provider: substrateProvider }); // 3. Craft the extrinsic const tx = api.tx.polkadotXcm.execute(message, maxWeight); // 4. Get the encoded XCM message // By using index 0, you'll get just the encoded XCM message. // If you wanted to get the maxWeight, you could use index 1 const encodedXcmMessage = tx.args[0].toHex(); console.log(`Encoded Calldata for XCM Message: ${encodedXcmMessage}`); api.disconnect(); }; getEncodedXcmMessage(); ``` ### Execute the XCM Message {: #execute-xcm-message } Now that you have the SCALE encoded XCM message, you can use the following code snippets to programmatically call the `xcmExecute` function of the XCM Utilities Precompile using your [Ethereum library](/builders/ethereum/libraries/){target=\_blank} of choice. Generally speaking, you'll take the following steps: 1. Create a provider and signer 2. Create an instance of the XCM Utilities Precompile to interact with 3. Define parameters required for the `xcmExecute` function, which will be the encoded calldata for the XCM message and the maximum weight to use to execute the message. You can set the `maxWeight` to be `400000000n`, which corresponds to the `refTime`. The `proofSize` will automatically be set to the default, which is 64KB 4. Execute the XCM message !!! remember The following snippets are for demo purposes only. Never store your private keys in a JavaScript or Python file. === "Ethers.js" ```js import { ethers } from 'ethers'; // Import Ethers library import abi from './xcmUtilsABI.js'; // Import the XCM Utilities Precompile ABI const privateKey = 'INSERT_YOUR_PRIVATE_KEY'; const xcmUtilsAddress = '0x000000000000000000000000000000000000080C'; /* Create Ethers provider and signer */ const provider = new ethers.JsonRpcProvider( 'https://rpc.api.moonbase.moonbeam.network' ); const signer = new ethers.Wallet(privateKey, provider); /* Create contract instance of the XCM Utilities Precompile */ const xcmUtils = new ethers.Contract( xcmUtilsAddress, abi, signer ); const executeXcmMessageLocally = async () => { /* Define parameters required for the xcmExecute function */ const encodedCalldata = 'INSERT_ENCODED_CALLDATA'; const maxWeight = '400000000'; /* Execute the custom XCM message */ const tx = await xcmUtils.xcmExecute(encodedCalldata, maxWeight); await tx.wait(); console.log(`Transaction receipt: ${tx.hash}`); }; executeXcmMessageLocally(); ``` === "Web3.js" ```js import { Web3 } from 'web3'; // Import Web3 library import abi from './xcmUtilsABI.js'; // Import the XCM Utilities Precompile ABI const privateKey = 'INSERT_PRIVATE_KEY'; const accountFrom = web3.eth.accounts.privateKeyToAccount(privateKey).address; const xcmUtilsAddress = '0x000000000000000000000000000000000000080C'; /* Create Web3 provider */ const web3 = new Web3('https://rpc.api.moonbase.moonbeam.network'); // Change to network of choice /* Create contract instance of the XCM Utilities Precompile */ const xcmUtils = new web3.eth.Contract( abi, xcmUtilsAddress, { from: accountFrom } // 'from' is necessary for gas estimation ); const executeXcmMessageLocally = async () => { /* Define parameters required for the xcmExecute function */ const encodedCalldata = 'INSERT_ENCODED_CALLDATA'; const maxWeight = '400000000'; /* Send the custom XCM message */ // Craft the extrinsic const tx = await xcmUtils.methods.xcmExecute(encodedCalldata, maxWeight); // Sign transaction const signedTx = await web3.eth.accounts.signTransaction( { to: xcmUtilsAddress, data: tx.encodeABI(), gas: await tx.estimateGas(), gasPrice: await web3.eth.getGasPrice(), nonce: await web3.eth.getTransactionCount(accountFrom), }, privateKey ); // Send the signed transaction const sendTx = await web3.eth.sendSignedTransaction(signedTx.rawTransaction); console.log(`Transaction receipt: ${sendTx.transactionHash}`); }; executeXcmMessageLocally(); ``` === "Web3.py" ```py from web3 import Web3 abi = "INSERT_XCM_UTILS_ABI" # Paste or import the XCM Utils ABI # This is for demo purposes, never store your private key in plain text private_key = "INSERT_PRIVATE_KEY" # The wallet address that corresponds to your private key address = "INSERT_ADDRESS" xcm_utils_address = "0x000000000000000000000000000000000000080C" ## Create Web3 provider ## web3 = Web3(Web3.HTTPProvider("https://rpc.api.moonbase.moonbeam.network")) ## Create contract instance of the XCM Utilities Precompile ## xcm_utils = web3.eth.contract( # XCM Utilities Precompile address address=xcm_utils_address, abi=abi, ) def execute_xcm_message_locally(): ## Define parameters required for the xcmExecute function ## encoded_calldata = "INSERT_ENCODED_CALLDATA" max_weight = 400000000 ## Execute the custom XCM message ## # Craft the extrinsic tx = xcm_utils.functions.xcmExecute(encoded_calldata, max_weight).build_transaction( { "from": address, "nonce": web3.eth.get_transaction_count(address), } ) # Sign transaction signedTx = web3.eth.account.sign_transaction(tx, private_key) # Send tx hash = web3.eth.send_raw_transaction(signedTx.rawTransaction) receipt = web3.eth.wait_for_transaction_receipt(hash) print(f"Transaction receipt: { receipt.transactionHash.hex() }") execute_xcm_message_locally() ``` And that's it! You've successfully used the Polkadot XCM Pallet and the XCM Utilities Precompile to execute a custom XCM message locally on Moonbase Alpha! ## Send an XCM Message Cross-Chain {: #send-xcm-message } This section of the guide covers the process of sending a custom XCM message cross-chain (i.e., from Moonbeam to a target chain, such as the relay chain) via two different methods: the `send` function of the Polkadot XCM Pallet and the `xcmSend` function of the [XCM Utilities Precompile](/builders/interoperability/xcm/xcm-utils/){target=\_blank}. For the XCM message to be successfully executed, the target chain needs to be able to understand the instructions in the message. If it doesn't, you'll see a `Barrier` filter on the destination chain. For security reasons, the XCM message is prepended with the [`DescendOrigin`](https://github.com/paritytech/xcm-format#descendorigin){target=\_blank} instruction to prevent XCM execution on behalf of the origin chain Sovereign account. **The example in this section will not work for the reasons mentioned above, it is purely for demonstration purposes**. In the following example, you'll be building an XCM message that contains the following XCM instructions, which will be executed in the Alphanet relay chain: - [`WithdrawAsset`](/builders/interoperability/xcm/core-concepts/instructions/#withdraw-asset){target=\_blank} - removes assets and places them into the holding register - [`BuyExecution`](/builders/interoperability/xcm/core-concepts/instructions/#buy-execution){target=\_blank} - takes the assets from holding to pay for execution fees. The fees to pay are determined by the target chain - [`DepositAsset`](/builders/interoperability/xcm/core-concepts/instructions/#deposit-asset){target=\_blank}- removes the assets from the holding register and deposits the equivalent assets to a beneficiary account Together, the intention of these instructions is to transfer the native asset of the relay chain, which is UNIT for the Alphanet relay chain, from Moonbase Alpha to an account on the relay chain. This example is for demonstration purposes only to show you how a custom XCM message could be sent cross-chain. Please keep in mind that the target chain needs to be able to understand the instructions in the message to execute them. ### Send an XCM Message with the Polkadot.js API {: #send-xcm-message-with-polkadotjs-api } In this example, you'll send a custom XCM message from your account on Moonbase Alpha to the relay chain using the [Polkadot.js API](/builders/substrate/libraries/polkadot-js-api/){target=\_blank} to interact directly with the Polkadot XCM Pallet. The `send` function of the Polkadot XCM Pallet accepts two parameters: `dest` and `message`. You can start assembling these parameters by taking the following steps: 1. Build the multilocation of the relay chain token, UNIT, for the `dest`: ```js const dest = { V4: { parents: 1, interior: null } }; ``` 2. Build the `WithdrawAsset` instruction, which will require you to define: - The multilocation of the UNIT token on the relay chain - The amount of UNIT tokens to withdraw ```js const instr1 = { WithdrawAsset: [ { id: { parents: 1, interior: null }, fun: { Fungible: 1000000000000n }, // 1 UNIT }, ], }; ``` 3. Build the `BuyExecution` instruction, which will require you to define: - The multilocation of the UNIT token on the relay chain - The amount of UNIT tokens to buy for execution - The weight limit ```js const instr2 = { BuyExecution: [ { id: { parents: 1, interior: null }, fun: { Fungible: 1000000000000n }, // 1 UNIT }, { Unlimited: null }, ], }; ``` 4. Build the `DepositAsset` instruction, which will require you to define: - The asset identifier for UNIT tokens. You can use the [`WildAsset` format](https://github.com/paritytech/xcm-format/blob/master/README.md#6-universal-asset-identifiers){target=\_blank}, which allows for wildcard matching, to identify the asset - The multilocation of the beneficiary account on the relay chain ```js const instr3 = { DepositAsset: { assets: { Wild: 'All' }, beneficiary: { parents: 1, interior: { X1: [ { AccountId32: { id: relayAccount, }, }, ], }, }, }, }; ``` 5. Combine the XCM instructions into a versioned XCM message: ```js const message = { V4: [instr1, instr2, instr3] }; ``` Now that you have the values for each of the parameters, you can write the script to send the XCM message. You'll take the following steps: 1. Provide the input data for the call. This includes: - The Moonbase Alpha endpoint URL to create the provider - The values for each of the parameters of the `send` function 2. Create a Keyring instance that will be used to send the transaction 3. Create the [Polkadot.js API](/builders/substrate/libraries/polkadot-js-api/){target=\_blank} provider 4. Craft the `polkadotXcm.send` extrinsic with the `dest` and `message` 5. Send the transaction using the `signAndSend` extrinsic and the Keyring instance you created in the second step !!! remember This is for demo purposes only. Never store your private key in a JavaScript file. ```js import { ApiPromise, WsProvider, Keyring } from '@polkadot/api'; // Version 10.13.1 import { cryptoWaitReady, decodeAddress } from '@polkadot/util-crypto'; // 1. Input data const providerWsURL = 'wss://wss.api.moonbase.moonbeam.network'; // You can use the decodeAddress function to ensure that your address is properly // decoded. If it isn't decoded, it will decode it and if it is, it will ignore it const privateKey = 'INSERT_PRIVATE_KEY'; const relayAccount = decodeAddress('INSERT_ADDRESS'); const dest = { V4: { parents: 1, interior: null } }; const instr1 = { WithdrawAsset: [ { id: { parents: 1, interior: null }, fun: { Fungible: 1000000000000n }, // 1 UNIT }, ], }; const instr2 = { BuyExecution: [ { id: { parents: 1, interior: null }, fun: { Fungible: 1000000000000n }, // 1 UNIT }, { Unlimited: null }, ], }; const instr3 = { DepositAsset: { assets: { Wild: 'All' }, beneficiary: { parents: 1, interior: { X1: [ { AccountId32: { id: relayAccount, }, }, ], }, }, }, }; const message = { V4: [instr1, instr2, instr3] }; const sendXcmMessage = async () => { // 2. Create Keyring instance await cryptoWaitReady(); const keyring = new Keyring({ type: 'ethereum' }); const alice = keyring.addFromUri(privateKey); // 3. Create Substrate API Provider const substrateProvider = new WsProvider(providerWsURL); const api = await ApiPromise.create({ provider: substrateProvider }); // 4. Create the extrinsic const tx = api.tx.polkadotXcm.send(dest, message); // 5. Send the transaction const txHash = await tx.signAndSend(alice); console.log(`Submitted with hash ${txHash}`); api.disconnect(); }; sendXcmMessage(); ``` !!! note You can view an example of the above script, which sends 1 UNIT to Bob's relay chain account, on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/extrinsics/decode/0x1c00040100040c0004010000070010a5d4e813010000070010a5d4e8000d0100010101000c36e9ba26fa63c60ec728fe75fe57b86a450d94e7fee7f9f9eddd0d3f400d67){target=\_blank} using the following encoded calldata: `0x1c00040100040c0004010000070010a5d4e813010000070010a5d4e8000d0100010101000c36e9ba26fa63c60ec728fe75fe57b86a450d94e7fee7f9f9eddd0d3f400d67`. Once the transaction is processed, a `polkadotXcm.sent` event is emitted with the details of the sent XCM message. ### Send an XCM Message with the XCM Utilities Precompile {: #send-xcm-utils-precompile } In this section, you'll use the `xcmSend` function of the [XCM Utilities Precompile](/builders/interoperability/xcm/xcm-utils/){target=\_blank}, which is only supported on Moonbase Alpha, to send an XCM message cross-chain. The XCM Utilities Precompile is located at the following address: === "Moonbase Alpha" ```text {{ networks.moonbase.precompiles.xcm_utils }} ``` Under the hood, the `xcmSend` function of the XCM Utilities Precompile calls the `send` function of the Polkadot XCM Pallet, which is a Substrate pallet that is coded in Rust. The benefit of using the XCM Utilities Precompile to call `xcmSend` is that you can do so via the Ethereum API and use Ethereum libraries like [Ethers.js](/builders/ethereum/libraries/ethersjs/){target=\_blank}. For the XCM message to be successfully executed, the target chain needs to be able to understand the instructions in the message. The `xcmSend` function accepts two parameters: the multilocation of the destination and the SCALE encoded versioned XCM message to be sent. First, you'll learn how to generate the encoded calldata for the XCM message, and then you'll learn how to use the encoded calldata to interact with the XCM Utilities Precompile. #### Generate the Encoded Calldata of an XCM Message {: #generate-encoded-calldata } To get the encoded calldata of the XCM message, you can create a script similar to the one you created in the [Send an XCM Message with the Polkadot.js API](#send-xcm-message-with-polkadotjs-api) section. Instead of building the message and sending the transaction, you'll build the message to get the encoded calldata. You'll take the following steps: 1. Provide the input data for the call. This includes: - The Moonbase Alpha endpoint URL to create the provider - The values for each of the parameters of the `send` function as defined in the [Send an XCM Message with the Polkadot.js API](#send-xcm-message-with-polkadotjs-api) section 2. Create the [Polkadot.js API](/builders/substrate/libraries/polkadot-js-api/){target=\_blank} provider 3. Craft the `polkadotXcm.execute` extrinsic with the `message` and `maxWeight` 4. Use the transaction to get the encoded calldata The entire script is as follows: ```js import { ApiPromise, WsProvider } from '@polkadot/api'; // Version 10.13.1 import { decodeAddress } from '@polkadot/util-crypto'; // 1. Input data const providerWsURL = 'wss://wss.api.moonbase.moonbeam.network'; // You can use the decodeAddress function to ensure that your address is properly // decoded. If it isn't decoded, it will decode it and if it is, it will ignore it const relayAccount = decodeAddress('INSERT_ADDRESS'); const dest = { V4: { parents: 1, interior: null } }; const instr1 = { WithdrawAsset: [ { id: { parents: 1, interior: null }, fun: { Fungible: 1000000000000n }, // 1 UNIT }, ], }; const instr2 = { BuyExecution: [ { id: { parents: 1, interior: null }, fun: { Fungible: 1000000000000n }, // 1 UNIT }, { Unlimited: null }, ], }; const instr3 = { DepositAsset: { assets: { Wild: 'All' }, beneficiary: { parents: 1, interior: { X1: [ { AccountId32: { id: relayAccount, }, }, ], }, }, }, }; const message = { V4: [instr1, instr2, instr3] }; const generateEncodedXcmMessage = async () => { // 2. Create Substrate API Provider const substrateProvider = new WsProvider(providerWsURL); const api = await ApiPromise.create({ provider: substrateProvider }); // 3. Create the extrinsic const tx = api.tx.polkadotXcm.send(dest, message); // 4. Get the encoded XCM message // By using index 1, you'll get just the encoded XCM message. // If you wanted to get the dest, you could use index 0 const encodedXcmMessage = tx.args[1].toHex(); console.log(`Encoded Calldata for XCM Message: ${encodedXcmMessage}`); api.disconnect(); }; generateEncodedXcmMessage(); ``` #### Send the XCM Message {: #send-xcm-message } Before you can send the XCM message, you'll also need to build the multilocation of the destination. For this example, you'll target the relay chain with Moonbase Alpha as the origin chain: ```js const dest = [ 1, // Parents: 1 [] // Interior: Here ]; ``` Now that you have the SCALE encoded XCM message and the destination multilocation, you can use the following code snippets to programmatically call the `xcmSend` function of the XCM Utilities Precompile using your [Ethereum library](/builders/ethereum/libraries/){target=\_blank} of choice. Generally speaking, you'll take the following steps: 1. Create a provider and signer 2. Create an instance of the XCM Utilities Precompile to interact with 3. Define parameters required for the `xcmSend` function, which will be the destination and the encoded calldata for the XCM message 4. Send the XCM message !!! remember The following snippets are for demo purposes only. Never store your private keys in a JavaScript or Python file. === "Ethers.js" ```js import { ethers } from 'ethers'; // Import Ethers library import abi from './xcmUtilsABI.js'; // Import the XCM Utilities Precompile ABI const privateKey = 'INSERT_PRIVATE_KEY'; const xcmUtilsAddress = '0x000000000000000000000000000000000000080C'; /* Create Ethers provider and signer */ const provider = new ethers.JsonRpcProvider( 'https://rpc.api.moonbase.moonbeam.network' ); const signer = new ethers.Wallet(privateKey, provider); /* Create contract instance of the XCM Utilities Precompile */ const xcmUtils = new ethers.Contract( xcmUtilsAddress, abi, signer ); const sendXcm = async () => { /* Define parameters required for the xcmSend function */ const encodedCalldata = 'INSERT_ENCODED_CALLDATA'; const dest = [ 1, // Parents: 1 [] // Interior: Here ]; /* Send the custom XCM message */ const tx = await xcmUtils.xcmSend(dest, encodedCalldata); await tx.wait(); console.log(`Transaction receipt: ${tx.hash}`); }; sendXcm(); ``` === "Web3.js" ```js import { Web3 } from 'web3'; // Import Web3 library import abi from './xcmUtilsABI.js'; // Import the XCM Utilities Precompile ABI const privateKey = 'INSERT_PRIVATE_KEY'; const accountFrom = web3.eth.accounts.privateKeyToAccount(privateKey).address; const xcmUtilsAddress = '0x000000000000000000000000000000000000080C'; /* Create Web3 provider */ const web3 = new Web3('https://rpc.api.moonbase.moonbeam.network'); // Change to network of choice /* Create contract instance of the XCM Utilities Precompile */ const xcmUtils = new web3.eth.Contract( abi, xcmUtilsAddress, { from: accountFrom } // 'from' is necessary for gas estimation ); const sendXcm = async () => { /* Define parameters required for the xcmSend function */ const encodedCalldata = 'INSERT_ENCODED_CALLDATA'; const dest = [ 1, // Parents: 1 [], // Interior: Here ]; /* Send the custom XCM message */ // Craft the extrinsic const tx = await xcmUtils.methods.xcmSend(dest, encodedCalldata); // Sign transaction const signedTx = await web3.eth.accounts.signTransaction( { to: xcmUtilsAddress, data: tx.encodeABI(), gas: await tx.estimateGas(), gasPrice: await web3.eth.getGasPrice(), nonce: await web3.eth.getTransactionCount(accountFrom), }, privateKey ); // Send the signed transaction const sendTx = await web3.eth.sendSignedTransaction(signedTx.rawTransaction); console.log(`Transaction receipt: ${sendTx.transactionHash}`); }; sendXcm(); ``` === "Web3.py" ```py from web3 import Web3 abi = "INSERT_XCM_UTILS_ABI" # Paste or import the XCM Utils ABI # This is for demo purposes, never store your private key in plain text private_key = "INSERT_PRIVATE_KEY" # The wallet address that corresponds to your private key address = "INSERT_ADDRESS" xcm_utils_address = "0x000000000000000000000000000000000000080C" ## Create Web3 provider ## web3 = Web3(Web3.HTTPProvider("https://rpc.api.moonbase.moonbeam.network")) ## Create contract instance of the XCM Utilities Precompile ## xcm_utils = web3.eth.contract( # XCM Utilities Precompile address address=xcm_utils_address, abi=abi, ) def send_xcm(): ## Define parameters required for the xcmSend function ## encoded_calldata = "INSERT_ENCODED_CALLDATA" xcm_dest = [1, []] # Parents: 1 # Interior: Here ## Send the custom XCM message ## # Craft the extrinsic tx = xcm_utils.functions.xcmSend(xcm_dest, encoded_calldata).build_transaction( { "from": address, "nonce": web3.eth.get_transaction_count(address), } ) # Sign transaction signed_tx = web3.eth.account.sign_transaction(tx, private_key) # Send tx hash = web3.eth.send_raw_transaction(signed_tx.rawTransaction) receipt = web3.eth.wait_for_transaction_receipt(hash) print(f"Transaction receipt: { receipt.transactionHash.hex() }") send_xcm() ``` And that's it! You've successfully used the Polkadot XCM Pallet and the XCM Utilities Precompile to send a message from Moonbase Alpha to another chain! --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/xc-registration/assets/ --- BEGIN CONTENT --- --- title: Register XC Assets description: This guide includes everything you need to know to register local and external XC-20s so you can begin transferring assets cross-chain via XCM. categories: XC-20 --- # How to Register Cross-Chain Assets via Governance ## Introduction {: #introduction } For an asset to be transferred across chains via XCM, there needs to be an open channel between the two chains, and the asset needs to be registered on the destination chain. If a channel does not exist between the two chains, one will need to be opened. Please check out the [XC Channel Registration](/builders/interoperability/xcm/xc-registration/xc-integration/){target=\_blank} guide for information on how to establish a channel between Moonbeam and another chain. This guide will show you how to register [external XC-20s](/builders/interoperability/xcm/xc20/overview/#external-xc20s){target=\_blank} on Moonbeam and provide the information you need to register Moonbeam assets, including Moonbeam native assets (GLMR, MOVR, and DEV) and [local XC-20s](/builders/interoperability/xcm/xc20/overview/#local-xc20s){target=\_blank} (XCM-enabled ERC-20s), on another chain. The examples in this guide use a CLI tool developed to ease the entire process, which you can find in the [xcm-tools GitHub repository](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank}. ```bash git clone https://github.com/Moonsong-Labs/xcm-tools && \ cd xcm-tools && \ yarn ``` ## Register External XC-20s on Moonbeam {: #register-xc-20s } Registering External XC-20s on Moonbeam is a multi-step process that, at a high level, involves proposing the asset registration on the [Moonbeam Community Forum](https://forum.moonbeam.network){target=\_blank} and creating an on-chain governance proposal. If a channel between Moonbeam and the origin chain of the asset does not yet exist, one will need to be opened. You can batch the channel-related calls with the asset registration calls, so you only need to submit a single proposal. You must start by creating a couple of forum posts: an [XCM Disclosure](/builders/interoperability/xcm/xc-registration/forum-templates/#xcm-disclosures){target=\_blank} post and an [XCM Proposal](/builders/interoperability/xcm/xc-registration/forum-templates/#xcm-proposals){target=\_blank} post. After you've collected feedback from community members, you can create a proposal to open a channel and register any assets. Please refer to the [Establishing an XC Integration with Moonbeam](/builders/interoperability/xcm/xc-registration/xc-integration/){target=\_blank} guide for more information on opening a channel. ![Asset registration if XC channel doesn't exist](/images/builders/interoperability/xcm/xc-registration/assets/assets-1.webp) If a channel between the chains already exists, you'll need to create a forum post to register the asset, collect feedback, and then submit the proposal to register the asset. ![Asset registration if XC channel exists](/images/builders/interoperability/xcm/xc-registration/assets/assets-2.webp) ### Create a Forum Post {: #create-a-forum-post } To create a forum post on the [Moonbeam Community Forum](https://forum.moonbeam.network){target=\_blank}, you'll need to make sure that you're adding the post to the correct category and adding relevant content. For general guidelines and a template to follow, please refer to the [Moonbeam Community Forum Templates for XCM Integrations](/builders/interoperability/xcm/xc-registration/forum-templates/#){target=\_blank} page. ### Calculate Relative Price {: #calculate-relative-price } An asset's `relativePrice` refers to a `u128` value that indicates how many units of said asset (in its smallest denomination) equate to one unit—i.e., `1 × 10^18 Wei`—of the native token (GLMR or MOVR). This helps determine how much of your asset to use for fees initially quoted in the native token, particularly in cross-chain messaging (XCM). You can use the following script (also available as part of [xcm-tools](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank} ) to calculate the correct `relativePrice` value for your asset. ??? code "Calculate Relative Price" ```typescript import axios from 'axios'; // CoinGecko IDs for the networks const NETWORK_IDS = { GLMR: 'moonbeam', MOVR: 'moonriver', }; async function calculateRelativePrice( assetPrice: number, assetDecimals: number, network: 'GLMR' | 'MOVR' ): Promise { try { // Fetch the native token price from CoinGecko const response = await axios.get( `https://api.coingecko.com/api/v3/simple/price?ids=${NETWORK_IDS[network]}&vs_currencies=usd` ); const nativeTokenPrice = response.data[NETWORK_IDS[network]].usd; // Calculate relative price with 18 decimal places // Formula: (assetPrice / nativeTokenPrice) * 10^18 // This gives us how many units of the asset we need to equal 1 unit of native token const relativePrice = BigInt( 0.175 * Math.pow(10, 18 - assetDecimals) * (assetPrice / nativeTokenPrice) * Math.pow(10, 18) ); // Return as string to preserve precision return relativePrice; } catch (error) { if (error instanceof Error) { throw new Error(`Failed to calculate relative price: ${error.message}`); } throw error; } } function validateInput( price: string, decimals: string, network: string ): { assetPrice: number; assetDecimals: number; network: 'GLMR' | 'MOVR' } { // Validate price const assetPrice = parseFloat(price); if (isNaN(assetPrice) || assetPrice <= 0) { throw new Error('Price must be a positive number'); } // Validate decimals const assetDecimals = parseFloat(decimals); if (isNaN(assetDecimals) || assetDecimals <= 0) { throw new Error('Decimals must be a positive number'); } // Validate network const upperNetwork = network.toUpperCase() as 'GLMR' | 'MOVR'; if (!['GLMR', 'MOVR'].includes(upperNetwork)) { throw new Error('Network must be either GLMR or MOVR'); } return { assetPrice, assetDecimals, network: upperNetwork }; } function printUsage() { console.log('\nUsage:'); console.log( 'npx ts-node calculate-relative-price.ts ' ); console.log('\nExample:'); console.log('npx ts-node calculate-relative-price.ts 0.25 12 GLMR'); console.log('\nParameters:'); console.log('price - The price of your asset in USD'); console.log('decimals - The decimals of your asset'); console.log('network - Either GLMR or MOVR'); } async function main() { try { // Get command line arguments const [, , price, decimals, network] = process.argv; // Check if help flag is passed if (price === '--help' || price === '-h') { printUsage(); return; } // Check if required arguments are provided if (!price || !decimals || !network) { console.error('Error: Missing required arguments'); printUsage(); process.exit(1); } // Validate inputs const { assetPrice, assetDecimals, network: validNetwork, } = validateInput(price, decimals, network); console.log( `\nCalculating relative price for asset worth $${assetPrice} against ${validNetwork}...` ); const relativePrice = await calculateRelativePrice( assetPrice, assetDecimals, validNetwork ); const nativeTokenPrice = ( await axios.get( `https://api.coingecko.com/api/v3/simple/price?ids=${NETWORK_IDS[validNetwork]}&vs_currencies=usd` ) ).data[NETWORK_IDS[validNetwork]].usd; const decimalRatio = nativeTokenPrice / assetPrice; console.log(`\nResults:`); console.log(`Asset Price: $${assetPrice}`); console.log(`Network: ${validNetwork}`); console.log(`Native Token Price (from CoinGecko): $${nativeTokenPrice}`); console.log(`\nRelative Price Analysis:`); console.log( `1 ${validNetwork} is equal to approximately ${decimalRatio.toFixed( 3 )} of your specified token.` ); console.log( `With 18 decimals, 1 ${validNetwork} or in WEI, 1000000000000000000 is equal to a relative price of ${relativePrice} units of your token` ); console.log(`\nRelative Price: ${relativePrice}`); console.log( `\nThe relative price you should specify in asset registration steps is ${relativePrice}\n` ); } catch (error) { console.error('\nError:', error instanceof Error ? error.message : error); process.exit(1); } } main(); ``` Only three parameters are required to calculate the relative price of an asset: - **Asset Price (USD)** - a positive number representing how much 1 unit (in human-readable form) of your asset costs in USD - **Asset Decimals** - the number of decimal places your asset uses. For example, if your token has 12 decimals, specify 12 - **Network** - either GLMR (Moonbeam) or MOVR (Moonriver). This should correspond to the network that you're registering the asset on, and this determines which native token’s USD price the script will fetch from CoinGecko First, ensure that you've installed the required dependencies by running: ```bash yarn ``` Execute the script, making sure to provide the USD price of the asset you're registering, the number of decimals it has, and the network you're registering the asset on (either GLMR or MOVR): ```bash yarn calculate-relative-price INSERT_ASSET_PRICE INSERT_DECIMALS GLMR ``` For example, if the asset you're registering has a USD price of $0.25 and 12 decimals and you're registering the asset on the Moonbeam network, you would run: ```bash yarn calculate-relative-price 0.25 12 GLMR ``` This instructs the script to calculate how many smallest units of an asset (priced at $0.25, with 12 decimals) correspond to 1 GLMR token.
yarn calculate-relative-price 0.04901 12 GLMR Calculating relative price for asset worth $0.04901 against GLMR... Results: Asset Price: $0.04901 Network: GLMR Native Token Price (from CoinGecko): $0.126009 Relative Price Analysis: 1 GLMR is equal to approximately 2.571 of your specified token. With 18 decimals, 1 GLMR (in WEI: 1000000000000000000) is equal to 68064582688538114392064 units of your token. Relative Price: 68064582688538114392064 The relative price you should specify in asset registration steps is 68064582688538114392064
Upon successful execution, the script prints the computed `relativePrice` as a `BigInt`. This value represents the scaled ratio between the asset’s USD price and the native token’s USD price, multiplied up to 18 decimals. You can then use this result in on-chain asset registration or fee calculation scenarios—especially where a `u128` 18-decimal format is required. For additional info, usage details, or to see an example in action, you can invoke the help command by running: ```bash yarn calculate-relative-price --help ``` ### Generate the Encoded Calldata for the Asset Registration {: #generate-encoded-calldata-for-asset-registration } Submitting a governance proposal on Moonbeam requires two steps: first, submit a preimage that defines the actions to be executed, then use that preimage to submit the proposal. For more details, see the [Governance on Moonbeam](/learn/features/governance/){target=\_blank} page. To submit a preimage for asset registration, you'll need the encoded calldata for both the `evmForeignAssets.createForeignAsset` and `xcmWeightTrader.addAsset` extrinsics. An existing asset's price can be updated with `xcmWeightTrader.editAsset`. Proposals must be submitted via the Fast General Admin track. A channel must be established before an asset can be registered. To get the encoded calldata for the `evmForeignAssets.createForeignAsset` extrinsic, you will need to provide the following arguments: - **`assetId`** - unique identifier of the asset, generated from the [`calculate-external-asset-info.ts`](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/calculate-external-asset-info.ts){target=\_blank} script - **`xcmLocation`** - the multilocation of the asset relative to Moonbeam - **`decimals`** - the number of decimals of the asset - **`symbol`** - the symbol of the asset. Remember that "xc" should be prepended to the symbol to indicate the asset is an XCM-enabled asset - **`name`** - the asset name Using the above information, you can generate the encoded call data for the `createForeignAsset` call either via the Polkadot API or on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbeam.network#/extrinsics){target=\_blank}. You can generate this required calldata using the [xcm-asset-registrator script](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/xcm-asset-registrator.ts){target=\_blank} as follows: ```bash yarn register-asset --w wss://wss.api.moonbeam.network \ --asset "INSERT_MULTILOCATION" \ --symbol "INSERT_ASSET_SYMBOL" \ --decimals INSERT_DECIMALS \ --name "INSERT_ASSET_NAME" \ --relative-price INSERT_RELATIVE_PRICE ``` Upon running the script with the relevant parameters, you'll see output like the following:
yarn register-asset --w wss://wss.api.moonbeam.network \ --asset '{ "parents": 1, "interior": {"X1": [{ "Parachain": 3370}]}}' \ --symbol "xcLAOS" \ --decimals 18 \ --name "LAOS" \ --relative-price 68064582688538114392064 yarn run v1.22.22 warning ../../../package.json: No license field $ ts-node 'scripts/xcm-asset-registrator.ts' --w wss://wss.api.moonbeam.network --asset '{ "parents": 1, "interior": {"X1": [{ "Parachain": 3370}]}}' --symbol xcLAOS --decimals 18 --name LAOS --relative-price 68064582688538114392064 XCM Version is V4 Encoded Call Data for registerAsset is 0x72008835e1b9f588de47ec5e4a828e4e70dd010100a934121878634c414f53104c414f53 Encoded Call Data for Set Relative Price is 0x7300010100a9340000805c9cf5d5c9690e000000000000 Encoded Call Data for batched is 0x1e000872008835e1b9f588de47ec5e4a828e4e70dd010100a934121878634c414f53104c414f537300010100a9340000805c9cf5d5c9690e000000000000 ✨ Done in 5.20s.
The script will provide the encoded call data for each of the following calls: - The `registerAsset` call - The `setRelativePrice` call - The `batch` call that combines all of the above ![Overview of the proposal process](/images/builders/interoperability/xcm/xc-registration/assets/assets-3.webp) ### Construct the Add Asset Call If you've already used the [xcm-asset-registrator script](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/xcm-asset-registrator.ts){target=\_blank} shown above, you can skip this section. This section dives into more detail about how the `xcmWeightTrader.addAsset` call is constructed. To get the encoded calldata for the `xcmWeightTrader.addAsset` extrinsic, you will need to provide the following arguments: - **`xcmLocation`** - the multilocation of the asset relative to Moonbeam - **`relativePrice`** - A numeric value (u128) representing the fraction of the native token’s price that your asset’s price constitutes, scaled to 18 decimals. This value calculates cross-chain fees by determining how many units of the non-native asset are required to cover XCM operation costs Using the above information, you can generate the encoded call data for the `addAsset` call either via the Polkadot API or on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbeam.network#/extrinsics){target=\_blank}. To create a batch transaction that combines both the `xcmWeightTrader.addAsset` and the `evmForeignAssets.createForeignAsset` calls together, you can use the [Polkadot API's `batch` method](/builders/substrate/libraries/polkadot-js-api/#batching-transactions){target=\_blank}. As mentioned previously, the [XCM asset registrator script](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/xcm-asset-registrator.ts){target=\_blank} can help you build and submit the required calls. ### Submit the Preimage and Proposal for Asset Registration {: #submit-preimage-proposal } Your next task is to submit the preimage of your batched call containing both the `xcmWeightTrader.addAsset` and the `evmForeignAssets.createForeignAsset` by following the guidelines in the [Submit a Democracy Proposal Guide](/tokens/governance/proposals/#submitting-a-preimage-of-the-proposal){target=\_blank}. You do not need to go through governance for Moonbase Alpha, as Moonbase Alpha has sudo access. Instead, you can provide the output of the batch call data to the Moonbeam team, and they can submit the call with sudo. This will be a faster and easier process than going through governance. However, you may still wish to go through governance on Moonbase Alpha to prepare for Moonbeam's governance process. After submitting the preimage, you can submit the proposal by following the guidelines in the [Submitting a Proposal](/tokens/governance/proposals/#submitting-a-proposal-v2){target=\_blank} section. If you prefer the script method and you're comfortable working with the scripts in the XCM tools repo, you can use the [generic call proposer](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/generic-call-proposer.ts){target=\_blank} by passing in the requisite calls, including the acceptance and proposal of the XCM Channel, and the asset registration. The [generic call proposer](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/generic-call-proposer.ts){target=\_blank} can help you assemble the multiple requisite calls as follows: ```bash yarn generic-call-propose \ --call INSERT_CALLDATA_INCOMING_XCM_CHANNEL \ --call INSERT_CALLDATA_OUTGOING_XCM_CHANNEL \ --call INSERT_CALLDATA_BATCH_ASSET_REGISTRATION \ --ws-provider INSERT_WSS_PROVIDER ``` ### Test the Asset Registration on Moonbeam {: #test-asset-registration } After your asset is registered, the team will provide the asset ID and the [XC-20 precompile](/builders/interoperability/xcm/xc20/interact/#the-erc20-interface){target=\_blank} address. Your XC-20 precompile address is calculated by converting the asset ID decimal number to hex and prepending it with F's until you get a 40-hex character (plus the “0x”) address. For more information on how it is calculated, please refer to the [Calculate External XC-20 Precompile Addresses](/builders/interoperability/xcm/xc20/interact/#calculate-xc20-address){target=\_blank} section of the External XC-20 guide. After the asset is successfully registered, you can transfer tokens from your parachain to the Moonbeam-based network you are integrating with. !!! note Remember that Moonbeam-based networks use AccountKey20 (Ethereum-style addresses). For testing, please also provide your parachain WSS endpoint so that the [Moonbeam dApp](https://apps.moonbeam.network){target=\_blank} can connect to it. Lastly, please fund the corresponding account: === "Moonbeam" ```text AccountId: {{ networks.moonbeam.xcm.channel.account_id }} Hex: {{ networks.moonbeam.xcm.channel.account_id_hex }} ``` === "Moonriver" ```text AccountId: {{ networks.moonriver.xcm.channel.account_id }} Hex: {{ networks.moonriver.xcm.channel.account_id_hex }} ``` === "Moonbase Alpha" ```text AccountId: {{ networks.moonbase.xcm.channel.account_id }} Hex: {{ networks.moonbase.xcm.channel.account_id_hex }} ``` !!! note For Moonbeam and Moonriver testing, please send $50 worth of tokens to the aforementioned account. In addition, provide an Ethereum-style account to send $50 worth of GLMR/MOVR for testing purposes. [XC-20s](/builders/interoperability/xcm/xc20/){target=\_blank} are Substrate-based assets with an [ERC-20 interface](/builders/interoperability/xcm/xc20/overview/#the-erc20-interface){target=\_blank}. This means they can be added to MetaMask and composed with any EVM DApp that exists in the ecosystem. The team can connect you with any DApp you find relevant for an XC-20 integration. If you need DEV tokens (the native token for Moonbase Alpha) to use your XC-20 asset, you can get some from the [Moonbase Alpha Faucet](/builders/get-started/networks/moonbase/#moonbase-alpha-faucet){target=\_blank}, which dispenses {{ networks.moonbase.website_faucet_amount }} every 24 hours. If you need more, feel free to reach out to the team on [Telegram](https://t.me/Moonbeam_Official){target=\_blank} or [Discord](https://discord.com/invite/PfpUATX){target=\_blank}. ### Set XC-20 Precompile Bytecode {: #set-bytecode } Once your XC-20 has been registered on Moonbeam, you can set the XC-20's precompile bytecode. This is necessary because precompiles are implemented inside the Moonbeam runtime and, by default, do not have bytecode. In Solidity, when a contract is called, there are checks that require the contract bytecode to be non-empty. So, setting the bytecode as a placeholder bypasses these checks and allows the precompile to be called. You can use the [Precompile Registry](/builders/ethereum/precompiles/utility/registry/){target=\_blank}, which is a Solidity interface, to update the XC-20 precompile's bytecode to avoid any issues and ensure that the precompile is callable from Solidity. To do so, you'll use the Precompile Registry's [`updateAccountCode` function](/builders/ethereum/precompiles/utility/registry/#the-solidity-interface){target=\_blank}. To get started, you'll need to [calculate your XC-20's precompile address](/builders/interoperability/xcm/xc20/overview/#calculate-xc20-address){target=\_blank} and have the Precompile Registry's ABI. ??? code "Precompile Registry ABI" ```js [ { "inputs": [ { "internalType": "address", "name": "a", "type": "address" } ], "name": "isActivePrecompile", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "a", "type": "address" } ], "name": "isPrecompile", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "a", "type": "address" } ], "name": "updateAccountCode", "outputs": [], "stateMutability": "nonpayable", "type": "function" } ] ``` Then, you can use the following scripts to set the dummy code for your XC-20's precompile. !!! remember The following snippets are for demo purposes only. Never store your private keys in a JavaScript or Python file. === "Ethers.js" ```js import { ethers } from 'ethers'; // Import Ethers library const privateKey = 'INSERT_PRIVATE_KEY'; const abi = 'INSERT_PRECOMPILE_REGISTRY_ABI'; const xc20Address = 'INSERT_XC_20_PRECOMPILE_ADDRESS'; const registryAddress = '0x0000000000000000000000000000000000000815'; // Create Ethers provider and signer const provider = new ethers.JsonRpcProvider( 'https://rpc.api.moonbase.moonbeam.network' ); const signer = new ethers.Wallet(privateKey, provider); // Create interface for the Precompile Registry const precompileRegistry = new ethers.Contract(registryAddress, abi, signer); const updateAccountCode = async () => { // Update the precompile bytecode await precompileRegistry.updateAccountCode(xc20Address); // Check the precompile bytecode const bytecode = await provider.getCode(xc20Address); console.log(`The XC-20 precompile's bytecode is: ${bytecode}`); }; updateAccountCode(); ``` === "Web3.js" ```js import { Web3 } from 'web3'; const privateKey = 'INSERT_PRIVATE_KEY'; const abi = 'INSERT_PRECOMPILE_REGISTRY_ABI'; const xc20Address = 'INSERT_XC_20_PRECOMPILE_ADDRESS'; const registryAddress = '0x0000000000000000000000000000000000000815'; // Create provider const web3 = new Web3('https://rpc.api.moonbase.moonbeam.network'); // Create interface for the Precompile Registry const precompileRegistry = new web3.eth.Contract(abi, registryAddress, { from: web3.eth.accounts.privateKeyToAccount(privateKey).address, }); const updateAccountCode = async () => { // Update the precompile bytecode await precompileRegistry.methods.updateAccountCode(xc20Address).call(); // Check the precompile bytecode const bytecode = await web3.eth.getCode(xc20Address); console.log(`The XC-20 precompile's bytecode is: ${bytecode}`); }; updateAccountCode(); ``` === "Web3.py" ```py from web3 import Web3 private_key = "INSERT_PRIVATE_KEY" abi = "INSERT_PRECOMPILE_REGISTRY_ABI" # Paste or import the Precompile Registry ABI xc20_address = "INSERT_XC_20_PRECOMPILE_ADDRESS" registry_address = "0x0000000000000000000000000000000000000815" # Create provider web3 = Web3(Web3.HTTPProvider("https://rpc.api.moonbase.moonbeam.network")) # Create interface for the Precompile Registry precompile_registry = web3.eth.contract(address=registry_address, abi=abi) def update_account_code(): # Update the precompile bytecode precompile_registry.functions.updateAccountCode(xc20_address).call() # Check the precompile bytecode bytecode = web3.eth.get_code(xc20_address) print("The XC-20 precompile's bytecode is: ", web3.to_hex(bytecode)) update_account_code() ``` After running the script to set the bytecode, you should see `The XC-20 precompile's bytecode is: 0x60006000fd` printed to your terminal. ## Register Moonbeam Assets on Another Chain {: #register-moonbeam-assets-on-another-chain } To enable cross-chain transfers of Moonbeam assets, including Moonbeam native assets (GLMR, MOVR, DEV) and local XC-20s (XCM-enabled ERC-20s) deployed on Moonbeam, between Moonbeam and another chain, you'll need to register the assets on the other chain. Since each chain stores cross-chain assets differently, the exact steps to register Moonbeam assets on another chain will vary depending on the chain. At the very least, you'll need to know the metadata and the multilocation of the assets on Moonbeam. There are additional steps aside from asset registration that will need to be taken to enable cross-chain integration with Moonbeam. For more information, please refer to the [Establishing an XC Integration with Moonbeam](/builders/interoperability/xcm/xc-registration/xc-integration/){target=\_blank} guide. ### Register Moonbeam Native Assets on Another Chain {: #register-moonbeam-native-assets } The metadata for each network is as follows: === "Moonbeam" | Variable | Value | |:-------------------:|:-------------------:| | Name | Glimmer | | Symbol | GLMR | | Decimals | 18 | | Existential deposit | 1 (1 * 10^-18 GLMR) | === "Moonriver" | Variable | Value | |:-------------------:|:-------------------:| | Name | Moonriver | | Symbol | MOVR | | Decimals | 18 | | Existential deposit | 1 (1 * 10^-18 MOVR) | === "Moonbase Alpha" | Variable | Value | |:-------------------:|:------------------:| | Name | DEV | | Symbol | DEV | | Decimals | 18 | | Existential deposit | 1 (1 * 10^-18 DEV) | The multilocation of Moonbeam native assets includes the parachain ID of the Moonbeam network and the pallet instance where Moonbeam assets live, which corresponds to the index of the Balances Pallet. The multilocation for each network is as follows: === "Moonbeam" ```js { V4: { parents: 1, interior: { X2: [ { Parachain: 2004 }, { PalletInstance: 10 } ] } } } ``` === "Moonriver" ```js { V4: { parents: 1, interior: { X2: [ { Parachain: 2023 }, { PalletInstance: 10 } ] } } } ``` === "Moonbase Alpha" ```js { V4: { parents: 1, interior: { X2: [ { Parachain: 1000 }, { PalletInstance: 3 } ] } } } ``` ### Register Local XC-20s on Another Chain {: #register-local-xc20 } The multilocation for local XC-20s include the parachain ID of Moonbeam, the pallet instance, and the address of the ERC-20. The pallet instance corresponds to the index of the ERC-20 XCM Bridge Pallet, as this is the pallet that enables any ERC-20 to be transferred via XCM. **To be registered on other chains, local XC-20s must strictly comply with the standard ERC-20 interface as described in [EIP-20](https://eips.ethereum.org/EIPS/eip-20){target=\_blank}. In particular, the [`transfer` function](https://eips.ethereum.org/EIPS/eip-20#transfer){target=\_blank} must be as described in EIP-20:** ```js function transfer(address _to, uint256 _value) public returns (bool success) ``` If the function selector of the `transfer` function deviates from the standard, the cross-chain transfer will fail. You can use the following multilocation to register a local XC-20: === "Moonbeam" ```js { parents: 1, interior: { X3: [ { Parachain: 2004 }, { PalletInstance: 110 }, { AccountKey20: { key: 'INSERT_ERC20_ADDRESS' } } ] } } ``` === "Moonriver" ```js { parents: 1, interior: { X3: [ { Parachain: 2023 }, { PalletInstance: 110 }, { AccountKey20: { key: 'INSERT_ERC20_ADDRESS' } } ] } } ``` === "Moonbase Alpha" ```js { parents: 1, interior: { X3: [ { Parachain: 1000 }, { PalletInstance: 48 }, { AccountKey20: { key: 'INSERT_ERC20_ADDRESS' } } ] } } ``` Since local XC-20s are ERC-20s on Moonbeam, there are no deposits required to create an ERC-20 on Moonbeam. However, deposits may be required to register the asset on another parachain. Please consult with the parachain team you wish to register the asset with for more information. ## Managing XC Assets After completing the [registration process](#introduction) for an XC asset, you may need to periodically update asset details, such as the XCM multilocation details or asset price. This section will cover these topics. ### Updating Foreign Asset XCM Location {: #updating-foreign-asset-xcm-location } You can update the multilocation of an asset with the `evmForeignAssets.changeXcmLocation` call, which takes as parameters the `assetId` and the new multilocation. You'll need to raise a [governance proposal](/tokens/governance/proposals/) and submit the update under the General Admin track. If you're testing in Moonbase Alpha, you can ask the Moonbeam Team to submit the extrinsic using Sudo to speed up the process. You can also submit the requisite governance proposal on Moonbase Alpha. ### Freezing a Foreign Asset {: #freezing-a--foreign-asset } You can freeze a foreign asset by calling `evmForeignAssets.freezeForeignAsset`, which takes as parameters the `assetId` and an `allowXcmDeposit` boolean. If set to true, XCM deposits from remote chains will still be allowed and mint tokens. If set to false, XCM deposits from remote chains will fail as no minting will be permitted. ### Paying XCM Fees with Foreign Assets {: #paying-xcm-fees-with-foreign-assets } After you've registered the foreign asset via the `evmForeignAssets` and the `xcmWeightTrader` pallet, your asset will now be among the supported assets for paying XCM fees. To verify, you can query the `xcmWeightTrader` pallet and the `supportedAssets` chain state query. Toggle the **Include Option** slider off to see the complete list, or you can filter the list by the multilocation of your asset. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/xc-registration/forum-templates/ --- BEGIN CONTENT --- --- title: Forum Templates for XCM Integrations description: Learn about and how to craft the two posts you need to make on the Moonbeam Community Forum when creating a cross-chain integration with Moonbeam. categories: XCM, Integrations --- # Moonbeam Community Forum Templates for XCM Integrations ## Introduction {: #introduction } When starting an XCM integration on Moonriver or Moonbeam MainNet, there are two preliminary posts that must be made on the [Moonbeam Community Forum](https://forum.moonbeam.network){target=\_blank} so that the voting community has the chance to provide feedback. The two preliminary posts are an XCM disclosure and an XCM proposal. **This step is not necessary when connecting to Moonbase Alpha.** If only an asset is being registered, the cross-chain channel must already be established, and so only an XCM proposal post is required to register the asset. It is recommended that this be done five days before the actual proposal is submitted on chain to provide time for community feedback. ## XCM Disclosures {: #xcm-disclosure } The first post that should be made are the key disclosures within the [XCM Disclosures category](https://forum.moonbeam.network/c/xcm-hrmp/xcm-disclosures/15){target=\_blank}, which highlight key information that is important to a voter's decision. This post is only required when establishing an XCM integration; it is not necessary if the integration already exists and you only need to register an asset. Once you hit the **New Topic** button, a template is provided with the relevant information to be filled in. Please use either the Moonbeam/Moonriver tag, depending on the network you are integrating with. In the post, please provide the following information: - **Title** - XCM Disclosure: *YOUR_NETWORK_NAME* - **Network Information** — one sentence summarizing your network and relevant links to your website, Twitter, and other social channels You'll also need to provide answers to the following questions: - Is the blockchain network's code open source? If so, please provide the GitHub link. If not, provide an explanation of why not - Is SUDO disabled on the network? If SUDO is disabled, is the network controlled by a select group of addresses? - Has the integration of the network been tested completely on the Moonbase Alpha TestNet? - (For Moonbeam HRMP proposals only) Does your network have a Kusama deployment? If so, provide its network name and whether the Kusama deployment is integrated with Moonriver - Is the blockchain network's code audited? If so, please provide: - Auditor name(s) - Dates of audit reports - Links to audit reports ## XCM Proposals {: #xcm-proposals } The second post is a preliminary draft of the proposal in the [XCM Proposals category](https://forum.moonbeam.network/c/xcm-hrmp/xcm-proposals/14){target=\_blank}. Once a proposal is submitted on-chain and available for voting, you must also add a description to it in either the [Moonbeam Polkassembly](https://moonbeam.polkassembly.io/opengov){target=\_blank} or [Moonriver Polkassembly](https://moonriver.polkassembly.io/opengov){target=\_blank}. Once you hit the **New Topic** button, a template is provided with the relevant information to be filled in. Please use either the Moonbeam or Moonriver tag, depending on the network you are integrating with. In both the Moonbeam XCM Proposals forum post and in Polkassembly, add the following sections and information: - **Title** — *YOUR_NETWORK_NAME* Proposal to Open Channel & Register *ASSET_NAME*. If you're only registering an asset, you can use: *YOUR_NETWORK_NAME* Proposal to Register *ASSET_NAME* - **Introduction** — one sentence summarizing the proposal - **Network Information** — one sentence summarizing your network and relevant links to your website, Twitter, and other social channels - **Summary** — brief description of the content of the proposal - **On-Chain Proposal Reference** — include if it is a Moonbeam or Moonriver proposal, the proposal number, and the proposal hash - **Technical Details** — provide technical information required for the community to understand the use cases and purpose of the proposal - **Additional Information** — any additional information you would like the community to know --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/xc-registration/ --- BEGIN CONTENT --- --- title: Register Cross-Chain Channels and Assets description: Learn how to create a cross-chain integration with Moonbeam and how to register cross-chain assets that can be transferred between Moonbeam and another chain. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/xc-registration/self-serve-asset-registration/ --- BEGIN CONTENT --- --- title: Self-Serve Asset Registration description: This guide shows sibling parachains how to register native tokens as foreign assets on Moonbeam via ForeignAssetOwnerOrigin to unlock ERC-20 UX on Moonbeam. categories: XCM --- # Self-Serve Asset Registration for Sibling Parachains ## Introduction {: #introduction } Registering your parachain's native tokens on Moonbeam or Moonriver lets your community enjoy ERC‑20–style UX and deep EVM integrations while retaining full on‑chain provenance. This guide shows sibling Polkadot parachain teams how to self‑register a foreign asset using the new `ForeignAssetOwnerOrigin` introduced in Moonbeam Runtime 3600. ### Why a New Origin? {: #why-a-new-origin } Moonbeam introduced a new dedicated origin called `ForeignAssetOwnerOrigin`, which only permits an XCM message whose origin contains the asset's multilocation to execute calls in the `evm‑foreign‑assets` pallet. In practice, that means only the sovereign account of the parachain that owns the asset, or Moonbeam governance, can create, freeze, unfreeze, or relocate it. Alongside this, a configurable runtime constant called `ForeignAssetCreationDeposit` is reserved from the caller's sovereign account at creation time. The deposit discourages spam registrations. ## Required Deposits {: #required-deposits } To prevent spam, a `ForeignAssetCreationDeposit` is required and locked for the lifetime of the asset. The deposit is funded from the sibling parachain's sovereign account on the Moonbeam network, which thus needs to be sufficiently funded to cover the asset deposit and the associated transaction fees. If the asset is destroyed through governance, the deposit is unreserved and returned to the original sovereign account. Deposits are network‑specific and can be adjusted by Moonbeam governance via the `parameters` pallet: === "Moonbeam" | Variable | Value | |:--------------:|:-------------------------------------------------:| | Foreign Asset Deposit | {{ networks.moonbeam.xcm.foreign_asset_deposit.display }} GLMR | === "Moonriver" | Variable | Value | |:--------------:|:-------------------------------------------------:| | Foreign Asset Deposit | {{ networks.moonriver.xcm.foreign_asset_deposit.display }} MOVR | === "Moonbase Alpha" | Variable | Value | |:--------------:|:-------------------------------------------------:| | Foreign Asset Deposit | {{ networks.moonbase.xcm.foreign_asset_deposit.display }} DEV | ## Prerequisites {: #prerequisites } There are a few prerequisites to be aware of: - The sibling parachain's [sovereign account](/builders/interoperability/xcm/core-concepts/sovereign-accounts/){target=\_blank} on Moonbeam must be sufficiently funded to cover the asset deposit and the transaction fees. It's recommended that you have an extra buffer of additional funds for any subsequent transactions. See this [guide to calculating a sovereign account](/builders/interoperability/xcm/core-concepts/sovereign-accounts/){target=\_blank} - Your parachain should support XCM V4 - Your parachain needs bidirectional XCM channels with Moonbeam. See this [guide for information on opening XCM channels with Moonbeam](/builders/interoperability/xcm/xc-registration/xc-integration/){target=\_blank} ## Assemble Your Asset Details {: #assemble-your-asset-details } Before you register your sibling-parachain token on Moonbeam, you'll need to gather four pieces of information: * **`AssetID`**: A deterministic `u128` derived from the token's `multilocation` (see below). * **`Decimals`**: How many decimal places the token uses (for example, `18`). * **`Symbol`**: A short ticker such as `xcTEST`. The ticker should be prepended with `xc`. * **`Name`**: A human-readable name such as `Test Token`. ```typescript const ASSET_ID = 42259045809535163221576417993425387648n; const DECIMALS = 18n; const SYMBOL = "xcTEST"; const NAME = "Test Token"; ``` ### How to Calculate Asset ID {: #calculate-asset-id } To generate a token's asset ID, you'll first need to know its multilocation. `assetLocation` is a SCALE‑encoded multilocation that pinpoints the existing token on your sibling parachain. There are various ways to define assets and your multilocation may including parachain ID, the pallet that manages assets there, and the local asset index. Because the extrinsic executes on Moonbeam, you describe the path from Moonbeam's perspective: first hop up one level to the Relay `("parents": 1)`, then down into your parachain `(Parachain: )`, the pallet, and the asset index. Moonbeam uses this to verify that the caller actually "contains" the asset before allowing any registration or updates. Once you've constructed your multilocation, keep it handy, as you'll need it in the next step. A typical asset multilocation looks like this: ```jsonc { "parents": 1, // Up to Relay "interior": { "X3": [ // Down to sibling para asset { "Parachain": 4 }, { "PalletInstance": 12 }, { "GeneralIndex": 15 } // Arbitrary example values ] } } ``` The XCM tools repo has a helpful [Calculate External Asset Info script](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/calculate-external-asset-info.ts){target=\_blank} that you can use to generate the asset ID programmatically. The script takes two parameters, namely, the multilocation of your asset and the target network (Moonbeam or Moonriver). Call the `calculate-external-asset-info.ts` helper script with your asset's multilocation and target network, as shown below, to easily generate its asset ID. ```bash ts-node scripts/calculate-external-asset-info.ts \ --asset '{"parents":1,"interior":{"X3":[{"Parachain":4},{"PalletInstance":12},{"GeneralIndex":15}]}}' \ --network moonbeam ``` The script will return the `assetID` you are now ready to pass to `evmForeignAssets.createForeignAsset`. ### Derive the XC-20 Address Convert `assetID` to hex, left-pad it to 32 hex chars, and prepend eight `F`s as follows: ```text xc20Address = 0xFFFFFFFF + hex(assetId).padStart(32, '0') ``` The XC-20 address of xcDOT as an example can be calculated like so: === "Formula" ```ts const xc20Address = `0xFFFFFFFF${hex(assetId).padStart(32, "0")}`; ``` === "Example" ```bash 0xFFFFFFFF1FCACBD218EDC0EBA20FC2308C778080 ``` ## Generate the Encoded Call Data {: #generate-the-encoded-call-data } The snippet below shows how to build the call that needs to be sent to Moonbeam that creates the foreign asset. Save the resulting hex string because you will embed it inside a subsequent XCM `Transact` call dispatched from your sibling parachain. ```ts import '@moonbeam-network/api-augment'; import { ApiPromise, WsProvider } from '@polkadot/api'; import { blake2AsHex } from '@polkadot/util-crypto'; const moonbeam = await ApiPromise.create({ provider: new WsProvider(MOONBEAM_WSS), }); const tx = moonbeam.tx.evmForeignAssets.createForeignAsset( ASSET_ID, assetLocation, DECIMALS, SYMBOL, NAME ); // SCALE-encoded call data (includes call index 0x3800) const encodedCall = tx.method.toHex(); console.log('Encoded call data:', encodedCall); // Optional: 32-byte call hash (blake2_256) console.log('Call hash:', blake2AsHex(encodedCall)); ``` ### Dispatch the Call with XCM Transact {: #dispatch-the-call-with-xcm-transact } To register your asset, wrap the SCALE‑encoded `createForeignAsset` bytes in a single `Transact` instruction executed from your parachain's sovereign account. The basic structure of the call is outlined below: ```text Transact { originKind: SovereignAccount, requireWeightAtMost: , call: } ``` Send the transact instruction via `xcmPallet.send`, targeting parachain `2004` for Moonbeam (or `2023` for Moonriver). ```rust xcmPallet.send( dest: { Parachain: 2004 }, message: VersionedXcm::V4(INSERT_TRANSACT_INSTRUCTION) ); ``` Finally, look for the following event emitted successfully on Moonbeam: ```text EvmForeignAssets.ForeignAssetCreated(assetId, location, creator) ``` Its presence confirms the XC-20 asset is live. ## Managing an Existing Foreign Asset {: #managing-an-existing-foreign-asset } After a foreign asset has been created, the following extrinsics can be used to update it. Note that in the case of the sovereign account sending a call, the sovereign account and location must still be inside the origin. Otherwise, the only other authorized origin is `Root` from a Moonbeam governance action. | Extrinsic | Who can call? | Notes | |-----------------------------------------------|--------------------------------------------------|-------------------------------------------------------| | `changeXcmLocation` | Sibling sovereign account or Moonbeam governance | Requires deposit already reserved. | | `freezeForeignAsset` / `unfreezeForeignAsset` | Sibling sovereign account or Moonbeam governance | `freeze` optionally destroys the asset's metadata. | ## FAQs {: #faqs } ### How do I reclaim the deposit? Deposits remain reserved for the life of the asset. If the asset is destroyed through governance, the deposit is unreserved and returned to the original sovereign account. ### Can a normal EOA register an asset? No. Calls from non‑sovereign, non‑governance accounts fail with `BadOrigin`. ### What happens if my XCM location is outside my origin? The call is rejected with `LocationOutsideOfOrigin`. Double‑check the `Parachain`, `PalletInstance`, and `GeneralIndex` fields. ### Is there a limit to how many assets can be created? Yes, there is a limit of `256` foreign assets per network (e.g., Moonbeam, Moonriver). Attempts beyond this return `TooManyForeignAssets`. If this threshold is approached, a revision can be made in a future runtime upgrade to lift this limit. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/xc-registration/xc-integration/ --- BEGIN CONTENT --- --- title: Open a Cross-Chain Channel description: Learn how to establish a cross-chain integration with a Moonbeam-based network. Including opening and accepting an HRMP channel and registering assets. categories: XCM, Integrations --- # How to Establish an XC Integration with Moonbeam ## Introduction {: #introduction } While Cross-Chain Message Passing (XCMP) is being developed, a stop-gap protocol has been implemented called Horizontal Relay-routed Message Passing (HRMP). It has the same interface and functionality as XCMP, but the messages are stored in and read from the relay chain. Whereas with XCMP, only the message's associated metadata is stored in the relay chain. Since all messages are passed via the relay chain with HRMP, it is much more demanding on resources. As such, HRMP will be phased out once XCMP is implemented. All XCMP channel integrations with Moonbeam are unidirectional, meaning messages flow only in one direction. If chain A initiates a channel to chain B, chain A will only be allowed to send messages to B, and B will not be able to send messages back to chain A. As such, chain B will also need to initiate a channel with chain A to send messages back and forth between the two chains. Once the XCMP (or HRMP) channels have been opened, the corresponding assets from both chains will need to be registered on the opposing chain before being able to be transferred. To find step-by-step details on how to register an asset, you can refer to the [How to Register Cross-Chain Assets](/builders/interoperability/xcm/xc-registration/assets/){target=\_blank} guide. This guide will cover the process of opening and accepting an HRMP channel between a parachain and a Moonbeam-based network. In addition, the guide provides the necessary steps to create a batch proposal that combines opening and accepting a channel and registering an asset on Moonbeam into a single proposal. All of the examples in this guide use a CLI tool developed to ease the entire process, which you can find in the [xcm-tools GitHub repository](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank}. ```bash git clone https://github.com/Moonsong-Labs/xcm-tools && \ cd xcm-tools && \ yarn ``` ## Moonbase Alpha XCM Integration Overview {: #moonbase-alpha-xcm } The first step for a Moonriver/Moonbeam XCM integration is to integrate with the Moonbase Alpha TestNet through the Alphanet relay chain. Then a Moonriver integration must be completed before proceeding with Moonbeam (if applicable). The entire process of getting started with Moonbase Alpha can be summarized as follows: 1. [Sync a node](#sync-a-node) with the Alphanet relay chain 2. [Calculate your parachain Sovereign account](#calculate-and-fund-the-parachain-sovereign-account) on the Alphanet relay chain 3. Once your node is fully synced, please get in touch with the Moonbeam team on [Telegram](https://t.me/Moonbeam_Official){target=\_blank} or [Discord](https://discord.com/invite/PfpUATX){target=\_blank}, so the team can onboard your parachain to the relay chain. Provide the following information for onboarding: - The WASM/Genesis head hash - Your parachain ID - Your Sovereign account's address. The Moonbeam team will fund your Sovereign account at the relay chain level. This step is required to be able to create the HRMP channel - The encoded call data to open an HRMP channel to your parachain, accept the incoming HRMP channel, and [register the assets](/builders/interoperability/xcm/xc-registration/assets/#register-xc-20s){target=\_blank} (if applicable). This will be executed through sudo 4. Open an HRMP channel to Moonbase Alpha from your parachain (through sudo or via governance) 5. Accept the HRMP channel from Moonbase Alpha (through sudo or via governance) 6. (Optional) [Register Moonbase Alpha's DEV token](/builders/interoperability/xcm/xc-registration/assets/#register-moonbeam-native-assets){target=\_blank} on your parachain 7. For testing the XCM integration, please send some tokens to: ```text AccountId (Encoded): 5GWpSdqkkKGZmdKQ9nkSF7TmHp6JWt28BMGQNuG4MXtSvq3e Decoded (32-Bytes): 0xc4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a063 ``` 8. Test the XCM integration ![Moonbase Alpha cross-chain integration process](/images/builders/interoperability/xcm/xc-registration/xc-integration/channels-1.webp) Once all of these steps are completed and both teams have successfully tested asset transfers, your parachain token can be added to the **Cross Chain Assets** section of the [Moonbeam DApp](https://apps.moonbeam.network/moonbase-alpha){target=\_blank}. If deposits and withdrawals work as expected, integration with Moonriver can begin. ### Sync a Node {: #sync-a-node } To sync a node, you can use the [Alphanet relay chain specs](https://raw.githubusercontent.com/moonbeam-foundation/moonbeam/refs/heads/master/specs/alphanet/westend-embedded-specs-v8.json){target=\_blank} (note: the relay chain is Westend-based, and will probably take one day to sync). For reference, you can use [Moonbase Alpha's spec file](https://raw.githubusercontent.com/moonbeam-foundation/moonbeam/runtime-1103/specs/alphanet/parachain-embedded-specs-v8.json){target=\_blank}. You'll need to adapt it to your chain. There are also some [snapshots for the Alphanet ecosystem relay chain](https://www.certhum.com/moonbase-databases){target=\_blank} you can use to quickly get started, these are provided by the community. ### Calculate and Fund the Parachain Sovereign Account {: #calculate-and-fund-the-parachain-sovereign-account } You can calculate the Sovereign account information using [a script from the xcm-tools repository](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank}. To run the script, you must provide the parachain ID and the name of the associated relay chain. You can find the parachain IDs that have already been used on the [relay chain's Polkadot.js Apps page](https://polkadot.js.org/apps/?rpc=wss://relay.api.moonbase.moonbeam.network#/parachains){target=\_blank}. The accepted values for the relay chain are `polkadot` (default), `kusama`, and `moonbase`. For example, Moonbase Alpha's Sovereign account for both the relay chain and other parachains can be obtained with the following: ```bash yarn calculate-sovereign-account --p 1000 --r moonbase ``` Which should result in the following response: ```text Sovereign Account Address on Relay: 0x70617261e8030000000000000000000000000000000000000000000000000000 Sovereign Account Address on other Parachains (Generic): 0x7369626ce8030000000000000000000000000000000000000000000000000000 Sovereign Account Address on Moonbase Alpha: 0x7369626ce8030000000000000000000000000000 ``` ## Moonriver & Moonbeam XCM Integration Overview {: #moonriver-moonbeam } From a technical perspective, the process of creating an HRMP channel with Moonriver and Moonbeam is nearly identical. However, engagement with the Moonbeam community is crucial and required before a proposal will pass. Please check the HRMP channel guidelines that the community voted on for [Moonriver](https://moonriver.polkassembly.io/referenda/0){target=\_blank} and [Moonbeam](https://moonbeam.polkassembly.io/proposal/21){target=\_blank} before starting. The process can be summarized in the following steps: 1. Open (or ensure there is) an HRMP channel from your chain to Moonriver/Moonbeam. Optionally, register MOVR/GLMR 2. Create [two Moonbeam Community forum posts](#create-forum-posts) with some key information for the XCM integration: - An [XCM Disclosure post](/builders/interoperability/xcm/xc-registration/forum-templates/#xcm-disclosure), where you'll provide some disclosures about the project, the code base, and social network channels - An [XCM Proposal post](/builders/interoperability/xcm/xc-registration/forum-templates/#xcm-proposals), where you'll provide some technical information about the proposal itself 3. Create a batch proposal on Moonbeam/Moonriver to: 1. Accept the incoming HRMP channel 2. Propose the opening of an outgoing HRMP channel from Moonriver/Moonbeam 3. Register the asset as an [XC-20 token](/builders/interoperability/xcm/xc20/overview/){target=\_blank} (if applicable) Proposals should be done in the General Admin Track from [OpenGov](/learn/features/governance/#opengov){target=\_blank}. The normal enactment times are as follows: - **Moonriver** - the Decision Period is approximately {{ networks.moonriver.governance.tracks.general_admin.decision_period.time }} and the enactment time is at least {{ networks.moonriver.governance.tracks.general_admin.min_enactment_period.time }} - **Moonbeam** - the Decision Period is approximately {{ networks.moonbeam.governance.tracks.general_admin.decision_period.time }} and the enactment time is at least {{ networks.moonbeam.governance.tracks.general_admin.min_enactment_period.time }} 4. Accept the HRMP channel from Moonriver/Moonbeam on the connecting parachain 5. Exchange $50 worth of tokens for testing the XCM integration. Please send the tokens to: ```text AccountId (Encoded): 5E6kHM4zFdH5KEJE3YEzX5QuqoETVKUQadeY8LVmeh2HyHGt Decoded (32-Bytes): 0x5a071f642798f89d68b050384132eea7b65db483b00dbb05548d3ce472cfef48 ``` 6. Provide an Ethereum-styled address for MOVR/GLMR 7. Test the XCM integration with the provided tokens An example of this process with a successful proposal on Moonbeam is depicted in the following diagram. ![Moonbeam and Moonriver cross-chain integration process](/images/builders/interoperability/xcm/xc-registration/xc-integration/channels-2.webp) Once these steps are successfully completed, marketing efforts can be coordinated, and the new XC-20 on Moonriver/Moonbeam can be added to the **Cross Chain Assets** section of the [Moonbeam DApp](https://apps.moonbeam.network){target=\_blank}. ### Create Forum Posts {: #create-forum-posts } To create forum posts on the [Moonbeam Community Forum](https://forum.moonbeam.network){target=\_blank}, you'll need to make sure that you're adding the posts to the correct category and adding relevant content. For general guidelines and templates to follow, please refer to the [Moonbeam Community Forum Templates for XCM Integrations](/builders/interoperability/xcm/xc-registration/forum-templates/#){target=\_blank} page. ## Creating HRMP Channels {: #create-an-hrmp-channel } Before any messages can be sent from your parachain to Moonbeam, an HRMP channel must be opened. To create an HRMP channel, you'll need to send an XCM message to the relay chain that will request a channel be opened through the relay chain. The message will need to contain **at least** the following XCM instructions: 1. [WithdrawAsset](/builders/interoperability/xcm/core-concepts/instructions/#withdraw-asset){target=\_blank} - takes funds out of the Sovereign account (in the relay chain) of the origin parachain to a holding state 2. [BuyExecution](/builders/interoperability/xcm/core-concepts/instructions/#buy-execution){target=\_blank} - buys execution time from the relay chain to execute the XCM message 3. [Transact](/builders/interoperability/xcm/core-concepts/instructions/#transact){target=\_blank} - provides the relay chain call data to be executed. In this case, the call will be an HRMP extrinsic !!! note You can add [DepositAsset](/builders/interoperability/xcm/core-concepts/instructions/#deposit-asset){target=\_blank} to refund the leftover funds after the execution. If this is not provided, no refunds will be made. In addition, you could also add a [RefundSurplus](/builders/interoperability/xcm/core-concepts/instructions/#refund-surplus){target=\_blank} after [Transact](/builders/interoperability/xcm/core-concepts/instructions/#transact){target=\_blank} to get any leftover funds not used for the Transact. But you'll have to calculate if it is worth paying the execution cost of the extra XCM instructions. To send these XCM messages to the relay chain, the [Polkadot XCM Pallet](https://github.com/paritytech/polkadot-sdk/tree/{{ polkadot_sdk }}/polkadot/xcm/pallet-xcm){target=\_blank} is typically invoked. Moonbeam also has an [XCM Transactor Pallet](/builders/interoperability/xcm/remote-execution/substrate-calls/xcm-transactor-pallet/){target=\_blank} that simplifies the process into a call that abstracts the XCM messaging constructor. You could potentially generate the calldata for an HRMP action by using Polkadot.js Apps, but the [xcm-tools GitHub repository](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank} can build it for you, and it is the recommended tool for this process. ```bash git clone https://github.com/Moonsong-Labs/xcm-tools && \ cd xcm-tools && \ yarn ``` The xcm-tools repository has a specific script for HRMP interactions called [`hrmp-channel-manipulator.ts`](https://github.com/Moonsong-Labs/xcm-tools/blob/main/scripts/hrmp-channel-manipulator.ts){target=\_blank}. This command generates encoded calldata for a specific HRMP action, as long as it is given the correct details. The script builds the XCM message with the DepositAsset XCM instruction but not with RefundSurplus. The encoded calldata is then used to submit a governance proposal that will execute the HRMP action. All HRMP-related proposals should be assigned to the General Admin Track. The `hrmp-channel-manipulator.ts` script is meant to be generic. It should work for any chain that includes the Polkadot XCM Pallet, although it will try to use the `hrmpManage` extrinsic of the XCM Transactor Pallet first. If the XCM Transactor Pallet doesn't exist on a chain, the `send` extrinsic of the Polkadot XCM Pallet will be used. **Note that it expects the pallet name to be `polkadotXcm`, as the extrinsic will be built as `api.tx.polkadotXcm.send()`**. For Moonbeam, the General Admin Track can't execute `polkadotXcm.send` calls, as such the `xcmTransactor.hrmpManage` extrinsic must be used. The following sections go through the steps of creating and accepting open channel requests in a Moonbeam-based network, but they can also be adapted to your parachain. ### Accept an HRMP Channel on Moonbeam {: #accept-an-hrmp-channel-on-moonbeam } When a parachain receives an incoming HRMP channel open request from another parachain, it must signal to the relay chain that it accepts this channel before the channel can be used. This requires an XCM message to the relay chain with the Transact instruction calling the HRMP Pallet and `hrmpAcceptOpenChannel` extrinsic. Fortunately, the [xcm-tools](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank} GitHub repository's `hrmp-channel-manipulator.ts` script can build the XCM for you! To use the script, you'll need to provide the following required arguments: - `--parachain-ws-provider` or `--w` - specifies the parachain WebSocket provider that will be issuing the requests - `--relay-ws-provider` or `--wr` - specifies the relay chain WebSocket provider that will be issuing the requests - `--hrmp-action` or `--hrmp` - accepts the following action to take, which can be any of the following: `accept`, `cancel`, `close`, and `open` - `--target-para-id` or `-p` - the target parachain ID for the requests Running the following command will provide the encoded calldata to accept an open HRMP channel request on a Moonbeam network. Replace `YOUR_PARACHAIN_ID` with the ID of your parachain: === "Moonbeam" ```bash yarn hrmp-manipulator --target-para-id YOUR_PARACHAIN_ID \ --parachain-ws-provider wss://wss.api.moonbeam.network \ --relay-ws-provider wss://rpc.polkadot.io \ --hrmp-action accept ``` === "Moonriver" ```bash yarn hrmp-manipulator --target-para-id YOUR_PARACHAIN_ID \ --parachain-ws-provider wss://wss.api.moonriver.moonbeam.network \ --relay-ws-provider wss://kusama-rpc.polkadot.io \ --hrmp-action accept ``` === "Moonbase Alpha" ```bash yarn hrmp-manipulator --target-para-id YOUR_PARACHAIN_ID \ --parachain-ws-provider wss://wss.api.moonbase.moonbeam.network \ --relay-ws-provider wss://relay.api.moonbase.moonbeam.network \ --hrmp-action accept ``` !!! note You can adapt the script for your parachain by changing the `parachain-ws-provider`. After running the script, you'll see output that looks like the following:
yarn hrmp-manipulator --target-para-id 3370 \ --parachain-ws-provider wss://moonbeam.public.blastapi.io \ --relay-ws-provider wss://polkadot-rpc.publicnode.com \ --hrmp-action accept yarn run v1.22.22 warning ../../../package.json: No license field $ ts-node 'scripts/hrmp-channel-manipulator.ts' --target-para-id 3370 --parachain-ws-provider wss://moonbeam.public.blastapi.io --relay-ws-provider wss://polkadot-rpc.publicnode.com --hrmp-action accept Genesis hash is: 0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3 Polkadot FeeAmount is: 10000000000 XCM Version is V4 Encoded Call Data for Tx is 0x6b09012a0d0000010401000100e40b5402000000000000000000000002286bee020004000100 ✨ Done in 4.39s.
Running the script as shown above will return the encoded calldata to accept an HRMP channel. You can also use the script to create and submit a preimage and proposal on chain for the given HRMP action. For Moonbeam and Moonriver, the proposal must be submitted via the General Admin Track. Please refer to the [README](https://github.com/Moonsong-Labs/xcm-tools/tree/main#hrmp-manipulator-script){target=\_blank} for a complete list of the arguments, including optional arguments, and examples on how to use the HRMP-manipulator script. If you plan to batch the transaction with other calls, copy the resultant calldata for later use when using the [batch transactions](#batch-actions-into-one) script. ### Open HRMP Channels from Moonbeam {: #open-an-hrmp-channel-from-moonbeam } Parachains need bidirectional HRMP channels before sending XCM to each other. The first step to establishing an HRMP channel is to create an open channel request. This requires an XCM message to the relay chain with the Transact instruction calling the HRMP Pallet and `hrmpInitOpenChannel` extrinsic. Fortunately, the [xcm-tools](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank} GitHub repository's `hrmp-channel-manipulator.ts` script can build the XCM for you! To use the script, you'll need to provide the following required arguments: - `--parachain-ws-provider` or `--w` - specifies the parachain WebSocket provider that will be issuing the requests - `--relay-ws-provider` or `--wr` - specifies the relay chain WebSocket provider that will be issuing the requests - `--hrmp-action` or `--hrmp` - accepts the following action to take, which can be any of the following: `accept`, `cancel`, `close`, and `open` - `--target-para-id` or `-p` - the target parachain ID for the requests Running the following command will provide the encoded calldata to create the HRMP channel request from a Moonbeam network. The maximum message size and capacity values can be obtained from the relay chain's Configuration Pallet and `activeConfig` extrinsic. Replace `YOUR_PARACHAIN_ID` with the ID of your parachain: === "Moonbeam" ```bash yarn hrmp-manipulator --target-para-id YOUR_PARACHAIN_ID \ --parachain-ws-provider wss://wss.api.moonbeam.network \ --relay-ws-provider wss://rpc.polkadot.io \ --max-capacity 1000 --max-message-size 102400 \ --hrmp-action open ``` === "Moonriver" ```bash yarn hrmp-manipulator --target-para-id YOUR_PARACHAIN_ID \ --parachain-ws-provider wss://wss.api.moonriver.moonbeam.network \ --relay-ws-provider wss://kusama-rpc.polkadot.io \ --max-capacity 1000 --max-message-size 102400 \ --hrmp-action open ``` === "Moonbase Alpha" ```bash yarn hrmp-manipulator --target-para-id YOUR_PARACHAIN_ID \ --parachain-ws-provider wss://wss.api.moonbase.moonbeam.network \ --relay-ws-provider wss://relay.api.moonbase.moonbeam.network \ --max-capacity 1000 --max-message-size 102400 \ --hrmp-action open ``` !!! note You can adapt the script for your parachain by changing the `parachain-ws-provider`. After running the script, you'll see output that looks like the following:
yarn hrmp-manipulator --target-para-id 3370 \ --parachain-ws-provider wss://moonbeam.public.blastapi.io \ --relay-ws-provider wss://polkadot-rpc.publicnode.com \ --max-capacity 1000 --max-message-size 102400 \ --hrmp-action open yarn run v1.22.22 warning ../../../package.json: No license field $ ts-node 'scripts/hrmp-channel-manipulator.ts' --target-para-id 3370 --parachain-ws-provider wss://moonbeam.public.blastapi.io --relay-ws-provider wss://polkadot-rpc.publicnode.com --max-capacity 1000 --max-message-size 102400 --hrmp-action open Genesis hash is: 0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3 Polkadot FeeAmount is: 10000000000 XCM Version is V4 Encoded Call Data for Tx is 0x6b09002a0d0000e803000000900100010401000100e40b5402000000000000000000000002286bee020004000100 ✨ Done in 4.25s.
Running the script as shown above will return the encoded calldata to open an HRMP channel. You can also use the script to create and submit a preimage and proposal on-chain for the given HRMP action. For Moonbeam and Moonriver, the proposal must be submitted via the General Admin Track. Please refer to the [README](https://github.com/Moonsong-Labs/xcm-tools/tree/main#hrmp-manipulator-script){target=\_blank} for a complete list of the arguments, including optional arguments, and examples on how to use the HRMP-manipulator script. If you plan to batch the transaction with other calls, copy the resultant calldata for later use when using the [batch transactions](#batch-actions-into-one) script. ## Batch Actions Into One {: #batch-actions-into-one } The most efficient way to complete the XCM process on parachains is to batch all transactions together. The [xcm-tools repository](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank} provides a script to batch extrinsic calls into a single call, thus requiring only a single transaction. This can be helpful if your parachain would like to open an HRMP channel and register an asset simultaneously. This **should be used** when proposing channel registration on a Moonbeam network. If you are registering an asset in addition to establishing a channel, please refer to the [How to Register Cross-Chain Assets](/builders/interoperability/xcm/xc-registration/assets/){target=\_blank} guide to learn how to generate the encoded calldata required for asset registration. The process of batching all of the transactions into one is depicted in the following diagram. ![Batch XCM integration process](/images/builders/interoperability/xcm/xc-registration/xc-integration/channels-3.webp) You will now use the encoded calldata outputs for opening a channel, accepting a channel, and registering an asset and insert them into the following command to send the batch proposal to democracy. You can add a `--call "INSERT_CALL"` for each call you want to batch. Replace the following values before running the command: - `OPEN_CHANNEL_CALL` is the SCALE encoded calldata for [opening an HRMP channel](#open-an-hrmp-channel-from-moonbeam) from Moonbeam to your parachain - `ACCEPT_INCOMING_CALL` is the SCALE encoded calldata for [accepting the channel request](#accept-an-hrmp-channel-on-moonbeam) from your parachain - `REGISTER_ASSET_CALL` is the SCALE encoded calldata for [registering a cross-chain asset](/builders/interoperability/xcm/xc-registration/assets/#register-xc-20s){target=\_blank}. If you have more than one asset to be registered on Moonbeam, you can include additional registration SCALE encoded calldata with additional `--call` flags === "Moonbeam" ```bash yarn generic-call-propose -w wss://wss.api.moonbeam.network \ --call "OPEN_CHANNEL_CALL" \ --call "ACCEPT_INCOMING_CALL" \ --call "REGISTER_ASSET_CALL" \ ``` === "Moonriver" ```bash yarn generic-call-propose -w wss://wss.api.moonriver.moonbeam.network \ --call "OPEN_CHANNEL_CALL" \ --call "ACCEPT_INCOMING_CALL" \ --call "REGISTER_ASSET_CALL" \ ``` === "Moonbase Alpha" ```bash yarn generic-call-propose -w wss://wss.api.moonbase.moonbeam.network \ --call "OPEN_CHANNEL_CALL" \ --call "ACCEPT_INCOMING_CALL" \ --call "REGISTER_ASSET_CALL" \ ``` !!! note You can readapt the script for your parachain by changing the `parachain-ws-provider`. With the encoded calldata, you can then submit the governance proposal. For Moonbeam and Moonriver, you must assign the proposal to the General Admin Track. It is recommended to become familiar with the [OpenGov: Governance v2 process on Moonbeam-based networks](/learn/features/governance/#opengov){target=\_blank}. If you want to send the governance proposal directly from the CLI, you'll need to use these additional flags: ```bash --account-priv-key YOUR_PRIVATE_KEY \ --send-preimage-hash true \ --send-proposal-as v2 \ --track '{ "Origins": "GeneralAdmin" }' ``` For Moonbase Alpha, you will not need to provide a private key or go through governance. Instead, you can use the `--sudo` flag and provide the output to the Moonbeam team so that the asset and channel can be added quickly through sudo. Feel free to check out the [additional flags](#additional-flags-xcm-tools) available for this script. ## Additional Flags for XCM-Tools {: #additional-flags-xcm-tools } The [xcm-tools GitHub repository](https://github.com/Moonsong-Labs/xcm-tools){target=\_blank} and most of its functions can be called with some additional flags that create some wrappers around the actions being taken. For example, you might want to wrap the send of the XCM message in sudo, or via a democracy proposal. The complete options that can be used with the script are as follows: | Flag | Type | Description | | :------------------: | :---------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | account-priv-key | string | (Required for send-proposal-as, send-preimage-hash) The private key of the account to send a transaction with | | sudo | boolean | Whether to wrap the extrinsic calldata inside of a `sudo.sudo` extrinsic. If `account-priv-key` is present, it will attempt to send the transaction | | send-preimage-hash | boolean | Whether to submit the encoded calldata as a preimage and retrieve its hash | | send-proposal-as | democracy/council-external/v2 | Whether to send the encoded calldata through democracy or Council (Governance v1), or OpenGov (Governance v2) | | collective-threshold | number | (Required for council-external) The threshold for the Council deciding the proposal | | delay | number | (Required for v2) The number of blocks to delay an OpenGovV2 proposal's execution by | | track | string (JSON encoded origin) | (Required for v2) The JSON encoded origin for an OpenGovV2 proposal. For Moonbeam networks: "Root", "WhitelistedCaller", "GeneralAdmin", "ReferendumCanceller", "ReferendumKiller" | | at-block | number | Whether to wrap the extrinsic calldata inside of a `scheduler.schedule` extrinsic. The block in the future that the action should be scheduled to take place | | fee-currency | string (multilocation) | (Required for non-Moonbeam chains that use XCM Transactor) The multilocation of the relay chain's asset | !!! note The track option must be specified like so: `'{ "Origins": "INSERT_ORIGIN" }'`, where you can insert any of the following as the Origin: "Root", "WhitelistedCaller", "GeneralAdmin", "ReferendumCanceller", "ReferendumKiller". --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/xc20/ --- BEGIN CONTENT --- --- title: Cross-Chain Assets & XC-20s description: Learn about cross-chain assets, referred to as XC-20s, and how to interact with them through the Ethereum API on Moonbeam. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/xc20/interact/ --- BEGIN CONTENT --- --- title: Interact with XC-20s description: Check out the XC-20 Solidity interfaces, including the ERC-20 and ERC-20 Permit interfaces, and how to interact with external XC-20s using these interfaces. categories: XC-20 --- # Interact with XC-20s on Moonbeam ## Introduction {: #introduction } As mentioned in the [XC-20s Overview](/builders/interoperability/xcm/xc20/overview/){target=\_blank} page, XC-20s are a unique asset class on Moonbeam. Although they are Substrate-native assets, they also have an ERC-20 interface and can be interacted with like any other ERC-20. Additionally, the ERC-20 Permit interface is available for all external XC-20s. This guide covers the XC-20 Solidity interfaces, including the standard ERC-20 interface and the ERC-20 Permit interface, and how to interact with external XC-20s using these interfaces. ## XC-20s Solidity Interface {: #xc20s-solidity-interface } Both types of XC-20s have the standard ERC-20 interface. In addition, all external XC-20s also possess the ERC-20 Permit interface. The following two sections describe each of the interfaces separately. ### The ERC-20 Solidity Interface {: #the-erc20-interface } As mentioned, you can interact with XC-20s via an ERC-20 interface. The [ERC20.sol](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/assets-erc20/ERC20.sol){target=\_blank} interface on Moonbeam follows the [EIP-20 Token Standard](https://eips.ethereum.org/EIPS/eip-20){target=\_blank}, which is the standard API interface for tokens within smart contracts. The standard defines the required functions and events that a token contract must implement to be interoperable with different applications. The interface includes the following functions: - **name()** — read-only function that returns the name of the token - **symbol()** — read-only function that returns the symbol of the token - **decimals()** — read-only function that returns the decimals of the token - **totalSupply()** — read-only function that returns the total number of tokens in existence - **balanceOf**(*address* who) — read-only function that returns the balance of the specified address - **allowance**(*address* owner, *address* spender) — read-only function that checks and returns the amount of tokens that a spender is allowed to spend on behalf of the owner - **transfer**(*address* to, *uint256* value) — transfers a given amount of tokens to a specified address and returns `true` if the transfer was successful - **approve**(*address* spender, *uint256* value) — approves the provided address to spend a specified amount of tokens on behalf of `msg.sender`. Returns `true` if successful - **transferFrom**(*address* from, *address* to, *uint256* value) — transfers tokens from one given address to another given address and returns `true` if successful !!! note The ERC-20 standard does not specify the implications of multiple calls to `approve`. Changing an allowance with this function numerous times enables a possible attack vector. To avoid incorrect or unintended transaction ordering, you can first reduce the `spender` allowance to `0` and then set the desired allowance afterward. For more details on the attack vector, you can check out the [ERC-20 API: An Attack Vector on Approve/TransferFrom Methods](https://docs.google.com/document/d/1YLPtQxZu1UAvO9cZ1O2RPXBbT0mooh4DYKjA_jp-RLM/edit#){target=_blank} overview. The interface also includes the following required events: - **Transfer**(*address indexed* from, *address indexed* to, *uint256* value) - emitted when a transfer has been performed - **Approval**(*address indexed* owner, *address indexed* spender, *uint256* value) - emitted when an approval has been registered ### The ERC-20 Permit Solidity Interface {: #the-erc20-permit-interface } External XC-20s also have the ERC-20 Permit interface. The [Permit.sol](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/assets-erc20/Permit.sol){target=\_blank} interface on Moonbeam follows the [EIP-2612 standard](https://eips.ethereum.org/EIPS/eip-2612){target=\_blank}, which extends the ERC-20 interface with the `permit` function. Permits are signed messages that can be used to change an account's ERC-20 allowance. Note that local XC-20s can have also the Permit interface, but it is not a requirement for them to be XCM-ready. The standard ERC-20 `approve` function is limited in its design as the `allowance` can only be modified by the sender of the transaction, the `msg.sender`. This can be seen in [OpenZeppelin's implementation of the ERC-20 interface](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol#L136){target=\_blank}, which sets the `owner` through the [`msgSender` function](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Context.sol#L17){target=\_blank}, which ultimately sets it to `msg.sender`. Instead of signing the `approve` transaction, a user can sign a message, and that signature can be used to call the `permit` function to modify the `allowance`. As such, it allows for gas-less token transfers. In addition, users no longer need to send two transactions to approve and transfer tokens. To see an example of the `permit` function, you can check out [OpenZeppelin's implementation of the ERC-20 Permit extension](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/4a9cc8b4918ef3736229a5cc5a310bdc17bf759f/contracts/token/ERC20/extensions/draft-ERC20Permit.sol#L41){target=\_blank}. The [Permit.sol](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/assets-erc20/Permit.sol){target=\_blank} interface includes the following functions: - **permit**(*address* owner, *address* spender, *uint256*, value, *uint256*, deadline, *uint8* v, *bytes32* r, *bytes32* s) - consumes an approval permit, which can be called by anyone - **nonces**(*address* owner) - returns the current nonce for the given owner - **DOMAIN_SEPARATOR**() - returns the EIP-712 domain separator, which is used to avoid replay attacks. It follows the [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612#specification){target=\_blank} implementation The **DOMAIN_SEPARATOR()** is defined in the [EIP-712 standard](https://eips.ethereum.org/EIPS/eip-712){target=\_blank}, and is calculated as: ```text keccak256(PERMIT_DOMAIN, name, version, chain_id, address) ``` The parameters of the hash can be broken down as follows: - **PERMIT_DOMAIN** - is the `keccak256` of `EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)` - **name** - is the token name but with the following considerations: - If the token has a name defined, the **name** for the domain is `XC20: `, where `` is the token name - If the token has no name defined, the **name** for the domain is `XC20: No name` - **version** - is the version of the signing domain. For this case, **version** is set to `1` - **chainId** - is the chain ID of the network - **verifyingContract** - is the XC-20 address !!! note Prior to runtime upgrade 1600, the **name** field did not follow the standard [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612#specification){target=\_blank} implementation. The calculation of the domain separator can be seen in [Moonbeam's EIP-2612](https://github.com/moonbeam-foundation/moonbeam/blob/perm-runtime-1502/precompiles/assets-erc20/src/eip2612.rs#L130-L154){target=\_blank} implementation, with a practical example shown in [OpenZeppelin's `EIP712` contract](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/4a9cc8b4918ef3736229a5cc5a310bdc17bf759f/contracts/utils/cryptography/draft-EIP712.sol#L70-L84){target=\_blank}. Aside from the domain separator, the [`hashStruct`](https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct){target=\_blank} guarantees that the signature can only be used for the `permit` function with the given function arguments. It uses a given nonce to ensure the signature is not subject to a replay attack. The calculation of the hash struct can be seen in [Moonbeam's EIP-2612](https://github.com/moonbeam-foundation/moonbeam/blob/perm-runtime-1502/precompiles/assets-erc20/src/eip2612.rs#L167-L175){target=\_blank} implementation, with a practical example shown in [OpenZeppelin's `ERC20Permit` contract](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/4a9cc8b4918ef3736229a5cc5a310bdc17bf759f/contracts/token/ERC20/extensions/draft-ERC20Permit.sol#L52){target=\_blank}. The domain separator and the hash struct can be used to build the [final hash](https://github.com/moonbeam-foundation/moonbeam/blob/perm-runtime-1502/precompiles/assets-erc20/src/eip2612.rs#L177-L181){target=\_blank} of the fully encoded message. A practical example is shown in [OpenZeppelin's `EIP712` contract](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/4a9cc8b4918ef3736229a5cc5a310bdc17bf759f/contracts/utils/cryptography/draft-EIP712.sol#L101){target=\_blank}. With the final hash and the `v`, `r`, and `s` values, the signature can be [verified and recovered](https://github.com/moonbeam-foundation/moonbeam/blob/perm-runtime-1502/precompiles/assets-erc20/src/eip2612.rs#L212-L224){target=\_blank}. If successfully verified, the nonce will increase by one and the allowance will be updated. ## Interact with External XC-20s Using an ERC-20 Interface {: #interact-with-the-precompile-using-remix } This section of the guide will show you how to interact with XC-20s via the ERC-20 interface using [Remix](/builders/ethereum/dev-env/remix/){target=\_blank}. Because local XC-20s are representations of regular ERC-20s, this section is focused on external XC-20s. To interact with external XC-20s, you'll need to first calculate the precompile address of the XC-20 asset you want to interact with. Then, you can interact with the ERC-20 interface as you would with any other ERC-20. You can adapt the instructions in this section to be used with the [Permit.sol](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/assets-erc20/Permit.sol){target=\_blank} interface. ### Checking Prerequisites {: #checking-prerequisites } To approve a spend or transfer external XC-20s via the ERC-20 interface, you will need: - [MetaMask installed and connected to the Moonbase Alpha](/tokens/connect/metamask/){target=\_blank} TestNet - Create or have two accounts on Moonbase Alpha - At least one of the accounts will need to be funded with `DEV` tokens. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} ### Calculate External XC-20 Precompile Addresses {: #calculate-xc20-address } Before you can interact with an external XC-20 via the ERC-20 interface, you need to derive the external XC-20's precompile address from the asset ID. The external XC-20 precompile address is calculated using the following: ```text address = '0xFFFFFFFF...' + DecimalToHex(AssetId) ``` Given the above calculation, the first step is to take the *u128* representation of the asset ID and convert it to a hex value. You can use your search engine of choice to look up a simple tool for converting decimals to hex values. For asset ID `42259045809535163221576417993425387648`, the hex value is `1FCACBD218EDC0EBA20FC2308C778080`. External XC-20 precompiles can only fall between `0xFFFFFFFF00000000000000000000000000000000` and `0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF`. Since Ethereum addresses are 40 characters long, you will need to start with the initial eight `F`s and then prepend `0`s to the hex value until the address has 40 characters. The hex value that was already calculated is 32 characters long, so prepending eight `F`s to the hex value will give you the 40-character address you need to interact with the XC-20 precompile. For this example, the full address is `0xFFFFFFFF1FCACBD218EDC0EBA20FC2308C778080`. Now that you've calculated the external XC-20 precompile address, you can use the address to interact with the XC-20 like you would with any other ERC-20 in Remix. ### Add & Compile the Interface {: #add-the-interface-to-remix } You can interact with the ERC-20 interface using [Remix](https://remix.ethereum.org){target=\_blank}. First, you will need to add the interface to Remix: 1. Get a copy of [ERC20.sol](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/assets-erc20/ERC20.sol){target=\_blank} 2. Paste the file contents into a Remix file named **IERC20.sol** ![Load the interface in Remix](/images/builders/interoperability/xcm/xc20/interact/interact-1.webp) Once you have the ERC-20 interface loaded in Remix, you will need to compile it: 1. Click on the **Compile** tab, second from top 2. Compile the **IERC20.sol** file ![Compiling IERC20.sol](/images/builders/interoperability/xcm/xc20/interact/interact-2.webp) If the interface was compiled successfully, you will see a green checkmark next to the **Compile** tab. ### Access the Precompile {: #access-the-precompile } Instead of deploying the ERC-20 precompile, you will access the interface given the address of the XC-20: 1. Click on the **Deploy and Run** tab directly below the **Compile** tab in Remix. Please note that the precompiled contract is already deployed 2. Make sure **Injected Web3** is selected in the **ENVIRONMENT** dropdown. Once you select **Injected Web3**, you might be prompted by MetaMask to connect your account to Remix 3. Make sure the correct account is displayed under **ACCOUNT** 4. Ensure **IERC20 - IERC20.sol** is selected in the **CONTRACT** dropdown. Since this is a precompiled contract, there is no need to deploy any code. Instead, you are going to provide the address of the precompile in the **At Address** field 5. Provide the address of the XC-20. For local XC-20s, which you should have already calculated in the [Calculate External XC-20 Precompile Addresses](#calculate-xc20-address){target=\_blank} section. For this example, you can use `0xFFFFFFFF1FCACBD218EDC0EBA20FC2308C778080` and click **At Address** ![Access the address](/images/builders/interoperability/xcm/xc20/interact/interact-3.webp) !!! note Optionally, you can checksum the XC-20 precompile address by going to your search engine of choice and searching for a tool to checksum the address. Once the address has been checksummed, you can use it in the **At Address** field instead. The **IERC20** precompile for the XC-20 will appear in the list of **Deployed Contracts**. Now you can feel free to call any of the standard ERC-20 functions to get information about the XC-20 or transfer the XC-20. ![Interact with the precompile functions](/images/builders/interoperability/xcm/xc20/interact/interact-4.webp) To learn how to interact with each of the functions, you can check out the [ERC-20 Precompile](/builders/ethereum/precompiles/ux/erc20/){target=\_blank} guide and modify it for interacting with the XC-20 Precompile. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/xc20/overview/ --- BEGIN CONTENT --- --- title: XC-20s and Cross-Chain Assets description: Learn about the types of cross-chain assets on Moonbeam, in particular, local and external XC-20s, and view a list of the external XC-20s on Moonbeam. categories: Basics, XC-20 --- # Overview of XC-20s ## Introduction {: #introduction } The [Cross-Consensus Message (XCM)](https://wiki.polkadot.network/learn/learn-xcm/){target=\_blank} format provides a universal way for blockchains to exchange messages and transfer assets. To extend this interoperability to the EVM, Moonbeam introduced XC-20s, ERC-20 tokens on Moonbeam that are fully compatible with XCM transfers. Any ERC-20 deployed on Moonbeam can be configured as an XC-20, making it accessible to any chain connected via XCM. This allows EVM-focused developers to work with familiar ERC-20 workflows while benefiting from Polkadot’s native cross-chain functionality, all without needing Substrate-specific expertise. From a technical standpoint, local XC-20s are ERC-20 tokens originating on Moonbeam (including bridged tokens deemed native once issued on Moonbeam), whereas external XC-20s are wrapped representations of tokens whose canonical ledger exists on another parachain or the relay chain. In all cases, XC-20s function just like standard ERC-20s—supporting common EVM-based use cases (such as DeFi, DEXs, and lending platforms)—but with the added advantage of seamless cross-chain operability. ![Moonbeam XC-20 XCM Integration With Polkadot](/images/builders/interoperability/xcm/overview/overview-3.webp) This page aims to cover the basics on XC-20s; if you want to learn how to interact with or transfer XC-20s, please refer to the [Send XC-20s guide](/builders/interoperability/xcm/xc20/send-xc20s/overview/){target=\_blank}. ## Types of XC-20s {: #types-of-xc-20s } There are two types of XC-20s: local and external. ### What are Local XC-20s? {: #local-xc20s } Local XC-20s are all ERC-20s that exist on the EVM, and that can be transferred cross-chain through XCM. For local XC-20s to be transferred to another parachain, the asset must be registered on that chain. When transferring local XC-20s, the underlying tokens reside in the destination chain's Sovereign account on Moonbeam. A [sovereign account](/builders/interoperability/xcm/core-concepts/sovereign-accounts/){target=\_blank} is a keyless account governed by a blockchain runtime—rather than an individual—that can hold assets and interact with other chains. Local XC-20s must follow [the ERC-20 interface outlined in this guide](/builders/interoperability/xcm/xc20/interact/#the-erc20-interface){target=\_blank}. They must implement the standard ERC-20 function signatures, including the correct function selector of the `transfer` function as described in [EIP-20](https://eips.ethereum.org/EIPS/eip-20){target=\_blank}. However, additional functionality can still be added as long as it doesn’t break the base methods. Creating a local XC-20 is equivalent to deploying a standard ERC-20 and enabling cross-chain features on any Moonbeam network. ### What are External XC-20s? {: #external-xc20s } External XC-20s are cross-chain tokens originating from another parachain or the relay chain, and they are represented on Moonbeam as ERC-20 tokens. The original tokens remain locked in a Moonbeam sovereign account on their home chain, while the wrapped ERC-20 representation can be freely utilized on Moonbeam. When you transfer external XC-20s, the canonical assets remain in the sovereign account on their source chain, while the ERC-20 representation is what circulates on Moonbeam. External XC-20s all have _xc_ prepended to their names to distinguish them as cross-chain assets. For example, DOT, native to the Polkadot relay chain, is known as xcDOT when represented as an XC-20 on Moonbeam. ### Local XC-20s vs External XC-20s {: #local-xc-20s-vs-external-xc-20s } Local XC-20s are EVM-native ERC-20 tokens whose “home” (or reserve chain) is Moonbeam from a Polkadot perspective. This includes tokens originally bridged in from outside Polkadot (for example, Wormhole-wrapped ETH), because once they’re issued on Moonbeam as ERC-20s, Polkadot views them as local to Moonbeam. When local XC-20s are transferred to another parachain, the tokens move into that chain’s sovereign account on Moonbeam. External XC-20s, on the other hand, are ERC-20 representations of tokens whose canonical ledger remains on another parachain or the relay chain. Moonbeam holds the “wrapped” version, while the underlying tokens stay locked in Moonbeam’s sovereign account on the originating chain. From a cross-chain transfer perspective, local and external XC-20s can be sent through Polkadot’s XCM infrastructure using the Ethereum or Substrate API. Because the underlying asset is an ERC-20 with EVM bytecode following the [EIP-20 token standard](https://eips.ethereum.org/EIPS/eip-20){target=\_blank}, both transfers initiated via the Substrate and Ehereum APIs generate EVM logs visible to EVM-based explorers such as [Moonscan](https://moonscan.io){target=\_blank}. In contrast, you can't send a regular ERC-20 transfer using the Substrate API. Aside from cross-chain transfers through XCM, all other XC-20 interactions (such as querying balances or adjusting allowances) must occur in the EVM. Cross-chain transfers of XC-20s are executed via the Polkadot XCM Pallet, which utilizes regular mint, burn, and transfer mechanisms of ERC-20s for the XCM asset flow. If you’d like to learn how to send XC-20s using that pallet, refer to the [Using the Polkadot XCM Pallet](/builders/interoperability/xcm/xc20/send-xc20s/xcm-pallet/){target=\_blank} guide. ## Asset Reserves {: #asset-reserves } When transferring tokens across chains in the Polkadot or Kusama ecosystems, each token has a “reserve” chain that holds its canonical ledger—the source of truth for minting, burning, and supply management. For XC-20s, understanding which chain is the reserve determines whether the asset is managed locally on Moonbeam or remotely on another chain. Regardless of where the reserve is located, XC-20s on Moonbeam are still ERC-20 tokens that developers and users can interact with in the EVM. However, from an XCM perspective, the reserve chain determines how the tokens are locked, unlocked, minted, or burned behind the scenes when performing cross-chain operations. ### Local Reserve Assets {: #local-reserve-assets } A local reserve asset on Moonbeam is a token whose canonical ledger—from an XCM perspective—resides natively on Moonbeam. In other words, Moonbeam is the asset’s home chain, where minting and burning take place. For example, Wormhole-wrapped ETH (wETH) is considered a local reserve asset on Moonbeam, even though Ethereum is the ultimate source of ETH. Once ETH is wrapped by Wormhole and enters the Polkadot ecosystem via Moonbeam, wETH can be transferred to other parachains through [Moonbeam Routed Liquidity (MRL)](/builders/interoperability/mrl/){target=\_blank}. The important caveat is that, on a purely Ethereum-level view, ETH remains governed by and minted on Ethereum. However, from an XCM standpoint, wETH on Moonbeam is treated as a local reserve asset, meaning the canonical supply of wETH (as far as Polkadot ecosystems are concerned) exists on Moonbeam. ### Remote Reserve Assets {: #remote-reserve-assets } A remote reserve asset is a token whose canonical ledger—the source of truth for minting and burning—resides on a chain different from where it’s currently in use. In the case of xcDOT on Moonbeam, the underlying DOT tokens representing the xcDOT remain locked in Moonbeam’s sovereign account on the Polkadot relay chain, while xcDOT functions as a wrapped representation in Moonbeam’s EVM environment. Users can hold and transact with xcDOT on Moonbeam (for DeFi, governance, and more), knowing that the underlying DOT is safely locked on the relay chain. At any point, the wrapped xcDOT can be redeemed for the original DOT, effectively burning the xcDOT and unlocking the corresponding DOT tokens on Polkadot. ## Current List of External XC-20s {: #current-xc20-assets } The current list of available external XC-20 assets per network is as follows: === "Moonbeam" | Origin | Symbol | XC-20 Address | |:---------------------:|:---------:|:------------------------------------------------------------------------------------------------------------------------------------:| | Polkadot | xcDOT | [0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080](https://moonscan.io/token/0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080){target=\_blank} | | Acala | xcaUSD | [0xfFfFFFFF52C56A9257bB97f4B2b6F7B2D624ecda](https://moonscan.io/token/0xfFfFFFFF52C56A9257bB97f4B2b6F7B2D624ecda){target=\_blank} | | Acala | xcACA | [0xffffFFffa922Fef94566104a6e5A35a4fCDDAA9f](https://moonscan.io/token/0xffffFFffa922Fef94566104a6e5A35a4fCDDAA9f){target=\_blank} | | Acala | xcLDOT | [0xFFfFfFffA9cfFfa9834235Fe53f4733F1b8B28d4](https://moonscan.io/token/0xFFfFfFffA9cfFfa9834235Fe53f4733F1b8B28d4){target=\_blank} | | Apillon | xcNCTR | [0xFfFFfFfF8A9736B44EbF188972725bED67BF694E](https://moonscan.io/token/0xFfFFfFfF8A9736B44EbF188972725bED67BF694E){target=\_blank} | | Astar | xcASTR | [0xFfFFFfffA893AD19e540E172C10d78D4d479B5Cf](https://moonscan.io/token/0xFfFFFfffA893AD19e540E172C10d78D4d479B5Cf){target=\_blank} | | Bifrost | xcBNC | [0xFFffffFf7cC06abdF7201b350A1265c62C8601d2](https://moonscan.io/token/0xFFffffFf7cC06abdF7201b350A1265c62C8601d2){target=\_blank} | | Bifrost | xcBNCS | [0xfFfffffF6aF229AE7f0F4e0188157e189a487D59](https://moonscan.io/token/0xfFfffffF6aF229AE7f0F4e0188157e189a487D59){target=\_blank} | | Bifrost | xcFIL | [0xfFFfFFFF6C57e17D210DF507c82807149fFd70B2](https://moonscan.io/token/0xfFFfFFFF6C57e17D210DF507c82807149fFd70B2){target=\_blank} | | Bifrost | xcvASTR | [0xFffFffff55C732C47639231a4C4373245763d26E](https://moonscan.io/token/0xFffFffff55C732C47639231a4C4373245763d26E){target=\_blank} | | Bifrost | xcvBNC | [0xffFffFff31d724194b6A76e1d639C8787E16796b](https://moonscan.io/token/0xffFffFff31d724194b6A76e1d639C8787E16796b){target=\_blank} | | Bifrost | xcvDOT | [0xFFFfffFf15e1b7E3dF971DD813Bc394deB899aBf](https://moonscan.io/token/0xFFFfffFf15e1b7E3dF971DD813Bc394deB899aBf){target=\_blank} | | Bifrost | xcvFIL | [0xFffffFffCd0aD0EA6576B7b285295c85E94cf4c1](https://moonscan.io/token/0xFffffFffCd0aD0EA6576B7b285295c85E94cf4c1){target=\_blank} | | Bifrost | xcvGLMR | [0xFfFfFFff99dABE1a8De0EA22bAa6FD48fdE96F6c](https://moonscan.io/token/0xFfFfFFff99dABE1a8De0EA22bAa6FD48fdE96F6c){target=\_blank} | | Bifrost | xcvMANTA | [0xFFfFFfFfdA2a05FB50e7ae99275F4341AEd43379](https://moonscan.io/token/0xFFfFFfFfdA2a05FB50e7ae99275F4341AEd43379){target=\_blank} | | Centrifuge | xcCFG | [0xFFfFfFff44bD9D2FFEE20B25D1Cf9E78Edb6Eae3](https://moonscan.io/token/0xFFfFfFff44bD9D2FFEE20B25D1Cf9E78Edb6Eae3){target=\_blank} | | Composable | xcIBCMOVR | [0xFfFfffFF3AFcd2cAd6174387df17180a0362E592](https://moonscan.io/token/0xFfFfffFF3AFcd2cAd6174387df17180a0362E592){target=\_blank} | | Composable | xcIBCPICA | [0xfFFFFfFFABe9934e61db3b11be4251E6e869cf59](https://moonscan.io/token/0xfFFFFfFFABe9934e61db3b11be4251E6e869cf59){target=\_blank} | | Composable | xcIBCIST | [0xfFfFffff6A3977d5B65D1044FD744B14D9Cef932](https://moonscan.io/token/0xfFfFffff6A3977d5B65D1044FD744B14D9Cef932){target=\_blank} | | Composable | xcIBCBLD | [0xFffFffff9664be0234ea4dc64558F695C4f2A9EE](https://moonscan.io/token/0xFffFffff9664be0234ea4dc64558F695C4f2A9EE){target=\_blank} | | Composable | xcIBCTIA | [0xFFFfFfff644a12F6F01b754987D175F5A780A75B](https://moonscan.io/token/0xFFFfFfff644a12F6F01b754987D175F5A780A75B){target=\_blank} | | Composable | xcIBCATOM | [0xffFFFffF6807D5082ff2f6F86BdE409245e2D953](https://moonscan.io/token/0xffFFFffF6807D5082ff2f6F86BdE409245e2D953){target=\_blank} | | Darwinia | xcRING | [0xFfffFfff5e90e365eDcA87fB4c8306Df1E91464f](https://moonscan.io/token/0xFfffFfff5e90e365eDcA87fB4c8306Df1E91464f){target=\_blank} | | DED | xcDED | [0xfFffFFFf5da2d7214D268375cf8fb1715705FdC6](https://moonscan.io/token/0xfFffFFFf5da2d7214D268375cf8fb1715705FdC6){target=\_blank} | | Equilibrium | xcEQ | [0xFffFFfFf8f6267e040D8a0638C576dfBa4F0F6D6](https://moonscan.io/token/0xFffFFfFf8f6267e040D8a0638C576dfBa4F0F6D6){target=\_blank} | | Equilibrium | xcEQD | [0xFFffFfFF8cdA1707bAF23834d211B08726B1E499](https://moonscan.io/token/0xFFffFfFF8cdA1707bAF23834d211B08726B1E499){target=\_blank} | | HydraDX | xcHDX | [0xFFFfFfff345Dc44DDAE98Df024Eb494321E73FcC](https://moonscan.io/token/0xFFFfFfff345Dc44DDAE98Df024Eb494321E73FcC){target=\_blank} | | Interlay | xcIBTC | [0xFFFFFfFf5AC1f9A51A93F5C527385edF7Fe98A52](https://moonscan.io/token/0xFFFFFfFf5AC1f9A51A93F5C527385edF7Fe98A52){target=\_blank} | | Interlay | xcINTR | [0xFffFFFFF4C1cbCd97597339702436d4F18a375Ab](https://moonscan.io/token/0xFffFFFFF4C1cbCd97597339702436d4F18a375Ab){target=\_blank} | | Manta | xcMANTA | [0xfFFffFFf7D3875460d4509eb8d0362c611B4E841](https://moonscan.io/token/0xfFFffFFf7D3875460d4509eb8d0362c611B4E841){target=\_blank} | | Nodle | xcNODL | [0xfffffffFe896ba7Cb118b9Fa571c6dC0a99dEfF1](https://moonscan.io/token/0xfffffffFe896ba7Cb118b9Fa571c6dC0a99dEfF1){target=\_blank} | | OriginTrail Parachain | xcNEURO | [0xFfffffFfB3229c8E7657eABEA704d5e75246e544](https://moonscan.io/token/0xFfffffFfB3229c8E7657eABEA704d5e75246e544){target=\_blank} | | Parallel | xcPARA | [0xFfFffFFF18898CB5Fe1E88E668152B4f4052A947](https://moonscan.io/token/0xFfFffFFF18898CB5Fe1E88E668152B4f4052A947){target=\_blank} | | Peaq | xcPEAQ | [0xFffFFFFFEC4908b74688a01374f789B48E9a3eab](https://moonscan.io/token/0xFffFFFFFEC4908b74688a01374f789B48E9a3eab){target=\_blank} | | Pendulum | xcPEN | [0xffFFfFFf2257622F345E1ACDe0D4f46D7d1D77D0](https://moonscan.io/token/0xffFFfFFf2257622F345E1ACDe0D4f46D7d1D77D0){target=\_blank} | | Phala | xcPHA | [0xFFFfFfFf63d24eCc8eB8a7b5D0803e900F7b6cED](https://moonscan.io/token/0xFFFfFfFf63d24eCc8eB8a7b5D0803e900F7b6cED){target=\_blank} | | Polkadex | xcPDEX | [0xfFffFFFF43e0d9b84010b1b67bA501bc81e33C7A](https://moonscan.io/token/0xfFffFFFF43e0d9b84010b1b67bA501bc81e33C7A){target=\_blank} | | Polkadot Asset Hub | xcPINK | [0xfFfFFfFf30478fAFBE935e466da114E14fB3563d](https://moonscan.io/token/0xfFfFFfFf30478fAFBE935e466da114E14fB3563d){target=\_blank} | | Polkadot Asset Hub | xcSTINK | [0xFffFffFf54c556bD1d0F64ec6c78f1B477525E56](https://moonscan.io/token/0xFffFffFf54c556bD1d0F64ec6c78f1B477525E56){target=\_blank} | | Polkadot Asset Hub | xcUSDC | [0xFFfffffF7D2B0B761Af01Ca8e25242976ac0aD7D](https://moonscan.io/token/0xFFfffffF7D2B0B761Af01Ca8e25242976ac0aD7D){target=\_blank} | | Polkadot Asset Hub | xcUSDT | [0xFFFFFFfFea09FB06d082fd1275CD48b191cbCD1d](https://moonscan.io/token/0xFFFFFFfFea09FB06d082fd1275CD48b191cbCD1d){target=\_blank} | | Polkadot Asset Hub | xcWIFD | [0xfffffffF2e1D1ac9eA1686255bEfe995B31abc96](https://moonscan.io/token/0xfffffffF2e1D1ac9eA1686255bEfe995B31abc96){target=\_blank} | | Snowbridge | WBTC.e | [0xfFffFFFf1B4Bb1ac5749F73D866FfC91a3432c47](https://moonscan.io/address/0xffffffff1B4BB1AC5749F73D866FFC91A3432C47){target=\_blank} | | Snowbridge | wstETH.e | [0xFfFFFfFF5D5DEB44BF7278DEE5381BEB24CB6573](https://moonscan.io/token/0xFfFFFfFF5D5DEB44BF7278DEE5381BEB24CB6573){target=\_blank} | | Snowbridge | WETH.e | [0xfFffFFFF86829AFE1521AD2296719DF3ACE8DED7](https://moonscan.io/token/0xfFffFFFF86829AFE1521AD2296719DF3ACE8DED7){target=\_blank} | | Subsocial | xcSUB | [0xfFfFffFf43B4560Bc0C451a3386E082bff50aC90](https://moonscan.io/token/0xfFfFffFf43B4560Bc0C451a3386E082bff50aC90){target=\_blank} | | Unique | xcUNQ | [0xFffffFFFD58f77E6693CFB99EbE273d73C678DC2](https://moonscan.io/token/0xFffffFFFD58f77E6693CFB99EbE273d73C678DC2){target=\_blank} | | Zeitgeist | xcZTG | [0xFFFFfffF71815ab6142E0E20c7259126C6B40612](https://moonscan.io/token/0xFFFFfffF71815ab6142E0E20c7259126C6B40612){target=\_blank} | _*You can check each [Asset ID](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbeam.network#/assets){target=\_blank} on Polkadot.js Apps_ === "Moonriver" | Origin | Symbol | XC-20 Address | |:----------------:|:-------:|:--------------------------------------------------------------------------------------------------------------------------------------------:| | Kusama | xcKSM | [0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080](https://moonriver.moonscan.io/token/0xffffffff1fcacbd218edc0eba20fc2308c778080){target=\_blank} | | Bifrost | xcBNC | [0xFFfFFfFFF075423be54811EcB478e911F22dDe7D](https://moonriver.moonscan.io/token/0xFFfFFfFFF075423be54811EcB478e911F22dDe7D){target=\_blank} | | Bifrost | xcvBNC | [0xFFffffff3646A00f78caDf8883c5A2791BfCDdc4](https://moonriver.moonscan.io/token/0xFFffffff3646A00f78caDf8883c5A2791BfCDdc4){target=\_blank} | | Bifrost | xcvKSM | [0xFFffffFFC6DEec7Fc8B11A2C8ddE9a59F8c62EFe](https://moonriver.moonscan.io/token/0xFFffffFFC6DEec7Fc8B11A2C8ddE9a59F8c62EFe){target=\_blank} | | Bifrost | xcvMOVR | [0xfFfffFfF98e37bF6a393504b5aDC5B53B4D0ba11](https://moonriver.moonscan.io/token/0xfFfffFfF98e37bF6a393504b5aDC5B53B4D0ba11){target=\_blank} | | Calamari | xcKMA | [0xffffffffA083189F870640B141AE1E882C2B5BAD](https://moonriver.moonscan.io/token/0xffffffffA083189F870640B141AE1E882C2B5BAD){target=\_blank} | | Crab | xcCRAB | [0xFFFffFfF8283448b3cB519Ca4732F2ddDC6A6165](https://moonriver.moonscan.io/token/0xFFFffFfF8283448b3cB519Ca4732F2ddDC6A6165){target=\_blank} | | Crust-Shadow | xcCSM | [0xffFfFFFf519811215E05eFA24830Eebe9c43aCD7](https://moonriver.moonscan.io/token/0xffFfFFFf519811215E05eFA24830Eebe9c43aCD7){target=\_blank} | | Heiko | xcHKO | [0xffffffFF394054BCDa1902B6A6436840435655a3](https://moonriver.moonscan.io/token/0xffffffFF394054BCDa1902B6A6436840435655a3){target=\_blank} | | Integritee | xcTEER | [0xFfFfffFf4F0CD46769550E5938F6beE2F5d4ef1e](https://moonriver.moonscan.io/token/0xFfFfffFf4F0CD46769550E5938F6beE2F5d4ef1e){target=\_blank} | | Karura | xcKAR | [0xFfFFFFfF08220AD2E6e157f26eD8bD22A336A0A5](https://moonriver.moonscan.io/token/0xFfFFFFfF08220AD2E6e157f26eD8bD22A336A0A5){target=\_blank} | | Karura | xcaSEED | [0xFfFffFFfa1B026a00FbAA67c86D5d1d5BF8D8228](https://moonriver.moonscan.io/token/0xFfFffFFfa1B026a00FbAA67c86D5d1d5BF8D8228){target=\_blank} | | Khala | xcPHA | [0xffFfFFff8E6b63d9e447B6d4C45BDA8AF9dc9603](https://moonriver.moonscan.io/token/0xffFfFFff8E6b63d9e447B6d4C45BDA8AF9dc9603){target=\_blank} | | Kintsugi | xcKINT | [0xfffFFFFF83F4f317d3cbF6EC6250AeC3697b3fF2](https://moonriver.moonscan.io/token/0xfffFFFFF83F4f317d3cbF6EC6250AeC3697b3fF2){target=\_blank} | | Kintsugi | xckBTC | [0xFFFfFfFfF6E528AD57184579beeE00c5d5e646F0](https://moonriver.moonscan.io/token/0xFFFfFfFfF6E528AD57184579beeE00c5d5e646F0){target=\_blank} | | Kusama Asset Hub | xcRMRK | [0xffffffFF893264794d9d57E1E0E21E0042aF5A0A](https://moonriver.moonscan.io/token/0xffffffFF893264794d9d57E1E0E21E0042aF5A0A){target=\_blank} | | Kusama Asset Hub | xcUSDT | [0xFFFFFFfFea09FB06d082fd1275CD48b191cbCD1d](https://moonriver.moonscan.io/token/0xFFFFFFfFea09FB06d082fd1275CD48b191cbCD1d){target=\_blank} | | Litmus | xcLIT | [0xfffFFfFF31103d490325BB0a8E40eF62e2F614C0](https://moonriver.moonscan.io/token/0xfffFFfFF31103d490325BB0a8E40eF62e2F614C0){target=\_blank} | | Mangata | xcMGX | [0xffFfFffF58d867EEa1Ce5126A4769542116324e9](https://moonriver.moonscan.io/token/0xffFfFffF58d867EEa1Ce5126A4769542116324e9){target=\_blank} | | Picasso | xcPICA | [0xFffFfFFf7dD9B9C60ac83e49D7E3E1f7A1370aD2](https://moonriver.moonscan.io/token/0xFffFfFFf7dD9B9C60ac83e49D7E3E1f7A1370aD2){target=\_blank} | | Robonomics | xcXRT | [0xFffFFffF51470Dca3dbe535bD2880a9CcDBc6Bd9](https://moonriver.moonscan.io/token/0xFffFFffF51470Dca3dbe535bD2880a9CcDBc6Bd9){target=\_blank} | | Shiden | xcSDN | [0xFFFfffFF0Ca324C842330521525E7De111F38972](https://moonriver.moonscan.io/token/0xFFFfffFF0Ca324C842330521525E7De111F38972){target=\_blank} | | Tinkernet | xcTNKR | [0xfFFfFffF683474B842852111cc31d470bD8f5081](https://moonriver.moonscan.io/token/0xffffffff683474b842852111cc31d470bd8f5081){target=\_blank} | | Turing | xcTUR | [0xfFffffFf6448d0746f2a66342B67ef9CAf89478E](https://moonriver.moonscan.io/token/0xfFffffFf6448d0746f2a66342B67ef9CAf89478E){target=\_blank} | _*You can check each [Asset ID](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonriver.moonbeam.network#/assets){target=\_blank} on Polkadot.js Apps_ === "Moonbase Alpha" | Origin | Symbol | XC-20 Address | |:--------------------:|:------:|:-------------------------------------------------------------------------------------------------------------------------------------------:| | Relay Chain Alphanet | xcUNIT | [0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080](https://moonbase.moonscan.io/token/0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080){target=\_blank} | _*You can check each [Asset ID](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/assets){target=\_blank} on Polkadot.js Apps_ ### Retrieve List of External XC-20s and Their Metadata {: #list-xchain-assets } To fetch a list of the currently available external XC-20s along with their associated metadata, you can query the chain state using the [Polkadot.js API](/builders/substrate/libraries/polkadot-js-api/){target=\_blank}. You'll take the following steps: 1. Create an API provider for the network you'd like to get the list of assets for. You can use the following WSS endpoints for each network: === "Moonbeam" ```text wss://wss.api.moonbeam.network ``` === "Moonriver" ```text wss://wss.api.moonriver.moonbeam.network ``` === "Moonbase Alpha" ```text {{ networks.moonbase.wss_url }} ``` 2. Query the `assets` pallet for all assets 3. Iterate over the list of assets to get all of the asset IDs along with their associated metadata ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const getXc20s = async () => { try { const substrateProvider = new WsProvider('INSERT_WSS_ENDPOINT'); const api = await ApiPromise.create({ provider: substrateProvider }); const assets = await api.query.assets.asset.entries(); await Promise.all( assets.map(async ([{ args: [id] }]) => { try { const metadata = await api.query.assets.metadata(id); const humanMetadata = metadata.toHuman(); console.log(`\nAsset ID: ${id}`); console.log('Metadata:'); console.log(' Name:', humanMetadata.name); console.log(' Symbol:', humanMetadata.symbol); console.log(' Decimals:', humanMetadata.decimals); console.log(' Deposit:', humanMetadata.deposit); console.log(' IsFrozen:', humanMetadata.isFrozen); console.log('-----'); } catch (error) { console.error(`Error fetching metadata for asset ${id}:`, error); } }) ); await api.disconnect(); } catch (error) { console.error('Error in getXc20s:', error); } }; getXc20s().catch(console.error); ``` The result will display the asset ID along with some additional information for all of the registered external XC-20s. ## Retrieve Local XC-20 Metadata {: #retrieve-local-xc20-metadata } Since local XC-20s are ERC-20s on Moonbeam that can be transferred via XCM to another parachain, you can interact with local XC-20s like you would an ERC-20. As long as you have the address and the ABI of the ERC-20, you can retrieve its metadata by interacting with its ERC-20 interface to retrieve the name, symbol, and decimals for the asset. The following is an example that retrieves the asset metadata for the [Jupiter token](https://moonbase.moonscan.io/token/0x9aac6fb41773af877a2be73c99897f3ddfacf576){target=\_blank} on Moonbase Alpha: === "Ethers.js" ```js import { ethers } from 'ethers'; const providerRPC = { moonbase: { name: 'moonbase', rpc: 'https://rpc.api.moonbase.moonbeam.network', // Insert your RPC URL here chainId: 1287, // 0x507 in hex, }, }; const provider = new ethers.JsonRpcProvider(providerRPC.moonbase.rpc, { chainId: providerRPC.moonbase.chainId, name: providerRPC.moonbase.name, }); // Replace with the address of the ERC-20 token const tokenAddress = '0x9Aac6FB41773af877a2Be73c99897F3DdFACf576'; const tokenABI = [ 'function name() view returns (string)', 'function symbol() view returns (string)', 'function decimals() view returns (uint8)', ]; const tokenContract = new ethers.Contract(tokenAddress, tokenABI, provider); async function getTokenMetadata() { try { const [name, symbol, decimals] = await Promise.all([ tokenContract.name(), tokenContract.symbol(), tokenContract.decimals(), ]); console.log(`Name: ${name}`); console.log(`Symbol: ${symbol}`); console.log(`Decimals: ${decimals}`); } catch (error) { console.error('Error fetching token metadata:', error); } } getTokenMetadata(); ``` === "Web3.js" ```js import { Web3 } from 'web3'; // Insert your RPC URL here const web3 = new Web3('https://rpc.api.moonbase.moonbeam.network'); // Replace with the address of the ERC-20 token const tokenAddress = '0x9Aac6FB41773af877a2Be73c99897F3DdFACf576'; const tokenABI = [ // ERC-20 ABI { constant: true, inputs: [], name: 'name', outputs: [{ name: '', type: 'string' }], payable: false, stateMutability: 'view', type: 'function', }, { constant: true, inputs: [], name: 'symbol', outputs: [{ name: '', type: 'string' }], payable: false, stateMutability: 'view', type: 'function', }, { constant: true, inputs: [], name: 'decimals', outputs: [{ name: '', type: 'uint8' }], payable: false, stateMutability: 'view', type: 'function', }, ]; const tokenContract = new web3.eth.Contract(tokenABI, tokenAddress); async function getTokenMetadata() { try { const [name, symbol, decimals] = await Promise.all([ tokenContract.methods.name().call(), tokenContract.methods.symbol().call(), tokenContract.methods.decimals().call(), ]); console.log(`Name: ${name}`); console.log(`Symbol: ${symbol}`); console.log(`Decimals: ${decimals}`); } catch (error) { console.error('Error fetching token metadata:', error); } } getTokenMetadata(); ``` === "Web3.py" ```py from web3 import Web3 web3 = Web3(Web3.HTTPProvider("https://rpc.api.moonbase.moonbeam.network")) # Replace with the address of the ERC-20 token token_address = "0x9Aac6FB41773af877a2Be73c99897F3DdFACf576" token_abi = [ # ERC-20 ABI { "constant": True, "inputs": [], "name": "name", "outputs": [{"name": "", "type": "string"}], "payable": False, "stateMutability": "view", "type": "function", }, { "constant": True, "inputs": [], "name": "symbol", "outputs": [{"name": "", "type": "string"}], "payable": False, "stateMutability": "view", "type": "function", }, { "constant": True, "inputs": [], "name": "decimals", "outputs": [{"name": "", "type": "uint8"}], "payable": False, "stateMutability": "view", "type": "function", }, ] token_contract = web3.eth.contract(address=token_address, abi=token_abi) def get_token_metadata(): try: name = token_contract.functions.name().call() symbol = token_contract.functions.symbol().call() decimals = token_contract.functions.decimals().call() print(f"Name: {name}") print(f"Symbol: {symbol}") print(f"Decimals: {decimals}") except Exception as e: print(f"Error fetching token metadata: {e}") get_token_metadata() ``` --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/xc20/send-xc20s/eth-api/ --- BEGIN CONTENT --- --- title: XCM Precompile description: Learn about the XCM Precompile and how to use it to transfer assets from Moonbeam networks to other parachains. categories: XCM, Precompiles --- # XCM Precompile ## Introduction {: #introduction } As a Polkadot parachain, Moonbeam has the inherent ability to communicate and exchange data with other connected parachains. This native cross-chain communication allows safe and fast token transfers leveraging the Cross-Consensus Message format (XCM for short), facilitating communication between different consensus systems. The communication protocol enabling token transfers is built on [Substrate](/builders/substrate/){target=\_blank} and runs on a lower level than the EVM, making it harder for EVM developers to access. Nevertheless, Moonbeam networks have an XCM Precompile that fills the gap between execution layers. This precompile exposes a smart contract interface that abstracts away the underlying complexities, making the execution of cross-chain token transfers as easy as any other smart contract call. This guide will show you how to interact with the [XCM Interface](https://github.com/Moonsong-Labs/moonkit/blob/main/precompiles/pallet-xcm/XcmInterface.sol){target=\_blank} precompile to execute cross-chain token transfers through the Ethereum API. The XCM Precompile is located at the following address: === "Moonbeam" ```text {{networks.moonbeam.precompiles.xcm_interface }} ``` === "Moonriver" ```text {{networks.moonriver.precompiles.xcm_interface }} ``` === "Moonbase Alpha" ```text {{networks.moonbase.precompiles.xcm_interface }} ``` !!! note There can be some unintended consequences when using the precompiled contracts on Moonbeam. Please refer to the [Security Considerations](/learn/core-concepts/security/){target=\_blank} page for more information. ## The XCM Solidity Interface {: #the-xcm-solidity-interface } The [`XCMInterface.sol`](https://github.com/Moonsong-Labs/moonkit/blob/main/precompiles/pallet-xcm/XcmInterface.sol){target=\_blank} is a Solidity interface that allows developers to interact with the methods of `pallet-xcm`. ??? code "XCMInterface.sol" ```solidity // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.3; /// @dev The XCM contract's address. address constant XCM_CONTRACT_ADDRESS = 0x000000000000000000000000000000000000081A; /// @dev The XCM contract's instance. XCM constant XCM_CONTRACT = XCM(XCM_CONTRACT_ADDRESS); /// @author The Moonbeam Team /// @title XCM precompile Interface /// @dev The interface that Solidity contracts use to interact with the substrate pallet-xcm. interface XCM { // A location is defined by its number of parents and the encoded junctions (interior) struct Location { uint8 parents; bytes[] interior; } // Support for Weights V2 struct Weight { uint64 refTime; uint64 proofSize; } // A way to represent fungible assets in XCM using Location format struct AssetLocationInfo { Location location; uint256 amount; } // A way to represent fungible assets in XCM using address format struct AssetAddressInfo { address asset; uint256 amount; } // The values start at `0` and are represented as `uint8` enum TransferType { Teleport, LocalReserve, DestinationReserve } /// @dev Function to send assets via XCM using transfer_assets() pallet-xcm extrinsic. /// @custom:selector 9ea8ada7 /// @param dest The destination chain. /// @param beneficiary The actual account that will receive the tokens on dest. /// @param assets The combination (array) of assets to send in Location format. /// @param feeAssetItem The index of the asset that will be used to pay for fees. function transferAssetsLocation( Location memory dest, Location memory beneficiary, AssetLocationInfo[] memory assets, uint32 feeAssetItem ) external; /// @dev Function to send assets via XCM to a 20 byte-like parachain /// using transfer_assets() pallet-xcm extrinsic. /// @custom:selector a0aeb5fe /// @param paraId The para-id of the destination chain. /// @param beneficiary The actual account that will receive the tokens on paraId destination. /// @param assets The combination (array) of assets to send in Address format. /// @param feeAssetItem The index of the asset that will be used to pay for fees. function transferAssetsToPara20( uint32 paraId, address beneficiary, AssetAddressInfo[] memory assets, uint32 feeAssetItem ) external; /// @dev Function to send assets via XCM to a 32 byte-like parachain /// using transfer_assets() pallet-xcm extrinsic. /// @custom:selector f23032c3 /// @param paraId The para-id of the destination chain. /// @param beneficiary The actual account that will receive the tokens on paraId destination. /// @param assets The combination (array) of assets to send in Address format. /// @param feeAssetItem The index of the asset that will be used to pay for fees. function transferAssetsToPara32( uint32 paraId, bytes32 beneficiary, AssetAddressInfo[] memory assets, uint32 feeAssetItem ) external; /// @dev Function to send assets via XCM to the relay chain /// using transfer_assets() pallet-xcm extrinsic. /// @custom:selector 6521cc2c /// @param beneficiary The actual account that will receive the tokens on the relay chain. /// @param assets The combination (array) of assets to send in Address format. /// @param feeAssetItem The index of the asset that will be used to pay for fees. function transferAssetsToRelay( bytes32 beneficiary, AssetAddressInfo[] memory assets, uint32 feeAssetItem ) external; /// @dev Function to send assets through transfer_assets_using_type_and_then() pallet-xcm /// extrinsic. /// Important: in this selector RemoteReserve type (for either assets or fees) is not allowed. /// If users want to send assets and fees (in Location format) with a remote reserve, /// they must use the selector fc19376c. /// @custom:selector 8425d893 /// @param dest The destination chain. /// @param assets The combination (array) of assets to send in Location format. /// @param assetsTransferType The TransferType corresponding to assets being sent. /// @param remoteFeesIdIndex The index of the asset (inside assets array) to use as fees. /// @param feesTransferType The TransferType corresponding to the asset used as fees. /// @param customXcmOnDest The XCM message to execute on destination chain. function transferAssetsUsingTypeAndThenLocation( Location memory dest, AssetLocationInfo[] memory assets, TransferType assetsTransferType, uint8 remoteFeesIdIndex, TransferType feesTransferType, bytes memory customXcmOnDest ) external; /// @dev Function to send assets through transfer_assets_using_type_and_then() pallet-xcm /// extrinsic. /// @custom:selector fc19376c /// @param dest The destination chain. /// @param assets The combination (array) of assets to send in Location format. /// @param remoteFeesIdIndex The index of the asset (inside assets array) to use as fees. /// @param customXcmOnDest The XCM message to execute on destination chain. /// @param remoteReserve The remote reserve corresponding for assets and fees. They MUST /// share the same reserve. function transferAssetsUsingTypeAndThenLocation( Location memory dest, AssetLocationInfo[] memory assets, uint8 remoteFeesIdIndex, bytes memory customXcmOnDest, Location memory remoteReserve ) external; /// @dev Function to send assets through transfer_assets_using_type_and_then() pallet-xcm /// extrinsic. /// Important: in this selector RemoteReserve type (for either assets or fees) is not allowed. /// If users want to send assets and fees (in Address format) with a remote reserve, /// they must use the selector aaecfc62. /// @custom:selector 998093ee /// @param dest The destination chain. /// @param assets The combination (array) of assets to send in Address format. /// @param assetsTransferType The TransferType corresponding to assets being sent. /// @param remoteFeesIdIndex The index of the asset (inside assets array) to use as fees. /// @param feesTransferType The TransferType corresponding to the asset used as fees. /// @param customXcmOnDest The XCM message to execute on destination chain. function transferAssetsUsingTypeAndThenAddress( Location memory dest, AssetAddressInfo[] memory assets, TransferType assetsTransferType, uint8 remoteFeesIdIndex, TransferType feesTransferType, bytes memory customXcmOnDest ) external; /// @dev Function to send assets through transfer_assets_using_type_and_then() pallet-xcm /// extrinsic. /// @custom:selector aaecfc62 /// @param dest The destination chain. /// @param assets The combination (array) of assets to send in Address format. /// @param remoteFeesIdIndex The index of the asset (inside assets array) to use as fees. /// @param customXcmOnDest The XCM message to execute on destination chain. /// @param remoteReserve The remote reserve corresponding for assets and fees. They MUST /// share the same reserve. function transferAssetsUsingTypeAndThenAddress( Location memory dest, AssetAddressInfo[] memory assets, uint8 remoteFeesIdIndex, bytes memory customXcmOnDest, Location memory remoteReserve ) external; } ``` The interface includes the necessary data structures along with the following functions: ???+ function "**transferAssetsToPara20**(_paraId, beneficiary, assets, feeAssetItem_) — sends assets via XCM to a 20 byte-like parachain using the underlying `transfer_assets()` transaction included in the XCM pallet module" === "Parameters" - `paraId` *uint32* - the para-id of the destination chain - `beneficiary` *address* - the ECDSA-type account in the destination chain that will receive the tokens - `assets` *AssetAddressInfo[] memory* - an array of assets to send in Address format - `feeAssetItem` *uint32* - the index of the asset that will be used to pay fees === "Example" - `paraId` - 888 - `beneficiary` - 0x3f0Aef9Bd799F1291b80376aD57530D353ab0217 - `assets` - [["0x0000000000000000000000000000000000000802", 1000000000000000000]] - `feeAssetItem` - 0 ??? function "**transferAssetsToPara32**(_paraId, beneficiary, assets, feeAssetItem_) — sends assets via XCM to a 32 byte-like parachain using the underlying `transfer_assets()` transaction included in the XCM pallet module" === "Parameters" - `paraId` *uint32* - the para-id of the destination chain - `beneficiary` *bytes32* - the actual account that will receive the tokens on paraId destination - `assets` *AssetAddressInfo[] memory* - an array of assets to send in Address format - `feeAssetItem` *uint32* - the index of the asset that will be used to pay fees === "Example" - `paraId` - 888 - `beneficiary` - 0xf831d83025f527daeed39a644d64d335a4e627b5f4becc78fb67f05976889a06 - `assets` - [["0x0000000000000000000000000000000000000802", 1000000000000000000]] - `feeAssetItem` - 0 ??? function "**transferAssetsToRelay**(_beneficiary, assets, feeAssetItem_) — sends assets via XCM to the relay chain using the underlying `transfer_assets()` transaction included in the XCM pallet module" === "Parameters" - `beneficiary` *bytes32* - the actual account that will receive the tokens on the relay chain - `assets` *AssetAddressInfo[] memory* - an array of assets to send in Address format - `feeAssetItem` *uint32* - the index of the asset that will be used to pay fees === "Example" - `beneficiary` - 0xf831d83025f527daeed39a644d64d335a4e627b5f4becc78fb67f05976889a06 - `assets` - [["0x0000000000000000000000000000000000000802", 1000000000000000000]] - `feeAssetItem` - 0 ??? function "**transferAssetsLocation**(_dest, beneficiary, assets, feeAssetItem_) — sends assets using the underlying `transfer_assets()` transaction included in the XCM pallet module" === "Parameters" - `dest` *Location memory* - the destination chain - `beneficiary` *Location memory* - the account in the destination chain that will receive the tokens - `assets` *AssetLocationInfo[] memory* - an array of assets to send - `feeAssetItem` *uint32* - the index of the asset that will be used to pay fees === "Example" - `dest` - ["1",[]] - `beneficiary` - [0, ["0x01f831d83025f527daeed39a644d64d335a4e627b5f4becc78fb67f05976889a0600"]] - `assets` - [[[1, ["0x010000000000000000000000000000000000000800"]], 1000000000000000000]] - `feeAssetItem` - 0 ??? function "**transferAssetsUsingTypeAndThenLocation**(_dest, assets, assetsTransferType, remoteFeesIdIndex, feesTransferType, customXcmOnDest_) — sends assets through `transfer_assets_using_type_and_then()` pallet-xcm extrinsic. Important: RemoteReserve type (for either assets or fees) is prohibited. For sending assets and fees (in Location format) with a remote reserve, use the subsequent `transferAssetsUsingTypeAndThenLocation` which shares the same function name as this but takes a different set of parameters" === "Parameters" - `dest` *Location memory* - the destination chain - `assets` *AssetLocationInfo[] memory* - an array of assets to send in Location format - `assetsTransferType` *TransferType* - the TransferType corresponding to assets being sent (Teleport = 0, LocalReserve = 1, DestinationReserve = 2) - `remoteFeesIdIndex` *uint8* - the index of the asset (inside assets array) to use as fees - `feesTransferType` *TransferType* - the TransferType corresponding to the asset used as fees (Teleport = 0, LocalReserve = 1, DestinationReserve = 2) - `customXcmOnDest` *bytes memory* - the XCM message to execute on destination chain === "Example" - `dest` - ["1",[]] - `assets` - [[[1, ["0x010000000000000000000000000000000000000802"]], 1000000000000000000]] - `assetsTransferType` - 0 - `remoteFeesIdIndex` - 0 - `feesTransferType` - 1 - `customXcmOnDest` - 0x0408000400010403001300008a5d784563010d01020400010300f8234bedd9553e7668c4e0d60aced12e22bd2d45 ??? function "**transferAssetsUsingTypeAndThenLocation**(_dest, assets, remoteFeesIdIndex, customXcmOnDest, remoteReserve_) — sends assets through `transfer_assets_using_type_and_then()` pallet-xcm extrinsic. Important: The remote reserve must be shared between assets and fees" === "Parameters" - `dest` *Location memory* - the destination chain - `assets` *AssetLocationInfo[] memory* - an array of assets to send in Location format - `remoteFeesIdIndex` *uint8* - the index of the asset (inside assets array) to use as fees - `customXcmOnDest` *bytes memory* - the XCM message to execute on destination chain - `remoteReserve` *Location memory* - the remote reserve corresponding for assets and fees (must be shared) === "Example" - `dest` - ["1",[]] - `assets` - [[[1, ["0x010000000000000000000000000000000000000800"]], 1000000000000000000]] - `remoteFeesIdIndex` - 0 - `customXcmOnDest` - 0x0408000400010403001300008a5d784563010d01020400010300f8234bedd9553e7668c4e0d60aced12e22bd2d45 - `remoteReserve` - [1,[]] ??? function "**transferAssetsUsingTypeAndThenAddress**(_dest, assets, assetsTransferType, remoteFeesIdIndex, feesTransferType, customXcmOnDest_) — sends assets through `transfer_assets_using_type_and_then()` pallet-xcm extrinsic. Important: RemoteReserve type (for either assets or fees) is not allowed. For sending assets and fees (in Address format) with a remote reserve, use the subsequent `transferAssetsUsingTypeAndThenAddress`, which shares the same name as this function but takes a different set of parameters" === "Parameters" - `dest` *Location memory* - the destination chain - `assets` *AssetAddressInfo[] memory* - an array of assets to send in Address format - `assetsTransferType` *TransferType* - the TransferType corresponding to assets being sent (Teleport = 0, LocalReserve = 1, DestinationReserve = 2) - `remoteFeesIdIndex` *uint8* - the index of the asset (inside assets array) to use as fees - `feesTransferType` *TransferType* - the TransferType corresponding to the asset used as fees (Teleport = 0, LocalReserve = 1, DestinationReserve = 2) - `customXcmOnDest` *bytes memory* - the XCM message to execute on destination chain === "Example" - `dest` - ["1",[]] - `assets` - [["0x0000000000000000000000000000000000000802", 1000000000000000000]] - `assetsTransferType` - 0 - `remoteFeesIdIndex` - 0 - `feesTransferType` - 1 - `customXcmOnDest` - 0x0408000400010403001300008a5d784563010d01020400010300f8234bedd9553e7668c4e0d60aced12e22bd2d45 ??? function "**transferAssetsUsingTypeAndThenAddress**(_dest, assets, remoteFeesIdIndex, customXcmOnDest, remoteReserve_) — sends assets through `transfer_assets_using_type_and_then()` pallet-xcm extrinsic. Important: The remote reserve must be shared between assets and fees" === "Parameters" - `dest` *Location memory* - the destination chain - `assets` *AssetAddressInfo[] memory* - an array of assets to send in Address format - `remoteFeesIdIndex` *uint8* - the index of the asset (inside assets array) to use as fees - `customXcmOnDest` *bytes memory* - the XCM message to execute on destination chain - `remoteReserve` *Location memory* - the remote reserve corresponding for assets and fees (must be shared) === "Example" - `dest` - ["1",[]] - `assets` - [["0x0000000000000000000000000000000000000802", 1000000000000000000]] - `remoteFeesIdIndex` - 0 - `customXcmOnDest` - 0x0408000400010403001300008a5d784563010d01020400010300f8234bedd9553e7668c4e0d60aced12e22bd2d45 - `remoteReserve` - [1,[]] ## Interact with the Solidity Interface {: #interact-with-the-solidity-interface } ### Checking Prerequisites {: #checking-prerequisites } To follow this tutorial, you must have your preferred EVM wallet configured and an account funded with native tokens. You can add Moonbeam to MetaMask wallet following this guide: [Interacting with Moonbeam Using MetaMask](/tokens/connect/metamask/){target=\_blank}. ### Remix Set Up {: #remix-set-up } You can interact with the XCM Precompile using [Remix](https://remix.ethereum.org){target=\_blank}. To add the precompile to Remix, you will need to: 1. Get a copy of [`XCMInterface.sol`](https://github.com/Moonsong-Labs/moonkit/blob/main/precompiles/pallet-xcm/XcmInterface.sol){target=\_blank} 2. Paste the file contents into a Remix file named `XCMInterface.sol` ### Compile the Contract {: #compile-the-contract } Next, you will need to compile the interface in Remix: 1. Click on the **Compile** tab, second from top 2. Compile the interface by clicking on **Compile XcmInterface.sol** ![Compiling XCMInterface.sol](/images/builders/interoperability/xcm/xc20/send-xc20s/eth-api/eth-api-1.webp) When the compilation is completed, you will see a green checkmark next to the **Compile** tab. ### Access the Contract {: #access-the-contract } Instead of deploying the precompile, you will access the interface given the address of the precompiled contract: 1. Click on the **Deploy and Run** tab directly below the **Compile** tab in Remix. Please note that the precompiled contracts are already accessible at their respective addresses. Therefore, there is no deployment step 2. Make sure **Injected Provider - Metamask** is selected in the **ENVIRONMENT** dropdown. Once you select **Injected Provider - Metamask**, you may be prompted by MetaMask to connect your account to Remix if it's not already connected 3. Make sure the correct account is displayed under **ACCOUNT** 4. Ensure **XCM - XcmInterface.sol** is selected in the **CONTRACT** dropdown. Given that it is a precompiled contract, there is no deployment step. Instead, you are going to provide the address of the precompile in the **At Address** field 5. Provide the address of the precompile: `{{networks.moonbeam.precompiles.xcm_interface}}` and click **At Address** ![Access the address](/images/builders/interoperability/xcm/xc20/send-xc20s/eth-api/eth-api-2.webp) The **XCM Interface** precompile will appear in the list of **Deployed Contracts**. ### Send Tokens Over to Another EVM-Compatible Appchain {: #transfer-to-evm-chains } To send tokens over to an account in another EVM-compatible appchain, please follow these steps: 1. Expand the **transferAssetsToPara20** function 2. Enter the appchain ID (paraId) 3. Enter the 20-byte (Ethereum-like) destination account (beneficiary) 4. Specify the tokens to be transferred. Note that this parameter is an array that contains at least one asset. Each asset is specified by its address and the total amount to transfer 5. Enter the index of the asset that will be used to pay the fees. This index is zero-based, so the first element is `0`, the second is `1`, and so on 6. Click **transact** 7. MetaMask will pop up, and you will be prompted to review the transaction details. Click **Confirm** to send the transaction ![Confirm Approve Transaction](/images/builders/interoperability/xcm/xc20/send-xc20s/eth-api/eth-api-3.webp) After the transaction is confirmed, wait a few blocks for the transfer to reach the destination chain and reflect the new balance. ### Send Tokens Over to a Substrate Appchain {: #transfer-to-substrate-chains } To send tokens over to an account in a Substrate appchain, please follow these steps: 1. Expand the **transferAssetsToPara32** function 2. Enter the appchain ID (`paraId`) 3. Enter the sr25519-type destination account (beneficiary) 4. Specify the tokens to be transferred. Note that this parameter is an array that contains at least one asset. Each asset is specified by its address and the total amount to transfer !!! note There can be some unintended consequences when using the precompiled contracts on Moonbeam. Please refer to the [Security Considerations](/learn/core-concepts/security/){target=\_blank} page for more information. 5. Enter the index of the asset that will be used to pay the fees. This index is zero-based, so the first element is `0`, the second is `1`, and so on 6. Click **transact** 7. MetaMask will pop up, and you will be prompted to review the transaction details. Click **Confirm** to send the transaction ![Confirm Approve Transaction](/images/builders/interoperability/xcm/xc20/send-xc20s/eth-api/eth-api-4.webp) After the transaction is confirmed, wait a few blocks for the transfer to reach the destination chain and reflect the new balance. ### Send Tokens Over to the Relay Chain {: #transfer-to-relay-chain } To send tokens over to an account in the relay chain, please follow these steps: 1. Expand the **transferAssetsToRelay** function 2. Enter the sr25519-type destination account (beneficiary) 3. Specify the tokens to be transferred. Note that this parameter is an array that contains at least one asset. Each asset is specified by its address and the total amount to transfer !!! note There can be some unintended consequences when using the precompiled contracts on Moonbeam. Please refer to the [Security Considerations](/learn/core-concepts/security/){target=\_blank} page for more information. 4. Enter the index of the asset that will be used to pay the fees. This index is zero-based, so the first element is `0`, the second is `1`, and so on 5. Click **transact** 6. MetaMask will pop up, and you will be prompted to review the transaction details. Click **Confirm** to send the transaction ![Confirm Approve Transaction](/images/builders/interoperability/xcm/xc20/send-xc20s/eth-api/eth-api-5.webp) After the transaction is confirmed, wait a few blocks for the transfer to reach the destination chain and reflect the new balance. ### Send Tokens Over Specific Locations {: #transfer-locations } There are two methods that share names with closely related methods, `transferAssetsUsingTypeAndThenLocation` and `transferAssetsUsingTypeAndThenAddress`. However, these are not duplicates. For each function, there is one that accepts five parameters and another that accepts six. The function with five parameters can only be used when the remote reserve is shared between assets and fees. If the remote reserve is not shared between assets and fees, you can use the six parameter version of the method to specify the information needed. The following example will demonstrate `transferAssetsUsingTypeAndThenAddress` when the remote reverse is shared between assets and fees. To follow along with the tutorial, take the following steps: 1. Expand the **transferAssetsUsingTypeAndThenAddress** function 2. Enter the multilocation that specifies the destination chain. Note that any chain can be specified, regardless of its configuration or type 3. Enter the combination array of assets to send in Address format 4. Enter the index of the asset that will be used to pay the fees. This index is zero-based, so the first element is `0`, the second is `1`, and so on 5. Enter the XCM message to be executed on destination chain. For more information about creating XCM call data see [Send and Execute XCM Messages](/builders/interoperability/xcm/send-execute-xcm/) 6. Enter the remote reserve, e.g. `[1,[]]` 7. Click **transact** 8. MetaMask will pop up, and you will be prompted to review the transaction details. Click **Confirm** to send the transaction ![Confirm Approve Transaction](/images/builders/interoperability/xcm/xc20/send-xc20s/eth-api/eth-api-6.webp) After the transaction is confirmed, wait a few blocks for the transfer to reach the destination chain and reflect the new balance. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/xc20/send-xc20s/ --- BEGIN CONTENT --- --- title: Send XC-20s via XCM description: This section shows you how to send XC-20s cross-chain from Moonbeam to other chains in the ecosystem using the X-Tokens Pallet and X-Tokens Precompile. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/xc20/send-xc20s/overview/ --- BEGIN CONTENT --- --- title: XC-20 Transfers Overview description: Explore the types of asset transfers and some of the fundamentals of remote asset transfers via XCM, including the XCM instructions for asset transfers. categories: Basics, XC-20 --- # Overview of XC-20 Transfers ## Introduction {: #introduction } Assets can move between parachains using XCM. Two main approaches exist: - **Asset teleporting** – destroys tokens on the reserve chain and mints the same amount on the destination chain. Each chain holds the native asset as a reserve, similar to a burn-mint bridging mechanism. Because each chain can create tokens, a degree of trust is required - **Remote transfers** – moves tokens from the reserve chain to a Sovereign account (an account on the reserve chain trustlessly controlled by the destination chain). The destination chain then mints a wrapped (also called “virtual” or “cross-chain”) representation. This wrapped version is always interchangeable 1:1 with the original asset, functioning like a lock-mint and burn-unlock bridge. The chain where the asset originates is known as the reserve chain ![Asset Teleporting and Remote Transfers](/images/builders/interoperability/xcm/xc20/send-xc20s/overview/overview-1.webp) Moonbeam currently uses remote transfers for XC-20 transfers. This page covers the fundamentals of XCM-based remote transfers. To learn how to perform XC-20 transfers, refer to the the [XC-20 transfers via the Substrate API](/builders/interoperability/xcm/xc20/send-xc20s/xcm-pallet/){target=\_blank} guide. ## XCM Instructions for Asset Transfers {: #xcm-instructions-for-asset-transfers } The XCM Pallet and Precompile abstract much of the complexity involved in cross-chain asset transfers, automatically constructing the necessary XCM messages. Nevertheless, having a basic understanding of the underlying instructions can be useful. For reference, you can find the Polkadot XCM Pallet extrinsics for sending XC-20s in the [Using the Polkadot XCM Pallet To Send XC-20s guide](/builders/interoperability/xcm/xc20/send-xc20s/xcm-pallet/){target=_blank}. The instructions in each XCM transfer vary depending on the asset and the transfer route. For example, returning a native token like xcDOT to its reserve chain (from Moonbeam to Polkadot) differs from sending DOT from Polkadot to Moonbeam. Below are examples of the instructions commonly involved in these token transfers. ### Instructions to Transfer a Reserve Asset from the Reserve Chain {: #transfer-native-from-origin } When DOT is transferred from Polkadot to Moonbeam, the following XCM instructions are executed in sequence: 1. [`TransferReserveAsset`](/builders/interoperability/xcm/core-concepts/instructions/#transfer-reserve-asset){target=_blank} - executes on Polkadot, moving the DOT from the sender and depositing it into Moonbeam’s Sovereign account on Polkadot 2. [`ReserveAssetDeposited`](/builders/interoperability/xcm/core-concepts/instructions/#reserve-asset-deposited){target=_blank} - executes on Moonbeam, minting the corresponding ERC-20 representation of DOT (xcDOT) on Moonbeam 3. [`ClearOrigin`](/builders/interoperability/xcm/core-concepts/instructions/#clear-origin){target=_blank} - executes on Moonbeam, clearing any origin data—previously set to Polkadot’s Sovereign account 4. [`BuyExecution`](/builders/interoperability/xcm/core-concepts/instructions/#buy-execution){target=_blank} - executes on Moonbeam, determining the execution fees. Here, a portion of the newly minted xcDOT is used to pay the cost of XCM 5. [`DepositAsset`](/builders/interoperability/xcm/core-concepts/instructions/#deposit-asset){target=_blank} - executes on Moonbeam, delivering the xcDOT to the intended recipient’s account on Moonbeam This process invokes `TransferReserveAsset` with `assets`, `dest`, and `xcm`parameters. Within the `xcm` parameter, you typically specify the `BuyExecution` and `DepositAsset` instructions. As shown in the [`TransferReserveAsset` instruction](https://github.com/paritytech/polkadot-sdk/blob/{{ polkadot_sdk }}/polkadot/xcm/xcm-executor/src/lib.rs#L630){target=\_blank}, the flow also includes `ReserveAssetDeposited` and `ClearOrigin` to complete the transfer. For more information on constructing an XCM message for asset transfers, such as DOT to Moonbeam, refer to the [Polkadot XCM Pallet guide](/builders/interoperability/xcm/xc20/send-xc20s/xcm-pallet/){target=\_blank}. ### Instructions to Transfer a Reserve Asset back to the Reserve Chain {: #transfer-native-to-origin } In scenarios where you want to move an asset back to its reserve chain, such as sending xcDOT from Moonbeam to Polkadot, Moonbeam uses the following set of XCM instructions: 1. [`WithdrawAsset`](/builders/interoperability/xcm/core-concepts/instructions/#withdraw-asset){target=_blank} – executes on Moonbeam, taking the specified token (xcDOT) from the sender 2. [`InitiateReserveWithdraw`](/builders/interoperability/xcm/core-concepts/instructions/#initiate-reserve-withdraw){target=_blank} – executes on Moonbeam, which, burns the token on Moonbeam (removing the wrapped representation), and sends an XCM message to Polkadot, indicating the tokens should be released there 3. [`WithdrawAsset`](/builders/interoperability/xcm/core-concepts/instructions/#withdraw-asset){target=_blank} – executes on Polkadot, removing the tokens from Moonbeam’s Sovereign account on Polkadot 4. [`ClearOrigin`](/builders/interoperability/xcm/core-concepts/instructions/#clear-origin){target=_blank} – gets executed on Polkadot. Clears any origin data (e.g., the Sovereign account on Moonbeam) 5. [`BuyExecution`](/builders/interoperability/xcm/core-concepts/instructions/#buy-execution){target=_blank} – Polkadot determines the execution fees and uses part of the DOT being transferred to pay for them 6. [`DepositAsset`](/builders/interoperability/xcm/core-concepts/instructions/#deposit-asset){target=_blank} – finally, the native DOT tokens are deposited into the specified Polkadot account Steps 3 through 6 are automatically triggered by the `InitiateReserveWithdraw` instruction (step 2) and execute on Polkadot. Once `InitiateReserveWithdraw` is invoked on Moonbeam, the assembled XCM message instructs Polkadot to run those final instructions, completing the cross-chain transfer. In other words, while Moonbeam constructs the XCM instructions behind the scenes, they ultimately execute on Polkadot to complete the asset’s return to its reserve chain. For more information on constructing an XCM message to transfer reserve assets to a target chain, such as xcDOT to Polkadot, you refer to the guide to the [Polkadot XCM Pallet](/builders/interoperability/xcm/xc20/send-xc20s/xcm-pallet/){target=_blank}. !!! note The specific instructions may vary over time, but this overall flow remains consistent: the tokens are withdrawn from the user on Moonbeam, burned from the local representation, and unlocked on the reserve chain. At the end of the process, they become fully accessible again on their reserve chain. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/xc20/send-xc20s/xcm-pallet/ --- BEGIN CONTENT --- --- title: Send XC-20s to Other Chains description: This guide introduces the Polkadot XCM Pallet and explains how to send XC-20s to another chain using some of the pallet's extrinsics. categories: XC-20 --- # Using the Polkadot XCM Pallet To Send XC-20s ## Introduction {: #introduction } !!! note The Polkadot XCM Pallet replaces the deprecated XTokens Pallet. Accordingly, ensure that you are using the Polkadot XCM Pallet to interact with XC-20s. Manually crafting an XCM message for fungible asset transfers is a challenging task. Consequently, developers can leverage wrapper functions and pallets to use XCM features on Polkadot and Kusama. One example of such wrappers is the [XCM](https://docs.polkadot.com/develop/interoperability/send-messages/){target=\_blank} Pallet, which provides different methods to transfer fungible assets via XCM. This guide will show you how to leverage the Polkadot XCM Pallet to send [XC-20s](/builders/interoperability/xcm/xc20/overview/){target=\_blank} from a Moonbeam-based network to other chains in the ecosystem (relay chain/parachains). **Developers must understand that sending incorrect XCM messages can result in the loss of funds.** Consequently, testing XCM features on a TestNet is essential before moving to a production environment. ## Nomenclature {: #nomenclature } Because there are various XCM-related pallets and precompiles with similar-sounding names, the following section will clarify the differences between each. - `PolkadotXCM` - this pallet (and the focus of this page) enables you to interact with XC-20s on Moonbeam, replacing the deprecated `XTokens` pallet - `pallet-xcm`- the general Polkadot XCM pallet allows you to interact with cross-chain assets. Moonbeam's `PolkadotXCM` pallet is essentially a wrapper of `pallet-xcm`. Because of this, you may see `PolkadotXCM` and `pallet-xcm` referred to interchangeably - `XTokens` - This pallet is now deprecated and replaced by `PolkadotXCM` - `XCMInterface.sol` - This precompile is the solidity interface that replaces `XTokens.sol` and enables you to interact with the methods of `PolkadotXCM` from the EVM via a solidity interface ## Polkadot XCM Pallet Interface {: #polkadotxcm-pallet-interface } ### Extrinsics {: #extrinsics } The Polkadot XCM Pallet provides the following extrinsics (functions): ??? function "**forceDefaultXcmVersion**(maybeXcmVersion) — sets a safe default XCM version for message encoding (admin origins only)" === "Parameters" - `maybeXcmVersion` - the default XCM encoding version to be used when a destination's supported version is unknown. Can be either: - A version number - `None` to disable the default version setting ??? function "**transferAssets**(dest, beneficiary, assets, feeAssetItem, weightLimit) — transfers assets from the local chain to a destination chain using reserve or teleport methods" === "Parameters" - `dest` - the destination context for the assets. Typically specified as: - `X2(Parent, Parachain(..))` for parachain to parachain transfers - `X1(Parachain(..))` for relay to parachain transfers - `beneficiary` - the recipient location in the context of the destination. Generally an `AccountId32` value - `assets` - the assets to be transferred. Must: - Have the same reserve location or be teleportable to destination (excluding fee assets) - Include assets for fee payment - `feeAssetItem` - the index in the `assets` array indicating which asset should be used to pay fees - `weightLimit` - the weight limit for XCM fee purchase on the destination chain. Can be defined as: - `Unlimited` - allows an unlimited amount of weight - `Limited` - specifies a maximum weight value The transfer behavior varies based on asset type: - **Local Reserve**: - Transfers assets to destination chain's sovereign account - Sends XCM to mint and deposit reserve-based assets to beneficiary - **Destination Reserve**: - Burns local assets - Notifies destination to withdraw reserves from this chain's sovereign account - Deposits to beneficiary - **Remote Reserve**: - Burns local assets - Sends XCM to move reserves between sovereign accounts - Notifies destination to mint and deposit to beneficiary - **Teleport**: - Burns local assets - Sends XCM to mint/teleport assets and deposit to beneficiary As a reminder, the origin must be capable of both withdrawing the specified assets and executing XCM. If more weight is needed than specified in `weightLimit`, the operation will fail and teleported assets may be at risk ??? function "**transferAssetsUsingTypeAndThen**(dest, assets, assetsTransferType, remoteFeesId, feesTransferType, customXcmOnDest, weightLimit) — transfers assets with explicit transfer types and custom destination behavior" === "Parameters" - `dest` - the destination context for the assets. Can be specified as: - `[Parent, Parachain(..)]` for parachain to parachain transfers - `[Parachain(..)]` for relay to parachain transfers - `(parents: 2, (GlobalConsensus(..), ..))` for cross-bridge ecosystem transfers - `assets` - the assets to be transferred. Must either: - Have the same reserve location - Be teleportable to destination - `assetsTransferType` - specifies how the main assets should be transferred: - `LocalReserve` - transfers to sovereign account, mints at destination - `DestinationReserve` - burns locally, withdraws from sovereign account at destination - `RemoteReserve(reserve)` - burns locally, moves reserves through specified chain (typically Asset Hub) - `Teleport` - burns locally, mints/teleports at destination - `remoteFeesId` - specifies which of the included assets should be used for fee payment - `feesTransferType` - specifies how the fee payment asset should be transferred (same options as `assetsTransferType`) - `customXcmOnDest` - XCM instructions to execute on the destination chain as the final step. Typically used to: - Deposit assets to beneficiary: `Xcm(vec![DepositAsset { assets: Wild(AllCounted(assets.len())), beneficiary }])` - Or perform more complex operations with the transferred assets - `weightLimit` - the weight limit for XCM fee purchase on the destination chain. Can be defined as: - `Unlimited` - allows an unlimited amount of weight - `Limited` - specifies a maximum weight value A few reminders: - `BuyExecution` is used to purchase execution time using the specified `remoteFeesId` asset - Fee payment asset can use a different transfer type than the main assets - The origin must be capable of both withdrawing the specified assets and executing XCM - If more weight is needed than specified in `weightLimit`, the operation will fail and transferred assets may be at risk ### Storage Methods {: #storage-methods } The Polkadot XCM Pallet includes the following read-only storage methods. Note, this is not an exhaustive list. To see the current available storage methods, check the [Chain State of Polkadot.js Apps](https://polkadot.js.org/apps/#/chainstate){target=\_blank}. ???+ function "**assetTraps**(h256 hash) — returns the count of trapped assets for a given hash" === "Parameters" - `hash`: `H256` - The hash identifier for the asset trap. When an asset is trapped, a unique hash identifier is assigned to it. You can omit this field to return information about all assets trapped === "Returns" Returns a `U32` (unsigned 32-bit integer) representing the number of times an asset has been trapped at this hash location. ```js // Example return values showing hash → count mappings [ [[0x0140f264543926e689aeefed15a8379f6e75a8c6884b0cef0832bb913a343b53], 1], [[0x0d14fd8859d8ff15dfe4d4002b402395129cdc4b69dea5575efa1dc205b96020], 425], [[0x166f82439fd2b25b28b82224e82ad9f26f2da26b8257e047182a6a7031accc9a], 3] ] ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://wss.api.moonbeam.network'), }); const hash = '0x166f82439fd2b25b28b82224e82ad9f26f2da26b8257e047182a6a7031accc9a'; const trapCount = await api.query.polkadotXcm.assetTraps(hash); console.log('Trap count:', trapCount.toNumber()); }; main(); ``` ??? function "**queryCounter**() — the latest available query index" === "Parameters" None === "Returns" `u64` - The latest available query index === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://wss.api.moonbeam.network'), }); const queryIndex = await api.query.polkadotXcm.queryCounter(); console.log('Query Index:', queryIndex.toNumber()); }; main(); ``` ??? function "**safeXcmVersion**() — default version to encode XCM when destination version is unknown" === "Parameters" None === "Returns" `u32` - default version to encode XCM when destination version is unknown === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://wss.api.moonbeam.network'), }); const safeVersion = await api.query.polkadotXcm.safeXcmVersion(); console.log('Safe XCM Version:', safeVersion.toHuman()); }; main(); ``` ??? function "**supportedVersion**(XcmVersion, Multilocation) — returns the supported XCM version for a given location" === "Parameters" - version `u32`: XcmVersion - The version number to check - location: MultiLocation - The location to check for version support === "Returns" Returns a mapping of locations to their supported XCM versions. Each entry contains a MultiLocation specifying the parachain location (including parent and interior information) and an XcmVersion number indicating the supported version === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://wss.api.moonbase.moonbeam.network'), }); const testLocation = { V4: { parents: 1, interior: 'Here', }, }; const supportedVersion = await api.query.polkadotXcm.supportedVersion( 4, // Testing XCM v4 testLocation ); console.log('Location:', JSON.stringify(testLocation, null, 2)); console.log('Supported Version:', supportedVersion.toHuman()); }; main(); ``` ??? function "**palletVersion**() — returns current pallet version from storage" === "Parameters" None === "Returns" A number representing the current version of the pallet. ```js // If using Polkadot.js API and calling toJSON() on the unwrapped value 0 ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://wss.api.moonbase.moonbeam.network'), }); const palletVersion = await api.query.polkadotXcm.palletVersion(); console.log("The pallet version is " + palletVersion); }; main(); ``` ### Pallet Constants {: #constants } There are no constants part of the Polkadot XCM pallet. ## Building an XCM Message with the Polkadot XCM Pallet {: #build-with-PolkadotXCM-pallet} This guide covers the process of building an XCM message using the Polkadot XCM Pallet, specifically the `transferAssets` function. !!! note Each parachain can allow and forbid specific methods from a pallet. Consequently, developers must ensure that they use methods that are allowed, or the transaction will fail with an error similar to `system.CallFiltered`. You'll be transferring xcUNIT tokens, which are the [XC-20](/builders/interoperability/xcm/xc20/overview/){target=\_blank} representation of the Alphanet relay chain token, UNIT. You can adapt this guide for any other XC-20. ### Checking Prerequisites {: #polkadotxcm-check-prerequisites} To follow along with the examples in this guide, you need to have the following: - An account with funds. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} - Some xcUNIT tokens. You can swap DEV tokens (Moonbase Alpha's native token) for xcUNITs on [Moonbeam-Swap](https://moonbeam-swap.netlify.app/#/swap){target=\_blank}, a demo Uniswap-V2 clone on Moonbase Alpha !!! note You can adapt this guide to transfer another [external XC-20 or a local XC-20](/builders/interoperability/xcm/xc20/overview/){target=\_blank}. For external XC-20s, you'll need the asset ID and the number of decimals the asset has. For local XC-20s, you'll need the contract address. ![Moonbeam Swap xcUNIT](/images/builders/interoperability/xcm/xc20/send-xc20s/xcm-pallet/xtokens-1.webp) To check your xcUNIT balance, you can add the XC-20's [precompile address](/builders/interoperability/xcm/xc20/overview/#calculate-xc20-address){target=\_blank} to MetaMask with the following address: ```text 0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080 ``` ### Polkadot XCM Transfer Assets Function {: #polkadotxcm-transfer-assets-function} In this example, you'll build an XCM message to transfer xcUNIT from Moonbase Alpha back to the Alphanet relay chain through the `transferAssets` function of the Polkadot XCM Pallet using the [Polkadot.js API](/builders/substrate/libraries/polkadot-js-api/){target=\_blank}. To perform a limited reserve transfer using the `polkadotXcm` pallet, follow these steps: 1. Install the required dependencies: `@polkadot/api` for blockchain interaction, `@polkadot/util` for utility functions, and `@polkadot/util-crypto` for cryptographic functions. 2. Set up your network connection by creating a WebSocket provider using the Moonbase Alpha endpoint: `wss://wss.api.moonbase.moonbeam.network`. Initialize the Polkadot API with this provider. 3. Configure your account using the Ethereum format. Create a keyring instance for Ethereum addresses, then add your account using your private key. Remember to prepend the private key with `0x`, which is omitted when exporting your keys from MetaMask !!! remember This is for demo purposes only. Never store your private key in a JavaScript file. 4. Prepare the destination address by converting the SS58 format address to raw bytes using the `decodeAddress` function. If the destination SS58 address is already in hexadecimal format, no conversion is needed 5. Construct the XCM transfer transaction with: the relay chain as the destination (parent chain with `parents: 1`), beneficiary (using `AccountId32` format), assets (amount with 12 decimals), fee asset item (0), and weight limit ('Unlimited'). ??? code "Define the destination, beneficiary, and asset" ```js // dest { V4: { parents: 1, interior: { Here: null } } }, // beneficiary { V4: { parents: 1, interior: { X1: [ { AccountId32: { id: Array.from(beneficiaryRaw), network: null } } ] } } }, // assets { V4: [ { fun: { Fungible: 1000000000000n }, id: { parents: 1, interior: { Here: null } } } ] }, 0, // feeAssetItem 'Unlimited' // weightLimit ); ``` 6. Submit your transaction and implement monitoring logic with error handling 7. Once the transaction is finalized, the script will automatically exit. Any errors during the process will be logged to the console for troubleshooting ???+ code "View the full script" ```js import { ApiPromise, WsProvider, Keyring } from '@polkadot/api'; import { decodeAddress } from '@polkadot/util-crypto'; const main = async () => { // Setup provider and API const wsProvider = new WsProvider('wss://wss.api.moonbase.moonbeam.network'); const api = await ApiPromise.create({ provider: wsProvider }); // Setup account with ethereum format const keyring = new Keyring({ type: 'ethereum' }); const account = keyring.addFromUri('INSERT_PRIVATE_KEY'); // Convert the SS58 address to raw bytes const beneficiaryRaw = decodeAddress('INSERT_DESTINATION_ADDRESS'); try { // Create the transaction (XCM v4) const tx = api.tx.polkadotXcm.transferAssets( // Destination (V4) { V4: { parents: 1, interior: { Here: null } } }, // Beneficiary (V4) { V4: { parents: 1, interior: { X1: [ { AccountId32: { network: null, id: beneficiaryRaw } } ] } } }, // Assets (V4) { V4: [ { fun: { Fungible: 1000000000000n }, id: { parents: 1, interior: { Here: null } } } ] }, 0, // feeAssetItem 'Unlimited' // weightLimit ); // Sign and send the transaction const unsub = await tx.signAndSend(account, ({ status }) => { if (status.isInBlock) { console.log(`Transaction included in blockHash ${status.asInBlock}`); } else if (status.isFinalized) { console.log(`Transaction finalized in blockHash ${status.asFinalized}`); unsub(); process.exit(0); } }); } catch (error) { console.error('Error:', error); process.exit(1); } }; main().catch(console.error); ``` !!! note You can view an example of the above script, which sends 1 xcUNIT to Alice's account on the relay chain, on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/extrinsics/decode/0x1c0b0401000400010100d4620637e11439598c5fbae0506dc68b9fb1edb33b316761bf99987a1034a96b0404010000070010a5d4e80000000000){target=\_blank} using the following encoded calldata: `0x1c0b0401000400010100d4620637e11439598c5fbae0506dc68b9fb1edb33b316761bf99987a1034a96b0404010000070010a5d4e80000000000`. Once the transaction is processed, the target account on the relay chain should have received the transferred amount minus a small fee that is deducted to execute the XCM on the destination chain. #### Troubleshooting If you're having difficulty replicating the demo, take the following troubleshooting steps: - Ensure your sending account is funded with DEV tokens - Ensure your sending account is funded with xcUNIT tokens (or another XC-20 that you have specified) - Check the [Explorer](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fmoonbase-alpha.public.blastapi.io#/explorer){target=\_blank} on Polkadot.js Apps on Moonbase Alpha to ensure a successful transaction on the origin chain - Check the [Explorer](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frelay.api.moonbase.moonbeam.network#/explorer){target=\_blank} on Polkadot.js Apps and review the XCM messages received on Moonbase Relay Chain --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/xc20/send-xc20s/xtokens-precompile/ --- BEGIN CONTENT --- --- title: Send XC-20s to Other Chains description: Learn how to send assets cross-chain via Cross-Consensus Messaging (XCM) using the X-Tokens Precompile with familiar Ethereum libraries like Ethers and Web3. categories: Precompiles, XC-20, Ethereum Toolkit --- # Using the X-Tokens Precompile To Send XC-20s ## Introduction {: #introduction } Building an XCM message for fungible asset transfers is not an easy task. Consequently, there are wrapper functions and pallets that developers can leverage to use XCM features on Polkadot and Kusama. One example of such wrappers is the [Polkadot XCM](/builders/interoperability/xcm/xc20/send-xc20s/xcm-pallet/){target=\_blank} Pallet, which provides different methods to transfer fungible assets via XCM. The [Polkadot XCM Pallet](/builders/interoperability/xcm/xc20/send-xc20s/xcm-pallet/){target=\_blank} is coded in Rust and is normally not accessible from the Ethereum API side of Moonbeam. However, the [XCM Precompile](/builders/interoperability/xcm/xc20/send-xc20s/eth-api/){target=\_blank} and the X-Tokens Precompile allow you to interact directly with the Polkadot XCM pallet to send XC-20s from a Solidity interface. This guide will show you how to leverage the X-Tokens Precompile to send [XC-20s](/builders/interoperability/xcm/xc20/overview/){target=\_blank} from a Moonbeam-based network to other chains in the ecosystem (relay chain/parachains) using Ethereum libraries like Ethers and Web3. **Developers must understand that sending incorrect XCM messages can result in the loss of funds.** Consequently, it is essential to test XCM features on a TestNet before moving to a production environment. ## X-Tokens Precompile Contract Address {: #contract-address } The X-Tokens Precompile is located at the following addresses: === "Moonbeam" ```text {{networks.moonbeam.precompiles.xtokens}} ``` === "Moonriver" ```text {{networks.moonriver.precompiles.xtokens}} ``` === "Moonbase Alpha" ```text {{networks.moonbase.precompiles.xtokens}} ``` !!! note There can be some unintended consequences when using the precompiled contracts on Moonbeam. Please refer to the [Security Considerations](/learn/core-concepts/security/){target=\_blank} page for more information. ## The X-Tokens Solidity Interface {: #xtokens-solidity-interface } [Xtokens.sol](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xtokens/Xtokens.sol){target=\_blank} is an interface through which developers can interact with the X-Tokens Pallet using the Ethereum API. ??? code "Xtokens.sol" ```solidity // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.3; /// @dev The Xtokens contract's address. address constant XTOKENS_ADDRESS = 0x0000000000000000000000000000000000000804; /// @dev The Xtokens contract's instance. Xtokens constant XTOKENS_CONTRACT = Xtokens(XTOKENS_ADDRESS); /// @author The Moonbeam Team /// @title Xtokens Interface /// @dev The interface through which solidity contracts will interact with xtokens pallet /// @custom:address 0x0000000000000000000000000000000000000804 interface Xtokens { // A multilocation is defined by its number of parents and the encoded junctions (interior) struct Multilocation { uint8 parents; bytes[] interior; } // A MultiAsset is defined by a multilocation and an amount struct MultiAsset { Multilocation location; uint256 amount; } // A Currency is defined by address and the amount to be transferred struct Currency { address currencyAddress; uint256 amount; } /// Transfer a token through XCM based on its currencyId /// /// @dev The token transfer burns/transfers the corresponding amount before sending /// @param currencyAddress The ERC20 address of the currency we want to transfer /// @param amount The amount of tokens we want to transfer /// @param destination The Multilocation to which we want to send the tokens /// @param weight The weight we want to buy in the destination chain /// (uint64::MAX means Unlimited weight) /// @custom:selector b9f813ff function transfer( address currencyAddress, uint256 amount, Multilocation memory destination, uint64 weight ) external; /// Transfer a token through XCM based on its currencyId specifying fee /// /// @dev The token transfer burns/transfers the corresponding amount before sending /// @param currencyAddress The ERC20 address of the currency we want to transfer /// @param amount The amount of tokens we want to transfer /// @param destination The Multilocation to which we want to send the tokens /// @param weight The weight we want to buy in the destination chain /// (uint64::MAX means Unlimited weight) /// @custom:selector 3e506ef0 function transferWithFee( address currencyAddress, uint256 amount, uint256 fee, Multilocation memory destination, uint64 weight ) external; /// Transfer a token through XCM based on its MultiLocation /// /// @dev The token transfer burns/transfers the corresponding amount before sending /// @param asset The asset we want to transfer, defined by its multilocation. /// Currently only Concrete Fungible assets /// @param amount The amount of tokens we want to transfer /// @param destination The Multilocation to which we want to send the tokens /// @param weight The weight we want to buy in the destination chain /// (uint64::MAX means Unlimited weight) /// @custom:selector b4f76f96 function transferMultiasset( Multilocation memory asset, uint256 amount, Multilocation memory destination, uint64 weight ) external; /// Transfer a token through XCM based on its MultiLocation specifying fee /// /// @dev The token transfer burns/transfers the corresponding amount before sending /// @param asset The asset we want to transfer, defined by its multilocation. /// Currently only Concrete Fungible assets /// @param amount The amount of tokens we want to transfer /// @param destination The Multilocation to which we want to send the tokens /// @param weight The weight we want to buy in the destination chain /// (uint64::MAX means Unlimited weight) /// @custom:selector 150c016a function transferMultiassetWithFee( Multilocation memory asset, uint256 amount, uint256 fee, Multilocation memory destination, uint64 weight ) external; /// Transfer several tokens at once through XCM based on its address specifying fee /// /// @dev The token transfer burns/transfers the corresponding amount before sending /// @param currencies The currencies we want to transfer, defined by their address and amount. /// @param feeItem Which of the currencies to be used as fee /// @param destination The Multilocation to which we want to send the tokens /// @param weight The weight we want to buy in the destination chain /// (uint64::MAX means Unlimited weight) /// @custom:selector ab946323 function transferMultiCurrencies( Currency[] memory currencies, uint32 feeItem, Multilocation memory destination, uint64 weight ) external; /// Transfer several tokens at once through XCM based on its location specifying fee /// /// @dev The token transfer burns/transfers the corresponding amount before sending /// @param assets The assets we want to transfer, defined by their location and amount. /// @param feeItem Which of the currencies to be used as fee /// @param destination The Multilocation to which we want to send the tokens /// @param weight The weight we want to buy in the destination chain /// (uint64::MAX means Unlimited weight) /// @custom:selector 797b45fd function transferMultiAssets( MultiAsset[] memory assets, uint32 feeItem, Multilocation memory destination, uint64 weight ) external; } ``` The interface includes the following functions: ???+ function "**transfer**(*address* currencyAddress, *uint256* amount, *Multilocation* *memory* destination, *uint64* weight) — transfer a currency, given the contract address of the currency" === "Parameters" - `currencyAddress` - the address of the asset to transfer - For [External XC-20s](/builders/interoperability/xcm/xc20/overview/#external-xc20s){target=\_blank}, provide the [XC-20 precompile address](/builders/interoperability/xcm/xc20/overview/#current-xc20-assets){target=\_blank} - For native tokens (i.e., GLMR, MOVR, and DEV), provide the [ERC-20 precompile](/builders/ethereum/precompiles/ux/erc20/#the-erc20-interface){target=\_blank} address, which is `{{networks.moonbeam.precompiles.erc20 }}` - For [Local XC-20s](/builders/interoperability/xcm/xc20/overview/#local-xc20s){target=\_blank}, provide the token's address - `amount` - the number of tokens that are going to be sent via XCM - `destination` - the multilocation of the destination address for the tokens being sent via XCM. It supports different address formats, such as 20- or 32-byte addresses (Ethereum or Substrate). The multilocation must be formatted in a particular way, which is described in the [Building the Precompile Multilocation](#building-the-precompile-multilocation) section - `weight` - the weight to be purchased to pay for XCM execution on the destination chain, which is charged from the transferred asset ??? function "**transferWithFee**(*address* currencyAddress, *uint256* amount, *uint256* fee, *Multilocation* *memory* destination, *uint64* weight) — transfer a currency, defined as either the native token (self-reserved) or the asset ID, and specify the fee separately from the amount" === "Parameters" - `currencyAddress` - the address of the asset to transfer - For [External XC-20s](/builders/interoperability/xcm/xc20/overview/#external-xc20s){target=\_blank}, provide the [XC-20 precompile address](/builders/interoperability/xcm/xc20/overview/#current-xc20-assets){target=\_blank} - For native tokens (i.e., GLMR, MOVR, and DEV), provide the [ERC-20 precompile](/builders/ethereum/precompiles/ux/erc20/#the-erc20-interface){target=\_blank} address, which is `{{networks.moonbeam.precompiles.erc20 }}` - For [Local XC-20s](/builders/interoperability/xcm/xc20/overview/#local-xc20s){target=\_blank}, provide the token's address - `amount` - the number of tokens that are going to be sent via XCM - `fee` — the amount to be spent to pay for the XCM execution in the target (destination) chain. If this value is not high enough to cover execution costs, the assets will be trapped in the destination chain - `destination` - the multilocation of the destination address for the tokens being sent via XCM. It supports different address formats, such as 20- or 32-byte addresses (Ethereum or Substrate). The multilocation must be formatted in a particular way, which is described in the [Building the Precompile Multilocation](#building-the-precompile-multilocation) section - `weight` - the weight to be purchased to pay for XCM execution on the destination chain, which is charged from the transferred asset ??? function "**transferMultiasset**(*Multilocation* *memory* asset, *uint256* amount, *Multilocation* *memory* destination, *uint64* weight) — transfer a fungible asset, defined by its multilocation" === "Parameters" - `asset` - the multilocation of the asset to transfer. The multilocation must be formatted in a particular way, which is described in the [Building the Precompile Multilocation](#building-the-precompile-multilocation) section - `amount` - the number of tokens that are going to be sent via XCM - `destination` - the multilocation of the destination address for the tokens being sent via XCM. It supports different address formats, such as 20- or 32-byte addresses (Ethereum or Substrate). The multilocation must be formatted in a particular way, which is described in the [Building the Precompile Multilocation](#building-the-precompile-multilocation) section - `weight` - the weight to be purchased to pay for XCM execution on the destination chain, which is charged from the transferred asset ??? function "**transferMultiassetWithFee**(*Multilocation* *memory* asset, *uint256* amount, *uint256* fee, *Multilocation* *memory* destination, *uint64* weight) — transfer a fungible asset, defined by its multilocation, and pay the fee with a different asset, also defined by its multilocation" === "Parameters" - `asset` - the multilocation of the asset to transfer. The multilocation must be formatted in a particular way, which is described in the [Building the Precompile Multilocation](#building-the-precompile-multilocation) section - `amount` - the number of tokens that are going to be sent via XCM - `fee` — the amount to be spent to pay for the XCM execution in the target (destination) chain. If this value is not high enough to cover execution costs, the assets will be trapped in the destination chain - `destination` - the multilocation of the destination address for the tokens being sent via XCM. It supports different address formats, such as 20- or 32-byte addresses (Ethereum or Substrate). The multilocation must be formatted in a particular way, which is described in the [Building the Precompile Multilocation](#building-the-precompile-multilocation) section - `weight` - the weight to be purchased to pay for XCM execution on the destination chain, which is charged from the transferred asset ??? function "**transferMulticurrencies**(*Currency[]* *memory* currencies, *uint32* feeItem, *Multilocation* *memory* destination, *uint64* weight) — transfer different currencies, specifying which is used as the fee. Each currency is defined as either the native token (self-reserved) or the asset ID" === "Parameters" - `currencies` - an array of the currencies to send, which are identified by their currency address, and the amount to send - `feeItem` — an index to define the asset position of an array of assets being sent, used to pay for the XCM execution in the target chain. For example, if only one asset is being sent, the `feeItem` would be `0` - `destination` - the multilocation of the destination address for the tokens being sent via XCM. It supports different address formats, such as 20- or 32-byte addresses (Ethereum or Substrate). The multilocation must be formatted in a particular way, which is described in the [Building the Precompile Multilocation](#building-the-precompile-multilocation) section - `weight` - the weight to be purchased to pay for XCM execution on the destination chain, which is charged from the transferred asset ??? function "**transferMultiassets**(*MultiAsset[]* *memory* assets, *uint32* feeItem, *Multilocation* *memory* destination, *uint64* weight) — transfer several fungible assets, defined by their multilocation, and pay the fee with one of the assets, also defined by its multilocation" === "Parameters" - `assets` - an array of the multilocations of each asset to transfer. The multilocation must be formatted in a particular way, which is described in the [Building the Precompile Multilocation](#building-the-precompile-multilocation) section - `feeItem` — an index to define the asset position of an array of assets being sent, used to pay for the XCM execution in the target chain. For example, if only one asset is being sent, the `feeItem` would be `0` - `destination` - the multilocation of the destination address for the tokens being sent via XCM. It supports different address formats, such as 20- or 32-byte addresses (Ethereum or Substrate). The multilocation must be formatted in a particular way, which is described in the [Building the Precompile Multilocation](#building-the-precompile-multilocation) section - `weight` - the weight to be purchased to pay for XCM execution on the destination chain, which is charged from the transferred asset ## Building the Precompile Multilocation {: #building-the-precompile-multilocation } [Multilocations](/builders/interoperability/xcm/core-concepts/multilocations/){target=\_blank} define a specific point in the entire relay chain/parachain ecosystem relative to a given origin. They are frequently used by the X-Tokens Precompile to define the location of assets and destination chains and accounts. Multilocations need to be formatted in a specific way that precompiles can understand, which is different than the format seen when interacting with pallets. In the X-Tokens Precompile interface, the `Multilocation` structure is defined as follows: ```solidity struct Multilocation { uint8 parents; bytes[] interior; } ``` As with a standard [multilocation](/builders/interoperability/xcm/core-concepts/multilocations/){target=\_blank}, there are `parents` and `interior` elements. However, instead of defining the multilocation as an object, with Ethereum libraries, the struct is defined as an array, which contains a `uint8` for the `parents` as the first element and a bytes array for the `interior` as the second element. The normal values you would see for the `parents` element are: | Origin | Destination | Parents Value | |:-----------:|:-----------:|:-------------:| | Parachain A | Parachain A | 0 | | Parachain A | Relay Chain | 1 | | Parachain A | Parachain B | 1 | For the `interior` element, the number of fields you need to drill down to in the target chain to reach the exact location of the target, such as the specific asset or account, represents the size of the bytes array: | Array | Size | Interior Value | |:------------:|:----:|:--------------:| | [] | 0 | Here | | [XYZ] | 1 | X1 | | [XYZ, ABC] | 2 | X2 | | [XYZ, ... N] | N | XN | !!! note Interior value `Here` is often used for the relay chain (either as a destination or to target the relay chain asset). Each field required to reach the exact location of the target needs to be defined as a hex string. The first byte (2 hexadecimal characters) corresponds to the selector of the field. For example: | Byte Value | Selector | Data Type | |:----------:|:--------------:|-----------| | 0x00 | Parachain | bytes4 | | 0x01 | AccountId32 | bytes32 | | 0x02 | AccountIndex64 | u64 | | 0x03 | AccountKey20 | bytes20 | | 0x04 | PalletInstance | byte | | 0x05 | GeneralIndex | u128 | | 0x06 | GeneralKey | bytes[] | Next, depending on the selector and its data type, the following bytes correspond to the actual data being provided. Note that for `AccountId32`, `AccountIndex64`, and `AccountKey20`, the optional `network` field is appended at the end. For example: | Selector | Data Value | Represents | |:--------------:|:----------------------:|:----------------------------------:| | Parachain | "0x00+000007E7" | Parachain ID 2023 | | AccountId32 | "0x01+AccountId32+00" | AccountId32, Network(Option) Null | | AccountId32 | "0x01+AccountId32+03" | AccountId32, Network Polkadot | | AccountKey20 | "0x03+AccountKey20+00" | AccountKey20, Network(Option) Null | | PalletInstance | "0x04+03" | Pallet Instance 3 | !!! note The `interior` data usually needs to be wrapped around quotes, or you might get an `invalid tuple value` error. The following code snippet goes through some examples of multilocation structures, as they would need to be fed into the X-Tokens Precompile functions: ```js // Multilocation targeting the relay chain or its asset from a parachain [ 1, // parents = 1 [], // interior = here ] // Multilocation targeting Moonbase Alpha DEV token from another parachain [ 1, // parents = 1 [ // interior = X2 (the array has a length of 2) '0x00000003E8', // Parachain selector + Parachain ID 1000 (Moonbase Alpha) '0x0403', // Pallet Instance selector + Pallet Instance 3 (Balances Pallet) ], ] // Multilocation targeting Alice's account on the relay chain from Moonbase Alpha [ 1, // parents = 1 [ // interior = X1 (the array has a length of 1) // AccountKey32 selector + AccountId32 address in hex + Network(Option) Null '0x01c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300', ], ] ``` ## Building an XCM Message {: #build-xcm-xtokens-precompile } This guide covers the process of building an XCM message using the X-Tokens Precompile, more specifically, with the `transfer` and `transferMultiasset` functions. Nevertheless, these two cases can be extrapolated to the other functions of the precompile, especially once you become familiar with multilocations. You'll be transferring xcUNIT tokens, which are the [XC-20](/builders/interoperability/xcm/xc20/overview/){target=\_blank} representation of the Alphanet relay chain token, UNIT. You can adapt this guide for any other XC-20. ### Checking Prerequisites {: #xtokens-check-prerequisites} To follow along with the examples in this guide, you need to have the following: - The ABI of the X-Tokens Precompile ??? code "X-Tokens Precompile ABI" ```js export default [ { inputs: [ { internalType: 'address', name: 'currencyAddress', type: 'address', }, { internalType: 'uint256', name: 'amount', type: 'uint256', }, { components: [ { internalType: 'uint8', name: 'parents', type: 'uint8', }, { internalType: 'bytes[]', name: 'interior', type: 'bytes[]', }, ], internalType: 'struct Xtokens.Multilocation', name: 'destination', type: 'tuple', }, { internalType: 'uint64', name: 'weight', type: 'uint64', }, ], name: 'transfer', outputs: [], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ { components: [ { components: [ { internalType: 'uint8', name: 'parents', type: 'uint8', }, { internalType: 'bytes[]', name: 'interior', type: 'bytes[]', }, ], internalType: 'struct Xtokens.Multilocation', name: 'location', type: 'tuple', }, { internalType: 'uint256', name: 'amount', type: 'uint256', }, ], internalType: 'struct Xtokens.MultiAsset[]', name: 'assets', type: 'tuple[]', }, { internalType: 'uint32', name: 'feeItem', type: 'uint32', }, { components: [ { internalType: 'uint8', name: 'parents', type: 'uint8', }, { internalType: 'bytes[]', name: 'interior', type: 'bytes[]', }, ], internalType: 'struct Xtokens.Multilocation', name: 'destination', type: 'tuple', }, { internalType: 'uint64', name: 'weight', type: 'uint64', }, ], name: 'transferMultiAssets', outputs: [], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ { components: [ { internalType: 'address', name: 'currencyAddress', type: 'address', }, { internalType: 'uint256', name: 'amount', type: 'uint256', }, ], internalType: 'struct Xtokens.Currency[]', name: 'currencies', type: 'tuple[]', }, { internalType: 'uint32', name: 'feeItem', type: 'uint32', }, { components: [ { internalType: 'uint8', name: 'parents', type: 'uint8', }, { internalType: 'bytes[]', name: 'interior', type: 'bytes[]', }, ], internalType: 'struct Xtokens.Multilocation', name: 'destination', type: 'tuple', }, { internalType: 'uint64', name: 'weight', type: 'uint64', }, ], name: 'transferMultiCurrencies', outputs: [], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ { components: [ { internalType: 'uint8', name: 'parents', type: 'uint8', }, { internalType: 'bytes[]', name: 'interior', type: 'bytes[]', }, ], internalType: 'struct Xtokens.Multilocation', name: 'asset', type: 'tuple', }, { internalType: 'uint256', name: 'amount', type: 'uint256', }, { components: [ { internalType: 'uint8', name: 'parents', type: 'uint8', }, { internalType: 'bytes[]', name: 'interior', type: 'bytes[]', }, ], internalType: 'struct Xtokens.Multilocation', name: 'destination', type: 'tuple', }, { internalType: 'uint64', name: 'weight', type: 'uint64', }, ], name: 'transferMultiasset', outputs: [], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ { components: [ { internalType: 'uint8', name: 'parents', type: 'uint8', }, { internalType: 'bytes[]', name: 'interior', type: 'bytes[]', }, ], internalType: 'struct Xtokens.Multilocation', name: 'asset', type: 'tuple', }, { internalType: 'uint256', name: 'amount', type: 'uint256', }, { internalType: 'uint256', name: 'fee', type: 'uint256', }, { components: [ { internalType: 'uint8', name: 'parents', type: 'uint8', }, { internalType: 'bytes[]', name: 'interior', type: 'bytes[]', }, ], internalType: 'struct Xtokens.Multilocation', name: 'destination', type: 'tuple', }, { internalType: 'uint64', name: 'weight', type: 'uint64', }, ], name: 'transferMultiassetWithFee', outputs: [], stateMutability: 'nonpayable', type: 'function', }, { inputs: [ { internalType: 'address', name: 'currencyAddress', type: 'address', }, { internalType: 'uint256', name: 'amount', type: 'uint256', }, { internalType: 'uint256', name: 'fee', type: 'uint256', }, { components: [ { internalType: 'uint8', name: 'parents', type: 'uint8', }, { internalType: 'bytes[]', name: 'interior', type: 'bytes[]', }, ], internalType: 'struct Xtokens.Multilocation', name: 'destination', type: 'tuple', }, { internalType: 'uint64', name: 'weight', type: 'uint64', }, ], name: 'transferWithFee', outputs: [], stateMutability: 'nonpayable', type: 'function', }, ]; ``` - An account with funds. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} - Some xcUNIT tokens. You can swap DEV tokens (Moonbase Alpha's native token) for xcUNITs on [Moonbeam-Swap](https://moonbeam-swap.netlify.app/#/swap){target=\_blank}, a demo Uniswap-V2 clone on Moonbase Alpha !!! note You can adapt this guide to transfer another [external XC-20 or a local XC-20](/builders/interoperability/xcm/xc20/overview/){target=\_blank}. For external XC-20s, you'll need the asset ID and the number of decimals the asset has. For local XC-20s, you'll need the contract address. ![Moonbeam Swap xcUNIT](/images/builders/interoperability/xcm/xc20/send-xc20s/xcm-pallet/xtokens-1.webp) To check your xcUNIT balance, you can add the XC-20's [precompile address](/builders/interoperability/xcm/xc20/interact/#calculate-xc20-address){target=\_blank} to MetaMask with the following address: ```text 0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080 ``` !!! note To test out the examples on Moonbeam or Moonriver, you can replace the RPC URL with your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. ### Determining Weight Needed for XCM Execution {: #determining-weight } To determine the weight needed for XCM execution on the destination chain, you'll need to know which XCM instructions are executed on the destination chain. You can find an overview of the XCM instructions used in the [XCM Instructions for Transfers via X-Tokens](/builders/interoperability/xcm/xc20/send-xc20s/overview/#xcm-instructions-for-asset-transfers){target=\_blank} guide. !!! note Some weights include database reads and writes; for example, the `WithdrawAsset` and `DepositAsset` instructions include both one database read and one write. To get the total weight, you'll need to add the weight of any required database reads or writes to the base weight of the given instruction. For Westend-based relay chains, like Alphanet, you can get the weight cost for read and write database operations for [Rocks DB](https://github.com/paritytech/polkadot-sdk/blob/polkadot-{{ networks.alphanet.spec_version }}/polkadot/runtime/westend/constants/src/weights/rocksdb_weights.rs#L27-L31){target=\_blank} (which is the default database) in the [polkadot-sdk](https://github.com/paritytech/polkadot-sdk){target=\_blank} repository on GitHub. Since Alphanet is a Westend-based relay chain, you can refer to the instruction weights defined in the [Westend runtime code](https://github.com/paritytech/polkadot-sdk/tree/polkadot-{{ networks.alphanet.spec_version }}/polkadot/runtime/westend){target=\_blank}, which are broken up into two types of instructions: [fungible](https://github.com/paritytech/polkadot-sdk/blob/polkadot-{{ networks.alphanet.spec_version }}/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs){target=\_blank} and [generic](https://github.com/paritytech/polkadot-sdk/blob/polkadot-{{ networks.alphanet.spec_version }}/polkadot/runtime/westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs){target=\_blank}. It's important to note that each chain defines its own weight requirements. To determine the weight required for each XCM instruction on a given chain, please refer to the chain's documentation or reach out to a member of their team. To learn how to find the weights required by Moonbeam, Polkadot, or Kusama, you can refer to our documentation on [Weights and Fees](/builders/interoperability/xcm/core-concepts/weights-fees/){target=\_blank}. ### X-Tokens Precompile Transfer Function {: #precompile-transfer } To use the `transfer` function of the X-Tokens Precompile, you'll take these general steps: 1. Create a provider using a Moonbase Alpha RPC endpoint 2. Create a signer to send the transaction. This example uses a private key to create the signer and is for demo purposes only. **Never store your private key in a JavaScript file** 3. Create a contract instance of the X-Tokens Precompile using the address and ABI of the precompile 4. Assemble the arguments for the `transfer` function: - `currencyAddress` - the address for xcUNIT: `0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080` - `amount` - 1 xcUNIT. Since xcUNIT has 12 decimals, you can use: `1000000000000` - `destination` - the multilocation of the destination, which targets Alice's account on the relay chain: `'0x01c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300'` - `weight` - the [weight](#determining-weight) to purchase for the XCM execution on the destination chain: `{{ networks.alphanet.xcm_message.transfer.weight.display }}` 5. Create the `transfer` function, passing in the arguments 6. Sign and send the transaction === "Ethers.js" ```js import { ethers } from 'ethers'; // Import Ethers library import abi from './xtokensABI.js'; // Import the X-Tokens ABI const privateKey = 'INSERT_PRIVATE_KEY'; // Create Ethers provider and signer const provider = new ethers.JsonRpcProvider( 'https://rpc.api.moonbase.moonbeam.network' ); const signer = new ethers.Wallet(privateKey, provider); // Create X-Tokens contract instance const xTokens = new ethers.Contract( '0x0000000000000000000000000000000000000804', abi, signer ); // Arguments for the transfer function const currencyAddress = '0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080'; // xcUNIT address const amount = 1000000000000; const destination = [ // Target the relay chain from Moonbase Alpha 1, // Target Alice's 32-byte relay chain account ['0x01c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300'], ]; const weight = 305986000; // Sends 1 xcUNIT to the relay chain using the transfer function async function transferToAlice() { // Creates, signs, and sends the transfer transaction const transaction = await xTokens.transfer( currencyAddress, amount, destination, weight ); // Waits for the transaction to be included in a block await transaction.wait(); console.log(transaction); } transferToAlice(); ``` === "Web3.js" ```js import Web3 from 'web3'; // Import Web3 library import abi from './xtokensABI.js'; // Import the X-Tokens ABI const privateKey = 'INSERT_PRIVATE_KEY'; // Create Web3 provider const web3 = new Web3('https://rpc.api.moonbase.moonbeam.network'); // Change to network of choice // Create contract instance const xTokens = new web3.eth.Contract( abi, '0x0000000000000000000000000000000000000804', { from: web3.eth.accounts.privateKeyToAccount(privateKey).address } // 'from' is necessary for gas estimation ); // Arguments for the transfer function const currencyAddress = '0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080'; // xcUNIT address const amount = 1000000000000; const destination = [ // Target the relay chain from Moonbase Alpha 1, // Target Alice's 32-byte relay chain account ['0x01c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300'], ]; const weight = 305986000; // Sends 1 xcUNIT to the relay chain using the transfer function async function transferToAlice() { // Create transaction const transferTx = xTokens.methods.transfer( currencyAddress, amount, destination, weight ); // Sign transaction const signedTx = await web3.eth.accounts.signTransaction( { to: '0x0000000000000000000000000000000000000804', data: transferTx.encodeABI(), gas: await transferTx.estimateGas(), }, privateKey ); // Send signed transaction const sendTx = await web3.eth.sendSignedTransaction(signedTx.rawTransaction); console.log(sendTx); } transferToAlice(); ``` === "Web3.py" ```py from web3 import Web3 abi = "INSERT_XTOKENS_ABI" # Paste or import the x-tokens ABI private_key = "INSERT_PRIVATE_KEY" # This is for demo purposes, never store your private key in plain text address = "INSERT_ADDRESS" # The wallet address that corresponds to your private key # Create Web3 provider web3 = Web3(Web3.HTTPProvider("https://rpc.api.moonbase.moonbeam.network")) # Create contract instance x_tokens = web3.eth.contract( address="0x0000000000000000000000000000000000000804", abi=abi ) # Arguments for the transfer function currencyAddress = "0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080" # xcUNIT address amount = 1000000000000 destination = [ # Target the relay chain from Moonbase Alpha 1, # Target Alice's 32-byte relay chain account ["0x01c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300"], ] weight = 305986000 # Sends 1 xcUNIT to the relay chain using the transfer function def transfer_to_alice(): # Create transaction transferTx = x_tokens.functions.transfer( currencyAddress, amount, destination, weight ).build_transaction( { "from": address, "nonce": web3.eth.get_transaction_count(address), } ) # Sign transaction signedTx = web3.eth.account.sign_transaction(transferTx, private_key) # Send tx and wait for receipt hash = web3.eth.send_raw_transaction(signedTx.rawTransaction) receipt = web3.eth.wait_for_transaction_receipt(hash) print(f"Tx successful with hash: { receipt.transactionHash.hex() }") transfer_to_alice() ``` ### X-Tokens Precompile Transfer Multiasset Function {: #precompile-transfer-multiasset} To use the `transfer` function of the X-Tokens Precompile, you'll take these general steps: 1. Create a provider using a Moonbase Alpha RPC endpoint 2. Create a signer to send the transaction. This example uses a private key to create the signer and is for demo purposes only. **Never store your private key in a JavaScript file** 3. Create a contract instance of the X-Tokens Precompile using the address and ABI of the precompile 4. Assemble the arguments for the `transferMultiasset` function: - `asset` - the multilocation for xcUNIT: `[1, []]` - `amount` - 1 xcUNIT. Since xcUNIT has 12 decimals, you can use: `1000000000000` - `destination` - the multilocation of the destination, which targets Alice's account on the relay chain: `'0x01c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300'` - `weight` - the [weight](#determining-weight) to purchase for the XCM execution on the destination chain: `{{ networks.alphanet.xcm_message.transfer.weight.numbers_only }}` 5. Create the `transferMultiasset` function, passing in the arguments 6. Sign and send the transaction === "Ethers.js" ```js import { ethers } from 'ethers'; // Import Ethers library import abi from './xtokensABI.js'; // Import the X-Tokens ABI const privateKey = 'INSERT_PRIVATE_KEY'; // Create Ethers provider and signer const provider = new ethers.JsonRpcProvider( 'https://rpc.api.moonbase.moonbeam.network' ); const signer = new ethers.Wallet(privateKey, provider); // Create X-Tokens contract instance const xTokens = new ethers.Contract( '0x0000000000000000000000000000000000000804', abi, signer ); // Arguments for the transfer multiasset function const asset = [1, []]; // Multilocation targeting the relay chain const amount = 1000000000000; const dest = [ // Target the relay chain from Moonbase Alpha 1, // Target Alice's 32-byte relay chain account ['0x01c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300'], ]; const weight = 305986000; // Sends 1 xcUNIT to the relay chain using the transferMultiasset function async function transferMultiassetToAlice() { const transaction = await xTokens.transferMultiasset( asset, amount, dest, weight ); await transaction.wait(); console.log(transaction); } transferMultiassetToAlice(); ``` === "Web3.js" ```js import Web3 from 'web3'; // Import Web3 library import abi from './xtokensABI.js'; // Import the X-Tokens ABI const privateKey = 'INSERT_PRIVATE_KEY'; // Create Web3 provider const web3 = new Web3('https://rpc.api.moonbase.moonbeam.network'); // Change to network of choice // Create contract instance const xTokens = new web3.eth.Contract( abi, '0x0000000000000000000000000000000000000804', { from: web3.eth.accounts.privateKeyToAccount(privateKey).address } // 'from' is necessary for gas estimation ); // Arguments for the transfer multiasset function const asset = [1, []]; // Multilocation targeting the relay chain const amount = 1000000000000; const dest = [ // Target the relay chain from Moonbase Alpha 1, // Target Alice's 32-byte relay chain account ['0x01c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300'], ]; const weight = 305986000; // Sends 1 xcUNIT to the relay chain using the transferMultiasset function async function transferMultiassetToAlice() { // Create transaction const transferTx = xTokens.methods.transferMultiasset( asset, amount, dest, weight ); // Sign transaction const signedTx = await web3.eth.accounts.signTransaction( { to: '0x0000000000000000000000000000000000000804', data: transferTx.encodeABI(), gas: await transferTx.estimateGas(), }, privateKey ); // Send signed transaction const sendTx = await web3.eth.sendSignedTransaction(signedTx.rawTransaction); console.log(sendTx); } transferMultiassetToAlice(); ``` === "Web3.py" ```py from web3 import Web3 abi = "INSERT_XTOKENS_ABI" # Paste or import the x-tokens ABI private_key = "INSERT_PRIVATE_KEY" # This is for demo purposes, never store your private key in plain text address = "INSERT_ADDRESS" # The wallet address that corresponds to your private key # Create Web3 provider web3 = Web3(Web3.HTTPProvider("https://rpc.api.moonbase.moonbeam.network")) # Create contract instance x_tokens = web3.eth.contract( address="0x0000000000000000000000000000000000000804", abi=abi ) # Arguments for the transfer function asset = [1, []] # Multilocation targeting the relay chain amount = 1000000000000 dest = [ # Target the relay chain from Moonbase Alpha 1, # Target Alice's 32-byte relay chain account ["0x01c4db7bcb733e117c0b34ac96354b10d47e84a006b9e7e66a229d174e8ff2a06300"], ] weight = 305986000 # Sends 1 xcUNIT to the relay chain using the transferMultiasset function def transfer_multiasset_to_alice(): # Create transaction transferTx = x_tokens.functions.transferMultiasset( asset, amount, dest, weight ).build_transaction( { "from": address, "nonce": web3.eth.get_transaction_count(address), } ) # Sign transaction signedTx = web3.eth.account.sign_transaction(transferTx, private_key) # Send tx and wait for receipt hash = web3.eth.send_raw_transaction(signedTx.rawTransaction) receipt = web3.eth.wait_for_transaction_receipt(hash) print(f"Tx successful with hash: { receipt.transactionHash.hex() }") transfer_multiasset_to_alice() ``` --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/interoperability/xcm/xcm-utils/ --- BEGIN CONTENT --- --- title: XCM Utilities Precompile Contract description: Learn the various XCM related utility functions available to smart contract developers with Moonbeam's precompiled XCM Utilities contract. keywords: solidity, ethereum, xcm, utils, moonbeam, precompiled, contracts categories: XCM --- # Interacting with the XCM Utilities Precompile ## Introduction {: #xcmutils-precompile} The XCM Utilities Precompile contract gives developers XCM-related utility functions directly within the EVM. This allows for easier transactions and interactions with other XCM-related precompiles. Similar to other [precompile contracts](/builders/ethereum/precompiles/){target=\_blank}, the XCM Utilities Precompile is located at the following addresses: === "Moonbeam" ```text {{networks.moonbeam.precompiles.xcm_utils }} ``` === "Moonriver" ```text {{networks.moonriver.precompiles.xcm_utils }} ``` === "Moonbase Alpha" ```text {{networks.moonbase.precompiles.xcm_utils}} ``` !!! note There can be some unintended consequences when using the precompiled contracts on Moonbeam. Please refer to the [Security Considerations](/learn/core-concepts/security/){target=\_blank} page for more information. ## The XCM Utilities Solidity Interface {: #xcmutils-solidity-interface } [XcmUtils.sol](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-utils/XcmUtils.sol){target=\_blank} is an interface to interact with the precompile. !!! note The precompile will be updated in the future to include additional features. Feel free to suggest additional utility functions in the [Discord](https://discord.com/invite/PfpUATX){target=\_blank}. The interface includes the following functions: - **multilocationToAddress**(*Multilocation memory* multilocation) — read-only function that returns the Computed Origin account from a given multilocation - **weightMessage**(*bytes memory* message) — read-only function that returns the weight that an XCM message will consume on the chain. The message parameter must be a SCALE encoded XCM versioned XCM message - **getUnitsPerSecond**(*Multilocation memory* multilocation) — read-only function that gets the units per second for a given asset in the form of a `Multilocation`. The multilocation must describe an asset that can be supported as a fee payment, such as an [external XC-20](/builders/interoperability/xcm/xc20/overview/#external-xc20s){target=\_blank}, or else this function will revert. !!! note Note that this function still returns units per second data but units per second has been deprecated and replaced by the calculation of relative price. See [XC asset registration](/builders/interoperability/xcm/xc-registration/assets#generate-encoded-calldata-for-asset-registration){target=\_blank} for more details. - **xcmExecute**(*bytes memory* message, *uint64* maxWeight) - **available on Moonbase Alpha only** - executes a custom XCM message given the SCALE encoded versioned message to be executed and the maximum weight to be consumed. This function *cannot* be called from a smart contract due to the nature of the `Transact` instruction - **xcmSend**(*Multilocation memory* dest, *bytes memory* message) - **available on Moonbase Alpha only** - sends a custom XCM message given the multilocation of the destination chain to send the message to and the SCALE encoded versioned message to be sent The `Multilocation` struct in the XCM Utilities Precompile is built the same as the [XCM Transactor Precompile's](/builders/interoperability/xcm/remote-execution/substrate-calls/xcm-transactor-precompile/#building-the-precompile-multilocation){target=\_blank} `Multilocation`. ## Using the XCM Utilities Precompile {: #using-the-xcmutils-precompile } The XCM Utilities precompile allows users to read data off of the Ethereum JSON-RPC instead of having to go through a Polkadot library. The functions are more for convenience, and less for smart contract use cases. For `multilocationToAddress`, one example use case is being able to allow transactions that originate from other parachains by whitelisting their Computed Origin addresses. A user can whitelist a multilocation by calculating and storing an address. EVM transactions can originate from other parachains via [remote EVM calls](/builders/interoperability/xcm/remote-execution/remote-evm-calls/){target=\_blank}. ```solidity // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.3; import "https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/xcm-utils/XcmUtils.sol"; contract MultilocationWhitelistExample { XcmUtils xcmutils = XcmUtils(0x000000000000000000000000000000000000080C); mapping(address => bool) public whitelistedAddresses; modifier onlyWhitelisted(address addr) { _; require(whitelistedAddresses[addr], "Address not whitelisted!"); _; } function addWhitelistedMultilocation( XcmUtils.Multilocation calldata externalMultilocation ) external onlyWhitelisted(msg.sender) { address derivedAddress = xcmutils.multilocationToAddress( externalMultilocation ); whitelistedAddresses[derivedAddress] = true; } ... } ``` To check out an example of how to use the `xcmExecute` function to execute a custom XCM message locally, please refer to the [Create and Execute Custom XCM Messages](/builders/interoperability/xcm/send-execute-xcm/#execute-xcm-utils-precompile){target=\_blank} guide. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/dev-env/chopsticks/ --- BEGIN CONTENT --- --- title: How to use Chopsticks to Fork Moonbeam description: Learn the basics of how to use Chopsticks to replay blocks, dissect state changes, test XCM interactions, and locally fork the entirety of a Moonbeam network. categories: Substrate Toolkit, Dev Environments --- # How to Use Chopsticks to Fork Moonbeam ## Introduction {: #introduction } [Chopsticks](https://github.com/AcalaNetwork/chopsticks){target=\_blank} provides a developer-friendly method of locally forking existing Substrate based chains. It allows for the replaying of blocks to easily examine how extrinsics affect state, the forking of multiple blocks for XCM testing, and more. This allows developers to test and experiment with their own custom blockchain configurations in a local development environment, without the need to deploy a live network. Overall, Chopsticks aims to simplify the process of building blockchain applications on Substrate and make it accessible to a wider range of developers. ## Forking Moonbeam with Chopsticks {: #forking-moonbeam } To use Chopsticks, you can install it as a package with the [Node package manager](https://nodejs.org/en){target=\_blank} or [Yarn](https://yarnpkg.com){target=\_blank}: ```bash npm i @acala-network/chopsticks@latest ``` Once installed, you can run commands with the Node package executor. For example, this runs Chopstick's base command: ```bash npx @acala-network/chopsticks@latest ``` To run Chopsticks, you will need some sort of configuration, typically through a file. Chopsticks' source repository includes a set of [YAML](https://yaml.org){target=\_blank} configuration files that can be used to create a local copy of a variety of Substrate chains. You can download the configuration files from the [source repository's `configs` folder](https://github.com/AcalaNetwork/chopsticks){target=\_blank}. Moonbeam, Moonriver, and Moonbase Alpha all have default files available: === "Moonbeam" ```yaml endpoint: wss://wss.api.moonbeam.network mock-signature-host: true db: ./db.sqlite import-storage: System: Account: - - - "0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac" - data: free: "100000000000000000000000" TechCommitteeCollective: Members: ["0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"] CouncilCollective: Members: ["0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"] TreasuryCouncilCollective: Members: ["0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"] AuthorFilter: EligibleRatio: 100 EligibleCount: 100 ``` === "Moonriver" ```yaml endpoint: wss://wss.moonriver.moonbeam.network mock-signature-host: true db: ./db.sqlite import-storage: System: Account: - - - "0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac" - data: free: "100000000000000000000000" TechCommitteeCollective: Members: ["0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"] CouncilCollective: Members: ["0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"] TreasuryCouncilCollective: Members: ["0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"] AuthorFilter: EligibleRatio: 100 EligibleCount: 100 ``` === "Moonbase Alpha" ```yaml endpoint: wss://wss.api.moonbase.moonbeam.network mock-signature-host: true db: ./db.sqlite import-storage: System: Account: - - - "0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac" - data: free: "100000000000000000000000" TechCommitteeCollective: Members: ["0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"] CouncilCollective: Members: ["0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"] TreasuryCouncilCollective: Members: ["0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"] Sudo: Key: "0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac" AuthorFilter: EligibleRatio: 100 EligibleCount: 100 ``` These are the settings that can be included in the config file: | Option | Description | |:--------------------------:|:------------------------------------------------------------------------------------------------------------:| | `genesis` | The link to a parachain's raw genesis file to build the fork from, instead of an endpoint. | | `timestamp` | Timestamp of the block to fork from. | | `endpoint` | The endpoint of the parachain to fork. | | `block` | Use to specify at which block hash or number to replay the fork. | | `wasm-override` | Path of the WASM to use as the parachain runtime, instead of an endpoint's runtime. | | `db` | Path to the name of the file that stores or will store the parachain's database. | | `config` | Path or URL of the config file. | | `port` | The port to expose an endpoint on. | | `build-block-mode` | How blocks should be built in the fork: batch, manual, instant. | | `import-storage` | A pre-defined JSON/YAML storage file path to override in the parachain's storage. | | `allow-unresolved-imports` | Whether to allow WASM unresolved imports when using a WASM to build the parachain. | | `html` | Include to generate storage diff preview between blocks. | | `mock-signature-host` | Mock signature host so that any signature starts with `0xdeadbeef` and filled by `0xcd` is considered valid. | You can use the configuration file with the base command `npx @acala-network/chopsticks@latest` to fork assets by providing it with the `--config` flag. You can use a raw GitHub URL of the default configuration files, a path to a local configuration file, or simply use the chain's name for the `--config` flag. For example, the following commands all use Moonbeam's configuration in the same way: === "Chain Name" ```bash npx @acala-network/chopsticks@latest --config=moonbeam ``` === "GitHub URL" ```bash npx @acala-network/chopsticks@latest \ --config=https://raw.githubusercontent.com/AcalaNetwork/chopsticks/master/configs/moonbeam.yml ``` === "Local File Path" ```bash npx @acala-network/chopsticks@latest --config=configs/moonbeam.yml ``` !!! note If using a file path, make sure you've downloaded the [Moonbeam configuration file](https://github.com/AcalaNetwork/chopsticks/blob/master/configs/moonbeam.yml){target=\_blank}, or have created your own. A configuration file is not necessary, however. All of the settings (except `genesis` and `timestamp`) can also be passed as flags to configure the environment completely in the command line. For example, the following command forks Moonbase Alpha at block 100. ```bash npx @acala-network/chopsticks@latest --endpoint {{ networks.moonbase.wss_url }} --block 100 ``` ### Quickstart {: #quickstart } The simplest way to fork Moonbeam is through the configuration files that are stored in the Chopsticks GitHub repository: === "Moonbeam" ```bash npx @acala-network/chopsticks@latest \ --config=https://raw.githubusercontent.com/AcalaNetwork/chopsticks/master/configs/moonbeam.yml ``` === "Moonriver" ```bash npx @acala-network/chopsticks@latest \ --config=https://raw.githubusercontent.com/AcalaNetwork/chopsticks/master/configs/moonriver.yml ``` === "Moonbase Alpha" ```bash npx @acala-network/chopsticks@latest \ --config=https://raw.githubusercontent.com/AcalaNetwork/chopsticks/master/configs/moonbase-alpha.yml ``` ### Interacting with a Fork {: #interacting-with-a-fork } When running a fork, by default it will be accessible at: ```text ws://localhost:8000 ``` You will be able to interact with the parachain via libraries such as [Polkadot.js](https://github.com/polkadot-js/common){target=\_blank} and its [user interface, Polkadot.js Apps](https://github.com/polkadot-js/apps){target=\_blank}. You can interact with Chopsticks via the [Polkadot.js Apps hosted user interface](https://polkadot.js.org/apps/#/explorer){target=\_blank}. To do so, visit the page and take the following steps: 1. Click the icon in the top left 2. Go to the bottom and open **Development** 3. Select the **Custom** endpoint and enter `ws://localhost:8000` 4. Click the **Switch** button ![Open WSS](/images/builders/substrate/dev-env/chopsticks/chopsticks-1.webp) ![Switch WSS](/images/builders/substrate/dev-env/chopsticks/chopsticks-2.webp) You should now be able to interact with the fork as you would an active parachain or relay chain. !!! note If your browser cannot connect to the WebSocket endpoint provided by Chopsticks, you might need to allow insecure connections for the Polkadot.js Apps URL. Another solution is to run the [Docker version of Polkadot.js Apps](https://github.com/polkadot-js/apps#docker){target=\_blank}. ## Replaying Blocks {: #replaying-blocks } In the case where you would like to replay a block and retrieve its information to dissect the effects of an extrinsic, you can use the `npx @acala-network/chopsticks@latest run-block` command. Its following flags are: | Flag | Description | |:--------------------------:|:--------------------------------------------------------------------------------------:| | `endpoint` | The endpoint of the parachain to fork. | | `block` | Use to specify at which block hash or number to replay the fork. | | `wasm-override` | Path of the WASM to use as the parachain runtime, instead of an endpoint's runtime. | | `db` | Path to the name of the file that stores or will store the parachain's database. | | `config` | Path or URL of the config file. | | `output-path=/[file_path]` | Use to print out results to a JSON file instead of printing it out in the console. | | `html` | Include to generate an HTML representation of the storage diff preview between blocks. | | `open` | Whether to open the HTML representation. | For example, running the following command will re-run Moonbeam's block 1000, and write the storage diff and other data in a `moonbeam-output.json` file: ```bash npx @acala-network/chopsticks@latest run-block \ --endpoint wss://wss.api.moonbeam.network \ --output-path=./moonbeam-output.json \ --block 1000 ``` ## XCM Testing {: #xcm-testing } To test out XCM messages between networks, you can fork multiple parachains and a relay chain locally. For example, the following will fork Moonriver, Karura, and Kusama given that you've downloaded the [`configs` directory from the source GitHub repository](https://github.com/AcalaNetwork/chopsticks/tree/master/configs){target=\_blank}: ```bash npx @acala-network/chopsticks@latest xcm \ --r=kusama.yml \ --p=moonriver.yml \ --p=karura.yml ``` You should see something like the following output: ```text [13:50:57.807] INFO (rpc/64805): Loading config file https://raw.githubusercontent.com/AcalaNetwork/chopsticks/master/configs/moonriver.yml [13:50:59.655] INFO (rpc/64805): Moonriver RPC listening on port 8000 [13:50:59.656] INFO (rpc/64805): Loading config file https://raw.githubusercontent.com/AcalaNetwork/chopsticks/master/configs/karura.yml [13:51:03.275] INFO (rpc/64805): Karura RPC listening on port 8001 [13:51:03.586] INFO (xcm/64805): Connected parachains [2000,2023] [13:51:03.586] INFO (rpc/64805): Loading config file https://raw.githubusercontent.com/AcalaNetwork/chopsticks/master/configs/kusama.yml [13:51:07.241] INFO (rpc/64805): Kusama RPC listening on port 8002 [13:51:07.700] INFO (xcm/64805): Connected relaychain 'Kusama' with parachain 'Moonriver' [13:51:08.386] INFO (xcm/64805): Connected relaychain 'Kusama' with parachain 'Karura' ``` Including the `r` flag as the relay chain is optional, as Chopsticks will automatically mock a relay chain between networks. You can also use a raw GitHub URL or the name of a popular branch, similar to the base command. ## WebSocket Commands {: #websocket-commands } Chopsticks' internal websocket server has special endpoints that allows the manipulation of the local Substrate chain. These are the methods that can be invoked: | Method | Parameters | Description | |:----------------:|:---------------------:|:-------------------------------------------------------------:| | `dev_newBlock` | `options` | Generates one or more new blocks. | | `dev_setStorage` | `values`, `blockHash` | Create or overwrite the value of any storage. | | `dev_timeTravel` | `date` | Sets the timestamp of the block to the `date` value. | | `dev_setHead` | `hashOrNumber` | Sets the head of the blockchain to a specific hash or number. | The parameters above are formatted in the following ways: | Parameter | Format | Example | |:--------------:|:-----------------------------------:|:----------------------------------------------------------------------:| | `options` | `{ "to": number, "count": number }` | `{ "count": 5 }` | | `values` | `Object` | `{ "Sudo": { "Key": "0x6Be02d1d3665660d22FF9624b7BE0551ee1Ac91b" } }` | | `blockHash` | `string` | `"0x1a34506b33e918a0106b100db027425a83681e2332fe311ee99d6156d2a91697"` | | `date` | `Date` | `"2030-08-15T00:00:00"` | | `hashOrNumber` | `number | string` | - **`options` { "to": number, "count": number }** - a JSON object where `"to"` will create blocks up to a certain value, and `"count"` will increase by a certain number of blocks. Use only one entry at a time within the JSON object - **`values` Object** - a JSON object resembling the path to a storage value, similar to what you would retrieve via Polkadot.js - **`blockHash` string** - optional, the blockhash at which the storage value is changed - **`date` Date** - a Date string (compatible with the JavaScript Date library) that will change the time stamp from which the next blocks being created will be at. All future blocks will be sequentially after that point in time - **`hashOrNumber` number | string** - if found, the chain head will be set to the block with the block number or block hash of this value Each method can be invoked by connecting to the websocket (`ws://localhost:8000` by default) and sending the data and parameters in the following format. Replace `METHOD_NAME` with the name of the method, and replace or delete `PARAMETER_1` and `PARAMETER_2` with the parameter data relevant to the method: ```json { "jsonrpc": "2.0", "id": 1, "method": "METHOD_NAME", "params": ["PARAMETER_1", "PARAMETER_2", "..."] } ```
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/dev-env/ --- BEGIN CONTENT --- --- title: Substrate Development Environments description: Explore development environments designed to facilitate access and interaction with the Substrate side of Moonbeam in a local development setting. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/ --- BEGIN CONTENT --- --- title: Substrate API description: Learn how to interact with the Substrate API when developing on Moonbeam, including how to use the Polkadot.js API for querying Moonbeam data. dropdown_description: Substrate libraries, tools, and low-level interfaces template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/interfaces/account/identity/ --- BEGIN CONTENT --- --- title: Identity Pallet description: This guide covers the available functions in the Identity Pallet on Moonbeam, which are used to create and manage on-chain identities. categories: Substrate Toolkit --- # The Identity Pallet ## Introduction {: #introduction } The [Substrate](/learn/platform/technology/#substrate-framework){target=\_blank} Identity Pallet is an out-of-the-box solution for adding personal information to your on-chain account. Personal information can include default fields such as your legal name, display name, website, Twitter handle, and Riot (now known as Element) name. You can also take advantage of custom fields to include any other relevant information. The pallet also includes functionality to request judgments and verify on-chain identities from registrars, which are accounts appointed via governance to verify the identity information submitted and provide judgment on their findings for a fee. This guide will provide an overview of the extrinsics, storage methods, and getters for the pallet constants available in the Identity Pallet on Moonbeam. This guide assumes you are familiar with identity-related terminology; if not, please check out the [Managing your Account Identity](/tokens/manage/identity/){target=\_blank} page for more information. ## Identity Pallet Interface {: #preimage-pallet-interface } ### Extrinsics {: #extrinsics } The Identity Pallet provides the following extrinsics (functions): ??? function "**addRegistrar**(account) - adds an account as a registrar. Must be executed by the General Admin Origin" === "Parameters" - `account` - the account to add as a registrar === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const account = INSERT_ACCOUNT; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.identity.addRegistrar(account); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**addSub**(sub, data) - adds an account as a sub-account of the caller. You can optionally provide a name for the sub-account. This function is not callable via a `NonTransfer` proxy. You can sign the transaction directly or use a different [proxy type](/tokens/manage/proxy-accounts/#proxy-types){target=\_blank} (`Any`, `IdentityJudgement`, etc.)" === "Parameters" - `sub` - the account to add as a sub-account - `data` - an object that specifies the name of the sub-account, where the key is the data type and the value is the data. You can use any of the following data types to define the name of the sub-account: - `None` - no name should be used - `Raw` - a raw value using hex or ascii - `BlakeTwo256` - a BLAKE2-256 hash value - `Sha256` - a SHA-256 value - `Keccak256` - a Keccak-256 value - `ShaThree256` - a SHA3-256 value === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const sub = 'INSERT_SUB_ACCOUNT'; const data = { INSERT_DATA_TYPE: 'INSERT_DATA' }; /* For None, use the following format: const data = { 'None': null }; For all other data types, use the name of the data type and the value formatted in that specific type. For example: const data = { 'Raw': 'Alice' }; */ const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.identity.addSub(sub, data); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**cancelRequest**(regIndex) - cancels the caller's request for judgment from a given registrar" === "Parameters" - `regIndex` - the index of the registrar === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const regIndex = 'INSERT_INDEX_OF_REGISTRAR'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.identity.cancelRequest(regIndex); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**clearIdentity**() - clears the identity for the caller" === "Parameters" None. === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.identity.clearIdentity(); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**killIdentity**(target) - removes an account's identity and sub-accounts. Must be executed by the General Admin Origin" === "Parameters" - `target` - the account to remove the identity and sub-accounts for === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const target = 'INSERT_TARGET_ACCOUNT'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.identity.killIdentity(target); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**provideJudgement**(regIndex, target, judgement, identity) - provides judgment on an account's identity. The caller must be the registrar account that corresponds to the `index`. Must be executed by a registrar" === "Parameters" - `regIndex` - the index of the registrar submitting the judgement - `target` - the account to provide the judgment for - `judgement` - the judgement or level of confidence in the identity information provided. There are seven levels of confidence, you can either provide the name or the index of the confidence level: - `Unknown` or `0` - no judgement made yet. This is the default value - `FeePaid` or `1` - indicates a user has requested judgement and it is in progress - `Reasonable` or `2` - the information appears reasonable, but no in-depth checks were performed using legal identity documents - `KnownGood` or `3` - the information is correct and is based upon review of legal identity documents - `OutOfDate` or `4` - the information used to be good, but is now out of date - `LowQuality` or `5` - the information is low quality or imprecise, but can be updated as needed - `Erroneous` or `6` - the information is erroneous and may indicate malicious intent. This state cannot be modified and can only be removed if the entire identity has been removed - `identity` - the 32-byte hash of the identity === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const regIndex = 'INSERT_REGISTRAR_INDEX'; const target = 'INSERT_TARGET_ACCOUNT'; const judgement = 'INSERT_JUDGEMENT'; const identity = 'INSERT_IDENTITY'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.identity.provideJudgement( regIndex, target, judgement, identity ); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**quitSub**() - removes the caller as a sub-identity account" === "Parameters" None. === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.identity.quitSub(); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**removeSub**(sub) - removes a sub-identity account for the caller" === "Parameters" - `sub` - the sub-identity account to remove === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const sub = 'INSERT_ACCOUNT'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.identity.removeSub(sub); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; ``` ??? function "**renameSub**(sub) - renames a sub-identity account for the caller" === "Parameters" - `sub` - the sub-identity account to rename === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const sub = 'INSERT_ACCOUNT'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.identity.rename(sub); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; ``` ??? function "**requestJudgement**(regIndex, maxFee) - requests judgment from a given registrar along with the maximum fee the caller is willing to pay" === "Parameters" - `regIndex` - the index of the registrar to request judgement from - `maxFee` - the maximum fee in Wei that can be paid to the registrar for providing judgement === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const regIndex = INSERT_REGISTRAR_INDEX; const maxFee = INSERT_MAX_FEE; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.identity.requestJudgement(regIndex, maxFee); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**setAccountId**(index, new) - sets a new account for an existing registrar. Must be executed by the registrar account that corresponds to the `index`." === "Parameters" - `index` - the index of the registrar - `new` - the account to set as the registrar's new account === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const index = INSERT_REGISTRAR_INDEX; const newAccount = 'INSERT_NEW_ACCOUNT'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.identity.setAccountId(index, newAccount); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**setFee**(index, fee) - sets the fee for a registar. Must be executed by the registrar account that corresponds to the `index`" === "Parameters" - `index` - the index of the registrar - `fee` - the fee in Wei required to be paid to the registrar for a judgement === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const index = INSERT_REGISTRAR_INDEX; const fee = INSERT_FEE; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.identity.setFee(index, fee); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**setFields**(index, fields) - sets the fields that a registrar cares about when providing judgements. Must be executed by the registrar account that corresponds to the `index`" === "Parameters" - `index` - the index of the registrar - `fields` - an array of the fields that the registrar cares about. The fields can be any of the following: - `Display` - a display name - `Legal` - a legal name - `Web` - a website - `Riot` - a Riot username - `Email` - an email address - `PpgFingerprint` - a PPG fingerprint - `Image` - an image - `Twitter` - a Twitter username === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const index = INSERT_REGISTRAR_INDEX; const fields = [INSERT_FIELDS]; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.identity.setFields(index, fields); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**setIdentity**(info) - sets the identity for the caller" === "Parameters" - `info` - the identity information. The identity information can include any of the following optional fields: - `display` - a display name - `legal` - a legal name - `web` - a website - `riot` - a Riot username - `email` - an email address - `ppgFingerprint` - a PPG fingerprint - `image` - an image - `twitter` - a Twitter username - `additional` - an array that contains custom fields for additional information. Each additional item is represented as an array that contains two objects: one for the field name and one for the field value. You can define the additional field names and values in the following formats: - `None` - no additional information should be used - `Raw` - a raw value using hex or ascii - `BlakeTwo256` - a BLAKE2-256 hash value - `Sha256` - a SHA-256 value - `Keccak256` - a Keccak-256 value - `ShaThree256` - a SHA3-256 value When setting an identity, a deposit is required. If setting additional fields, an additional deposit will be required per each additional field. For more information, please refer to the [Manage an Identity](/tokens/manage/identity#general-definitions){target=_blank} documentation. === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; /* Add as many or as few fields as you would like */ const info = { display: 'INSERT_DISPLAY_NAME', legal: 'INSERT_LEGAL_NAME', additional: [[{ Raw: 'Discord' }, { Raw: 'INSERT_DISCORD_USERNAME' }]], }; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.identity.setIdentity(info); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**setSubs**(subs) - sets the sub-accounts for the caller. This function is not callable via a `NonTransfer` proxy. You can sign the transaction directly or use a different [proxy type](/tokens/manage/proxy-accounts/#proxy-types){target=\_blank} (`Any`, `IdentityJudgement`, etc.)" === "Parameters" - `subs` - an array that defines the sub-accounts. Each sub-account is represented as an array itself, with the address of the sub-account as the zero index and the name as the first index. The name is an object that can be defined in the following formats: - `None` - no additional information should be used - `Raw` - a raw value using hex or ascii - `BlakeTwo256` - a BLAKE2-256 hash value - `Sha256` - a SHA-256 value - `Keccak256` - a Keccak-256 value - `ShaThree256` - a SHA3-256 value === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const subs = [ [INSERT_ACCOUNT, { Raw: 'INSERT_SUB_ACCOUNT_NAME' }], [INSERT_ACCOUNT, { None: null }], ]; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.identity.setSubs(subs); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ### Storage Methods {: #storage-methods } The Identity Pallet includes the following read-only storage methods to obtain chain state data: ??? function "**authorityOf**(account) – returns authority properties for a given account" === "Parameters" - `account` – the 20-byte account ID (`AccountId20`) you want to inspect. === "Returns" An `Option` If the supplied account **is not** a username-granting authority, the call returns `null`. === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Connect to Moonbase const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-rpc.dwellir.com'), }); // --- OPTION 1: Check a single account ---------------------- // const account = '0x1234...'; // AccountId20 as hex // const infoOpt = await api.query.identity.authorityOf(account); // console.log(infoOpt.isSome ? infoOpt.unwrap().toHuman() : 'Not an authority'); // --- OPTION 2: List *all* registered authorities ----------- const entries = await api.query.identity.authorityOf.entries(); if (entries.length === 0) { console.log('No authority accounts are registered.'); } else { console.log(`Found ${entries.length} authority account(s):\n`); for (const [storageKey, optProps] of entries) { if (optProps.isSome) { const account = storageKey.args[0].toString(); const { allowAutoClaim, deposit, provider } = optProps.unwrap(); console.log(`• ${account}`); console.log(` allowAutoClaim : ${allowAutoClaim.toString()}`); console.log(` deposit : ${deposit.toString()}`); console.log(` provider : ${provider.toString()}\n`); } } } await api.disconnect(); }; main().catch(console.error); ``` ??? function "**identityOf**(account) - returns identity information for a given account" === "Parameters" - `account` - the account to get identity information for === "Returns" Identity information for the given account, including judgments (if the account has requested a judgment from a registrar), the deposit is held for the identity and the identity information. If the account does not have an identity set, `null` is returned. ```js // If using Polkadot.js API and calling toJSON() on the query results { judgements: [], deposit: '0x00000000000000000e53d254821d0000', info: { additional: [ [Array] ], display: { raw: '0x416c697468' }, legal: { none: null }, web: { none: null }, riot: { none: null }, email: { raw: '0x616c69746840616c6974682e636f6d' }, pgpFingerprint: null, image: { none: null }, twitter: { none: null } } } ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; // Helper function to decode hex to string const hexToString = (hex) => { // Remove '0x' prefix if present const cleanHex = hex.startsWith('0x') ? hex.slice(2) : hex; // Convert hex to string const str = Buffer.from(cleanHex, 'hex').toString('utf8'); return str; }; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { const account = 'INSERT_ACCOUNT'; const identity = await api.query.identity.identityOf(account); console.log('Raw identity response:', identity.toString()); if (identity) { // Parse the raw response const rawResponse = JSON.parse(identity.toString()); if (rawResponse[0]) { const formattedIdentity = { judgements: rawResponse[0].judgements, deposit: rawResponse[0].deposit, info: { additional: rawResponse[0].info.additional, display: rawResponse[0].info.display.raw ? hexToString(rawResponse[0].info.display.raw) : null, legal: rawResponse[0].info.legal, web: rawResponse[0].info.web, riot: rawResponse[0].info.riot, email: rawResponse[0].info.email, pgpFingerprint: rawResponse[0].info.pgpFingerprint, image: rawResponse[0].info.image, twitter: rawResponse[0].info.twitter, }, }; console.log( 'Formatted Identity:', JSON.stringify(formattedIdentity, null, 2) ); } else { console.log('No identity data found in the response'); } } else { console.log('No identity found for this account'); } } catch (error) { console.error('Error querying identity:', error); } finally { await api.disconnect(); } }; main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**palletVersion**() - returns the current pallet version" === "Parameters" None === "Returns" The version of the pallet, e.g. `1` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Create the API instance const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Query the identity pallet version const version = await api.query.identity.palletVersion(); // Log the version to console console.log('Identity Pallet Version:', version.toString()); // Disconnect from the API await api.disconnect(); }; main().catch(console.error); ``` ??? function "**pendingUsernames**(username) - returns information for a pending username" === "Parameters" - `username` – the username to query. Pass it as a `Bytes` value (hex-encoded or plain ASCII). === "Returns" An `Option` that is: - `null` – if the username is **not** pending, or - `(AccountId20, u32, PalletIdentityProvider)` – when pending, where - `AccountId20` is the account that has been offered the username - `u32` is the **block number deadline** by which the account must accept it - `PalletIdentityProvider` is the authority that issued the username === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Connect to a Moonbase RPC endpoint const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-rpc.dwellir.com'), }); // Fetch *all* [StorageKey, Option<(AccountId20, u32, PalletIdentityProvider)>] pairs const entries = await api.query.identity.pendingUsernames.entries(); if (entries.length === 0) { console.log('There are no pending usernames right now.'); } else { console.log(`Found ${entries.length} pending username(s):\n`); for (const [storageKey, optValue] of entries) { if (optValue.isSome) { const [account, deadline, provider] = optValue.unwrap(); // The username itself is part of the storage key after the 32-byte hash prefix // api.registry.createType('Bytes', rawBytes) makes it human-readable const raw = storageKey.args[0]; // Bytes const username = api.registry.createType('Bytes', raw).toUtf8(); console.log(`• ${username}`); console.log(` owner : ${account.toString()}`); console.log(` expires : block ${deadline.toNumber()}`); console.log(` provider: ${provider.toString()}\n`); } } } await api.disconnect(); }; main().catch(console.error); ``` ??? function "**registrars**() - returns the set of registrars" === "Parameters" None === "Returns" The set of registrators as a vector === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Create the API instance const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Query the registrars const registrars = await api.query.identity.registrars(); // Format and log the registrars data const formattedRegistrars = registrars .map((reg) => { if (!reg.isSome) return null; const { account, fee, fields } = reg.unwrap(); return { account: account.toString(), fee: fee.toHuman(), fields: fields.toNumber(), }; }) .filter((reg) => reg !== null); console.log('Registrars:', JSON.stringify(formattedRegistrars, null, 2)); // Disconnect from the API await api.disconnect(); }; main().catch(console.error); ``` ??? function "**subsOf**(AccountId20) - returns the sub-identities for all accounts or a given account" === "Parameters" - `AccountId20` the account to check the sub-identities for === "Returns" The sub-identities, if any. ``` Raw subs response: [0,[]] Formatted Subs: { "deposit": "0", "subAccounts": [] } Number of sub-accounts: 0 ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { const account = 'INSERT_ACCOUNT'; const subs = await api.query.identity.subsOf(account); // Log raw response for debugging console.log('Raw subs response:', subs.toString()); if (subs) { // The response includes a tuple of [deposit, accounts] const [deposit, subAccounts] = subs; const formattedSubs = { deposit: deposit.toHuman(), subAccounts: subAccounts.toHuman(), }; console.log('Formatted Subs:', JSON.stringify(formattedSubs, null, 2)); console.log('Number of sub accounts:', subAccounts.length); } else { console.log('No sub identities found for this account'); } } catch (error) { console.error('Error querying sub identities:', error); } finally { await api.disconnect(); } }; main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**superOf**(AccountId20) - returns the super identity of all sub-accounts or for a given sub-account" === "Parameters" - `AccountId20` - the account to check the super identities of === "Returns" The super identities, if any. === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { const account = 'INSERT_ACCOUNT'; const superOf = await api.query.identity.superOf(account); // Log raw response for debugging console.log('Raw superOf response:', superOf.toString()); if (superOf.isSome) { // The response includes a tuple of [parentAccount, dataName] const [parentAccount, dataName] = superOf.unwrap(); const formattedSuper = { parentAccount: parentAccount.toString(), dataName: dataName.toHuman(), }; console.log( 'Formatted Super Identity:', JSON.stringify(formattedSuper, null, 2) ); } else { console.log('This account is not a sub-identity of any other account'); } } catch (error) { console.error('Error querying super identity:', error); } finally { await api.disconnect(); } }; main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**unbindingUsernames**(username) – returns the block height at which a username being revoked will be released" === "Parameters" - `username` – the username to inspect, supplied as `Bytes` (plain ASCII or hex). === "Returns" An `Option`: it is `null` when the username is **not** in the unbinding process; otherwise it contains the block number after which the username becomes free to claim again. === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Connect to Moonbase const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-rpc.dwellir.com'), }); // Fetch every (StorageKey, Option) pair const entries = await api.query.identity.unbindingUsernames.entries(); if (entries.length === 0) { console.log('There are no usernames in the unbinding process.'); } else { console.log(`Found ${entries.length} unbinding username(s):\n`); for (const [storageKey, optBlock] of entries) { if (optBlock.isSome) { // The username itself is the single argument encoded in the storage key const rawUsername = storageKey.args[0]; const username = api.registry.createType('Bytes', rawUsername).toUtf8(); const releaseBlock = optBlock.unwrap().toNumber(); console.log(`${username} → releases at block ${releaseBlock}`); } } } await api.disconnect(); }; main().catch(console.error); ``` ??? function "**usernameInfoOf**(username) – returns information for a given username" === "Parameters" - `username` – the username to look up. Supply it as a `Bytes` value (plain ASCII or hex). === "Returns" An `AccountId20` of the Account currently bound to the username and a provider value, i.e., the authority that issued the username. If the username is **unregistered**, the call returns `null`. === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Connect to Moonbase-Alpha const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-rpc.dwellir.com'), }); // Username to query (ASCII automatically wrapped as Bytes) const username = api.registry.createType('Bytes', 'alice'); // Fetch username information const infoOpt = await api.query.identity.usernameInfoOf(username); if (infoOpt.isSome) { const { owner, provider } = infoOpt.unwrap(); console.log(`Username : ${username.toUtf8()}`); console.log(` Owner account : ${owner.toString()}`); console.log(` Issued by : ${provider.toString()}`); } else { console.log('Username is not registered.'); } await api.disconnect(); }; main().catch(console.error); ``` ??? function "**usernameOf**(account) – returns the primary username bound to an account" === "Parameters" - `account` – the `AccountId20` you want to query. === "Returns" Returns an `Option`: it is null when the account has no primary username; otherwise, it contains a Bytes value with the UTF-8 (or hex-encoded) string of the account’s primary username. === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Connect to Moonbase const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-rpc.dwellir.com'), }); // Replace with any AccountId20 you wish to inspect const account = 'INSERT_ACCOUNT'; // Query the storage item const usernameOpt = await api.query.identity.usernameOf(account); if (usernameOpt.isSome) { // Convert Bytes → UTF-8 for readability const username = usernameOpt.unwrap().toUtf8(); console.log(`Primary username for ${account}: ${username}`); } else { console.log(`Account ${account} has no primary username set.`); } await api.disconnect(); }; main().catch(console.error); ``` ### Pallet Constants {: #constants } The Identity Pallet includes the following read-only functions to obtain pallet constants: ??? function "**basicDeposit**() - returns the amount held on deposit for a registered identity" === "Parameters" None === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Query the basicDeposit constant const basicDeposit = api.consts.identity.basicDeposit; // Log raw response for debugging console.log('Raw basicDeposit response:', basicDeposit.toString()); // Format the deposit amount console.log('Basic Deposit (formatted):', basicDeposit.toHuman()); } catch (error) { console.error('Error querying basic deposit:', error); } finally { await api.disconnect(); } }; main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` === "Example Response" ```bash Raw basicDeposit response: 1025800000000000000 Basic Deposit (formatted): 1,025,800,000,000,000,000 ``` ??? function "**byteDeposit**() - returns the amount held on deposit per additional bytes of data for a registered identity" === "Parameters" None === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Query the byteDeposit constant const byteDeposit = api.consts.identity.byteDeposit; // Log raw response for debugging console.log('Raw byteDeposit response:', byteDeposit.toString()); // Format the deposit amount console.log('Byte Deposit (formatted):', byteDeposit.toHuman()); } catch (error) { console.error('Error querying byte deposit:', error); } finally { await api.disconnect(); } }; main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` === "Example Response" ``` Raw byteDeposit response: 100000000000000 Byte Deposit (formatted): 100,000,000,000,000 ``` ??? function "**maxRegistrars**() - returns the maximum number of registrars allowed in the system" === "Parameters" None === "Returns" - `u32` - Maximum number of registrars allowed === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Query the maxRegistrars constant const maxRegistrars = api.consts.identity.maxRegistrars; // Get the number as a plain integer console.log('Max Registrars (number):', maxRegistrars.toNumber()); } catch (error) { console.error('Error querying max registrars:', error); } finally { await api.disconnect(); } }; main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**maxSubAccounts**() - returns the maximum number of sub-accounts allowed per account" === "Parameters" None === "Returns" - `u32` - Maximum number of sub-accounts allowed per identity === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { const maxSubAccounts = api.consts.identity.maxSubAccounts; console.log('Max SubAccounts (number):', maxSubAccounts.toNumber()); } catch (error) { console.error('Error querying max subaccounts:', error); } finally { await api.disconnect(); } }; main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**subAccountDeposit**() - returns the amount held on deposit for a registered sub-account" === "Parameters" None === "Returns" - `Balance` - Amount of currency held on deposit for a sub-account === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { const subAccountDeposit = api.consts.identity.subAccountDeposit; console.log('SubAccount Deposit:', subAccountDeposit.toHuman()); } catch (error) { console.error('Error querying subaccount deposit:', error); } finally { await api.disconnect(); } }; main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**pendingUsernameExpiration**() - returns the time period for which a username remains pending" === "Parameters" None === "Returns" - `BlockNumber` - Number of blocks before a pending username expires === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Query the pendingUsernameExpiration constant from identity pallet const pendingExpiration = api.consts.identity.pendingUsernameExpiration; console.log('Pending Username Expiration:', pendingExpiration.toHuman()); } catch (error) { console.error('Error querying pending username expiration:', error); } finally { await api.disconnect(); } }; main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**maxSuffixLength**() - returns the maximum length allowed for a username suffix" === "Parameters" None === "Returns" - `u32` - Maximum number of characters allowed in a username suffix === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { const maxSuffixLength = api.consts.identity.maxSuffixLength; console.log('Max Suffix Length:', maxSuffixLength.toHuman()); } catch (error) { console.error('Error querying max suffix length:', error); } finally { await api.disconnect(); } }; main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**maxUsernameLength**() - returns the maximum length allowed for a username" === "Parameters" None === "Returns" - `u32` - Maximum number of characters allowed in a username === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { const maxUsernameLength = api.consts.identity.maxUsernameLength; console.log('Max Username Length:', maxUsernameLength.toHuman()); } catch (error) { console.error('Error querying max username length:', error); } finally { await api.disconnect(); } }; main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/interfaces/account/ --- BEGIN CONTENT --- --- title: Substrate Interfaces for Account Management description: Explore low-level Substrate interfaces for advanced account management, including proxy control, identity verification, and multisig transactions. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/interfaces/account/multisig/ --- BEGIN CONTENT --- --- title: Multisig Pallet description: Learn about the Multisig Pallet, which taps into Substrate functionality to provide the ability to approve and dispatch calls from a multisig on Moonbeam. categories: Substrate Toolkit --- # The Multisig Pallet ## Introduction {: #introduction } Multisig wallets are a special type of wallet that requires multiple signatures in order to execute transactions, as the name implies. A multisig has a set of signers and defines a threshold for the number of signatures required to approve a transaction. This type of wallet provides an additional layer of security and decentralization. The Multisig Pallet on Moonbeam taps into Substrate functionality to allow for the ability to natively approve and dispatch calls from a multisig. With the Multisig Pallet, multiple signers, also referred to as signatories in Substrate, approve and dispatch transactions from an origin that is derivable deterministically from the set of signers' account IDs and the threshold for the number of accounts from the set that must approve calls before they can be dispatched. This page will provide an overview of the extrinsics, storage methods, and getters for the pallet constants available in the Multisig Pallet on Moonbeam. It will also include a brief demo on how to create a multisig account and send a transaction that requires two of three signers to approve and dispatch the transaction. ## Multisig Pallet Interface {: #multisig-pallet-interface } ### Extrinsics {: #extrinsics } The Multisig Pallet provides the following extrinsics (functions): ??? function "**asMulti**(threshold, otherSignatories, maybeTimepoint, call, maxWeight) - approves and if possible dispatches a call from a composite origin formed from a number of signed origins (a multisig). If the call has been approved by enough of the other signatories, the call will be dispatched. The [`depositBase`](#constants) will be reserved if this is the first approval plus the `threshold` times the [`depositFactor`](#constants). The total reserved amount will be returned once the call is dispatched or cancelled. This function should be used if it is the final approval, otherwise you'll want to use `approveAsMulti` instead since it only requires a hash of the call" === "Parameters" - `threshold` - The total number of approvals required for the dispatch to be executed - `otherSignatories` - The accounts (other than the sender) who can approve the dispatch - `maybeTimepoint` - The timepoint (block number and transaction index) of the first approval transaction. Must be `None` if this is the first approval - `call` - The actual call to be executed once approved - `maxWeight` - The maximum weight allowed for the dispatch === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; import { bnToHex, stringToHex } from '@polkadot/util'; const main = async () => { // Initialize API connection const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); const keyring = new Keyring({ type: 'ethereum' }); try { // Configuration const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const MULTISIG_ADDRESS = 'INSERT_ADDRESS_MULTISIG'; // Multisig parameters const threshold = 2; const otherSignatories = ['INSERT_SIGNER_1', 'INSERT_SIGNER_2'].sort(); // Addresses must be sorted // Create an EVM transaction const TARGET_ADDRESS = 'INSERT_DESTINATION_ADDRESS'; const VALUE = '1000000000000000000'; // 1 TOKEN in Wei // Construct the EVM call data const call = api.tx.evm.call( MULTISIG_ADDRESS, // source address TARGET_ADDRESS, // target address VALUE, // value in Wei '0x', // input data (empty for simple transfer) '2100000', // gas limit '1000000000', // max fee per gas (1 GWei) '1000000000', // max priority fee per gas (1 GWei) null, // nonce (optional) [] // access list (optional) ); // Weight limits for the dispatch const maxWeight = { refTime: '806342022', proofSize: '211174', }; const account = keyring.addFromUri(PRIVATE_KEY); // Check for existing timepoint const callHash = call.method.hash.toHex(); const multisigs = await api.query.multisig.multisigs( MULTISIG_ADDRESS, callHash ); let maybeTimepoint = null; if (multisigs.isSome) { const multisigInfo = multisigs.unwrap(); maybeTimepoint = { height: multisigInfo.when.height.toNumber(), index: multisigInfo.when.index.toNumber(), }; } console.log('Validation checks:'); console.log('Account address:', account.address); console.log('Multisig address:', MULTISIG_ADDRESS); console.log('Other signatories:', otherSignatories); console.log('Threshold:', threshold); console.log('Call hash:', callHash); console.log('Max weight:', maxWeight); console.log('Timepoint:', maybeTimepoint); // Create and send the asMulti transaction const tx = api.tx.multisig.asMulti( threshold, otherSignatories, maybeTimepoint, call, maxWeight ); // Sign and send the transaction await tx.signAndSend(account, ({ status, events }) => { if (status.isInBlock) { console.log(`Transaction included in block hash: ${status.asInBlock}`); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } }); // Check for specific multisig events const multisigEvent = events.find( ({ event }) => event.section === 'multisig' && (event.method === 'MultisigExecuted' || event.method === 'NewMultisig') ); if (multisigEvent) { console.log('Multisig event:', multisigEvent.event.method); } process.exit(0); } }); } catch (error) { console.error('Error in multisig execution:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` === "Example Response" ``` Validation checks: Account address: 0x3B939FeaD1557C741Ff06492FD0127bd287A421e Multisig address: 0x2c6a9d09E7C01f3D4154000193BDDcC597523221 Other signatories: [ '0x253b05C595222a1e3E7Bcf1611cA1307194a030F', '0x4B718e1CCeb83bfE87FD5f79cb98FFc2d4600C7E' ] Threshold: 2 Call hash: 0xdbbc67f35ca518976f4d392fb32745786e6b58fc526fab0dafb6eda44d9850a3 Max weight: { refTime: '806342022', proofSize: '211174' } Timepoint: null Transaction included in block hash: 0x0050f1b137e5814dc4eb16390d10287d9234de1d5827dd64ba85c878d4c53849 balances.Withdraw: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",4858229333763] balances.Reserved: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e","0x00000000000000000e1107d468560000"] multisig.NewMultisig: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e","0x2c6a9d09E7C01f3D4154000193BDDcC597523221","0xdbbc67f35ca518976f4d392fb32745786e6b58fc526fab0dafb6eda44d9850a3"] balances.Deposit: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",1222550823750] balances.Deposit: ["0x6d6F646c70632f74727372790000000000000000",727135702003] transactionPayment.TransactionFeePaid: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",3635678510013,0] system.ExtrinsicSuccess: [{"weight":{"refTime":404917324,"proofSize":5587},"class":"Normal","paysFee":"Yes"}] Multisig event: NewMultisig ``` ??? function "**approveAsMulti**(threshold, otherSignatories, maybeTimepoint, callHash, maxWeight) - approves a call from a composite origin. For the final approval, you'll want to use `asMulti` instead" === "Parameters" - `threshold` - The total number of approvals required for the dispatch to be executed - `otherSignatories` - The accounts (other than the sender) who can approve the dispatch - `maybeTimepoint` - The timepoint (block number and transaction index) of the first approval transaction. Must be `None` if this is the first approval - `callHash` - The hash of the call to be executed - `maxWeight` - The maximum weight allowed for the dispatch === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); const keyring = new Keyring({ type: 'ethereum' }); try { const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const threshold = 2; const otherSignatories = ['INSERT_SIGNER_1', 'INSERT_SIGNER_2'].sort(); const callHash = 'INSERT_CALL_HASH'; const maxWeight = { refTime: '806342022', proofSize: '211174', }; // Query the multisig address instead of the signer's address const MULTISIG_ADDRESS = 'INSERT_ADDRESS_MULTISIG'; const multisigs = await api.query.multisig.multisigs( MULTISIG_ADDRESS, callHash ); if (!multisigs.isSome) { console.error('No existing multisig found for this call hash'); process.exit(1); } const multisigInfo = multisigs.unwrap(); const timepoint = { height: multisigInfo.when.height.toNumber(), index: multisigInfo.when.index.toNumber(), }; const account = keyring.addFromUri(PRIVATE_KEY); console.log('Found timepoint:', timepoint); console.log('Validation checks:'); console.log('Account address:', account.address); console.log('Multisig address:', MULTISIG_ADDRESS); console.log('Other signatories:', otherSignatories); console.log('Threshold:', threshold); console.log('Call hash:', callHash); console.log('Max weight:', maxWeight); console.log('Timepoint:', timepoint); const tx = api.tx.multisig.approveAsMulti( threshold, otherSignatories, timepoint, callHash, maxWeight ); await tx.signAndSend(account, ({ status, events }) => { if (status.isInBlock) { console.log(`Transaction included in block hash: ${status.asInBlock}`); events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } }); process.exit(0); } }); } catch (error) { console.error('Error in multisig approval:', error); process.exit(1); } }; main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` === "Example Response" ```bash Found timepoint: { height: 9174086, index: 5 } Validation checks: Account address: 0x3B939FeaD1557C741Ff06492FD0127bd287A421e Multisig address: 0x2c6a9d09E7C01f3D4154000193BDDcC597523221 Other signatories: [ '0x253b05C595222a1e3E7Bcf1611cA1307194a030F', '0x4B718e1CCeb83bfE87FD5f79cb98FFc2d4600C7E' ] Threshold: 2 Call hash: 0xa2902805948bdd92fcaf661965215efd6a5980d0092c065e7470859c1b37b6a9 Max weight: { refTime: '806342022', proofSize: '211174' } Timepoint: { height: 9174086, index: 5 } Transaction included in block hash: 0xb7b0f712dc7aa3d471e1db89e0d182b59e1febf8bb1df73a03f36417fe19b506 balances.Withdraw: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",4512391685922] multisig.MultisigApproval: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",{"height":9174086,"index":5},"0x2c6a9d09E7C01f3D4154000193BDDcC597523221","0xa2902805948bdd92fcaf661965215efd6a5980d0092c065e7470859c1b37b6a9"] balances.Deposit: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",1025179732500] balances.Deposit: ["0x6d6F646c70632f74727372790000000000000000",697442390685] transactionPayment.TransactionFeePaid: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",3487211953422,0] system.ExtrinsicSuccess: [{"weight":{"refTime":389364247,"proofSize":5587},"class":"Normal","paysFee":"Yes"}] ``` ??? function "**asMultiThreshold**(otherSignatories, call) - immediately dispatches a multisig call using a single approval from the caller" === "Parameters" - `otherSignatories` - The accounts (other than the sender) who can approve the dispatch - `call` - The actual call to be executed once approved === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); const keyring = new Keyring({ type: 'ethereum' }); try { const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const threshold = 2; const otherSignatories = ['INSERT_SIGNER_1', 'INSERT_SIGNER_2'].sort(); const callHash = 'INSERT_CALL_HASH'; const maxWeight = { refTime: '806342022', proofSize: '211174', }; const MULTISIG_ADDRESS = 'INSERT_ADDRESS_MULTISIG'; const multisigs = await api.query.multisig.multisigs( MULTISIG_ADDRESS, callHash ); if (!multisigs.isSome) { console.error('No existing multisig found for this call hash'); process.exit(1); } const multisigInfo = multisigs.unwrap(); const timepoint = { height: multisigInfo.when.height.toNumber(), index: multisigInfo.when.index.toNumber(), }; const account = keyring.addFromUri(PRIVATE_KEY); console.log('Found timepoint:', timepoint); console.log('Validation checks:'); console.log('Account address:', account.address); console.log('Multisig address:', MULTISIG_ADDRESS); console.log('Other signatories:', otherSignatories); console.log('Threshold:', threshold); console.log('Call hash:', callHash); console.log('Max weight:', maxWeight); console.log('Timepoint:', timepoint); const tx = api.tx.multisig.approveAsMulti( threshold, otherSignatories, timepoint, callHash, maxWeight ); await tx.signAndSend(account, ({ status, events }) => { if (status.isInBlock) { console.log(`Transaction included in block hash: ${status.asInBlock}`); events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } }); process.exit(0); } }); } catch (error) { console.error('Error in multisig approval:', error); process.exit(1); } }; main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` === "Example Response" ``` Found timepoint: { height: 9174086, index: 5 } Validation checks: Account address: 0x3B939FeaD1557C741Ff06492FD0127bd287A421e Multisig address: 0x2c6a9d09E7C01f3D4154000193BDDcC597523221 Other signatories: [ '0x253b05C595222a1e3E7Bcf1611cA1307194a030F', '0x4B718e1CCeb83bfE87FD5f79cb98FFc2d4600C7E' ] Threshold: 2 Call hash: 0xa2902805948bdd92fcaf661965215efd6a5980d0092c065e7470859c1b37b6a9 Max weight: { refTime: '806342022', proofSize: '211174' } Timepoint: { height: 9174086, index: 5 } Transaction included in block hash: 0xb7b0f712dc7aa3d471e1db89e0d182b59e1febf8bb1df73a03f36417fe19b506 balances.Withdraw: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",4512391685922] multisig.MultisigApproval: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",{"height":9174086,"index":5},"0x2c6a9d09E7C01f3D4154000193BDDcC597523221","0xa2902805948bdd92fcaf661965215efd6a5980d0092c065e7470859c1b37b6a9"] balances.Deposit: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",1025179732500] balances.Deposit: ["0x6d6F646c70632f74727372790000000000000000",697442390685] transactionPayment.TransactionFeePaid: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",3487211953422,0] system.ExtrinsicSuccess: [{"weight":{"refTime":389364247,"proofSize":5587},"class":"Normal","paysFee":"Yes"}] ``` ??? function "**cancelAsMulti**(threshold, otherSignatories, maybeTimepoint, callHash) - cancels a preexisting, ongoing call from a composite origin. Any reserved deposit will be returned upon successful cancellation" === "Parameters" - `threshold` - The total number of approvals required for the dispatch to be executed - `otherSignatories` - The accounts (other than the sender) who can approve the dispatch - `maybeTimepoint` - The timepoint (block number and transaction index) of the first approval transaction. Must be `None` if this is the first approval - `callHash` - The hash of the call to be executed === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); const keyring = new Keyring({ type: 'ethereum' }); try { const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const threshold = 2; const otherSignatories = ['INSERT_SIGNER_1', 'INSERT_SIGNER_2'].sort(); const callHash = 'INSERT_CALL_HASH'; // Query the multisig address for the timepoint const MULTISIG_ADDRESS = 'INSERT_ADDRESS_MULTISIG'; const multisigs = await api.query.multisig.multisigs( MULTISIG_ADDRESS, callHash ); if (!multisigs.isSome) { console.error('No existing multisig found for this call hash'); process.exit(1); } const multisigInfo = multisigs.unwrap(); const timepoint = { height: multisigInfo.when.height.toNumber(), index: multisigInfo.when.index.toNumber(), }; const account = keyring.addFromUri(PRIVATE_KEY); console.log('Found timepoint:', timepoint); console.log('Validation checks:'); console.log('Account address:', account.address); console.log('Multisig address:', MULTISIG_ADDRESS); console.log('Other signatories:', otherSignatories); console.log('Threshold:', threshold); console.log('Call hash:', callHash); console.log('Timepoint:', timepoint); const tx = api.tx.multisig.cancelAsMulti( threshold, otherSignatories, timepoint, callHash ); await tx.signAndSend(account, ({ status, events }) => { if (status.isInBlock) { console.log(`Transaction included in block hash: ${status.asInBlock}`); events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } }); process.exit(0); } }); } catch (error) { console.error('Error in multisig cancellation:', error); process.exit(1); } }; main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` === "Example Response" ```bash Found timepoint: { height: 9174086, index: 5 } Validation checks: Account address: 0x3B939FeaD1557C741Ff06492FD0127bd287A421e Multisig address: 0x2c6a9d09E7C01f3D4154000193BDDcC597523221 Other signatories: [ '0x253b05C595222a1e3E7Bcf1611cA1307194a030F', '0x4B718e1CCeb83bfE87FD5f79cb98FFc2d4600C7E' ] Threshold: 2 Call hash: 0xa2902805948bdd92fcaf661965215efd6a5980d0092c065e7470859c1b37b6a9 Max weight: { refTime: '806342022', proofSize: '211174' } Timepoint: { height: 9174086, index: 5 } Transaction included in block hash: 0xb7b0f712dc7aa3d471e1db89e0d182b59e1febf8bb1df73a03f36417fe19b506 balances.Withdraw: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",4512391685922] multisig.MultisigApproval: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",{"height":9174086,"index":5},"0x2c6a9d09E7C01f3D4154000193BDDcC597523221","0xa2902805948bdd92fcaf661965215efd6a5980d0092c065e7470859c1b37b6a9"] balances.Deposit: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",1025179732500] balances.Deposit: ["0x6d6F646c70632f74727372790000000000000000",697442390685] transactionPayment.TransactionFeePaid: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",3487211953422,0] system.ExtrinsicSuccess: [{"weight":{"refTime":389364247,"proofSize":5587},"class":"Normal","paysFee":"Yes"}] ``` ### Storage Methods {: #storage-methods } The Multisig Pallet includes the following read-only storage methods to obtain chain state data: ??? function "**multisigs**() - returns the set of open multisig operations for a given account." === "Parameters" - `account` - The address of the multisig - `callHash` - (Optional) The hash of the multisig call === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // The account to query multisigs for const account = 'INSERT_ACCOUNT'; // Get all storage keys and values for this account's multisigs const entries = await api.query.multisig.multisigs.entries(account); if (entries.length === 0) { console.log('No multisigs found for this account'); } else { console.log(`Found ${entries.length} multisig(s):`); entries.forEach(([key, value]) => { // The key contains the call hash in its final 32 bytes const callHash = key.args[1].toHex(); console.log('\nCall Hash:', callHash); console.log('Details:', value.unwrap().toHuman()); }); } } catch (error) { console.error('Error querying multisigs:', error); } finally { await api.disconnect(); } }; main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` === "Example Response" ``` [ [ [ 0x2c6a9d09E7C01f3D4154000193BDDcC597523221 0xa2902805948bdd92fcaf661965215efd6a5980d0092c065e7470859c1b37b6a9 ] { when: { height: 9,174,086 index: 5 } deposit: 1,013,600,000,000,000,000 depositor: 0x253b05C595222a1e3E7Bcf1611cA1307194a030F approvals: [ 0x253b05C595222a1e3E7Bcf1611cA1307194a030F ] } ] ] ``` ??? function "**palletVersion**() - returns the current pallet version" === "Parameters" None === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Create the API instance const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Query the identity pallet version const version = await api.query.multisig.palletVersion(); // Log the version to console console.log('Identity Pallet Version:', version.toString()); // Disconnect from the API await api.disconnect(); }; main().catch(console.error); ``` === "Example Response" `1` ### Pallet Constants {: #constants } The Multisig Pallet includes the following read-only functions to obtain pallet constants: ??? function "**depositBase**() - returns the base amount of currency needed to reserve for creating a multisig execution or to store a dispatch call for later. This is held for an additional storage item whose key size is `32 + sizeof(AccountId)` bytes, which is `32 + 20` on Moonbeam, and whose value size is `4 + sizeof((BlockNumber, Balance, AccountId))` bytes, which is `4 + 4 + 16 +20` bytes on Moonbeam" === "Parameters" None === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { const depositBase = api.consts.multisig.depositBase; console.log('Multisig Deposit Base:', depositBase.toHuman()); } catch (error) { console.error('Error querying deposit base:', error); } finally { await api.disconnect(); } }; main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` === "Example Response" ``` Multisig Deposit Base: 1,009,600,000,000,000,000 ``` ??? function "**depositFactor**() - returns the amount of currency needed per unit threshold when creating a multisig execution. This is held for adding 20 bytes more into a preexisting storage value" === "Parameters" None === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { const depositFactor = api.consts.multisig.depositFactor; console.log('Multisig Deposit Factor:', depositFactor.toHuman()); } catch (error) { console.error('Error querying deposit factor:', error); } finally { await api.disconnect(); } }; main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` === "Example Response" ``` Multisig Deposit Factor: 2,000,000,000,000,000 ``` ??? function "**maxSignatories**() - returns the maximum amount of signatories allowed in the multisig" === "Parameters" None === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { const maxSignatories = api.consts.multisig.maxSignatories; console.log('Multisig Max Signatories:', maxSignatories.toHuman()); } catch (error) { console.error('Error querying max signatories:', error); } finally { await api.disconnect(); } }; main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` === "Example Response" ``` Multisig Max Signatories: 100 ``` ## How to Create a Multisig Account {: #create-a-multisig-account } You can easily create a multisig account from the Polkadot.js Apps interface. The easiest way to do so is from the [**Accounts** page](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/accounts){target=\_blank}. To get started, go ahead and click on **Multisig**. ![Add a multisig on Polkadot.js Apps](/images/builders/substrate/interfaces/account/multisig/multisig-1.webp) Next, you can take the following steps: 1. Choose which accounts you want to add to the multisig. For this example, three accounts will be chosen: Alice, Bob, and Charlie 2. Enter a number for **threshold**. This example will use `2` 3. Add a name for the multisig. This example uses `ABC` for Alice, Bob, and Charlie 4. Click **Create** ![Set up the multisig members](/images/builders/substrate/interfaces/account/multisig/multisig-2.webp) Now, the ABC multisig account will appear under the **multisig** section on the **Accounts** page. ![View the multisig account on the Accounts page of Polkadot.js Apps](/images/builders/substrate/interfaces/account/multisig/multisig-3.webp) You can click on the colored icon next to the multisig account to copy the address and fund it with DEV tokens. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank}. ## How to Create a Multisig Transaction {: #create-a-multisig-transaction } Now that you've created a multisig account, you can create a multisig call from one of the accounts that make up the multisig. This example will create the call from Alice's account. As such, Alice will need to submit a deposit. The deposit is calculated as follows: ```text Deposit = depositBase + threshold * depositFactor ``` You can retrieve the `depositBase` and `depositFactor` using the getter functions for the [Pallet Constants](#constants). Once the call is approved and dispatched or cancelled the deposit will be returned to Alice. Since there is a threshold of two for this multisig, at least Bob or Charlie will need to approve the call if not both of them. The last account to approve the call will also need to dispatch the call. Dispatching the call is done automatically when the `asMulti` function is used to approve the call. With the basics out of the way, you can begin to create a multisig call. For this example, you can create a call that will transfer 0.1 DEV from the ABC multisig account to Charlie's account. First, you'll need to get the encoded call data for the transfer. Go ahead and navigate to the [**Extrinsics** page on Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/extrinsics){target=\_blank} and take the following steps: 1. Make sure an account is selected. It doesn't have to be the ABC multisig account, as the selected account is not included in the encoded call data 2. Select the **balances** pallet and the **transfer** extrinsic 3. Set Charlie as the **dest** account 4. Enter the amount to transfer, which is `0.1` DEV for this example 5. Click the copy button next to the **encoded call data** 6. Click the copy button next to the **encoded call hash**. Please note that you do not have to submit the extrinsic, you only need the encoded call data and the encoded call hash ![Get the encoded call data for a balance transfer](/images/builders/substrate/interfaces/account/multisig/multisig-4.webp) Make sure you've copied and saved the encoded call data and the encoded call hash as you'll need them both to approve the multisig call later on in the tutorial. For this example, the encoded call data and hash are as follows: === "Encoded call data" ```text 0x0300798d4ba9baf0064ec19eb4f0a1a45785ae9d6dfc1300008a5d78456301 ``` === "Encoded call hash" ```text 0x76d1a0a8f6eb177dd7a561ef954e83893823fa5d77f576910f3fdc6cb4666dea ``` Next, you can create the multisig call by using the `asMulti` extrinsic, you'll take the following steps: 1. Select the account you want to create the call with. For this example, Alice is used 2. Select the **multisig** pallet and the **asMulti** extrinsic 3. Set the threshold of the multisig to the same value as you initially set from the **Accounts** page, which should be `2` 4. Add the other accounts that are associated with the multisig: Bob and Charlie 5. Since this is the first transaction to create the multisig call, make sure the **include option** slider is toggled off for the **maybeTimepoint** field. You would only enter this information for approvals that rely on knowing the timepoint at which the call was created 6. Provide the call information for the balance transfer similarly to how you did it in the previous set of steps. Select the **balances** pallet and the **transfer** extrinsic 7. Set the **dest** account to Charlie 8. Set the **value** to `0.1` DEV tokens 9. You can leave the **refTime** and **proofSize** fields set to `0` 10. Click **Submit Transaction** to create the multisig call ![Create a multisig call](/images/builders/substrate/interfaces/account/multisig/multisig-5.webp) Now that you've created the multisig call, you can submit approval transactions from either Bob's or Charlie's account, or both. Remember, for the call to be approved and dispatched, you need to have at least two of three members of the multisig to approve it. Since Alice created the multisig call, that means she has already automatically approved it. You can easily approve the transactions through the **Accounts** page of Polkadot.js Apps. Next to your multisig account, you'll notice there is a multisig icon there that you can hover over. Once you hover over it, you'll be able to click on **View pending approvals**. ![View pending multisig approvals](/images/builders/substrate/interfaces/account/multisig/multisig-6.webp) The **pending call hashes** pop-up will appear where you can follow these steps: 1. Since you should only have one hash at this point, you can select it from this list. If you have multiple hashes, you can compare the hashes in the list with the encoded call hash you copied earlier on in this section 2. The **depositor** should be automatically populated. For this example, it should be Alice 3. For the **approval type**, you can choose to either approve or reject the call. For this example, you can select **Approve this call hash** 4. Choose the account you want to approve the transaction from. This example uses Bob's account 5. Click **Approve** to submit the approval transaction. Under the hood, this uses the `approveAsMulti` extrinsic of the Multisig Pallet ![Approve a multisig call](/images/builders/substrate/interfaces/account/multisig/multisig-7.webp) So far, Alice and Bob have approved the multisig call, which means the threshold has been met. However, the call has not been dispatched yet since you have not yet submitted an executing approval. To do so, you'll take the same steps as above plus these additional steps: 1. Select the account you want to approve the transaction from. This example uses Charlie's account 2. Toggle the **multisig message with call (for final approval)** switch to on. Under the hood, this switches the extrinsic to `asMulti`, which automatically approves and dispatches the call if the threshold for approvals has been met as is the case at this point 3. The **call data for final approval** field will appear. Enter the encoded call data that you copied earlier on in this section 4. Click **Approve** to submit the approval, which will also dispatch the multisig call ![Approve and dispatch a multisig call](/images/builders/substrate/interfaces/account/multisig/multisig-8.webp) Once the final transaction has been submitted, 0.1 DEV tokens will be transferred from the ABC multisig account to Charlie's account and the multisig deposit will be returned to Alice's account. And that's it! You've successfully created a multisig call, approved the call, and dispatched it. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/interfaces/account/proxy/ --- BEGIN CONTENT --- --- title: Proxy Pallet description: Learn how to use the available extrinsics, storage methods, and constants in the Proxy Pallet on Moonbeam to make calls on an account's behalf. keywords: proxy, substrate, moonbeam, polkadot categories: Substrate Toolkit --- # The Proxy Pallet ## Introduction {: #introduction } Proxy accounts can be set up to perform a limited number of actions on behalf of users and are useful for keeping the underlying accounts safe. They allow users to keep their primary account secured safely in cold storage while enabling the proxy to actively perform functions and participate in the network with the weight of the tokens in the primary account. [Substrate's proxy pallet](https://wiki.polkadot.network/learn/learn-proxies/){target=\_blank} enables you to create proxy accounts, remove proxy accounts, make calls as a proxy account, and announce proxy transactions. To add and remove proxy accounts, you can use the proxy precompile: a Solidity interface that can be interacted through the Ethereum API. For more information on how to use this contract, please refer to the [Proxy Precompile](/builders/ethereum/precompiles/account/proxy/){target=\_blank} guide. This page will provide an overview of the extrinsics, storage methods, and getters for the pallet constants available in the proxy pallet. ## Proxy Pallet Interface {: #proxy-pallet-interface } ### Extrinsics {: #extrinsics } The proxy pallet provides the following extrinsics (functions): ??? function "**addProxy**(delegate, proxyType, delay) - registers a proxy account for the sender that is able to make calls on the sender's behalf. If `delay` is set to a value greater than 0, the proxy account will have to announce a transaction and wait that value of blocks before attempting to execute it as a proxy. Emits a `ProxyAdded` event" === "Parameters" - `delegate` - The account that will act as proxy (H160 format address, e.g., '0x123...'). This address will be able to submit transactions on behalf of the caller - `proxyType` - The permissions granted to the proxy account. Available options are: - `Any`: Allows all transactions - `NonTransfer`: Allows all transactions except balance transfers - `Governance`: Allows governance-related transactions - `Staking`: Allows staking-related transactions - `CancelProxy`: Only allows canceling other proxies - `Balances`: Allows balance transfers - `AuthorMapping`: Allows author mapping transactions - `IdentityJudgement`: Allows providing identity judgements - `delay` - Number of blocks that must pass after announcing a proxy transaction before it can be executed (u32). Set to `0` for immediate execution === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup account from private key const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const account = keyring.addFromUri(PRIVATE_KEY); // Use an existing account as proxy const proxyAccount = 'INSERT_PROXY_ACCOUNT'; // Define proxy parameters // Use the Staking variant from the ProxyType enum const proxyType = { Staking: null }; const delay = 0; // No delay console.log('Validation checks:'); console.log('Account address:', account.address); console.log('Proxy account address:', proxyAccount); console.log('Proxy type:', JSON.stringify(proxyType)); console.log('Delay:', delay); // Create the addProxy transaction const tx = api.tx.proxy.addProxy(proxyAccount, proxyType, delay); // Sign and send the transaction await tx.signAndSend(account, ({ status, events }) => { if (status.isInBlock) { console.log(`Transaction included in block hash: ${status.asInBlock}`); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful proxy addition if (section === 'proxy' && method === 'ProxyAdded') { console.log('Proxy successfully added!'); } }); process.exit(0); } }); } catch (error) { console.error('Error in adding proxy:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` === "Example Response" ``` Validation checks: Account address: 0x3B939FeaD1557C741Ff06492FD0127bd287A421e Proxy account address: 0x569BE8d8b04538318e1722f6e375FD381D2da865 Proxy type: {"Staking":null} Delay: 0 Transaction included in block hash: 0xd9763b3eec3e50dfeec246f1537421a632ec5a3ab821a5e5e6b507c12930cd64 balances.Withdraw: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",3431276154061] balances.Reserved: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",2100000000000000] proxy.ProxyAdded: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e","0x569BE8d8b04538318e1722f6e375FD381D2da865","Staking",0] Proxy successfully added! balances.Deposit: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",0] balances.Deposit: ["0x6d6F646c70632f74727372790000000000000000",686255230813] transactionPayment.TransactionFeePaid: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",3431276154061,0] system.ExtrinsicSuccess: [{"weight":{"refTime":398219506,"proofSize":4310},"class":"Normal","paysFee":"Yes"}] ``` ??? function "**announce**(real, callHash) - registers an announcement of a proxy transaction by proxy accounts that require a delay. Emits an `Announced` event" === "Parameters" - `real` - The account being proxied (H160 format address, e.g., '0x123...'). This is the account on whose behalf the delayed proxy intends to execute a call - `callHash` - The hash of the call that the proxy intends to execute after the delay period (32-byte hex string, e.g., '0x570ff355...'). This hash is derived from the actual call data that will be executed later === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup accounts const PROXY_PRIVATE_KEY = 'INSERT_PROXY_PRIVATE_KEY'; const proxyAccount = keyring.addFromUri(PROXY_PRIVATE_KEY); // The real account that the proxy will act on behalf of const realAccount = 'INSERT_REAL_ACCOUNT'; // Use the provided call hash const callHash = 'INSERT_CALL_HASH'; console.log('Validation checks:'); console.log('Proxy account address:', proxyAccount.address); console.log('Real account address:', realAccount); console.log('Call hash:', callHash); // Create the announce transaction const tx = api.tx.proxy.announce(realAccount, callHash); // Sign and send the transaction await tx.signAndSend(proxyAccount, ({ status, events }) => { if (status.isInBlock) { console.log(`Transaction included in block hash: ${status.asInBlock}`); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful announcement if (section === 'proxy' && method === 'Announced') { console.log('Proxy call successfully announced!'); console.log( 'You can execute the actual call after the delay period' ); } }); process.exit(0); } }); } catch (error) { console.error('Error in announcing proxy call:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` === "Example Response" ``` Validation checks: Proxy account address: 0x569BE8d8b04538318e1722f6e375FD381D2da865 Real account address: 0x3B939FeaD1557C741Ff06492FD0127bd287A421e Call hash: 0x570ff355e1471d3528cb4e2586bee7eafebc2efc89dd6f827188c69b15fff965 Transaction included in block hash: 0xdb5b9bb961ce3153387d2131911de218c08b8b09d8a625f36271ad98b2abf567 balances.Withdraw: ["0x569BE8d8b04538318e1722f6e375FD381D2da865",3682233905542] balances.Reserved: ["0x569BE8d8b04538318e1722f6e375FD381D2da865","0x00000000000000000df77377c5f40000"] proxy.Announced: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e","0x569BE8d8b04538318e1722f6e375FD381D2da865","0x570ff355e1471d3528cb4e2586bee7eafebc2efc89dd6f827188c69b15fff965"] Proxy call successfully announced! You can execute the actual call after the delay period balances.Deposit: ["0x569BE8d8b04538318e1722f6e375FD381D2da865",0] balances.Deposit: ["0x6d6F646c70632f74727372790000000000000000",736446781109] transactionPayment.TransactionFeePaid: ["0x569BE8d8b04538318e1722f6e375FD381D2da865",3682233905542,0] system.ExtrinsicSuccess: [{"weight":{"refTime":577384531,"proofSize":5302},"class":"Normal","paysFee":"Yes"}] ``` ??? function "**proxy**(real, forceProxyType, call) - makes a transaction as a proxy. Emits a `ProxyExecuted` event" === "Parameters" - `real` - The account being proxied (H160 format address, e.g., '0x123...'). This is the account on whose behalf the proxy will execute the call - `forceProxyType` - The type of proxy right required to execute this call. Must match the proxy type that was specified when the proxy was added. Available options are: - `Any`: Allows all transactions - `NonTransfer`: Allows all transactions except balance transfers - `Governance`: Allows governance-related transactions - `Staking`: Allows staking-related transactions - `CancelProxy`: Only allows canceling other proxies - `Balances`: Allows balance transfers - `AuthorMapping`: Allows author mapping transactions - `IdentityJudgement`: Allows providing identity judgements - `call` - The actual call data to be executed by the proxy on behalf of the real account. This is the transaction that will be performed (e.g., a transfer, a stake, or any other valid runtime call) === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup proxy account from private key const PROXY_PRIVATE_KEY = 'INSERT_PROXY_PRIVATE_KEY'; const proxyAccount = keyring.addFromUri(PROXY_PRIVATE_KEY); // The real account that we're making the transaction for const realAccount = 'INSERT_REAL_ACCOUNT'; // Destination account for the simple demo transfer const destinationAccount = 'INSERT_DESTINATION_ADDRESS'; // Amount to transfer (1 DEV = 1e18 Wei) const transferAmount = '1000000000000000000'; // 1 DEV // Create the transfer call that we want to make via proxy const transferCall = api.tx.balances.transferAllowDeath( destinationAccount, transferAmount ); // Create the proxy transaction // We'll specify Balances as the force proxy type since we're doing a transfer const tx = api.tx.proxy.proxy( realAccount, { Any: null }, // forceProxyType transferCall ); console.log('Validation checks:'); console.log('Proxy account:', proxyAccount.address); console.log('Real account:', realAccount); console.log('Destination account:', destinationAccount); console.log('Transfer amount:', transferAmount, 'Wei (1 DEV)'); // Sign and send the transaction await tx.signAndSend(proxyAccount, ({ status, events }) => { if (status.isInBlock) { console.log(`Transaction included in block hash: ${status.asInBlock}`); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful transfer if (section === 'balances' && method === 'Transfer') { console.log('\nTransfer successfully executed via proxy!'); const [from, to, amount] = data; console.log('From:', from.toString()); console.log('To:', to.toString()); console.log('Amount:', amount.toString()); } }); process.exit(0); } }); } catch (error) { console.error('Error in proxy transaction:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` === "Example Response" ``` Validation checks: Proxy account: 0x3B939FeaD1557C741Ff06492FD0127bd287A421e Real account: 0x569BE8d8b04538318e1722f6e375FD381D2da865 Destination account: 0x8c9c5F11d162a69E979F2DB9047A862ecbcA23Cb Transfer amount: 1000000000000000000 Wei (1 DEV) Force proxy type: Balances Transaction included in block hash: 0xc347d714324e795c0e27ef574c8f924d7a52935314044cf2e2a395bc32ef5070 balances.Withdraw: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",3817444390449] balances.Transfer: ["0x569BE8d8b04538318e1722f6e375FD381D2da865","0x8c9c5F11d162a69E979F2DB9047A862ecbcA23Cb","0x00000000000000000de0b6b3a7640000"] Transfer successfully executed via proxy! From: 0x569BE8d8b04538318e1722f6e375FD381D2da865 To: 0x8c9c5F11d162a69E979F2DB9047A862ecbcA23Cb Amount: 1000000000000000000 proxy.ProxyExecuted: [{"ok":null}] balances.Deposit: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",0] balances.Deposit: ["0x6d6F646c70632f74727372790000000000000000",763488878090] transactionPayment.TransactionFeePaid: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",3817444390449,0] system.ExtrinsicSuccess: [{"weight":{"refTime":684752866,"proofSize":8691},"class":"Normal","paysFee":"Yes"}] ``` ??? function "**proxyAnnounced**(delegate, real, forceProxyType, call) - makes a transaction as a proxy and removes previous corresponding announcements. Emits a `ProxyExecuted` event" === "Parameters" - `delegate` - The account that previously made the announcement (H160 format address, e.g., '0x123...'). This must match the proxy account that called the announce function - `real` - The account being proxied (H160 format address, e.g., '0x123...'). This is the account on whose behalf the proxy will execute the call - `forceProxyType` - The type of proxy right required to execute this call. Must match the proxy type that was specified when the proxy was added. Available options are: - `Any`: Allows all transactions - `NonTransfer`: Allows all transactions except balance transfers - `Governance`: Allows governance-related transactions - `Staking`: Allows staking-related transactions - `CancelProxy`: Only allows canceling other proxies - `Balances`: Allows balance transfers - `AuthorMapping`: Allows author mapping transactions - `IdentityJudgement`: Allows providing identity judgements - `call` - The actual call to be executed (must match the call that was previously announced). This is the transaction that will be performed (e.g., a transfer, a stake, or any other valid runtime call) === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup proxy account from private key (this is the account executing the call) const PROXY_PRIVATE_KEY = 'INSERT_PROXY_PRIVATE_KEY'; const proxyAccount = keyring.addFromUri(PROXY_PRIVATE_KEY); // The account that delegated proxy rights const realAccount = 'INSERT_REAL_ACCOUNT'; // The delegate account (the proxy account that made the announcement) const delegateAccount = proxyAccount.address; // Destination account for the transfer const destinationAccount = 'INSERT_DESTINATION_ADDRESS'; // Amount to transfer (1 DEV = 1e18 Wei) const transferAmount = '1000000000000000000'; // 1 DEV // Create the transfer call that was previously announced const transferCall = api.tx.balances.transferAllowDeath( destinationAccount, transferAmount ); // Create the proxyAnnounced transaction const tx = api.tx.proxy.proxyAnnounced( delegateAccount, realAccount, { Balances: null }, // forceProxyType transferCall ); console.log('Validation checks:'); console.log('Delegate (Proxy) account:', delegateAccount); console.log('Real account:', realAccount); console.log('Force proxy type: Balances'); console.log('Call details:'); console.log('- Destination:', destinationAccount); console.log('- Amount:', transferAmount, 'Wei (1 DEV)'); // Sign and send the transaction await tx.signAndSend(proxyAccount, ({ status, events }) => { if (status.isInBlock) { console.log(`Transaction included in block hash: ${status.asInBlock}`); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful proxy execution if (section === 'proxy' && method === 'ProxyExecuted') { console.log('\nProxy call successfully executed!'); } // Log successful transfer if (section === 'balances' && method === 'Transfer') { const [from, to, amount] = data; console.log('Transfer details:'); console.log('From:', from.toString()); console.log('To:', to.toString()); console.log('Amount:', amount.toString()); } }); process.exit(0); } }); } catch (error) { console.error('Error in proxy announced transaction:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` === "Example Response" ``` Validation checks: Proxy account: 0x3B939FeaD1557C741Ff06492FD0127bd287A421e Real account: 0x569BE8d8b04538318e1722f6e375FD381D2da865 Destination account: 0x8c9c5F11d162a69E979F2DB9047A862ecbcA23Cb Transfer amount: 1000000000000000000 Wei (1 DEV) Force proxy type: Balances Transaction included in block hash: 0xc347d714324e795c0e27ef574c8f924d7a52935314044cf2e2a395bc32ef5070 balances.Withdraw: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",3817444390449] balances.Transfer: ["0x569BE8d8b04538318e1722f6e375FD381D2da865","0x8c9c5F11d162a69E979F2DB9047A862ecbcA23Cb","0x00000000000000000de0b6b3a7640000"] Transfer successfully executed via proxy! From: 0x569BE8d8b04538318e1722f6e375FD381D2da865 To: 0x8c9c5F11d162a69E979F2DB9047A862ecbcA23Cb Amount: 1000000000000000000 proxy.ProxyExecuted: [{"ok":null}] balances.Deposit: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",0] balances.Deposit: ["0x6d6F646c70632f74727372790000000000000000",763488878090] transactionPayment.TransactionFeePaid: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",3817444390449,0] system.ExtrinsicSuccess: [{"weight":{"refTime":684752866,"proofSize":8691},"class":"Normal","paysFee":"Yes"}] ``` ??? function "**rejectAnnouncement**(delegate, callHash) - if the sender is a prime account, this removes a specific announcement from their proxy account" === "Parameters" - `delegate` - The account that previously made the announcement (H160 format address, e.g., '0x123...'). This must match the proxy account that called the announce function - `callHash` - The hash call to be executed (must match the call that was previously announced) === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup the real account (the one that will reject the announcement) const REAL_PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const realAccount = keyring.addFromUri(REAL_PRIVATE_KEY); // The proxy account that made the announcement const delegateAccount = 'INSERT_PROXY_ACCOUNT'; // The call hash of the announcement to reject const callHash = 'INSERT_CALL_HASH'; console.log('Validation checks:'); console.log('Real account (rejector):', realAccount.address); console.log('Delegate account to reject:', delegateAccount); console.log('Call hash to reject:', callHash); // Create the reject announcement transaction const tx = api.tx.proxy.rejectAnnouncement(delegateAccount, callHash); // Sign and send the transaction await tx.signAndSend(realAccount, ({ status, events }) => { if (status.isInBlock) { console.log(`Transaction included in block hash: ${status.asInBlock}`); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful rejection if (section === 'proxy' && method === 'AnnouncementRejected') { console.log('\nAnnouncement successfully rejected!'); const [accountId, hash] = data; console.log('Rejected delegate:', accountId.toString()); console.log('Rejected call hash:', hash.toString()); } }); process.exit(0); } }); } catch (error) { console.error('Error in rejecting announcement:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` === "Example Response" Validation checks: Real account (rejector): 0x569BE8d8b04538318e1722f6e375FD381D2da865 Delegate account to reject: 0x569BE8d8b04538318e1722f6e375FD381D2da865 Call hash to reject: 0xaf2dd398c8ee31d963d1f24764b8857e27314b3e937385c3ff60c034a36e925c Transaction included in block hash: 0x76073a7b5eae1b9efb4a8142916fb33fa9f11a31f9e1f231ecb1ebd1af7a2a47 balances.Withdraw: ["0x569BE8d8b04538318e1722f6e375FD381D2da865",3621382860542] balances.Deposit: ["0x569BE8d8b04538318e1722f6e375FD381D2da865",0] balances.Deposit: ["0x6d6F646c70632f74727372790000000000000000",724276572109] transactionPayment.TransactionFeePaid: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",3621382860542,0] ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",3817444390449,0] system.ExtrinsicSuccess: [{"weight":{"refTime":684752866,"proofSize":8691},"class":"Normal","paysFee":"Yes"}] ??? function "**removeAnnouncement**(real, callHash) - if the sender is a proxy account, this removes a specific announcement to their prime account" === "Parameters" - `real` - The account that was designated as the real account in the original announcement (H160 format address, e.g., '0x123...'). This is the account on whose behalf the proxy had announced a future transaction - `callHash` - The hash of the call from the original announcement (32-byte hex string, e.g., '0x570ff355...'). This uniquely identifies which announced transaction should be removed === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup the proxy account (the one that will remove its own announcement) const PROXY_PRIVATE_KEY = 'INSERT_PROXY_PRIVATE_KEY'; const proxyAccount = keyring.addFromUri(PROXY_PRIVATE_KEY); // The real account that the announcement was made for const realAccount = 'INSERT_REAL_ACCOUNT'; // The call hash of the announcement to remove const callHash = 'INSERT_CALL_HASH'; console.log('Validation checks:'); console.log('Proxy account (remover):', proxyAccount.address); console.log('Real account:', realAccount); console.log('Call hash to remove:', callHash); // Create the remove announcement transaction const tx = api.tx.proxy.removeAnnouncement(realAccount, callHash); // Sign and send the transaction await tx.signAndSend(proxyAccount, ({ status, events }) => { if (status.isInBlock) { console.log(`Transaction included in block hash: ${status.asInBlock}`); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful announcement removal if (section === 'proxy' && method === 'AnnouncementRejected') { console.log('\nAnnouncement successfully removed!'); const [accountId, hash] = data; console.log('Removed for real account:', accountId.toString()); console.log('Removed call hash:', hash.toString()); } }); process.exit(0); } }); } catch (error) { console.error('Error in removing announcement:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` === "Example Response" ``` Validation checks: Proxy account (remover): 0x3B939FeaD1557C741Ff06492FD0127bd287A421e Real account: 0x569BE8d8b04538318e1722f6e375FD381D2da865 Call hash to remove: 0x570ff355e1471d3528cb4e2586bee7eafebc2efc89dd6f827188c69b15fff965 Transaction included in block hash: 0x767724a583d93b558c56f2e241d2334bf91773269ceb1e0a60435f7cbbe2205a balances.Withdraw: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",3621330308042] balances.Deposit: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",0] balances.Deposit: ["0x6d6F646c70632f74727372790000000000000000",724266061609] transactionPayment.TransactionFeePaid: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",3621330308042,0] ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",3817444390449,0] system.ExtrinsicSuccess: [{"weight":{"refTime":684752866,"proofSize":8691},"class":"Normal","paysFee":"Yes"}] ``` ??? function "**removeProxies**() - unregisters all proxy accounts for the sender" === "Parameters" None === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup the account that wants to remove all its proxies const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const account = keyring.addFromUri(PRIVATE_KEY); console.log('Validation checks:'); console.log('Account removing all proxies:', account.address); // Optional: Query existing proxies before removal const proxies = await api.query.proxy.proxies(account.address); console.log('\nCurrent proxies before removal:', proxies.toHuman()); // Create the removeProxies transaction const tx = api.tx.proxy.removeProxies(); // Sign and send the transaction await tx.signAndSend(account, ({ status, events }) => { if (status.isInBlock) { console.log( `\nTransaction included in block hash: ${status.asInBlock}` ); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful proxy removals if (section === 'proxy' && method === 'ProxyRemoved') { console.log('\nProxy successfully removed!'); const [delegator, delegate, proxyType, delay] = data; console.log('Delegator:', delegator.toString()); console.log('Removed delegate:', delegate.toString()); console.log('Proxy type:', proxyType.toString()); console.log('Delay:', delay.toString()); } }); // Optional: Query proxies after removal to confirm api.query.proxy.proxies(account.address).then((afterProxies) => { console.log('\nProxies after removal:', afterProxies.toHuman()); process.exit(0); }); } }); } catch (error) { console.error('Error in removing all proxies:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` === "Example Response" ``` Validation checks: Account removing all proxies: 0x3B939FeaD1557C741Ff06492FD0127bd287A421e Current proxies before removal: [ [ { delegate: '0x0000000000000000000000000000000000000000', proxyType: 'Governance', delay: '0' }, { delegate: '0x4b8C667590E6a28497Ea4be5FACB7e9869A64EAE', proxyType: 'Staking', delay: '0' }, { delegate: '0x569BE8d8b04538318e1722f6e375FD381D2da865', proxyType: 'Staking', delay: '0' }, { delegate: '0x569BE8d8b04538318e1722f6e375FD381D2da865', proxyType: 'Balances', delay: '100' } ], '1,009,200,000,000,000,000' ] Transaction included in block hash: 0x2ef80fe655c98f47ba82cc2ee7937e03d2c6211195dc03ef02e6d47fbbdcd944 balances.Withdraw: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",3403192090986] balances.Unreserved: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e","0x00000000000000000e01660d93530000"] balances.Deposit: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",0] balances.Deposit: ["0x6d6F646c70632f74727372790000000000000000",680638418198] transactionPayment.TransactionFeePaid: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",3403192090986,0] system.ExtrinsicSuccess: [{"weight":{"refTime":395752965,"proofSize":4310},"class":"Normal","paysFee":"Yes"}] Proxies after removal: [ [], '0' ] ``` ??? function "**removeProxy**(delegate, proxyType, delay) - unregisters a specific proxy account for the sender. Emits a `ProxyRemoved` event" === "Parameters" - `delegate` - The proxy account to remove (H160 format address, e.g., '0x123...'). This must be an existing proxy account that was previously registered using addProxy - `proxyType` - The type of proxy to remove. Must match exactly what was set when the proxy was added. Available options are: - `Any`: Allows all transactions - `NonTransfer`: Allows all transactions except balance transfers - `Governance`: Allows governance-related transactions - `Staking`: Allows staking-related transactions - `CancelProxy`: Only allows canceling other proxies - `Balances`: Allows balance transfers - `AuthorMapping`: Allows author mapping transactions - `IdentityJudgement`: Allows providing identity judgements - `delay` - The announcement delay in blocks that was set when adding the proxy (u32). Must match exactly what was set when the proxy was added (e.g., if proxy was added with delay=100, must use delay=100 to remove it) === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup the account that wants to remove a specific proxy const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const account = keyring.addFromUri(PRIVATE_KEY); // The proxy account to remove const proxyToRemove = 'INSERT_PROXY_ACCOUNT'; // Must match the original proxy type and delay that was set when adding the proxy const proxyType = { Any: null }; const delay = 0; console.log('Validation checks:'); console.log('Account removing proxy:', account.address); console.log('Proxy being removed:', proxyToRemove); console.log('Proxy type:', JSON.stringify(proxyType)); console.log('Delay:', delay); // Optional: Query existing proxies before removal const proxiesBefore = await api.query.proxy.proxies(account.address); console.log('\nCurrent proxies before removal:', proxiesBefore.toHuman()); // Create the removeProxy transaction const tx = api.tx.proxy.removeProxy(proxyToRemove, proxyType, delay); // Sign and send the transaction await tx.signAndSend(account, ({ status, events }) => { if (status.isInBlock) { console.log( `\nTransaction included in block hash: ${status.asInBlock}` ); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful proxy removal if (section === 'proxy' && method === 'ProxyRemoved') { console.log('\nProxy successfully removed!'); const [delegator, delegate, proxyType, delay] = data; console.log('Delegator:', delegator.toString()); console.log('Removed delegate:', delegate.toString()); console.log('Proxy type:', proxyType.toString()); console.log('Delay:', delay.toString()); } }); // Optional: Query proxies after removal to confirm api.query.proxy.proxies(account.address).then((afterProxies) => { console.log('\nProxies after removal:', afterProxies.toHuman()); process.exit(0); }); } }); } catch (error) { console.error('Error in removing proxy:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` === "Example Response" ``` Validation checks: Account removing proxy: 0x3B939FeaD1557C741Ff06492FD0127bd287A421e Proxy being removed: 0x569BE8d8b04538318e1722f6e375FD381D2da865 Proxy type: {"Any":null} Delay: 0 Current proxies before removal: [ [ { delegate: '0x569BE8d8b04538318e1722f6e375FD381D2da865', proxyType: 'Any', delay: '0' } ], '1,002,900,000,000,000,000' ] Transaction included in block hash: 0x8402c11ca656798ad54eea16c5c05b5fefa5d5d23beb590d214d2fa4168d8af9 balances.Withdraw: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",3431367169061] balances.Unreserved: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e","0x00000000000000000deb043c853d4000"] proxy.ProxyRemoved: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e","0x569BE8d8b04538318e1722f6e375FD381D2da865","Any",0] Proxy successfully removed! Delegator: 0x3B939FeaD1557C741Ff06492FD0127bd287A421e Removed delegate: 0x569BE8d8b04538318e1722f6e375FD381D2da865 Proxy type: Any Delay: 0 balances.Deposit: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",0] balances.Deposit: ["0x6d6F646c70632f74727372790000000000000000",686273433813] transactionPayment.TransactionFeePaid: ["0x3B939FeaD1557C741Ff06492FD0127bd287A421e",3431367169061,0] system.ExtrinsicSuccess: [{"weight":{"refTime":398292318,"proofSize":4310},"class":"Normal","paysFee":"Yes"}] Proxies after removal: [ [], '0' ] ``` !!! note Anonymous proxies are disabled on Moonbeam networks because they are easy to misuse. Incorrect usage can cause a permanent loss of funds and unreserved balances. ### Storage Methods {: #storage-methods } The proxy pallet includes the following read-only storage methods to obtain chain state data: ??? function "**announcements**(AccountId20) - returns all announcements made by the specified proxy account" === "Parameters" - `AccountId20` - The proxy account's address in H160 format (e.g., '0x123...') whose announcements you want to query === "Returns" Returns a tuple containing: - Array of announcements, each containing: - real: AccountId20 (The account the announcement was made for) - callHash: H256 (The hash of the announced call) - height: BlockNumber (The block number when announced) - Balance (The amount reserved to place the announcements) === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { try { // Initialize connection to the network const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // The proxy address to query const proxyAddress = 'INSERT_PROXY_ACCOUNT'; // Query announcements const announcements = await api.query.proxy.announcements(proxyAddress); // Log the results console.log('Querying announcements for proxy:', proxyAddress); console.log( '\nAnnouncements:', JSON.stringify(announcements.toHuman(), null, 2) ); process.exit(0); } catch (error) { console.error('Error occurred:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**palletVersion**() - returns the current pallet version" === "Parameters" - None === "Returns" Returns a single number representing the current version of the proxy pallet === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { try { // Initialize connection to the network const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Query pallet version const version = await api.query.proxy.palletVersion(); // Log the result console.log('Proxy Pallet Version:', version.toHuman()); process.exit(0); } catch (error) { console.error('Error occurred:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**proxies**(AccountId20) - returns a map and count of all proxy accounts for a specified primary account" === "Parameters" - `AccountId20` - The primary account's address in H160 format (e.g., '0x123...') whose proxies you want to query === "Returns" Returns a tuple containing: - Array of ProxyDefinition, each containing: - delegate: AccountId20 (The proxy account address) - proxyType: Enum (The type of proxy) - delay: Number (The announcement delay in blocks) - Balance (The amount reserved to place the proxies) === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { try { // Initialize connection to the network const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // The account address to query proxies for const accountAddress = 'INSERT_REAL_ACCOUNT'; // Query proxies const [proxies, deposit] = await api.query.proxy.proxies(accountAddress); // Log the results with formatted JSON console.log('Querying proxies for account:', accountAddress); console.log('\nProxies:', JSON.stringify(proxies.toHuman(), null, 2)); console.log('Required deposit:', deposit.toHuman()); // Display in a more readable format console.log('\nProxy Details:'); proxies.forEach((proxy, index) => { console.log(`\nProxy #${index + 1}:`); console.log(' Delegate:', proxy.delegate.toString()); console.log(' Proxy Type:', proxy.proxyType.toString()); console.log(' Delay:', proxy.delay.toString()); }); process.exit(0); } catch (error) { console.error('Error occurred:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ### Pallet Constants {: #constants } The proxy pallet includes the following read-only functions to obtain pallet constants: ??? function "**announcementDepositBase**() - returns the base amount of currency needed to reserve for creating an announcement" === "Parameters" - None === "Returns" Returns a Balance value representing the base deposit amount in Wei required for creating a proxy announcement === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Query the base deposit const baseDeposit = await api.consts.proxy.announcementDepositBase; console.log('Announcement Base Deposit:', baseDeposit.toHuman()); process.exit(0); }; main().catch(console.error); ``` ??? function "**announcementDepositFactor**() - returns the amount of currency needed per announcement made" === "Parameters" None === "Returns" Returns a Balance value representing the additional deposit amount in Wei required for each announcement made === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Query the deposit factor const depositFactor = await api.consts.proxy.announcementDepositFactor; console.log('Announcement Deposit Factor:', depositFactor.toHuman()); process.exit(0); }; main().catch(console.error); ``` ??? function "**maxPending**() - returns the maximum amount of time-delayed announcements that are allowed to be pending" === "Parameters" None === "Returns" Returns a u32 value representing the maximum number of announcements that can be pending for a proxy account === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Query max pending announcements const maxPending = await api.consts.proxy.maxPending; console.log('Maximum Pending Announcements:', maxPending.toHuman()); process.exit(0); }; main().catch(console.error); ``` ??? function "**maxProxies**() - returns the maximum amount of proxies allowed for a single account" === "Parameters" None === "Returns" Returns a u32 value representing the maximum number of proxy accounts that can be registered to a single account === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Query max proxies allowed const maxProxies = await api.consts.proxy.maxProxies; console.log('Maximum Proxies per Account:', maxProxies.toHuman()); process.exit(0); }; main().catch(console.error); ``` ??? function "**proxyDepositBase**() - returns the base amount of currency needed to reserve for creating a proxy" === "Parameters" None === "Returns" Returns a Balance value representing the base deposit amount in Wei required for creating a proxy === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Query the base deposit for proxy creation const baseDeposit = await api.consts.proxy.proxyDepositBase; console.log('Proxy Base Deposit:', baseDeposit.toHuman()); process.exit(0); }; main().catch(console.error); ``` ??? function "**proxyDepositFactor**() - returns the amount of currency needed per proxy added" === "Parameters" None === "Returns" Returns a Balance value representing the additional deposit amount in Wei required for each proxy registered === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Query the deposit factor for proxies const depositFactor = await api.consts.proxy.proxyDepositFactor; console.log('Proxy Deposit Factor:', depositFactor.toHuman()); process.exit(0); }; main().catch(console.error); ``` --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/interfaces/features/governance/conviction-voting/ --- BEGIN CONTENT --- --- title: Conviction Voting Pallet description: This guide covers the available functions in the Conviction Voting Pallet on Moonbeam, which are used to vote, delegate votes, remove votes, and more. keywords: democracy, substrate, pallet, moonbeam, polkadot, voting, vote, referenda categories: Substrate Toolkit --- # The Conviction Voting Pallet ## Introduction {: #introduction } The Conviction Voting Pallet allows token holders to make, delegate, and manage Conviction-weighted votes on referenda. Governance-related functionality is based on three new pallets and precompiles: the [Preimage Pallet](/builders/substrate/interfaces/features/governance/preimage/){target=\_blank} and [Preimage Precompile](/builders/ethereum/precompiles/features/governance/preimage/){target=\_blank}, the [Referenda Pallet](/builders/substrate/interfaces/features/governance/referenda/){target=\_blank} and [Referenda Precompile](/builders/ethereum/precompiles/features/governance/referenda/){target=\_blank}, and the [Conviction Voting Pallet](/builders/substrate/interfaces/features/governance/conviction-voting/){target=\_blank} and [Conviction Voting Precompile](/builders/ethereum/precompiles/features/governance/conviction-voting/){target=\_blank}. The aforementioned precompiles are Solidity interfaces that enable you to perform governance functions using the Ethereum API. This guide will provide an overview of the extrinsics, storage methods, and getters for the pallet constants available in the Conviction Voting Pallet on Moonbeam on Moonbeam. This guide assumes you are familiar with governance-related terminology; if not, please check out the [governance overview page](/learn/features/governance/#opengov){target=_blank} for more information. ## Conviction Voting Pallet Interface {: #preimage-pallet-interface } ### Extrinsics {: #extrinsics } The Conviction Voting Pallet provides the following extrinsics (functions): ??? function "**delegate**(class, to, conviction, balance) - delegate the voting power (with some given Conviction) to another account for a particular class (Origin and, by extension, Track) of polls (referenda). The balance delegated is locked for as long as it's delegated, and thereafter for the time appropriate for the Conviction's lock period. Emits a `Delegated` event" === "Parameters" - `class` - the index of the Track that the delegate account is permitted to vote on proposals for. The index for each Track is as follows: - `0` - Root Track - `1` - Whitelisted Track - `2` - General Admin Track - `3` - Emergency Canceller Track - `4` - Emergency Killer Track - `to` - the account to delegate voting power to - `conviction` - the [Conviction multiplier](/learn/features/governance#conviction-multiplier-v2){target=_blank} value to use for the delegation. You can specify either the name of the Conviction multiplier value or the index associated with the value: - `'None'` or `0` - `'Locked1x'` or `1` - `'Locked2x'` or `2` - `'Locked3x'` or `3` - `'Locked4x'` or `4` - `'Locked5x'` or `5` - `'Locked6x'` or `6` - `balance` -the number of tokens to delegate to the other account in Wei === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const classIndex = INSERT_TRACK_INDEX; const to = INSERT_DELEGATE_ACCOUNT; const conviction = INSERT_CONVICTION; const balance = INSERT_BALANCE_TO_DELEGATE; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.convictionVoting.delegate( classIndex, to, conviction, balance ); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**removeOtherVote**(target, class, index) - removes a vote for a poll (referendum). If the `target` is equal to the signer, then this function is exactly equivalent to `removeVote`. If not equal to the signer, then the vote must have expired, either because the poll was canceled, the voter lost the poll, or because the Conviction period is over" === "Parameters" - `target` - the voter to remove the vote for - `class` - the index of the Track the poll belongs to. The index for each Track is as follows: - `0` - Root Track - `1` - Whitelisted Track - `2` - General Admin Track - `3` - Emergency Canceller Track - `4` - Emergency Killer Track - `index` - the index of the poll (referendum) === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const target = INSERT_ADDRESS; const classIndex = INSERT_TRACK_INDEX; const index = INSERT_REFERENDUM_INDEX; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.convictionVoting.removeOtherVote(target, classIndex, index); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**removeVote**(class, index) - removes a vote for a poll" This can occur if one of the following is true: - If the poll was canceled, tokens are immediately available for unlocking if there is no other pending lock - If the poll is ongoing, the token holder's votes no longer count for the tallying, and tokens are immediately available for unlocking if there is no other pending lock - If the poll has ended, there are two different scenarios: - If the token holder voted against the tallied result or voted with no Conviction, the tokens are immediately available for unlocking if there is no other pending lock - If, however, the poll has ended and the results coincide with the vote of the token holder (with a given Conviction) and the lock period of the Conviction is not over, then the lock will be aggregated into the overall account's lock. This may involve _overlocking_ (where the two locks are combined into a single lock that is the maximum of both the amount locked and the time it is locked) === "Parameters" - `class` - the index of the Track the poll belongs to. The index for each Track is as follows: - `0` - Root Track - `1` - Whitelisted Track - `2` - General Admin Track - `3` - Emergency Canceller Track - `4` - Emergency Killer Track - `index` - the index of the poll (referendum) === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const classIndex = INSERT_TRACK_INDEX; const index = INSERT_REFERENDUM_INDEX; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.convictionVoting.removeVote(classIndex, index); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**undelegate**(class) - undelegates the voting power for a particular class (Origin and, by extension, Track) of polls (referenda). Tokens may be unlocked after an amount of time consistent with the lock period of the Conviction with which the delegation was issued. Emits an `Undelegated` event" === "Parameters" - `class` - the index of the Track to remove the voting power for. The index for each Track is as follows: - `0` - Root Track - `1` - Whitelisted Track - `2` - General Admin Track - `3` - Emergency Canceller Track - `4` - Emergency Killer Track === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const classIndex = INSERT_TRACK_INDEX; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.convictionVoting.undelegate(classIndex); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**unlock**(class, target) - removes a lock for a prior vote or delegation vote within a particular class (Origin and, by extension, Track), which has expired" === "Parameters" - `class` - the index of the Track that the poll is assigned to. The index for each Track is as follows: - `0` - Root Track - `1` - Whitelisted Track - `2` - General Admin Track - `3` - Emergency Canceller Track - `4` - Emergency Killer Track - `target` - the account to remove the lock for === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const classIndex = INSERT_TRACK_INDEX; const target = INSERT_ADDRESS; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.convictionVoting.unlock(classIndex, target); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**vote**(pollIndex, vote) - submits a vote in a poll (referendum). If the vote is "Aye", the vote is to enact the proposal; if it is a "Nay", the vote is to keep the status quo" === "Parameters" - `pollIndex` - the index of the poll (referendum) - `vote` - the vote and the amount to lock for the vote. There are three types of votes: - `Standard` - votes a Conviction-weighted vote, with a given amount locked for "Aye" or "Nay". To use `Standard`, you'll have to specify the following: - `aye` - a boolean indicating whether the vote is an "Aye" or a "Nay" - `conviction` - the [Conviction multiplier](/learn/features/governance#conviction-multiplier-v2){target=_blank} value to use for the delegation. You can specify either the name of the Conviction multiplier value or the index associated with the value: - `0` or `'None'` - `1` or `'Locked1x'` - `2` or `'Locked2x'` - `3` or `'Locked3x'` - `4` or `'Locked4x'` - `5` or `'Locked5x'` - `6` or `'Locked6x'` - balance - the number of tokens to lock for the vote - `Split` - votes a split vote, with a given amount locked for "Aye" and a given amount locked for "Nay". To use `Split`, you'll have to specify the following: - `aye` - the balance to lock for an "Aye" vote - `nay` - the balance to lock for a "Nay" vote - `SplitAbstain` - votes a split abstained vote, with a given amount locked for "Aye", a given amount locked for "Nay", and a given amount locked for an abstain vote (support). To use `SplitAbstain`, you'll have to specify the following: - `aye` - the balance to lock for an "Aye" vote - `nay` - the balance to lock for a "Nay" vote - `abstain` - the balance to lock for an abstain vote === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const pollIndex = INSERT_REFERENDUM_INDEX; const vote = INSERT_VOTE; /* For Standard, use the following format: const vote = { Standard: { Vote: { aye: INSERT_BOOLEAN, conviction: INSERT_CONVICTION }, balance: INSERT_BALANCE, }, }; For Split, use the following format: const vote = { Split: { aye: INSERT_BALANCE, nay: INSERT_BALANCE, }, }; For SplitAbstrain, use the following format: const vote = { SplitAbstain: { aye: INSERT_BALANCE, nay: INSERT_BALANCE, abstain: INSERT_BALANCE, }, }; */ const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.convictionVoting.vote(pollIndex, vote); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ### Storage Methods {: #storage-methods } The Conviction Voting Pallet includes the following read-only storage methods to obtain chain state data: ??? function "**classLocksFor**(account) - returns the voting classes (Origins and, by extension, Tracks), which have a non-zero lock requirement, and the lock amounts that they require" === "Parameters" - `account` - the account to get voting information for === "Returns" An array containing the class locks. Each class lock is an array that includes the index of the class (Origin and, by extension, Track) and the balance the voter has locked in the class. The index for each Track is as follows: - `0` - Root Track - `1` - Whitelisted Track - `2` - General Admin Track - `3` - Emergency Canceller Track - `4` - Emergency Killer Track ```js // If using Polkadot.js API and calling toJSON() on the query results [ [ 2, // Index of the class '0x00000000000000000de0b6b3a7640000' // Amount locked ] ] ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const account = INSERT_ADDRESS; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const classLocksFor = await api.query.convictionVoting.classLocksFor(account); }; main(); ``` ??? function "**palletVersion**() - returns the current pallet version" === "Parameters" None. === "Returns" A number representing the current version of the pallet. ```js // If using Polkadot.js API and calling toJSON() on the query results 0 ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const palletVersion = await api.query.convictionVoting.palletVersion(); }; main(); ``` ??? function "**votingFor**(account, class) - returns all of the votes for a particular voter in a particular voting class (Origin and, by extension, Track)" === "Parameters" - `account` - the account to get the voting information for - `class` - the index of the voting class. The index for each Track is as follows: - `0` - Root Track - `1` - Whitelisted Track - `2` - General Admin Track - `3` - Emergency Canceller Track - `4` - Emergency Killer Track === "Returns" The voting information for the given voter. The voter can be either `casting`, if the voter isn't actively delegating, or `delegating`, if the user is actively delegating The information for each type. === "Casting" If the voter isn't actively delegating. If the voter was previously assigned as a delegate, any delegate votes will appear under `delegations`. ```js { casting: { votes: [ [ 0, // Track Index { standard: { // Vote type can be either Standard, Split, or SplitAbstain vote: '0x81', // The vote (Aye or Nay) and the Conviction balance: '0x0000000000001999c6880e003a480000' // Vote value } } ] ], delegations: { // Delegate votes votes: '0x000000000000000ad78ebc5ac6200000', // Total Conviction-weighted votes capital: '0x00000000000000056bc75e2d63100000' // Total delegated amount }, prior: [ // Locked votes. After unlocking votes, this will reset to [0, 0] 56328, // The block at which the delegated amount can be unlocked '0x00000000000000056bc75e2d63100000' // The delegated amount ] } } ``` === "Delegating" If the voter is actively delegating their votes to another voter. If the voter was previously delegated by another voter, their votes will appear under `delegations`. ```js // If using Polkadot.js API and calling toJSON() on the query results { delegating: { balance: '0x00000000000000056bc75e2d63100000', // The delegated amount target: '0x3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0', // The delegate account conviction: 'Locked2x', // The permitted Conviction delegations: { // Delegate votes (if voter was previously delegated) votes: 0, // Total Conviction-weighted votes capital: 0 // Total delegated amount }, prior: [ // Locked votes 0, // The block at which the delegated amount can be unlocked 0 // The delegated amount ] } } ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const account = INSERT_ADDRESS; const classIndex = INSERT_TRACK_INDEX; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const votingFor = await api.query.convictionVoting.votingFor( account, classIndex ); }; main(); ``` ### Pallet Constants {: #constants } The Conviction Voting Pallet includes the following read-only functions to obtain pallet constants: ??? function "**maxVotes**() - returns the maximum number of concurrent votes an account may have" === "Parameters" None. === "Returns" The maximum number of votes. ```js // If using Polkadot.js API and calling toJSON() on the result 20 ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const maxVotes = api.consts.convictionVoting.maxVotes; }; main(); ``` ??? function "**voteLockingPeriod**() - returns the minimum period of vote locking. It should not be shorter than the Enactment Period to ensure that, in the case of an approval, those successful voters are locked into the consequences that their votes entail" === "Parameters" None. === "Returns" The vote-locking period. ```js // If using Polkadot.js API and calling toJSON() on the result 7200 ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const voteLockingPeriod = api.consts.convictionVoting.voteLockingPeriod; }; main(); ``` --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/interfaces/features/governance/ --- BEGIN CONTENT --- --- title: Governance-related Substrate Interfaces description: Utilize low-level Substrate interfaces for robust governance capabilities, including submitting proposals and voting on referenda. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/interfaces/features/governance/parameters/ --- BEGIN CONTENT --- --- title: Parameters Pallet description: Learn how Moonbeam's Parameters Pallet safely and dynamically modifies network config items via on-chain governance, removing the need for runtime upgrades. categories: Substrate Toolkit --- # The Parameters Pallet ## Introduction {: #introduction } The Parameters Pallet on Moonbeam is a governance-focused module that enables community-driven modifications to key network configuration items, such as the deposit requirement for the randomness module, directly on-chain through proposals and votes, without necessarily requiring a runtime upgrade. By removing the need for frequent code changes, the Parameters Pallet allows the network to respond more quickly to evolving needs while maintaining transparency and consensus. This guide will provide an overview of the extrinsics, storage methods, and getters for the pallet constants available in the Parameters Pallet on Moonbeam. This guide assumes you are familiar with governance-related terminology; if not, please check out the [governance overview page](/learn/features/governance/#opengov){target=_blank} for more information. ## Parameters Pallet Interface {: #parameter-pallet-interface } ### Extrinsics {: #extrinsics } The Parameters Pallet provides one extrinsic (function): ???+ function "**setParameter**(keyValue) - sets the value of a parameter" === "Parameters" - `keyValue` - the key to the storage item to be modified === "Example" Suppose you want to adjust the deposit parameter for the randomness pallet. You'd start by crafting a call to the `setParameter` function, specifying the randomness pallet's key and the new deposit value. In Polkadot.js Apps, this involves selecting `parameters.setParameter(keyValue)` and then updating the deposit field for `PalletRandomness`. While you can generate and review this call data beforehand, the actual change must still go through the [governance process](/learn/features/governance/#roadmap-of-a-proposal-v2){target=\_blank}—meaning it needs to be proposed, voted on, and approved by the community before the new deposit value takes effect on-chain === "Polkadot.js API Example" ```js // This is an example of crafting the encoded call data via the Polkadot API // but remember you won't submit the call here as it needs to go thru governance. import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Replace with your node's WSS endpoint const provider = new WsProvider('INSERT_WSS_ENDPOINT'); const api = await ApiPromise.create({ provider }); // Construct the setParameter call for changing the randomness deposit // Keep in mind that actual submission must go through governance (proposal, voting, etc.) const tx = api.tx.parameters.setParameter({ PalletRandomness: { // The deposit parameter is declared as a tuple: (variant, Option). // Here we're setting the deposit to 5 tokens (5000000000000000000), // e.g., 'MoonbaseRuntimeRuntimeParamsDynamicParamsPalletRandomnessDeposit' is the variant, // and the second element is the actual deposit value in the Option. Deposit: [ 'MoonbaseRuntimeRuntimeParamsDynamicParamsPalletRandomnessDeposit', '5000000000000000000', ], }, }); // Print out the call in hex format (useful for creating a governance proposal) console.log('Encoded call data:', tx.toHex()); await api.disconnect(); }; main(); ``` ### Storage Methods {: #storage-methods } The Parameters Pallet includes the following read-only storage methods to obtain chain state data: ???+ function "**parameters**(parameters) - when queried with a parameter key, it returns either the corresponding value variant (e.g., `RuntimeConfig` with `FeesTreasuryProportion`) or `None` if no value is set" === "Parameters" - `parameters` - the name of the pallet combined with the specific key identifying the storage item to retrieve === "Returns" The `parameters` storage method is a dictionary that stores dynamic runtime parameters under specific keys. When queried with a parameter key, it returns either the corresponding value variant (e.g., `RuntimeConfig` with `FeesTreasuryProportion`) or `None` if no value is set === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Replace with the appropriate WebSocket endpoint const provider = new WsProvider('INSERT_WSS_ENDPOINT'); const api = await ApiPromise.create({ provider }); // Define the parameter key const paramKey = { RuntimeConfig: 'FeesTreasuryProportion', }; // Query the storage const currentValue = await api.query.parameters.parameters(paramKey); if (currentValue.isSome) { const unwrapped = currentValue.unwrap(); console.log('Unwrapped value (toHuman):', unwrapped.toHuman()); console.log('Unwrapped value (toJSON):', unwrapped.toJSON()); } else { console.log('None. No value stored for the given key.'); } // Disconnect once done await api.disconnect(); }; main(); ``` ??? function "**palletVersion**() - returns the current pallet version" === "Parameters" None === "Returns" A number representing the current version of the pallet ```js // If using Polkadot.js API and calling toJSON() on the query results 0 ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const palletVersion = await api.query.parameters.palletVersion(); console.log('The palletVersion is ' + palletVersion); }; main(); ``` ### Pallet Constants {: #constants } The Parameters Pallet does not have any constants. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/interfaces/features/governance/preimage/ --- BEGIN CONTENT --- --- title: Preimage Pallet description: Learn about the available extrinsics and storage methods for the Preimage Pallet on Moonbeam, which are used to store and manage on-chain preimages. keywords: democracy, substrate, pallet, moonbeam, polkadot, preimage categories: Substrate Toolkit --- # The Preimage Pallet ## Introduction {: #introduction } The Preimage Pallet allows users and the runtime to store the preimage of some encoded call data on chain. Furthermore, other pallets can use preimage hashes to store and manage large byte-blobs. For example, token holders can submit a governance proposal through the Referenda Pallet using a preimage hash of the action to be carried out. Governance-related functionality is based on three new pallets and precompiles: the [Preimage Pallet](/builders/substrate/interfaces/features/governance/preimage/){target=\_blank} and [Preimage Precompile](/builders/ethereum/precompiles/features/governance/preimage/){target=\_blank}, the [Referenda Pallet](/builders/substrate/interfaces/features/governance/referenda/){target=\_blank} and [Referenda Precompile](/builders/ethereum/precompiles/features/governance/referenda/){target=\_blank}, and the [Conviction Voting Pallet](/builders/substrate/interfaces/features/governance/conviction-voting/){target=\_blank} and [Conviction Voting Precompile](/builders/ethereum/precompiles/features/governance/conviction-voting/){target=\_blank}. The aforementioned precompiles are Solidity interfaces that enable you to perform governance functions using the Ethereum API. This guide will provide an overview of the extrinsics, storage methods, and getters for the pallet constants available in the Preimage Pallet on Moonbeam. This guide assumes you are familiar with governance-related terminology; if not, please check out the [governance overview page](/learn/features/governance/#opengov){target=_blank} for more information. ## Preimage Pallet Interface {: #preimage-pallet-interface } ### Extrinsics {: #extrinsics } The Preimage Pallet provides the following extrinsics (functions): ??? function "**notePreimage**(encodedProposal) - registers a preimage for an upcoming proposal, given the encoded preimage of a proposal. If the preimage was previously requested, no fees or deposits are taken for providing the preimage. Otherwise, a deposit is taken proportional to the size of the preimage. Emits a `Noted` event" === "Parameters" - `encodedProposal` - the encoded call data of the action that is being proposed. Please refer to the [How to Generate the Encoded Proposal](#generate-encoded-proposal) section for more information === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const encodedProposal = INSERT_ENCODED_PROPOSAL; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.preimage.notePreimage(encodedProposal); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**requestPreimage**(bytes) - requests a preimage to be uploaded to the chain without paying any fees or deposits. Once the preimage request has been submitted on-chain, the user who submitted the preimage and deposit will get their deposit back, and they will no longer control the preimage. Must be executed by the Root Origin. Emits a `Requested` event" === "Parameters" - `bytes` - the hash of a preimage === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const bytes = INSERT_PREIMAGE_HASH; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.preimage.requestPreimage(bytes); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**unnotePreimage**(hash) - clears an unrequested preimage from the runtime storage, given the hash of the preimage to be removed. Emits a `Cleared` event" === "Parameters" - `hash` - the hash of a preimage === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const hash = INSERT_PREIMAGE_HASH; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.preimage.unnotePreimage(hash); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**unrequestPreimage**(hash) - clears a previously made request for a preimage. Must be executed by the Root Origin. Emits a `Cleared` event" === "Parameters" - `hash` - the hash of a preimage === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const hash = INSERT_PREIMAGE_HASH; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.preimage.unrequestPreimage(hash); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ### Storage Methods {: #storage-methods } The Preimage Pallet includes the following read-only storage methods to obtain chain state data: ??? function "**palletVersion**() - returns the current pallet version" === "Parameters" None. === "Returns" A number representing the current version of the pallet. ```js // If using Polkadot.js API and calling toJSON() on the query results 0 ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const palletVersion = await api.query.preimage.palletVersion(); }; main(); ``` ??? function "**preimageFor**([hash, length]) - returns the encoded proposal for a preimage, given the hash and length of the preimage" === "Parameters" - `[hash, length]` - a tuple containing the hash and the length of the preimage === "Returns" The encoded call data of the proposal. ```js // If using Polkadot.js API and calling toJSON() on the query results 0x00002c68656c6c6f5f776f726c64 ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const preimageInfo = [INSERT_PREIMAGE_HASH, INSERT_PREIMAGE_LENGTH]; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const preimageFor = await api.query.preimage.preimageFor(preimageInfo); }; main(); ``` ??? function "**statusFor**(hash) - returns the request status for a given preimage hash" === "Parameters" - `hash` - the preimage hash to get the request status for === "Returns" Status information for the preimage, which includes the status, the preimage deposit information, and the length of the preimage. The status can be either `unrequested` or `requested`. ```js { unrequested: { // Request status deposit: [ '0x3B939FeaD1557C741Ff06492FD0127bd287A421e', // Depositor '0x00000000000000004569f6996d8c8000' // Amount deposited ], len: 18 // Length of the preimage } } ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const hash = INSERT_PREIMAGE_HASH; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const statusFor = await api.query.preimage.statusFor(hash); }; main(); ``` ## How to Generate an Encoded Proposal {: #generate-encoded-proposal } To generate an encoded proposal, you must first create the extrinsic that will be run if the proposal passes the governance process. Instead of attempting to send the extrinsic, you'll obtain the SCALE-encoded hash of the extrinsic, which you'll use to submit the preimage. For example, if you wanted to set an on-chain remark that said "Hello World," you could generate the encoded call data using the following snippet: ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('ws://127.0.0.1:9944'), }); const encodedProposal = api.tx.system.remark('Hello World').method.toHex(); api.disconnect(); }; main(); ``` Then, you can use the encoded call data to submit the preimage for the proposal: ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const encodedProposal = api.tx.system.remark('Hello World').method.toHex(); const tx = api.tx.preimage.notePreimage(encodedProposal); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/interfaces/features/governance/referenda/ --- BEGIN CONTENT --- --- title: Referenda Pallet description: This guide covers the available functions for the Referenda Pallet on Moonbeam, of which are used to view and submit data related to on-chain referenda keywords: democracy, substrate, pallet, moonbeam, polkadot, voting, vote, referenda categories: Substrate Toolkit --- # The Referenda Pallet ## Introduction {: #introduction } The Referenda Pallet allows token holders to make, delegate, and manage Conviction-weighted votes on referenda. Governance-related functionality is based on three new pallets and precompiles: the [Preimage Pallet](/builders/substrate/interfaces/features/governance/preimage/){target=\_blank} and [Preimage Precompile](/builders/ethereum/precompiles/features/governance/preimage/){target=\_blank}, the [Referenda Pallet](/builders/substrate/interfaces/features/governance/referenda/){target=\_blank} and [Referenda Precompile](/builders/ethereum/precompiles/features/governance/referenda/){target=\_blank}, and the [Conviction Voting Pallet](/builders/substrate/interfaces/features/governance/conviction-voting/){target=\_blank} and [Conviction Voting Precompile](/builders/ethereum/precompiles/features/governance/conviction-voting/){target=\_blank}. The aforementioned precompiles are Solidity interfaces that enable you to perform governance functions using the Ethereum API. This guide will provide an overview of the extrinsics, storage methods, and getters for the pallet constants available in the Referenda Pallet on Moonbeam. This guide assumes you are familiar with governance-related terminology, if not, please check out the [governance overview page](/learn/features/governance/#opengov){target=\_blank} for more information. ## Referenda Pallet Interface {: #referenda-pallet-interface } ### Extrinsics {: #extrinsics } The Referenda Pallet provides the following extrinsics (functions): ??? function "**cancel**(index) - cancels an ongoing referendum given the index of the referendum to cancel. This type of action requires a proposal to be created and assigned to either the Root Track or the Emergency Canceller Track" === "Parameters" - `index` - the index of the referendum to cancel === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const index = INSERT_REFERENDUM_INDEX; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.referenda.cancel(index); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**kill**(index) - cancels an ongoing referendum and slashes the deposits given the index of the referendum to cancel. This type of action requires a proposal to be created and assigned to either the Root Track or the Emergency Killer Track" === "Parameters" - `index` - the index of the referendum to kill === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const index = INSERT_REFERENDUM_INDEX; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.referenda.kill(index); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**placeDecisionDeposit**(index) - posts the Decision Deposit for a referendum, given the index of the referendum" === "Parameters" - `index` - the index of the referendum to place the Decision Deposit for === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const index = INSERT_REFERENDUM_INDEX; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.referenda.placeDecisionDeposit(index); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**refundDecisionDeposit**(index) - refunds the Decision Deposit for a closed referendum back to the depositor, given the index of the referendum" === "Parameters" - `index` - the index of the referendum to refund the Decision Deposit for === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const index = INSERT_REFERENDUM_INDEX; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.referenda.refundDecisionDeposit(index); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**refundSubmissionDeposit**(index) - refunds the Submission Deposit for a closed referendum back to the depositor, given the index of the referendum" === "Parameters" - `index` - the index of the referendum to refund the Submission Deposit for === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const index = INSERT_REFERENDUM_INDEX; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.referenda.refundSubmissionDeposit(index); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**submit**(proposalOrigin, proposal, enactmentMoment) - proposes a referendum on a privileged action given the Origin from which the proposal should be executed, the proposal, and the moment that the proposal should be enacted" === "Parameters" - `proposalOrigin` - the Origin and, by extension, the Track from which the proposal should be executed. Typically, this should be set to one of the following: - `system` - indicates the proposal should be executed by a system-level Origin. You can specify the name of the Origin or the index associated with the Origin: - `Root` or `0` - submits a proposal to the Root Track - `Origins` - indicates the proposal should be executed by one of the governance Origins. To submit a proposal to any of the Tracks aside from Root, you can specify the name of the Origin or the index associated with the Origin: - `WhitelistedCaller` or `0` - submits a proposal to the Whitelisted Track - `GeneralAdmin` or `1` - submits a proposal to the General Admin Track - `ReferendumCanceller` or `2` - submits a proposal to the Emergency Canceller Track - `ReferendumKiller` or `3` - submits a proposal to the Emergency Killer Track - `proposal` - the action being proposed. To define the proposal to submit, you can use the following method: - `Lookup` - defines the preimage associated with the proposal using the following arguments: - `hash_` - the hash of the preimage - `len` - the length of the preimage - `enactmentMoment` - when the proposal will be executed, either at a specific block or after a specific number of blocks: - `At` - a specific block to enact the proposal at - `After` - the number of blocks to delay enactment after proposal approval === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const proposalOrigin = INSERT_PROPOSAL_ORIGIN; /* For Root Origin, use the following format: const proposalOrigin = { system: 'Root' }; For all other OpenGov Origins, use the following format: const proposalOrigin = { Origins: 'INSERT_ORIGIN_NAME_OR_INDEX' }; */ const proposal = { Lookup: { hash_: 'INSERT_PREIMAGE_HASH', len: 'INSERT_PREIMAGE_LENGTH', }, }; const enactmentMoment = { At: INSERT_BLOCK }; /* Or for After, use the following: const enactmentMoment = { After: INSERT_BLOCK } */ const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.referenda.submit(proposalOrigin, proposal, enactmentMoment); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ### Storage Methods {: #storage-methods } The Referenda Pallet includes the following read-only storage methods to obtain chain state data: ??? function "**decidingCount**(index) - returns the number of referenda being decided currently" === "Parameters" - `index` - the index of the Track to get the deciding count for. The index for each Track is as follows: - `0` - Root Track - `1` - Whitelisted Track - `2` - General Admin Track - `3` - Emergency Canceller Track - `4` - Emergency Killer Track === "Returns" The number of referenda currently being decided on for the given Track. ```js // If using Polkadot.js API and calling toJSON() on the query results 1 ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const track = INSERT_TRACK_INDEX; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const statusFor = await api.query.referenda.decidingCount(track); }; main(); ``` ??? function "**palletVersion**() - returns the current pallet version" === "Parameters" None. === "Returns" A number representing the current version of the pallet. ```js // If using Polkadot.js API and calling toJSON() on the query results 0 ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const palletVersion = await api.query.referenda.palletVersion(); }; main(); ``` ??? function "**referendumCount**() - returns the number of referenda started so far" === "Parameters" None. === "Returns" The number of referenda started so far. ```js // If using Polkadot.js API and calling toJSON() on the query results 1 ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const statusFor = await api.query.referenda.referendumCount(); }; main(); ``` ??? function "**referendumInfoFor**(index) - returns information concerning any given referendum" === "Parameters" - `index` - the index of the referendum to get the information for === "Returns" The status of the referendum and additional information depending on the status. The status can be any of the following: === "Ongoing" The referendum has been submitted and is being voted on. The returned data includes information on the proposal, the deposits, the current state of the referendum, and more. ```js // If using Polkadot.js API and calling toJSON() on the query results { ongoing: { track: 2, origin: { origins: 'GeneralAdmin' }, proposal: { lookup: { hash: '0xa5d90079f950888dabb2ef77e159096701784141dd2c8c95a67ced96ec0c1c21', len: 15 } }, enactment: { after: 100 }, submitted: 5724140, submissionDeposit: { who: '0xD720165D294224A7d16F22ffc6320eb31f3006e1', amount: '0x00000000000000008ac7230489e80000' }, decisionDeposit: { who: '0xD720165D294224A7d16F22ffc6320eb31f3006e1', amount: '0x000000000000001b1ae4d6e2ef500000' }, deciding: { since: 5724440, confirming: null }, tally: { ayes: 0, nays: 0, support: 0 }, inQueue: false, alarm: [ 5825240, [ 5825240, 0 ] ] } } ``` === "Approved" The referendum finished with approval. The returned data includes the block at which the proposal was approved and deposit information, including the account(s) that placed a deposit and the deposit amount for that account. ```js // If using Polkadot.js API and calling toJSON() on the query results { approved: [ 3715966, // Block at which the proposal was approved { // Deposit information who: '0xE6c5B9500035cb5557E8FDBAa758d78a15361A0E', amount: '0x00000000000000056bc75e2d63100000' }, null // Additional deposit information or null if there isn't any ] } ``` === "Rejected" The referendum ended with a rejection. The returned data includes the block at which the proposal was rejected and deposit information, including the account(s) that placed a deposit and the deposit amount for that account. ```js // If using Polkadot.js API and calling toJSON() on the query results { rejected: [ 5213165, // Block at which the proposal was rejected { // Deposit information who: '0xb926E36D439106090Be1151347CFB916E44AFE00', amount: '0x00000000000000008ac7230489e80000' }, null // Additional deposit information or null if there isn't any ] } ``` === "Cancelled" The referendum ended with a cancellation. The returned data includes the block at which the proposal was cancelled and deposit information, including the account(s) that placed a deposit and the deposit amount for that account. ```js // If using Polkadot.js API and calling toJSON() on the query results { cancelled: [ 3613947, // Block at which the proposal was cancelled { // Deposit information who: '0xE6c5B9500035cb5557E8FDBAa758d78a15361A0E', amount: '0x00000000000000056bc75e2d63100000' }, null // Additional deposit information or null if there isn't any ] } ``` === "Timed Out" The referendum ended and was never decided. The returned data includes the block at which the proposal timed out and deposit information, including the account(s) that placed a deposit and the deposit amount for that account. ```js // If using Polkadot.js API and calling toJSON() on the query results { timedOut: [ 4585127, // Block at which the proposal timed out { // Deposit information who: '0x657a901AFC4d85A28eEf0F6696E42ae2099219cd', amount: '0x00000000000000008ac7230489e80000' }, null // Additional deposit information or null if there isn't any ] } ``` === "Killed" The referendum ended with a kill. The block at which the referendum was killed is returned. ```js // If using Polkadot.js API and calling toJSON() on the query results { killed: 1806494 } // The block at which the referendum was killed ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const index = INSERT_REFERENDUM_INDEX; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const referendumInfoFor = await api.query.referenda.referendumInfoFor(index); }; main(); ``` ??? function "**trackQueue**(index) - returns the sorted list of referenda ready to be decided but not yet being decided on for a given Track. The referenda are sorted by Conviction-weighted approvals" === "Parameters" - `index` - the index of the Track to get the queue information for. The index for each Track is as follows: - `0` - Root Track - `1` - Whitelisted Track - `2` - General Admin Track - `3` - Emergency Canceller Track - `4` - Emergency Killer Track === "Returns" The list of referenda queued for a given Track. This should return an empty array if the deciding count is less than the maximum number of referenda that can be decided on. ```js // If using Polkadot.js API and calling toJSON() on the query results [ [ 5, // Referendum Index 0 // Track Index ] ] ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const index = INSERT_TRACK_INDEX; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const trackQueue = await api.query.referenda.trackQueue(index); }; main(); ``` ### Pallet Constants {: #constants } The Referenda Pallet includes the following read-only functions to obtain pallet constants: ??? function "**maxQueued**() - returns the maximum size of the referendum queue for a single Track" === "Parameters" None. === "Returns" The maximum number of queued referenda for a single Track. ```js // If using Polkadot.js API and calling toJSON() on the query results 100 ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const maxQueued = api.consts.referenda.maxQueued; }; main(); ``` ??? function "**submissionDeposit**() - returns the minimum amount to be used as a deposit for a public referendum proposal" === "Parameters" None. === "Returns" The minimum amount required for the Submission Deposit. ```js // If using Polkadot.js API and calling toJSON() on the query results 0x00000000000000008ac7230489e80000 ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const submissionDeposit = api.consts.referenda.submissionDeposit; }; main(); ``` ??? function "**tracks**() - returns information concerning the different referendum Tracks" === "Parameters" None. === "Returns" Information on each Track. This includes [general](/learn/features/governance#general-parameters-by-track){target=_blank}, [period](/learn/features/governance#period-parameters-by-track){target=_blank}, and [Approval and Support](/learn/features/governance#support-and-approval-parameters-by-track){target=_blank} parameters. ```js // If using Polkadot.js API and calling toJSON() on the query results [ [ 0, // Track Index { name: 'root', maxDeciding: 5, decisionDeposit: '0x000000000000152d02c7e14af6800000', preparePeriod: 7200, decisionPeriod: 100800, confirmPeriod: 7200, minEnactmentPeriod: 7200, minApproval: { reciprocal: { factor: 999999999, xOffset: 999999999, yOffset: 0 } }, minSupport: { linearDecreasing: { length: 1000000000, floor: 5000000, ceil: 250000000 } } } ], [ 1, { name: 'whitelisted_caller', maxDeciding: 100, decisionDeposit: '0x000000000000021e19e0c9bab2400000', preparePeriod: 50, decisionPeriod: 100800, confirmPeriod: 50, minEnactmentPeriod: 150, minApproval: { reciprocal: { factor: 999999999, xOffset: 999999999, yOffset: 0 } }, minSupport: { reciprocal: { factor: 60061, xOffset: 2994150, yOffset: -59882 } } } ], [ 2, { name: 'general_admin', maxDeciding: 10, decisionDeposit: '0x000000000000001b1ae4d6e2ef500000', preparePeriod: 300, decisionPeriod: 100800, confirmPeriod: 7200, minEnactmentPeriod: 7200, minApproval: { reciprocal: { factor: 999999999, xOffset: 999999999, yOffset: 0 } }, minSupport: { reciprocal: { factor: 222222224, xOffset: 333333335, yOffset: -166666668 } } } ], [ 3, { name: 'referendum_canceller', maxDeciding: 20, decisionDeposit: '0x000000000000021e19e0c9bab2400000', preparePeriod: 300, decisionPeriod: 100800, confirmPeriod: 900, minEnactmentPeriod: 50, minApproval: { reciprocal: { factor: 999999999, xOffset: 999999999, yOffset: 0 } }, minSupport: { reciprocal: { factor: 787400, xOffset: 1572327, yOffset: -786164 } } } ], [ 4, { name: 'referendum_killer', maxDeciding: 100, decisionDeposit: '0x000000000000043c33c1937564800000', preparePeriod: 300, decisionPeriod: 100800, confirmPeriod: 900, minEnactmentPeriod: 50, minApproval: { reciprocal: { factor: 999999999, xOffset: 999999999, yOffset: 0 } }, minSupport: { reciprocal: { factor: 869501, xOffset: 8620680, yOffset: -862069 } } } ] ] ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tracks = api.consts.referenda.tracks; }; main(); ``` ??? function "**undecidingTimeout**() - the number of blocks after submission that a referendum must begin being decided by. Once this passes, then anyone may cancel the referendum" === "Parameters" None. === "Returns" The number of blocks before a timeout occurs. ```js // If using Polkadot.js API and calling toJSON() on the query results 151200 ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const undecidingTimeout = api.consts.referenda.undecidingTimeout; }; main(); ``` --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/interfaces/features/ --- BEGIN CONTENT --- --- title: Access Network Features via Substrate description: Discover low-level Substrate interfaces that unlock functionality for interacting with critical network features like governance, staking, and randomness. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/interfaces/features/randomness/ --- BEGIN CONTENT --- --- title: Randomness Pallet description: Learn about the available extrinsics, storage methods, and constants in the Randomness Pallet on Moonbeam to retrieve data on randomness requests and results. keywords: randomness, VRF, substrate, pallet, moonbeam, polkadot categories: Substrate Toolkit --- # The Randomness Pallet ## Introduction {: #introduction } Moonbeam utilizes verifiable random functions (VRF) to generate randomness that can be verified on-chain. A VRF is a cryptographic function that takes some input and produces random values, along with a proof of authenticity that these random values were generated by the submitter. The proof can be verified by anyone to ensure the random values generated were calculated correctly. For more information on Moonbeam's on-chain randomness, such as an overview on the randomness sources, the request and fulfill cycle, and more, please refer to the [Randomness on Moonbeam](/learn/features/randomness/){target=\_blank} overview page. The randomness pallet enables you to check on randomness requests that have not been fulfilled or purged, randomness results, and more. To actually request and fulfill randomness, you can use the randomness precompile and randomness consumer contracts. The precompile is a Solidity interface that enables you to request randomness, check on the status of requests, fulfill requests, and more through the Ethereum API. For more information on how to use both of these contracts, please refer to the [Randomness Precompile](/builders/ethereum/precompiles/features/randomness/){target=\_blank} guide. This page will provide an overview of the storage methods and getters for the pallet constants available in the randomness pallet. ## Randomness Pallet Interface {: #randomness-pallet-interface } ### Storage Methods {: #storage-methods } The randomness pallet includes the following read-only storage methods to obtain chain state data: ??? function "**localVrfOutput**() - returns the current local per-block VRF randomness" === "Parameters" None === "Returns" `H256` - A 32-byte (256-bit) hex value, starting with "0x"` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the local VRF output from randomness pallet const localVrf = await api.query.randomness.localVrfOutput(); console.log('Local VRF Output:', localVrf.toString()); process.exit(0); } catch (error) { console.error('Error querying local VRF output:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**palletVersion**() - returns the current pallet version" === "Parameters" None === "Returns" `u16` - The pallet version === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the pallet version from randomness pallet const version = await api.query.randomness.palletVersion(); console.log('Randomness Pallet Version:', version.toString()); process.exit(0); } catch (error) { console.error('Error querying randomness pallet version:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**randomnessResults**(PalletRandomnessRequestType) - snapshot of randomness to fulfill all requests that are for the same raw randomness" === "Parameters" - `PalletRandomnessRequestType` - You can optionally provide the type of randomness you'd like, e.g. `Local` or `BabeEpoch` Randomness. If you omit this, you'll receive all types of randomness. === "Returns" The query returns mappings of request types to their randomness outcomes, where: 1. Key: Identifies the source and timing of the randomness request. e.g. `{ Local: '4,619,640' }` indicates this was a Local randomness request from block number 4,619,640. The Local type uses block numbers as identifiers, while BabeEpoch uses epoch numbers. 2. Value: Contains two pieces of information, including `randomness`: A 32-byte hex string (0x15b5f6...c816) representing the random value generated and `requestCount`: The number of requests that used this same random value (e.g. '1') Multiple requests for randomness at the same block/epoch would share the same random value, which is why there's a requestCount field. === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Query Babe Epoch randomness results const babeResults = await api.query.randomness.randomnessResults({ BabeEpoch: 0, }); console.log('\nBabe Epoch Randomness Results:'); console.log(babeResults.toHuman()); // Query Local randomness results const localResults = await api.query.randomness.randomnessResults({ Local: 0, }); console.log('\nLocal Randomness Results:'); console.log(localResults.toHuman()); // Get the available keys/entries console.log('\nAll Available Randomness Results:'); const entries = await api.query.randomness.randomnessResults.entries(); entries.forEach(([key, value]) => { console.log( 'Key:', key.args.map((k) => k.toHuman()) ); console.log('Value:', value.toHuman()); console.log('---'); }); process.exit(0); } catch (error) { console.error('Error querying randomness results:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**relayEpoch**() - returns the relay epoch" === "Parameters" None === "Returns" `u64` - the relay epoch === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the relay epoch const relayEpoch = await api.query.randomness.relayEpoch(); console.log('Current Relay Epoch:', relayEpoch.toString()); process.exit(0); } catch (error) { console.error('Error querying relay epoch:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**requestCount**() - returns the number of randomness requests made so far, and is used to generate the next request's uid" === "Parameters" None === "Returns" `u64` - the request count === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the request count const requestCount = await api.query.randomness.requestCount(); console.log('Total Randomness Requests:', requestCount.toString()); console.log( 'Next Request UID will be:', (Number(requestCount) + 1).toString() ); process.exit(0); } catch (error) { console.error('Error querying request count:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**requests**(u64) - returns a given randomness request or all of the randomness requests that have not been fulfilled nor purged yet" === "Parameters" - `u64` - The request ID number (optional) === "Returns" Returns an Option containing the request information if it exists and hasn't been fulfilled/purged, including: - The request type (Local or Babe) - When it can be fulfilled - Number of random words requested - The requester's information === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // First get the current request count const requestCount = await api.query.randomness.requestCount(); console.log('Total Request Count:', requestCount.toString()); // Query most recent request as an example if (requestCount > 0) { const latestRequestId = requestCount - 1; const specificRequest = await api.query.randomness.requests(latestRequestId); console.log('\nLatest Request (ID:', latestRequestId.toString(), '):'); if (specificRequest.isSome) { console.log(specificRequest.unwrap().toHuman()); } else { console.log('Request has been fulfilled or purged'); } } // Query all available requests console.log('\nAll Pending Requests:'); const allRequests = await api.query.randomness.requests.entries(); if (allRequests.length === 0) { console.log('No pending requests found'); } else { allRequests.forEach(([key, value]) => { const requestId = key.args[0].toString(); console.log('\nRequest ID:', requestId); if (value.isSome) { const request = value.unwrap(); console.log('Request Details:', request.toHuman()); } }); // Show some statistics console.log('\nRequest Statistics:'); console.log('Total Pending Requests:', allRequests.length); } process.exit(0); } catch (error) { console.error('Error querying randomness requests:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ### Pallet Constants {: #constants } The randomness pallet includes the following read-only functions to obtain pallet constants: ??? function "**blockExpirationDelay**() - the number of blocks that must pass before a local VRF request expires and can be purged" === "Parameters" None === "Returns" `u32` - the number of blocks that must pass before a local VRF request expires and can be purged === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the block expiration delay constant const blockExpirationDelay = await api.consts.randomness.blockExpirationDelay; console.log( 'Block Expiration Delay:', blockExpirationDelay.toString(), 'blocks' ); process.exit(0); } catch (error) { console.error('Error querying block expiration delay:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**deposit**() - the amount that should be taken as a security deposit when requesting random words. There is one deposit per request" === "Parameters" None === "Returns" `u128` - the amount that should be taken as a security deposit when requesting random words === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the deposit constant const deposit = await api.consts.randomness.deposit; console.log('Randomness Request Deposit:', deposit.toString(), 'Wei'); console.log( 'Deposit in DEV:', (BigInt(deposit) / BigInt(10 ** 18)).toString() ); process.exit(0); } catch (error) { console.error('Error querying randomness deposit:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**epochExpirationDelay**() - the number of epochs that must pass before a BABE request expires and can be purged" === "Parameters" None === "Returns" `u64` - the number of epochs that must pass before a BABE request expires and can be purged === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the epoch expiration delay constant const epochExpirationDelay = await api.consts.randomness.epochExpirationDelay; console.log( 'Epoch Expiration Delay:', epochExpirationDelay.toString(), 'epochs' ); process.exit(0); } catch (error) { console.error('Error querying epoch expiration delay:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**maxBlockDelay**() - the maximum number of blocks (after the block in which the request was made) that can pass before a local VRF request is fulfilled" === "Parameters" None === "Returns" `u32` - the maximum number of blocks that can pass before a local VRF request is fulfilled === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the maximum block delay constant const maxBlockDelay = await api.consts.randomness.maxBlockDelay; console.log('Maximum Block Delay:', maxBlockDelay.toString(), 'blocks'); process.exit(0); } catch (error) { console.error('Error querying max block delay:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**maxRandomWords**() - the maximum number of random words that can be requested" === "Parameters" None === "Returns" `u8` - the maximum number of random words that can be requested === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the maximum random words constant const maxRandomWords = await api.consts.randomness.maxRandomWords; console.log('Maximum Random Words:', maxRandomWords.toString(), 'words'); process.exit(0); } catch (error) { console.error('Error querying max random words:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**minBlockDelay**() - the minimum number of blocks (after the block in which the request was made) that must pass before a local VRF request can be fulfilled" === "Parameters" None === "Returns" `u32` - the minimum number of blocks (after the block in which the request was made) that must pass before a local VRF request can be fulfilled === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the minimum block delay constant const minBlockDelay = await api.consts.randomness.minBlockDelay; console.log('Minimum Block Delay:', minBlockDelay.toString(), 'blocks'); process.exit(0); } catch (error) { console.error('Error querying min block delay:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/interfaces/features/staking/ --- BEGIN CONTENT --- --- title: Parachain Staking Pallet description: Learn about the Parachain Staking Pallet interface on Moonbeam, which can be used to perform delegator and collator activities and retrieve staking information. keywords: staking, substrate, pallet, moonbeam, polkadot categories: Substrate Toolkit, Staking --- # The Parachain Staking Pallet ## Introduction {: #introduction } Moonbeam uses a Delegated Proof of Stake (DPoS) system that determines which collators are eligible to produce blocks based on their total stake in the network. For general information on staking, such as general terminology, staking variables, and more, please refer to the [Staking on Moonbeam](/learn/features/staking/){target=\_blank} page. The DPoS system is powered by the [parachain staking](https://github.com/moonbeam-foundation/moonbeam/tree/master/pallets/parachain-staking/src){target=\_blank} pallet, allowing token holders (delegators) to express exactly which collator candidates they would like to support and with what quantity of stake. The design of the parachain staking pallet is such that it enforces shared risk/reward on chain between delegators and candidates. Some of the functionality of the parachain staking pallet is also available through a staking precompile. The precompile is a Solidity interface that enables you to perform staking actions through the Ethereum API. Please refer to the [Staking Precompile](/builders/ethereum/precompiles/features/staking/){target=\_blank} guide for more information. This guide will provide an overview of the extrinsics, storage methods, and getters for the pallet constants available in the parachain staking pallet. ## Exit Delays {: #exit-delays } Some of the staking pallet extrinsics include exit delays that you must wait before the request can be executed. The exit delays to note are as follows: === "Moonbeam" | Variable | Value | |:-----------------------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------:| | Decrease candidate bond | {{ networks.moonbeam.collator_timings.can_bond_less.rounds }} rounds ({{ networks.moonbeam.collator_timings.can_bond_less.hours }} hours) | | Decrease delegator bond | {{ networks.moonbeam.delegator_timings.del_bond_less.rounds }} rounds ({{ networks.moonbeam.delegator_timings.del_bond_less.hours }} hours) | | Revoke delegation | {{ networks.moonbeam.delegator_timings.revoke_delegations.rounds }} rounds ({{ networks.moonbeam.delegator_timings.revoke_delegations.hours }} hours) | | Leave candidates | {{ networks.moonbeam.collator_timings.leave_candidates.rounds }} rounds ({{ networks.moonbeam.collator_timings.leave_candidates.hours }} hours) | | Leave delegators | {{ networks.moonbeam.delegator_timings.leave_delegators.rounds }} rounds ({{ networks.moonbeam.delegator_timings.leave_delegators.hours }} hours) | === "Moonriver" | Variable | Value | |:-----------------------:|:-------------------------------------------------------------------------------------------------------------------------------------------------------:| | Decrease candidate bond | {{ networks.moonriver.collator_timings.can_bond_less.rounds }} rounds ({{ networks.moonriver.collator_timings.can_bond_less.hours }} hours) | | Decrease delegator bond | {{ networks.moonriver.delegator_timings.del_bond_less.rounds }} rounds ({{ networks.moonriver.delegator_timings.del_bond_less.hours }} hours) | | Revoke delegation | {{ networks.moonriver.delegator_timings.revoke_delegations.rounds }} rounds ({{ networks.moonriver.delegator_timings.revoke_delegations.hours }} hours) | | Leave candidates | {{ networks.moonriver.collator_timings.leave_candidates.rounds }} rounds ({{ networks.moonriver.collator_timings.leave_candidates.hours }} hours) | | Leave delegators | {{ networks.moonriver.delegator_timings.leave_delegators.rounds }} rounds ({{ networks.moonriver.delegator_timings.leave_delegators.hours }} hours) | === "Moonbase Alpha" | Variable | Value | |:-----------------------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------:| | Decrease candidate bond | {{ networks.moonbase.collator_timings.can_bond_less.rounds }} rounds ({{ networks.moonbase.collator_timings.can_bond_less.hours }} hours) | | Decrease delegator bond | {{ networks.moonbase.delegator_timings.del_bond_less.rounds }} rounds ({{ networks.moonbase.delegator_timings.del_bond_less.hours }} hours) | | Revoke delegation | {{ networks.moonbase.delegator_timings.revoke_delegations.rounds }} rounds ({{ networks.moonbase.delegator_timings.revoke_delegations.hours }} hours) | | Leave candidates | {{ networks.moonbase.collator_timings.leave_candidates.rounds }} rounds ({{ networks.moonbase.collator_timings.leave_candidates.hours }} hours) | | Leave delegators | {{ networks.moonbase.delegator_timings.leave_delegators.rounds }} rounds ({{ networks.moonbase.delegator_timings.leave_delegators.hours }} hours) | ## Parachain Staking Pallet Interface {: #parachain-staking-pallet-interface } ### Extrinsics {: #extrinsics } The parachain staking pallet provides the following extrinsics (functions): ??? function "**cancelCandidateBondLess**() - cancels a pending scheduled request to decrease a candidate's self bond amount" === "Parameters" None === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup account from private key const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const account = keyring.addFromUri(PRIVATE_KEY); console.log('Account address:', account.address); // Create the cancel transaction const tx = api.tx.parachainStaking.cancelCandidateBondLess(); // Sign and send the transaction await tx.signAndSend(account, ({ status, events }) => { if (status.isInBlock) { console.log(`Transaction included in block hash: ${status.asInBlock}`); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful cancellation if ( section === 'parachainStaking' && method === 'CancelledCandidateBondLess' ) { const [candidate, amount, executeRound] = data; console.log('\nSuccessfully cancelled bond decrease request!'); console.log('Candidate:', candidate.toString()); console.log('Amount that was to be decreased:', amount.toString()); console.log( 'Round it was to be executed:', executeRound.toString() ); } }); process.exit(0); } }); } catch (error) { console.error('Error in cancelling candidate bond less:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**cancelDelegationRequest**(candidate) - cancels any pending delegation requests provided the address of a candidate" === "Parameters" - `candidate` - The address of the relevant collator === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup delegator account from private key const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const delegator = keyring.addFromUri(PRIVATE_KEY); // The candidate's address for which to cancel the delegation request const candidateAddress = 'INSERT_COLLATOR_ADDRESS'; console.log('Delegator address:', delegator.address); console.log('Candidate address:', candidateAddress); // Create the cancel delegation request transaction const tx = api.tx.parachainStaking.cancelDelegationRequest(candidateAddress); // Sign and send the transaction await tx.signAndSend(delegator, ({ status, events }) => { if (status.isInBlock) { console.log(`Transaction included in block hash: ${status.asInBlock}`); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful cancellation if ( section === 'parachainStaking' && method === 'CancelledDelegationRequest' ) { const [delegatorAddress, scheduledRequest, candidateAddress] = data; console.log('\nSuccessfully cancelled delegation request!'); console.log('Delegator:', delegatorAddress.toString()); console.log('Candidate:', candidateAddress.toString()); const request = scheduledRequest.toJSON(); console.log('Request details:'); console.log('- Execution round:', request.whenExecutable); if (request.action.decrease) { console.log('- Action: Decrease by', request.action.decrease); } else if (request.action.revoke) { console.log('- Action: Revoke amount', request.action.revoke); } } }); process.exit(0); } }); } catch (error) { console.error('Error in cancelling delegation request:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**cancelLeaveCandidates**(candidateCount) - cancels a candidate's pending scheduled request to leave the candidate pool given the current number of candidates in the pool" === "Parameters" - `candidateCount` - The current number of collator candidates in the pool === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup candidate account from private key const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const candidate = keyring.addFromUri(PRIVATE_KEY); // First, get the current candidate count from the chain const candidates = await api.query.parachainStaking.candidatePool(); const candidateCount = candidates.length; console.log('Candidate address:', candidate.address); console.log('Current candidate count:', candidateCount); // Create the cancel leave candidates transaction const tx = api.tx.parachainStaking.cancelLeaveCandidates(candidateCount); // Sign and send the transaction await tx.signAndSend(candidate, ({ status, events }) => { if (status.isInBlock) { console.log(`Transaction included in block hash: ${status.asInBlock}`); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful cancellation if ( section === 'parachainStaking' && method === 'CancelledLeaveCandidates' ) { const [candidateAddress, candidateCount] = data; console.log('\nSuccessfully cancelled leave candidates request!'); console.log('Candidate:', candidateAddress.toString()); console.log( 'Candidate count at cancellation:', candidateCount.toString() ); } }); process.exit(0); } }); } catch (error) { console.error('Error in cancelling leave candidates request:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**candidateBondMore**(more) - request to increase a candidate's self bond by a specified amount" === "Parameters" - `more` - The amount of WEI by which to increase the candidate's self bond === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup candidate account from private key const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const candidate = keyring.addFromUri(PRIVATE_KEY); // Amount to increase bond by (e.g., 1 DEV = 1_000_000_000_000_000_000) const moreBond = '1000000000000000000'; console.log('Candidate address:', candidate.address); console.log('Increasing bond by:', moreBond, 'Wei (1 DEV)'); // Query current bond before increasing const candidateInfo = await api.query.parachainStaking.candidateInfo( candidate.address ); if (candidateInfo.isSome) { console.log('Current bond:', candidateInfo.unwrap().bond.toString()); } // Create the increase bond transaction const tx = api.tx.parachainStaking.candidateBondMore(moreBond); // Sign and send the transaction await tx.signAndSend(candidate, ({ status, events }) => { if (status.isInBlock) { console.log(`Transaction included in block hash: ${status.asInBlock}`); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful bond increase if ( section === 'parachainStaking' && method === 'CandidateBondedMore' ) { const [candidateAddress, amount, newTotal] = data; console.log('\nSuccessfully increased candidate bond!'); console.log('Candidate:', candidateAddress.toString()); console.log('Amount increased:', amount.toString()); console.log('New total bond:', newTotal.toString()); } }); // Query updated bond after transaction api.query.parachainStaking .candidateInfo(candidate.address) .then((newInfo) => { if (newInfo.isSome) { console.log('\nUpdated bond:', newInfo.unwrap().bond.toString()); } process.exit(0); }); } }); } catch (error) { console.error('Error in increasing candidate bond:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**delegateWithAutoCompound**(candidate, amount, autoCompound, candidateDelegationCount, candidateAutoCompoundingDelegationCount, delegationCount) - delegates a collator candidate and sets the percentage of rewards to auto-compound given an integer (no decimals) for the `amount` between 0-100. If the caller is not a delegator, this function adds them to the set of delegators. If the caller is already a delegator, then it adjusts their delegation amount" === "Parameters" - `candidate` - The collator's address you want to delegate to - `amount` - The amount to delegate (in Wei, e.g. 1000000000000000000 for 1 DEV) - `autoCompound` - The percentage of rewards to automatically compound (0-100) - `candidateDelegationCount` - The current number of delegations to the collator - `candidateAutoCompoundingDelegationCount` - The current number of auto-compounding delegations for the collator - `delegationCount` - The total number of delegations you have across all collators === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup delegator account from private key const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const delegator = keyring.addFromUri(PRIVATE_KEY); // The candidate's address to delegate to const candidateAddress = 'INSERT_COLLATOR_ADDRESS'; // Amount to delegate (e.g., 1 DEV = 1_000_000_000_000_000_000) const amount = '1000000000000000000'; // Auto-compound percentage (0-100) const autoCompound = 50; // 50% of rewards will be auto-compounded // Get current delegation counts const candidateInfo = await api.query.parachainStaking.candidateInfo(candidateAddress); const delegatorState = await api.query.parachainStaking.delegatorState( delegator.address ); const autoCompoundDelegations = await api.query.parachainStaking.autoCompoundingDelegations( candidateAddress ); // Get delegation counts let candidateDelegationCount = 0; let candidateAutoCompoundingDelegationCount = 0; let delegationCount = 0; if (candidateInfo.isSome) { candidateDelegationCount = candidateInfo.unwrap().delegationCount; } candidateAutoCompoundingDelegationCount = autoCompoundDelegations.length; if (delegatorState.isSome) { delegationCount = delegatorState.unwrap().delegations.length; } console.log('Delegation Details:'); console.log('Delegator address:', delegator.address); console.log('Candidate address:', candidateAddress); console.log('Delegation amount:', amount, 'Wei (1 DEV)'); console.log('Auto-compound percentage:', autoCompound, '%'); console.log('\nCurrent Stats:'); console.log( 'Candidate delegation count:', candidateDelegationCount.toString() ); console.log( 'Candidate auto-compounding delegation count:', candidateAutoCompoundingDelegationCount.toString() ); console.log('Delegator total delegations:', delegationCount.toString()); // Create the delegate with auto-compound transaction const tx = api.tx.parachainStaking.delegateWithAutoCompound( candidateAddress, amount, autoCompound, candidateDelegationCount, candidateAutoCompoundingDelegationCount, delegationCount ); // Sign and send the transaction await tx.signAndSend(delegator, ({ status, events }) => { if (status.isInBlock) { console.log( `\nTransaction included in block hash: ${status.asInBlock}` ); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful delegation if (section === 'parachainStaking' && method === 'Delegation') { const [delegator, amount, candidate, autoCompound] = data; console.log('\nSuccessfully delegated with auto-compound!'); console.log('Delegator:', delegator.toString()); console.log('Candidate:', candidate.toString()); console.log('Amount:', amount.toString()); console.log( 'Auto-compound percentage:', autoCompound.toString(), '%' ); } }); process.exit(0); } }); } catch (error) { console.error('Error in delegation with auto-compound:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**delegatorBondMore**(candidate, more) - request to increase a delegator's amount delegated for a specific candidate" === "Parameters" - `candidate` - the address of the respective collator - `more` - The amount you want to increase your delegation by (in Wei, e.g. 1000000000000000000 for 1 DEV) === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup delegator account from private key const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const delegator = keyring.addFromUri(PRIVATE_KEY); // The candidate's address for which to increase delegation const candidateAddress = 'INSERT_COLLATOR_ADDRESS'; // Amount to increase delegation by (e.g., 1 DEV = 1_000_000_000_000_000_000) const moreBond = '1000000000000000000'; // Query current delegation before increasing const delegatorState = await api.query.parachainStaking.delegatorState( delegator.address ); console.log('Current Delegation Info:'); console.log('Delegator address:', delegator.address); console.log('Candidate address:', candidateAddress); if (delegatorState.isSome) { const state = delegatorState.unwrap(); const currentDelegation = state.delegations.find( (d) => d.owner.toString().toLowerCase() === candidateAddress.toLowerCase() ); if (currentDelegation) { console.log( 'Current delegation amount:', currentDelegation.amount.toString() ); } } console.log('Amount to increase by:', moreBond, 'Wei (1 DEV)'); // Create the increase delegation transaction const tx = api.tx.parachainStaking.delegatorBondMore( candidateAddress, moreBond ); // Sign and send the transaction await tx.signAndSend(delegator, ({ status, events }) => { if (status.isInBlock) { console.log( `\nTransaction included in block hash: ${status.asInBlock}` ); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful bond increase if ( section === 'parachainStaking' && method === 'DelegationIncreased' ) { const [delegator, candidate, amount, inTopDelegations] = data; console.log('\nSuccessfully increased delegation!'); console.log('Delegator:', delegator.toString()); console.log('Candidate:', candidate.toString()); console.log('Amount increased by:', amount.toString()); console.log('In top delegations:', inTopDelegations.toString()); } }); // Query updated delegation after transaction api.query.parachainStaking .delegatorState(delegator.address) .then((newState) => { if (newState.isSome) { const state = newState.unwrap(); const updatedDelegation = state.delegations.find( (d) => d.owner.toString().toLowerCase() === candidateAddress.toLowerCase() ); if (updatedDelegation) { console.log( '\nNew delegation amount:', updatedDelegation.amount.toString() ); } } process.exit(0); }); } }); } catch (error) { console.error('Error in increasing delegation:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**executeCandidateBondLess**(candidate) - executes any scheduled due requests to decrease a candidate's self bond amount" === "Parameters" - `candidate` - the address of the respective collator === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup account from private key (this can be any account, doesn't need to be the candidate) const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const executor = keyring.addFromUri(PRIVATE_KEY); // The candidate's address whose bond decrease should be executed const candidateAddress = 'INSERT_COLLATOR_ADDRESS'; // Query current candidate info before execution const candidateInfo = await api.query.parachainStaking.candidateInfo(candidateAddress); console.log('Execution Details:'); console.log('Executor address:', executor.address); console.log('Candidate address:', candidateAddress); if (candidateInfo.isSome) { const info = candidateInfo.unwrap(); console.log('\nCandidate current bond:', info.bond.toString()); console.log('Candidate status:', info.status.toString()); } // Create the execute bond decrease transaction const tx = api.tx.parachainStaking.executeCandidateBondLess(candidateAddress); // Sign and send the transaction await tx.signAndSend(executor, ({ status, events }) => { if (status.isInBlock) { console.log( `\nTransaction included in block hash: ${status.asInBlock}` ); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful execution if ( section === 'parachainStaking' && method === 'CandidateBondedLess' ) { const [candidate, amount, newBond] = data; console.log('\nSuccessfully executed candidate bond decrease!'); console.log('Candidate:', candidate.toString()); console.log('Amount decreased:', amount.toString()); console.log('New bond amount:', newBond.toString()); } }); // Query updated candidate info after execution api.query.parachainStaking .candidateInfo(candidateAddress) .then((newInfo) => { if (newInfo.isSome) { const info = newInfo.unwrap(); console.log('\nUpdated candidate bond:', info.bond.toString()); } process.exit(0); }); } }); } catch (error) { console.error('Error in executing candidate bond decrease:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**executeDelegationRequest**(delegator, candidate) - executes any scheduled due delegation requests for a specific delegator provided the address of the candidate" === "Parameters" - `delegator` - The address of the delegator who made the delegation request - `candidate` - The collator's address associated with the delegation request === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup executor account from private key (this can be any account) const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const executor = keyring.addFromUri(PRIVATE_KEY); // The delegator's address whose request will be executed const delegatorAddress = 'INSERT_DELEGATOR_ADDRESS'; // The candidate's address for the delegation request const candidateAddress = 'INSERT_COLLATOR_ADDRESS'; // Query current delegation info before execution const delegatorState = await api.query.parachainStaking.delegatorState(delegatorAddress); console.log('Execution Details:'); console.log('Executor address:', executor.address); console.log('Delegator address:', delegatorAddress); console.log('Candidate address:', candidateAddress); if (delegatorState.isSome) { const state = delegatorState.unwrap(); const currentDelegation = state.delegations.find( (d) => d.owner.toString().toLowerCase() === candidateAddress.toLowerCase() ); if (currentDelegation) { console.log( '\nCurrent delegation amount:', currentDelegation.amount.toString() ); } } // Create the execute delegation request transaction const tx = api.tx.parachainStaking.executeDelegationRequest( delegatorAddress, candidateAddress ); // Sign and send the transaction await tx.signAndSend(executor, ({ status, events }) => { if (status.isInBlock) { console.log( `\nTransaction included in block hash: ${status.asInBlock}` ); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful delegation decrease/revoke if ( section === 'parachainStaking' && method === 'DelegationDecreased' ) { const [delegator, candidate, amount, inTopDelegations] = data; console.log('\nSuccessfully executed delegation decrease!'); console.log('Delegator:', delegator.toString()); console.log('Candidate:', candidate.toString()); console.log('Amount decreased:', amount.toString()); console.log('In top delegations:', inTopDelegations.toString()); } if ( section === 'parachainStaking' && method === 'DelegationRevoked' ) { const [delegator, candidate, amount] = data; console.log('\nSuccessfully executed delegation revocation!'); console.log('Delegator:', delegator.toString()); console.log('Candidate:', candidate.toString()); console.log('Amount revoked:', amount.toString()); } }); // Query updated delegation info after execution api.query.parachainStaking .delegatorState(delegatorAddress) .then((newState) => { if (newState.isSome) { const state = newState.unwrap(); const updatedDelegation = state.delegations.find( (d) => d.owner.toString().toLowerCase() === candidateAddress.toLowerCase() ); if (updatedDelegation) { console.log( '\nNew delegation amount:', updatedDelegation.amount.toString() ); } else { console.log('\nDelegation has been fully revoked'); } } process.exit(0); }); } }); } catch (error) { console.error('Error in executing delegation request:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**executeLeaveCandidates**(candidate, candidateDelegationCount) - executes any scheduled due requests to leave the set of collator candidates" === "Parameters" - `candidate` - The address of the collator who requested to leave the candidate pool - `candidateDelegationCount` - The current number of delegations for the leaving candidate === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup executor account from private key (this can be any account) const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const executor = keyring.addFromUri(PRIVATE_KEY); // The candidate's address who is scheduled to leave const candidateAddress = 'INSERT_COLLATOR_ADDRESS'; // Get candidate information and delegation count const candidateInfo = await api.query.parachainStaking.candidateInfo(candidateAddress); let candidateDelegationCount = 0; console.log('Execution Details:'); console.log('Executor address:', executor.address); console.log('Candidate address:', candidateAddress); if (candidateInfo.isSome) { const info = candidateInfo.unwrap(); candidateDelegationCount = info.delegationCount; console.log('\nCandidate Information:'); console.log('Current bond:', info.bond.toString()); console.log('Delegation count:', candidateDelegationCount.toString()); console.log('Status:', info.status.toString()); } else { console.log('\nWarning: Candidate info not found'); } // Create the execute leave candidates transaction const tx = api.tx.parachainStaking.executeLeaveCandidates( candidateAddress, candidateDelegationCount ); // Sign and send the transaction await tx.signAndSend(executor, ({ status, events }) => { if (status.isInBlock) { console.log( `\nTransaction included in block hash: ${status.asInBlock}` ); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful execution of leave request if (section === 'parachainStaking' && method === 'CandidateLeft') { const [candidate, amount, remainingCount] = data; console.log('\nSuccessfully executed leave candidates request!'); console.log('Candidate:', candidate.toString()); console.log('Amount unlocked:', amount.toString()); console.log('Remaining candidates:', remainingCount.toString()); } }); // Query final candidate state api.query.parachainStaking .candidateInfo(candidateAddress) .then((finalState) => { if (finalState.isNone) { console.log( '\nCandidate has been successfully removed from the candidate pool' ); } else { console.log('\nWarning: Candidate still exists in the pool'); console.log('Current state:', finalState.unwrap().toString()); } process.exit(0); }); } }); } catch (error) { console.error('Error in executing leave candidates request:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**goOffline**() - allows a collator candidate to temporarily leave the pool of candidates without unbonding" === "Parameters" None === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup collator account from private key const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const collator = keyring.addFromUri(PRIVATE_KEY); // Query current collator info before going offline const candidateInfo = await api.query.parachainStaking.candidateInfo( collator.address ); console.log('Collator Details:'); console.log('Collator address:', collator.address); if (candidateInfo.isSome) { const info = candidateInfo.unwrap(); console.log('\nCurrent Status:'); console.log('Bond:', info.bond.toString()); console.log('Delegation Count:', info.delegationCount.toString()); console.log('Status:', info.status.toString()); } else { console.log('\nWarning: Not found in candidate pool'); process.exit(1); } // Create the go offline transaction const tx = api.tx.parachainStaking.goOffline(); // Sign and send the transaction await tx.signAndSend(collator, ({ status, events }) => { if (status.isInBlock) { console.log( `\nTransaction included in block hash: ${status.asInBlock}` ); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful offline status change if ( section === 'parachainStaking' && method === 'CandidateWentOffline' ) { const [collatorAccount] = data; console.log('\nSuccessfully went offline!'); console.log('Collator:', collatorAccount.toString()); } }); // Query final collator state api.query.parachainStaking .candidateInfo(collator.address) .then((finalState) => { if (finalState.isSome) { const info = finalState.unwrap(); console.log('\nUpdated Status:'); console.log('Bond:', info.bond.toString()); console.log('Delegation Count:', info.delegationCount.toString()); console.log('Status:', info.status.toString()); } process.exit(0); }); } }); } catch (error) { console.error('Error in going offline:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**goOnline**() - allows a collator candidate to rejoin the pool of candidates after previously calling `goOffline()`" === "Parameters" None === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup collator account from private key const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const collator = keyring.addFromUri(PRIVATE_KEY); // Query current collator info before going online const candidateInfo = await api.query.parachainStaking.candidateInfo( collator.address ); console.log('Collator Details:'); console.log('Collator address:', collator.address); if (candidateInfo.isSome) { const info = candidateInfo.unwrap(); console.log('\nCurrent Status:'); console.log('Bond:', info.bond.toString()); console.log('Delegation Count:', info.delegationCount.toString()); console.log('Status:', info.status.toString()); } else { console.log('\nWarning: Not found in candidate pool'); process.exit(1); } // Create the go online transaction const tx = api.tx.parachainStaking.goOnline(); // Sign and send the transaction await tx.signAndSend(collator, ({ status, events }) => { if (status.isInBlock) { console.log( `\nTransaction included in block hash: ${status.asInBlock}` ); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful online status change if ( section === 'parachainStaking' && method === 'CandidateBackOnline' ) { const [collatorAccount] = data; console.log('\nSuccessfully went back online!'); console.log('Collator:', collatorAccount.toString()); } }); // Query final collator state api.query.parachainStaking .candidateInfo(collator.address) .then((finalState) => { if (finalState.isSome) { const info = finalState.unwrap(); console.log('\nUpdated Status:'); console.log('Bond:', info.bond.toString()); console.log('Delegation Count:', info.delegationCount.toString()); console.log('Status:', info.status.toString()); } process.exit(0); }); } }); } catch (error) { console.error('Error in going online:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**joinCandidates**(bond, candidateCount) - request to join the set of collator candidates with a specified bond amount and provided the current candidate count" === "Parameters" - `bond` - The amount to stake as collator bond (in Wei, e.g. 500000000000000000000 for 500 DEV) - `candidateCount` - The total number of candidates currently in the candidate pool === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup account from private key const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const account = keyring.addFromUri(PRIVATE_KEY); // Set bond amount to 500 DEV (multiply by 10^18 for proper decimals) const bondAmount = '500000000000000000000'; // Get current candidate count const candidates = await api.query.parachainStaking.candidatePool(); const candidateCount = candidates.length; // Check account balance const balance = await api.query.system.account(account.address); console.log('Join Candidates Details:'); console.log('Account address:', account.address); console.log('Current free balance:', balance.data.free.toString()); console.log('Bond amount:', bondAmount, '(501 DEV)'); console.log('Current candidate count:', candidateCount); // Create the join candidates transaction const tx = api.tx.parachainStaking.joinCandidates( bondAmount, candidateCount ); // Sign and send the transaction await tx.signAndSend(account, ({ status, events }) => { if (status.isInBlock) { console.log( `\nTransaction included in block hash: ${status.asInBlock}` ); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful joining if ( section === 'parachainStaking' && method === 'JoinedCollatorCandidates' ) { const [account, amountLocked, newTotalAmountLocked] = data; console.log('\nSuccessfully joined collator candidates!'); console.log('Account:', account.toString()); console.log('Amount locked:', amountLocked.toString()); console.log( 'New total amount locked:', newTotalAmountLocked.toString() ); } }); // Query final candidate state api.query.parachainStaking .candidateInfo(account.address) .then((finalState) => { if (finalState.isSome) { const info = finalState.unwrap(); console.log('\nNew Candidate Status:'); console.log('Bond:', info.bond.toString()); console.log('Delegation Count:', info.delegationCount.toString()); console.log('Status:', info.status.toString()); } // Get updated candidate count api.query.parachainStaking.candidatePool().then((newCandidates) => { console.log('New candidate count:', newCandidates.length); process.exit(0); }); }); } }); } catch (error) { console.error('Error in joining candidates:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**notifyInactiveCollator**(collator) - marks a collator as inactive if they have not been producing blocks for the maximum number of offline rounds, as returned by the [`maxOfflineRounds` pallet constant](#constants)" === "Parameters" - `collator` - the address of the collator to be notified === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup notifier account from private key (this can be any account) const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const notifier = keyring.addFromUri(PRIVATE_KEY); // The potentially inactive collator's address const inactiveCollator = 'INSERT_COLLATOR_ADDRESS'; // Get max offline rounds from constants const maxOfflineRounds = await api.consts.parachainStaking.maxOfflineRounds; // Get current round info const round = await api.query.parachainStaking.round(); // Get collator info const collatorInfo = await api.query.parachainStaking.candidateInfo(inactiveCollator); console.log('Notify Inactive Collator Details:'); console.log('Notifier address:', notifier.address); console.log('Inactive collator address:', inactiveCollator); console.log('Maximum allowed offline rounds:', maxOfflineRounds.toString()); console.log('Current round:', round.current.toString()); if (collatorInfo.isSome) { const info = collatorInfo.unwrap(); console.log('\nCollator Current Status:'); console.log('Bond:', info.bond.toString()); console.log('Delegation Count:', info.delegationCount.toString()); console.log('Status:', info.status.toString()); } // Create the notify inactive collator transaction const tx = api.tx.parachainStaking.notifyInactiveCollator(inactiveCollator); // Sign and send the transaction await tx.signAndSend(notifier, ({ status, events }) => { if (status.isInBlock) { console.log( `\nTransaction included in block hash: ${status.asInBlock}` ); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful notification if ( section === 'parachainStaking' && method === 'CollatorWentOffline' ) { const [collatorAccount] = data; console.log('\nSuccessfully notified inactive collator!'); console.log('Collator:', collatorAccount.toString()); } }); // Query final collator state api.query.parachainStaking .candidateInfo(inactiveCollator) .then((finalState) => { if (finalState.isSome) { const info = finalState.unwrap(); console.log('\nUpdated Collator Status:'); console.log('Bond:', info.bond.toString()); console.log('Delegation Count:', info.delegationCount.toString()); console.log('Status:', info.status.toString()); } process.exit(0); }); } }); } catch (error) { console.error('Error in notifying inactive collator:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**scheduleCandidateBondLess**(less) - schedules a request to decrease a candidate's self bond by a specified amount. There is an [exit delay](#exit-delays) that must be waited before you can execute the request via the `executeCandidateBondLess` extrinsic" === "Parameters" - `less` - The amount you want to decrease your delegation by (in Wei, e.g. 1000000000000000000 for 1 DEV) === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup candidate account from private key const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const candidate = keyring.addFromUri(PRIVATE_KEY); // Amount to decrease bond by (e.g., 1 DEV = 1_000_000_000_000_000_000) const decreaseAmount = '1000000000000000000'; // 1 DEV // Get current candidate info const candidateInfo = await api.query.parachainStaking.candidateInfo( candidate.address ); console.log('Schedule Bond Decrease Details:'); console.log('Candidate address:', candidate.address); console.log('Bond decrease amount:', decreaseAmount, 'Wei (1 DEV)'); if (candidateInfo.isSome) { const info = candidateInfo.unwrap(); console.log('\nCurrent Candidate Status:'); console.log('Current bond:', info.bond.toString()); console.log('Delegation Count:', info.delegationCount.toString()); console.log('Status:', info.status.toString()); } else { console.log('\nWarning: Account is not a candidate'); process.exit(1); } // Create the schedule bond decrease transaction const tx = api.tx.parachainStaking.scheduleCandidateBondLess(decreaseAmount); // Get current round const round = await api.query.parachainStaking.round(); const currentRound = round.current.toNumber(); // Sign and send the transaction await tx.signAndSend(candidate, ({ status, events }) => { if (status.isInBlock) { console.log( `\nTransaction included in block hash: ${status.asInBlock}` ); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful scheduling if ( section === 'parachainStaking' && method === 'CandidateBondLessRequested' ) { const [candidate, amountToDecrease, executeRound] = data; console.log('\nSuccessfully scheduled bond decrease!'); console.log('Candidate:', candidate.toString()); console.log('Amount to decrease:', amountToDecrease.toString()); console.log('Execute round:', executeRound.toString()); console.log( `\nNote: You must wait until round ${executeRound.toString()} to execute the decrease request` ); } }); // Query final candidate state api.query.parachainStaking .candidateInfo(candidate.address) .then((finalState) => { if (finalState.isSome) { const info = finalState.unwrap(); console.log('\nUpdated Candidate Status:'); console.log('Bond:', info.bond.toString()); console.log('Delegation Count:', info.delegationCount.toString()); console.log('Status:', info.status.toString()); } process.exit(0); }); } }); } catch (error) { console.error('Error in scheduling bond decrease:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**scheduleDelegatorBondLess**(candidate, less) - schedules a request for a delegator to bond less with respect to a specific candidate. There is an [exit delay](#exit-delays) that must be waited before you can execute the request via the `executeDelegationRequest` extrinsic" === "Parameters" - `candidate` - The collator's address for which you want to decrease your delegation - `less` - The amount you want to decrease your delegation by (in Wei, e.g. 1000000000000000000 for 1 DEV) === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup delegator account from private key const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const delegator = keyring.addFromUri(PRIVATE_KEY); // The candidate's address to decrease delegation for const candidateAddress = 'INSERT_COLLATOR_ADDRESS'; // Amount to decrease delegation by (e.g., 1 DEV = 1_000_000_000_000_000_000) const decreaseAmount = '1000000000000000000'; // 1 DEV // Get current delegation info const delegatorState = await api.query.parachainStaking.delegatorState( delegator.address ); console.log('Schedule Delegation Decrease Details:'); console.log('Delegator address:', delegator.address); console.log('Candidate address:', candidateAddress); console.log('Amount to decrease:', decreaseAmount, 'Wei (1 DEV)'); if (delegatorState.isSome) { const state = delegatorState.unwrap(); const currentDelegation = state.delegations.find( (d) => d.owner.toString().toLowerCase() === candidateAddress.toLowerCase() ); if (currentDelegation) { console.log( '\nCurrent Delegation Amount:', currentDelegation.amount.toString() ); } else { console.log( '\nWarning: No existing delegation found for this candidate' ); process.exit(1); } } else { console.log('\nWarning: Account is not a delegator'); process.exit(1); } // Get current round const round = await api.query.parachainStaking.round(); console.log('Current round:', round.current.toString()); // Create the schedule decrease transaction const tx = api.tx.parachainStaking.scheduleDelegatorBondLess( candidateAddress, decreaseAmount ); // Sign and send the transaction await tx.signAndSend(delegator, ({ status, events }) => { if (status.isInBlock) { console.log( `\nTransaction included in block hash: ${status.asInBlock}` ); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful scheduling if ( section === 'parachainStaking' && method === 'DelegationDecreaseScheduled' ) { const [delegator, candidate, amountToDecrease, executeRound] = data; console.log('\nSuccessfully scheduled delegation decrease!'); console.log('Delegator:', delegator.toString()); console.log('Candidate:', candidate.toString()); console.log('Amount to decrease:', amountToDecrease.toString()); console.log('Execute round:', executeRound.toString()); console.log( `\nNote: You must wait until round ${executeRound.toString()} to execute the decrease request` ); } }); // Query final delegation state api.query.parachainStaking .delegatorState(delegator.address) .then((finalState) => { if (finalState.isSome) { const state = finalState.unwrap(); const updatedDelegation = state.delegations.find( (d) => d.owner.toString().toLowerCase() === candidateAddress.toLowerCase() ); if (updatedDelegation) { console.log('\nCurrent Delegation Status:'); console.log('Amount:', updatedDelegation.amount.toString()); console.log( 'Note: Amount will decrease after execution in the scheduled round' ); } } process.exit(0); }); } }); } catch (error) { console.error('Error in scheduling delegation decrease:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**scheduleLeaveCandidates**(candidateCount) - schedules a request for a candidate to remove themselves from the candidate pool. There is an [exit delay](#exit-delays) that must be waited before you can execute the request via the `executeLeaveCandidates` extrinsic" === "Parameters" - `candidateCount` - The total number of candidates currently in the candidate pool === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup collator account from private key const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const collator = keyring.addFromUri(PRIVATE_KEY); // Get current candidate pool information const candidates = await api.query.parachainStaking.candidatePool(); const candidateCount = candidates.length; // Get current candidate info const candidateInfo = await api.query.parachainStaking.candidateInfo( collator.address ); console.log('Schedule Leave Details:'); console.log('Collator address:', collator.address); console.log('Current candidate count:', candidateCount); if (candidateInfo.isSome) { const info = candidateInfo.unwrap(); console.log('\nCurrent Candidate Status:'); console.log('Bond:', info.bond.toString()); console.log('Delegation Count:', info.delegationCount.toString()); console.log('Status:', info.status.toString()); } else { console.log('\nWarning: Account is not a candidate'); process.exit(1); } // Create the schedule leave transaction const tx = api.tx.parachainStaking.scheduleLeaveCandidates(candidateCount); // Get the current round const round = await api.query.parachainStaking.round(); const currentRound = round.current.toNumber(); // Sign and send the transaction await tx.signAndSend(collator, ({ status, events }) => { if (status.isInBlock) { console.log( `\nTransaction included in block hash: ${status.asInBlock}` ); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful scheduling if ( section === 'parachainStaking' && method === 'CandidateScheduledExit' ) { const [round, candidate, scheduledExit] = data; console.log('\nSuccessfully scheduled leave candidates!'); console.log('Candidate:', candidate.toString()); console.log('Current round:', round.toString()); console.log('Scheduled exit round:', scheduledExit.toString()); console.log( `\nNote: You must wait until round ${scheduledExit.toString()} to execute the leave request` ); } }); // Query final candidate state api.query.parachainStaking .candidateInfo(collator.address) .then((finalState) => { if (finalState.isSome) { const info = finalState.unwrap(); console.log('\nUpdated Candidate Status:'); console.log('Bond:', info.bond.toString()); console.log('Delegation Count:', info.delegationCount.toString()); console.log( 'Status:', info.status.toString(), '(Leaving status shows the exit round)' ); } process.exit(0); }); } }); } catch (error) { console.error('Error in scheduling leave candidates:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**scheduleRevokeDelegation**(collator) - schedules a request to revoke a delegation given the address of a candidate. There is an [exit delay](#exit-delays) that must be waited before you can execute the request via the `executeDelegationRequest` extrinsic" === "Parameters" - `collator` - The collator's address from which you want to revoke your delegation === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup delegator account from private key const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const delegator = keyring.addFromUri(PRIVATE_KEY); // The collator's address to revoke delegation from const collatorAddress = 'INSERT_COLLATOR_ADDRESS'; // Get current delegation info const delegatorState = await api.query.parachainStaking.delegatorState( delegator.address ); console.log('Schedule Revoke Delegation Details:'); console.log('Delegator address:', delegator.address); console.log('Collator address:', collatorAddress); if (delegatorState.isSome) { const state = delegatorState.unwrap(); const currentDelegation = state.delegations.find( (d) => d.owner.toString().toLowerCase() === collatorAddress.toLowerCase() ); if (currentDelegation) { console.log( '\nCurrent Delegation Amount:', currentDelegation.amount.toString() ); } else { console.log( '\nWarning: No existing delegation found for this collator' ); process.exit(1); } } else { console.log('\nWarning: Account is not a delegator'); process.exit(1); } // Get current round const round = await api.query.parachainStaking.round(); console.log('Current round:', round.current.toString()); // Create the schedule revoke transaction const tx = api.tx.parachainStaking.scheduleRevokeDelegation(collatorAddress); // Sign and send the transaction await tx.signAndSend(delegator, ({ status, events }) => { if (status.isInBlock) { console.log( `\nTransaction included in block hash: ${status.asInBlock}` ); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful scheduling if ( section === 'parachainStaking' && method === 'DelegationRevocationScheduled' ) { const [round, delegator, candidate, executeRound] = data; console.log('\nSuccessfully scheduled delegation revocation!'); console.log('Round:', round.toString()); console.log('Delegator:', delegator.toString()); console.log('Collator:', candidate.toString()); console.log('Execute round:', executeRound.toString()); console.log( `\nNote: You must wait until round ${executeRound.toString()} to execute the revocation request` ); } }); // Query final delegation state api.query.parachainStaking .delegatorState(delegator.address) .then((finalState) => { if (finalState.isSome) { const state = finalState.unwrap(); const updatedDelegation = state.delegations.find( (d) => d.owner.toString().toLowerCase() === collatorAddress.toLowerCase() ); if (updatedDelegation) { console.log('\nCurrent Delegation Status:'); console.log('Amount:', updatedDelegation.amount.toString()); console.log( 'Note: Delegation will be fully revoked after execution in the scheduled round' ); } } process.exit(0); }); } }); } catch (error) { console.error('Error in scheduling delegation revocation:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**setAutoCompound**(candidate, value, candidateAutoCompoundingDelegationCountHint, delegationCountHint) - sets the percentage of rewards to be auto-compounded for an existing delegation given an integer (no decimals) for the `value` between 0-100" === "Parameters" - `candidate` - The collator's address you're delegating to - `value` - Auto-compound percentage (0-100) - `candidateAutoCompoundingDelegationCountHint` - Number of auto-compounding delegations for this collator - `delegationCountHint` - Total number of delegations you have across all collators === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { Keyring } from '@polkadot/keyring'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); // Initialize the keyring with ethereum type const keyring = new Keyring({ type: 'ethereum' }); try { // Setup delegator account from private key const PRIVATE_KEY = 'INSERT_PRIVATE_KEY'; const delegator = keyring.addFromUri(PRIVATE_KEY); // The candidate's address for the delegation const candidateAddress = 'INSERT_COLLATOR_ADDRESS'; // Auto-compound percentage (0-100) const autoCompoundValue = 50; // 50% of rewards will be auto-compounded // Get auto-compounding delegations count const autoCompoundDelegations = await api.query.parachainStaking.autoCompoundingDelegations( candidateAddress ); const candidateAutoCompoundingDelegationCount = autoCompoundDelegations.length; // Get delegator state for delegation count const delegatorState = await api.query.parachainStaking.delegatorState( delegator.address ); let delegationCount = 0; console.log('Set Auto-Compound Details:'); console.log('Delegator address:', delegator.address); console.log('Candidate address:', candidateAddress); console.log('Auto-compound percentage:', autoCompoundValue, '%'); if (delegatorState.isSome) { const state = delegatorState.unwrap(); delegationCount = state.delegations.length; const currentDelegation = state.delegations.find( (d) => d.owner.toString().toLowerCase() === candidateAddress.toLowerCase() ); if (currentDelegation) { console.log( '\nCurrent Delegation Amount:', currentDelegation.amount.toString() ); } else { console.log( '\nWarning: No existing delegation found for this candidate' ); process.exit(1); } } else { console.log('\nWarning: Account is not a delegator'); process.exit(1); } console.log('\nDelegation Counts:'); console.log( 'Auto-compounding delegations:', candidateAutoCompoundingDelegationCount ); console.log('Total delegations:', delegationCount); // Create the set auto-compound transaction const tx = api.tx.parachainStaking.setAutoCompound( candidateAddress, autoCompoundValue, candidateAutoCompoundingDelegationCount, delegationCount ); // Sign and send the transaction await tx.signAndSend(delegator, ({ status, events }) => { if (status.isInBlock) { console.log( `\nTransaction included in block hash: ${status.asInBlock}` ); // Process events events.forEach(({ event }) => { const { section, method, data } = event; console.log(`\t${section}.${method}:`, data.toString()); // Handle any failures if (section === 'system' && method === 'ExtrinsicFailed') { const [dispatchError] = data; let errorInfo; if (dispatchError.isModule) { const decoded = api.registry.findMetaError( dispatchError.asModule ); errorInfo = `${decoded.section}.${decoded.name}: ${decoded.docs}`; } else { errorInfo = dispatchError.toString(); } console.error('Failure reason:', errorInfo); } // Log successful auto-compound setting if (section === 'parachainStaking' && method === 'AutoCompoundSet') { const [candidate, delegator, value] = data; console.log('\nSuccessfully set auto-compound percentage!'); console.log('Candidate:', candidate.toString()); console.log('Delegator:', delegator.toString()); console.log('Auto-compound value:', value.toString(), '%'); } }); // Query updated auto-compound settings api.query.parachainStaking .autoCompoundingDelegations(candidateAddress) .then((newAutoCompound) => { const delegatorSetting = newAutoCompound.find( (d) => d.delegator.toString().toLowerCase() === delegator.address.toLowerCase() ); if (delegatorSetting) { console.log('\nUpdated Auto-Compound Setting:'); console.log('Value:', delegatorSetting.value.toString(), '%'); } process.exit(0); }); } }); } catch (error) { console.error('Error in setting auto-compound:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ### Storage Methods {: #storage-methods } The parachain staking pallet includes the following read-only storage methods to obtain chain state data: ??? function "**atStake**(u32, AccountId20) - provides a snapshot of a collator's delegation stake and the percentage of rewards set to auto-compound given a round number and, optionally, the collator's address" === "Parameters" - `u32` - round number - `AccountId20` - collator address to query. If omitted, information about all collators will be returned === "Returns" Information about a collator's delegations including delegator addresses, amounts, and auto-compound percentages === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get current round information const round = await api.query.parachainStaking.round(); const currentRound = round.current.toNumber(); // Example collator address const collatorAddress = 'INSERT_COLLATOR_ADDRESS'; console.log('Query Parameters:'); console.log('Current round:', currentRound); console.log('Collator address:', collatorAddress); // Query current round console.log('\nQuerying current round stake...'); const currentStake = await api.query.parachainStaking.atStake( currentRound, collatorAddress ); if (currentStake) { console.log('\nCurrent Round Stake Details:'); const stakeInfo = currentStake.toHuman(); console.log(JSON.stringify(stakeInfo, null, 2)); // Get raw values for calculations if needed const rawStake = currentStake.toJSON(); console.log('\nRaw Stake Values:'); console.log('Total stake:', rawStake.total); console.log('Own stake:', rawStake.bond); } // Query previous round const previousRound = currentRound - 1; console.log('\nQuerying previous round stake...'); const previousStake = await api.query.parachainStaking.atStake( previousRound, collatorAddress ); if (previousStake) { console.log('\nPrevious Round Stake Details:'); const previousStakeInfo = previousStake.toHuman(); console.log(JSON.stringify(previousStakeInfo, null, 2)); } // Get scheduled delegation requests const delegationRequests = await api.query.parachainStaking.delegationScheduledRequests( collatorAddress ); console.log('\nScheduled Delegation Changes:'); if (delegationRequests.length > 0) { console.log(JSON.stringify(delegationRequests.toHuman(), null, 2)); } else { console.log('No scheduled delegation changes'); } // Get auto-compound settings const autoCompound = await api.query.parachainStaking.autoCompoundingDelegations( collatorAddress ); console.log('\nAuto-Compound Settings:'); if (autoCompound.length > 0) { console.log(JSON.stringify(autoCompound.toHuman(), null, 2)); } else { console.log('No auto-compound settings found'); } process.exit(0); } catch (error) { console.error('Error querying at stake:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**autoCompoundingDelegations**(AccountId20) - returns a list of delegators for a given candidate that have set up auto-compounding along with the percentage of rewards set to be auto-compounded" === "Parameters" - `AccountId20` - the collator address to query. If omitted, information about all collators will be returned === "Returns" The list of delegators who have auto-compounding enabled and the respective percentage of rewards they have set to be auto-compounded === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Example candidate address const candidateAddress = 'INSERT_COLLATOR_ADDRESS'; console.log('Query Parameters:'); console.log('Candidate address:', candidateAddress); // Query auto-compounding delegations const autoCompoundDelegations = await api.query.parachainStaking.autoCompoundingDelegations( candidateAddress ); // Get candidate info const candidateInfo = await api.query.parachainStaking.candidateInfo(candidateAddress); if (candidateInfo.isSome) { const info = candidateInfo.unwrap(); console.log('\nCandidate Information:'); console.log('Total delegations:', info.delegationCount.toString()); console.log('Bond amount:', info.bond.toString()); } console.log('\nAuto-Compounding Delegations:'); if (autoCompoundDelegations.length > 0) { console.log( 'Total auto-compounding delegators:', autoCompoundDelegations.length ); // Display each auto-compounding delegation autoCompoundDelegations.forEach((delegation, index) => { const { delegator, value } = delegation; console.log(`\nDelegator #${index + 1}:`); console.log('Address:', delegator.toString()); console.log('Auto-compound percentage:', value.toString(), '%'); }); // Get more detailed information for each delegator console.log('\nDetailed Delegation Information:'); for (const delegation of autoCompoundDelegations) { const delegatorState = await api.query.parachainStaking.delegatorState( delegation.delegator ); if (delegatorState.isSome) { const state = delegatorState.unwrap(); const specificDelegation = state.delegations.find( (d) => d.owner.toString().toLowerCase() === candidateAddress.toLowerCase() ); if (specificDelegation) { console.log(`\nDelegator ${delegation.delegator.toString()}:`); console.log( 'Delegation amount:', specificDelegation.amount.toString() ); console.log( 'Auto-compound value:', delegation.value.toString(), '%' ); } } } // Calculate some statistics const averageCompounding = autoCompoundDelegations.reduce( (acc, curr) => acc + curr.value.toNumber(), 0 ) / autoCompoundDelegations.length; console.log('\nStatistics:'); console.log( 'Average auto-compound percentage:', averageCompounding.toFixed(2), '%' ); const maxCompounding = Math.max( ...autoCompoundDelegations.map((d) => d.value.toNumber()) ); const minCompounding = Math.min( ...autoCompoundDelegations.map((d) => d.value.toNumber()) ); console.log('Highest auto-compound setting:', maxCompounding, '%'); console.log('Lowest auto-compound setting:', minCompounding, '%'); } else { console.log('No auto-compounding delegations found for this candidate'); } process.exit(0); } catch (error) { console.error('Error querying auto-compounding delegations:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**awardedPts**(u32, AccountId20) - returns the awarded points for each collator per round given a round number and, optionally, the collator's address" === "Parameters" - `u32` - the round number - `AccountId20` - the collator to query. If omitted, information about all collators will be returned === "Returns" The number of awarded points for a given round and collator. === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get current round information const round = await api.query.parachainStaking.round(); const currentRound = round.current.toNumber(); // Example collator address - you can set this to null to query all collators const collatorAddress = 'INSERT_COLLATOR_ADDRESS'; // Query several recent rounds const roundsToQuery = 5; const rounds = Array.from( { length: roundsToQuery }, (_, i) => currentRound - i ); console.log('Query Parameters:'); console.log('Current round:', currentRound); console.log('Collator address:', collatorAddress || 'All collators'); console.log(`Querying last ${roundsToQuery} rounds:`, rounds); // Store points data for analysis const pointsData = {}; // Query points for each round for (const roundNumber of rounds) { let roundPoints; if (collatorAddress) { // Query specific collator roundPoints = await api.query.parachainStaking.awardedPts( roundNumber, collatorAddress ); console.log( `\nRound ${roundNumber} Points for ${collatorAddress}:`, roundPoints.toString() ); pointsData[roundNumber] = { [collatorAddress]: roundPoints.toNumber(), }; } else { // Query all collators for this round roundPoints = await api.query.parachainStaking.awardedPts.entries(roundNumber); console.log(`\nRound ${roundNumber} Points:`); pointsData[roundNumber] = {}; for (const [key, points] of roundPoints) { const collator = key.args[1].toString(); const pointsValue = points.toNumber(); console.log(`Collator ${collator}: ${pointsValue} points`); pointsData[roundNumber][collator] = pointsValue; } } } // Calculate statistics console.log('\nStatistics:'); if (collatorAddress) { // Statistics for specific collator const collatorPoints = rounds.map( (r) => pointsData[r][collatorAddress] || 0 ); const totalPoints = collatorPoints.reduce((a, b) => a + b, 0); const averagePoints = totalPoints / rounds.length; const maxPoints = Math.max(...collatorPoints); const minPoints = Math.min(...collatorPoints); console.log(`\nCollator ${collatorAddress}:`); console.log('Total points:', totalPoints); console.log('Average points per round:', averagePoints.toFixed(2)); console.log('Highest points:', maxPoints); console.log('Lowest points:', minPoints); } else { // Statistics for all collators const collators = new Set( rounds.flatMap((r) => Object.keys(pointsData[r])) ); for (const collator of collators) { const collatorPoints = rounds.map((r) => pointsData[r][collator] || 0); const totalPoints = collatorPoints.reduce((a, b) => a + b, 0); const averagePoints = totalPoints / rounds.length; const maxPoints = Math.max(...collatorPoints); const minPoints = Math.min(...collatorPoints); console.log(`\nCollator ${collator}:`); console.log('Total points:', totalPoints); console.log('Average points per round:', averagePoints.toFixed(2)); console.log('Highest points:', maxPoints); console.log('Lowest points:', minPoints); console.log('Points history:', collatorPoints.join(', ')); } } // Get current selected candidates for context const selectedCandidates = await api.query.parachainStaking.selectedCandidates(); console.log('\nCurrently Selected Candidates:', selectedCandidates.length); console.log(selectedCandidates.map((c) => c.toString()).join('\n')); process.exit(0); } catch (error) { console.error('Error querying awarded points:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**bottomDelegations**(AccountId20) - returns at the most the bottom 50 delegations for all candidates or for a given candidate's address" === "Parameters" - `AccountId20` - the collator to query. If omitted, information about all collators will be returned === "Returns" The bottom 50 delegations for a given collator address === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Example candidate address const candidateAddress = 'INSERT_COLLATOR_ADDRESS'; // Get candidate info first const candidateInfo = await api.query.parachainStaking.candidateInfo(candidateAddress); console.log('Query Parameters:'); console.log('Candidate address:', candidateAddress); if (candidateInfo.isSome) { const info = candidateInfo.unwrap(); console.log('\nCandidate Information:'); console.log('Total delegations:', info.delegationCount.toString()); console.log('Bond amount:', info.bond.toString(), 'Wei'); } // Query bottom delegations const bottomDelegations = await api.query.parachainStaking.bottomDelegations(candidateAddress); if (bottomDelegations.isSome) { const delegations = bottomDelegations.unwrap(); console.log('\nBottom Delegations:'); console.log( 'Total bottom delegations found:', delegations.delegations.length ); // Sort delegations by amount in descending order const sortedDelegations = [...delegations.delegations].sort( (a, b) => BigInt(b.amount) - BigInt(a.amount) ); // Display each delegation sortedDelegations.forEach((delegation, index) => { console.log(`\nDelegation #${index + 1}:`); console.log('Delegator:', delegation.owner.toString()); console.log('Amount:', delegation.amount.toString(), 'Wei'); // Convert Wei to DEV (1 DEV = 10^18 Wei) const devAmount = BigInt(delegation.amount) / BigInt(10 ** 18); console.log('Amount in DEV:', devAmount.toString(), 'DEV'); }); // Calculate some statistics if (sortedDelegations.length > 0) { const total = sortedDelegations.reduce( (acc, curr) => acc + BigInt(curr.amount), BigInt(0) ); const average = total / BigInt(sortedDelegations.length); const highest = sortedDelegations[0].amount; const lowest = sortedDelegations[sortedDelegations.length - 1].amount; console.log('\nStatistics:'); console.log('Total delegated in bottom:', total.toString(), 'Wei'); console.log('Average delegation:', average.toString(), 'Wei'); console.log('Highest bottom delegation:', highest.toString(), 'Wei'); console.log('Lowest bottom delegation:', lowest.toString(), 'Wei'); // Show in DEV for readability console.log('\nStatistics (in DEV):'); console.log( 'Total delegated:', (BigInt(total) / BigInt(10 ** 18)).toString(), 'DEV' ); console.log( 'Average delegation:', (BigInt(average) / BigInt(10 ** 18)).toString(), 'DEV' ); console.log( 'Highest bottom delegation:', (BigInt(highest) / BigInt(10 ** 18)).toString(), 'DEV' ); console.log( 'Lowest bottom delegation:', (BigInt(lowest) / BigInt(10 ** 18)).toString(), 'DEV' ); } // Get top delegations for comparison const topDelegations = await api.query.parachainStaking.topDelegations(candidateAddress); if (topDelegations.isSome) { const top = topDelegations.unwrap(); console.log('\nComparison with Top Delegations:'); console.log('Number of top delegations:', top.delegations.length); console.log('Number of bottom delegations:', sortedDelegations.length); if (top.delegations.length > 0) { const lowestTop = top.delegations[top.delegations.length - 1].amount; console.log('Lowest top delegation:', lowestTop.toString(), 'Wei'); console.log( 'Lowest top delegation in DEV:', (BigInt(lowestTop) / BigInt(10 ** 18)).toString(), 'DEV' ); } } } else { console.log('\nNo bottom delegations found for this candidate'); } process.exit(0); } catch (error) { console.error('Error querying bottom delegations:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**candidateInfo**(AccountId20) - returns candidate information such as the candidate's bond, delegation count, and more for all candidates or for a given candidate's address" === "Parameters" - `AccountId20` - The collator address to query. If omitted, information about all collators will be returned === "Returns" Information about the relevant collator including collator bond, total backing stake, delegation count, lowest included delegation amount, collator status, and capacity information === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Example candidate address const candidateAddress = 'INSERT_COLLATOR_ADDRESS'; console.log('Query Parameters:'); console.log('Candidate address:', candidateAddress); // Query candidate info const candidateInfo = await api.query.parachainStaking.candidateInfo(candidateAddress); if (candidateInfo.isSome) { const info = candidateInfo.unwrap(); console.log('\nCandidate Information:'); console.log('Bond:', info.bond.toString(), 'Wei'); console.log( 'Bond in DEV:', (BigInt(info.bond) / BigInt(10 ** 18)).toString(), 'DEV' ); console.log('Delegation Count:', info.delegationCount.toString()); console.log('Status:', info.status.toString()); console.log( 'Lowest Top Delegation Amount:', info.lowestTopDelegationAmount.toString(), 'Wei' ); console.log( 'Lowest Top Delegation in DEV:', (BigInt(info.lowestTopDelegationAmount) / BigInt(10 ** 18)).toString(), 'DEV' ); console.log( 'Highest Bottom Delegation Amount:', info.highestBottomDelegationAmount.toString(), 'Wei' ); console.log( 'Highest Bottom Delegation in DEV:', ( BigInt(info.highestBottomDelegationAmount) / BigInt(10 ** 18) ).toString(), 'DEV' ); console.log( 'Lowest Bottom Delegation Amount:', info.lowestBottomDelegationAmount.toString(), 'Wei' ); console.log( 'Lowest Bottom Delegation in DEV:', ( BigInt(info.lowestBottomDelegationAmount) / BigInt(10 ** 18) ).toString(), 'DEV' ); console.log('Top Capacity:', info.topCapacity.toString()); console.log('Bottom Capacity:', info.bottomCapacity.toString()); // Get additional context const round = await api.query.parachainStaking.round(); console.log('\nCurrent Round:', round.current.toString()); // Check if in selected candidates const selectedCandidates = await api.query.parachainStaking.selectedCandidates(); const isSelected = selectedCandidates.some( (c) => c.toString() === candidateAddress ); console.log('Is Selected Candidate:', isSelected); // Get top delegations const topDelegations = await api.query.parachainStaking.topDelegations(candidateAddress); if (topDelegations.isSome) { const top = topDelegations.unwrap(); console.log('\nTop Delegations Count:', top.delegations.length); console.log('Total Top Delegated:', top.total.toString(), 'Wei'); console.log( 'Total Top Delegated in DEV:', (BigInt(top.total) / BigInt(10 ** 18)).toString(), 'DEV' ); } // Get bottom delegations const bottomDelegations = await api.query.parachainStaking.bottomDelegations(candidateAddress); if (bottomDelegations.isSome) { const bottom = bottomDelegations.unwrap(); console.log('\nBottom Delegations Count:', bottom.delegations.length); console.log('Total Bottom Delegated:', bottom.total.toString(), 'Wei'); console.log( 'Total Bottom Delegated in DEV:', (BigInt(bottom.total) / BigInt(10 ** 18)).toString(), 'DEV' ); } // Get auto-compounding delegations const autoCompounding = await api.query.parachainStaking.autoCompoundingDelegations( candidateAddress ); console.log( '\nAuto-compounding Delegations Count:', autoCompounding.length ); // Calculate some total statistics const totalStake = BigInt(info.bond) + (topDelegations.isSome ? BigInt(topDelegations.unwrap().total) : BigInt(0)) + (bottomDelegations.isSome ? BigInt(bottomDelegations.unwrap().total) : BigInt(0)); console.log('\nTotal Statistics:'); console.log('Total Stake:', totalStake.toString(), 'Wei'); console.log( 'Total Stake in DEV:', (totalStake / BigInt(10 ** 18)).toString(), 'DEV' ); // Check recent points (last 3 rounds) console.log('\nRecent Points:'); const currentRound = round.current.toNumber(); for (let i = 0; i < 3; i++) { const roundNumber = currentRound - i; const points = await api.query.parachainStaking.awardedPts( roundNumber, candidateAddress ); console.log(`Round ${roundNumber}: ${points.toString()} points`); } } else { console.log('\nNo candidate information found for this address'); } process.exit(0); } catch (error) { console.error('Error querying candidate info:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**candidatePool**() - returns a list of each of the candidates in the pool and their total backing stake" === "Parameters" None === "Returns" A list of each of the candidates in the pool and their total backing stake === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get current round information const round = await api.query.parachainStaking.round(); console.log('Current Round:', round.current.toString()); // Query candidate pool const candidatePool = await api.query.parachainStaking.candidatePool(); console.log('\nCandidate Pool Information:'); console.log('Total Candidates:', candidatePool.length); // Sort candidates by amount, handling BigInt comparison correctly const sortedCandidates = [...candidatePool].sort((a, b) => { const amountA = BigInt(a.amount); const amountB = BigInt(b.amount); if (amountA < amountB) return 1; if (amountA > amountB) return -1; return 0; }); // Get selected candidates for comparison const selectedCandidates = await api.query.parachainStaking.selectedCandidates(); const selectedSet = new Set(selectedCandidates.map((c) => c.toString())); // Track total stake in pool let totalStake = BigInt(0); // Display each candidate's information console.log('\nDetailed Candidate Information:'); for (const [index, candidate] of sortedCandidates.entries()) { const { owner, amount } = candidate; totalStake += BigInt(amount); // Get candidate info const candidateInfo = await api.query.parachainStaking.candidateInfo(owner); console.log(`\nCandidate #${index + 1}:`); console.log('Address:', owner.toString()); console.log('Total Stake:', amount.toString(), 'Wei'); console.log( 'Total Stake in DEV:', (BigInt(amount) / BigInt(10 ** 18)).toString(), 'DEV' ); console.log('Is Selected Collator:', selectedSet.has(owner.toString())); if (candidateInfo.isSome) { const info = candidateInfo.unwrap(); console.log('Self Bond:', info.bond.toString(), 'Wei'); console.log( 'Self Bond in DEV:', (BigInt(info.bond) / BigInt(10 ** 18)).toString(), 'DEV' ); console.log('Delegation Count:', info.delegationCount.toString()); console.log('Status:', info.status.toString()); } // Get auto-compounding delegations count const autoCompounding = await api.query.parachainStaking.autoCompoundingDelegations(owner); console.log('Auto-compounding Delegations:', autoCompounding.length); // Get recent points (last 3 rounds) const currentRound = round.current.toNumber(); let totalPoints = 0; console.log('Recent Points:'); for (let i = 0; i < 3; i++) { const roundNumber = currentRound - i; const points = await api.query.parachainStaking.awardedPts( roundNumber, owner ); console.log(` Round ${roundNumber}: ${points.toString()} points`); totalPoints += points.toNumber(); } console.log( 'Average Points (last 3 rounds):', (totalPoints / 3).toFixed(2) ); } // Display pool statistics console.log('\nPool Statistics:'); console.log('Total Candidates:', candidatePool.length); console.log('Selected Collators:', selectedCandidates.length); console.log('Total Stake in Pool:', totalStake.toString(), 'Wei'); console.log( 'Total Stake in Pool (DEV):', (totalStake / BigInt(10 ** 18)).toString(), 'DEV' ); console.log( 'Average Stake per Candidate (DEV):', (totalStake / BigInt(candidatePool.length) / BigInt(10 ** 18)).toString(), 'DEV' ); // Calculate stake distribution const stakes = sortedCandidates.map((c) => BigInt(c.amount)); const median = stakes[Math.floor(stakes.length / 2)]; const highest = stakes[0]; const lowest = stakes[stakes.length - 1]; console.log('\nStake Distribution:'); console.log( 'Highest Stake (DEV):', (highest / BigInt(10 ** 18)).toString() ); console.log('Median Stake (DEV):', (median / BigInt(10 ** 18)).toString()); console.log('Lowest Stake (DEV):', (lowest / BigInt(10 ** 18)).toString()); process.exit(0); } catch (error) { console.error('Error querying candidate pool:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**candidateState**(AccountId20) - *deprecated as of runtime 1200* - use `candidateInfo` instead" === "Parameters" - `AccountId20` - the collator account to query === "Returns" *Deprecated as of runtime 1200* - use `candidateInfo` instead === "Polkadot.js API Example" *Deprecated as of runtime 1200* - use `candidateInfo` instead ??? function "**collatorCommission**() - returns the commission percent taken off of rewards for all collators" === "Parameters" None === "Returns" The percent collator commission, e.g. `20.00%` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Query collator commission const commission = await api.query.parachainStaking.collatorCommission(); // Get the current round for context const round = await api.query.parachainStaking.round(); // Get selected candidates count for context const selectedCandidates = await api.query.parachainStaking.selectedCandidates(); console.log('\nCollator Commission Information:'); console.log('Current Round:', round.current.toString()); console.log('Commission Rate:', commission.toString(), 'Per Billion'); // Convert to percentage (commission is stored as parts per billion) const commissionPercent = (Number(commission) / 10_000_000).toFixed(2); console.log('Commission Percentage:', commissionPercent + '%'); console.log('\nNetwork Context:'); console.log('Active Collators:', selectedCandidates.length); // Example calculation for a reward const exampleReward = BigInt(1000000000000000000); // 1 DEV const commissionAmount = (exampleReward * BigInt(commission)) / BigInt(1000000000); console.log('\nExample Reward Calculation:'); console.log('For a reward of 1 DEV:'); console.log( 'Commission Amount:', (commissionAmount / BigInt(10 ** 18)).toString(), 'DEV' ); console.log( 'Remaining Reward:', ((exampleReward - commissionAmount) / BigInt(10 ** 18)).toString(), 'DEV' ); process.exit(0); } catch (error) { console.error('Error querying collator commission:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**collatorState2**(AccountId20) - *deprecated as of runtime 1001* - use `candidateInfo` instead" === "Parameters" - `AccountId20` - the collator to query === "Returns" Deprecated as of runtime 1001* - use `candidateInfo` instead === "Polkadot.js API Example" Deprecated as of runtime 1001* - use `candidateInfo` instead ??? function "**delayedPayouts**(u32) - returns the delayed payouts for all rounds or for a given round" === "Parameters" - `u32` - the round to query. If omitted, the latest round information will be returned === "Returns" The round issuance, the total staking reward, and collator commission. === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get current round information const round = await api.query.parachainStaking.round(); const currentRound = round.current.toNumber(); console.log('Current Round:', currentRound); // Query several recent rounds for delayed payouts const roundsToCheck = 5; const rounds = Array.from( { length: roundsToCheck }, (_, i) => currentRound - i ); console.log( '\nChecking Delayed Payouts for the Last', roundsToCheck, 'Rounds:' ); // Track statistics let totalPayouts = 0; let totalRewards = BigInt(0); for (const roundNumber of rounds) { console.log(`\nRound ${roundNumber}:`); const delayedPayout = await api.query.parachainStaking.delayedPayouts(roundNumber); if (delayedPayout.isSome) { const payout = delayedPayout.unwrap(); // Debug log to see the structure console.log( 'Raw payout data:', JSON.stringify(payout.toJSON(), null, 2) ); // Safely access the data const payoutData = payout.toJSON(); console.log('Found Delayed Payout:'); if (payoutData) { totalPayouts++; // Calculate total rewards if data is available if (payoutData.colReward && payoutData.delReward) { const roundReward = BigInt(payoutData.colReward) + BigInt(payoutData.delReward); totalRewards += roundReward; console.log('Collator:', payoutData.toCollator); console.log('Collator Reward:', payoutData.colReward, 'Wei'); console.log( 'Collator Reward in DEV:', (BigInt(payoutData.colReward) / BigInt(10 ** 18)).toString(), 'DEV' ); console.log('Total Delegator Reward:', payoutData.delReward, 'Wei'); console.log( 'Total Delegator Reward in DEV:', (BigInt(payoutData.delReward) / BigInt(10 ** 18)).toString(), 'DEV' ); console.log('Total Round Reward:', roundReward.toString(), 'Wei'); console.log( 'Total Round Reward in DEV:', (roundReward / BigInt(10 ** 18)).toString(), 'DEV' ); // Get collator information if available if (payoutData.toCollator) { const collatorInfo = await api.query.parachainStaking.candidateInfo( payoutData.toCollator ); if (collatorInfo.isSome) { const info = collatorInfo.unwrap(); console.log('\nCollator Information:'); console.log( 'Delegation Count:', info.delegationCount.toString() ); console.log('Self Bond:', info.bond.toString(), 'Wei'); console.log( 'Self Bond in DEV:', (BigInt(info.bond) / BigInt(10 ** 18)).toString(), 'DEV' ); } // Get awarded points for context const points = await api.query.parachainStaking.awardedPts( roundNumber, payoutData.toCollator ); console.log('Points earned in round:', points.toString()); } } } } else { console.log('No delayed payout found'); } } // Display statistics console.log('\nPayout Statistics:'); console.log('Total Rounds with Payouts:', totalPayouts); console.log( 'Average Payouts per Round:', (totalPayouts / roundsToCheck).toFixed(2) ); if (totalPayouts > 0) { console.log( 'Average Reward per Payout:', (totalRewards / BigInt(totalPayouts) / BigInt(10 ** 18)).toString(), 'DEV' ); console.log( 'Total Rewards:', (totalRewards / BigInt(10 ** 18)).toString(), 'DEV' ); } process.exit(0); } catch (error) { console.error('Error querying delayed payouts:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**delegationScheduledRequests**(AccountId20) - returns the outstanding scheduled delegation requests for all collators or for a given collator's address" === "Parameters" - `AccountId20` - the address of the collator. If omitted, information about all collators will be returned === "Returns" The set of pending scheduled delegation requests including the delegator's address, the action requested, and eligible block at which the action can be executed. === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Example collator address const collatorAddress = 'INSERT_COLLATOR_ADDRESS'; // Get current round information for context const round = await api.query.parachainStaking.round(); const currentRound = round.current.toNumber(); console.log('Query Parameters:'); console.log('Collator address:', collatorAddress); console.log('Current round:', currentRound); // Get collator info for context const collatorInfo = await api.query.parachainStaking.candidateInfo(collatorAddress); if (collatorInfo.isSome) { const info = collatorInfo.unwrap(); console.log('\nCollator Information:'); console.log('Delegation Count:', info.delegationCount.toString()); console.log('Current Bond:', info.bond.toString(), 'Wei'); console.log( 'Current Bond in DEV:', (BigInt(info.bond) / BigInt(10 ** 18)).toString(), 'DEV' ); } // Query scheduled delegation requests const requests = await api.query.parachainStaking.delegationScheduledRequests( collatorAddress ); console.log('\nScheduled Delegation Requests:'); if (requests.length > 0) { console.log('Total requests:', requests.length); // Process each request requests.forEach((request, index) => { console.log(`\nRequest #${index + 1}:`); const { delegator, whenExecutable, action } = request; console.log('Delegator:', delegator.toString()); console.log('Executable at round:', whenExecutable.toString()); console.log( 'Rounds until executable:', whenExecutable.toNumber() - currentRound ); // Handle different types of actions if (action.isDecrease) { const amount = action.asDecrease; console.log('Action: Decrease'); console.log('Amount:', amount.toString(), 'Wei'); console.log( 'Amount in DEV:', (BigInt(amount) / BigInt(10 ** 18)).toString(), 'DEV' ); } else if (action.isRevoke) { const amount = action.asRevoke; console.log('Action: Revoke'); console.log('Amount:', amount.toString(), 'Wei'); console.log( 'Amount in DEV:', (BigInt(amount) / BigInt(10 ** 18)).toString(), 'DEV' ); } }); // Calculate some statistics let totalDecreaseAmount = BigInt(0); let totalRevokeAmount = BigInt(0); let decreaseCount = 0; let revokeCount = 0; requests.forEach((request) => { if (request.action.isDecrease) { totalDecreaseAmount += BigInt(request.action.asDecrease); decreaseCount++; } else if (request.action.isRevoke) { totalRevokeAmount += BigInt(request.action.asRevoke); revokeCount++; } }); console.log('\nRequest Statistics:'); console.log('Decrease requests:', decreaseCount); if (decreaseCount > 0) { console.log( 'Total decrease amount:', totalDecreaseAmount.toString(), 'Wei' ); console.log( 'Total decrease amount in DEV:', (totalDecreaseAmount / BigInt(10 ** 18)).toString(), 'DEV' ); console.log( 'Average decrease amount in DEV:', ( totalDecreaseAmount / BigInt(decreaseCount) / BigInt(10 ** 18) ).toString(), 'DEV' ); } console.log('Revoke requests:', revokeCount); if (revokeCount > 0) { console.log( 'Total revoke amount:', totalRevokeAmount.toString(), 'Wei' ); console.log( 'Total revoke amount in DEV:', (totalRevokeAmount / BigInt(10 ** 18)).toString(), 'DEV' ); console.log( 'Average revoke amount in DEV:', ( totalRevokeAmount / BigInt(revokeCount) / BigInt(10 ** 18) ).toString(), 'DEV' ); } // Show impact on collator's delegation const totalImpact = totalDecreaseAmount + totalRevokeAmount; console.log('\nTotal Impact:'); console.log('Total amount to be removed:', totalImpact.toString(), 'Wei'); console.log( 'Total amount to be removed in DEV:', (totalImpact / BigInt(10 ** 18)).toString(), 'DEV' ); } else { console.log('No scheduled delegation requests found'); } process.exit(0); } catch (error) { console.error('Error querying delegation requests:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**delegatorState**(AccountId20) - returns delegator information such as their delegations, delegation status, and total delegation amount for all delegators or for a given delegator's address" === "Parameters" - `AccountId20` - the address of the delegator to query === "Returns" Delegator state information including the collators delegated and their respective amounts === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Example delegator address const delegatorAddress = 'INSERT_DELEGATOR_ADDRESS'; // Get current round information for context const round = await api.query.parachainStaking.round(); const currentRound = round.current.toNumber(); console.log('Query Parameters:'); console.log('Delegator address:', delegatorAddress); console.log('Current round:', currentRound); // Query delegator state const delegatorState = await api.query.parachainStaking.delegatorState(delegatorAddress); if (delegatorState.isSome) { const state = delegatorState.unwrap(); const delegations = state.delegations; console.log('\nDelegator Information:'); console.log('Total Delegations:', delegations.length); // Calculate total delegated amount let totalDelegated = BigInt(0); delegations.forEach((d) => { totalDelegated += BigInt(d.amount); }); console.log('Total Amount Delegated:', totalDelegated.toString(), 'Wei'); console.log( 'Total Amount Delegated in DEV:', (totalDelegated / BigInt(10 ** 18)).toString(), 'DEV' ); // Show detailed delegation information console.log('\nDetailed Delegations:'); for (const [index, delegation] of delegations.entries()) { console.log(`\nDelegation #${index + 1}:`); console.log('Collator:', delegation.owner.toString()); console.log('Amount:', delegation.amount.toString(), 'Wei'); console.log( 'Amount in DEV:', (BigInt(delegation.amount) / BigInt(10 ** 18)).toString(), 'DEV' ); // Get collator information const collatorInfo = await api.query.parachainStaking.candidateInfo( delegation.owner ); if (collatorInfo.isSome) { const info = collatorInfo.unwrap(); console.log('Collator Status:', info.status.toString()); console.log('Collator Total Bond:', info.bond.toString(), 'Wei'); console.log( 'Collator Delegation Count:', info.delegationCount.toString() ); } // Check auto-compound setting const autoCompoundDelegations = await api.query.parachainStaking.autoCompoundingDelegations( delegation.owner ); const autoCompound = autoCompoundDelegations.find( (d) => d.delegator.toString().toLowerCase() === delegatorAddress.toLowerCase() ); if (autoCompound) { console.log( 'Auto-compound Percentage:', autoCompound.value.toString(), '%' ); } else { console.log('Auto-compound: Not set'); } // Check for scheduled requests const requests = await api.query.parachainStaking.delegationScheduledRequests( delegation.owner ); const delegatorRequests = requests.filter( (r) => r.delegator.toString().toLowerCase() === delegatorAddress.toLowerCase() ); if (delegatorRequests.length > 0) { console.log('\nPending Requests:'); delegatorRequests.forEach((request) => { console.log( 'Executable at round:', request.whenExecutable.toString() ); if (request.action.isDecrease) { console.log('Action: Decrease'); console.log( 'Amount:', request.action.asDecrease.toString(), 'Wei' ); console.log( 'Amount in DEV:', ( BigInt(request.action.asDecrease) / BigInt(10 ** 18) ).toString(), 'DEV' ); } else if (request.action.isRevoke) { console.log('Action: Revoke'); console.log('Amount:', request.action.asRevoke.toString(), 'Wei'); console.log( 'Amount in DEV:', (BigInt(request.action.asRevoke) / BigInt(10 ** 18)).toString(), 'DEV' ); } }); } } // Calculate statistics const amounts = delegations.map((d) => BigInt(d.amount)); const averageDelegation = totalDelegated / BigInt(delegations.length); const maxDelegation = amounts.reduce( (a, b) => (a > b ? a : b), BigInt(0) ); const minDelegation = amounts.reduce( (a, b) => (a < b ? a : b), amounts[0] || BigInt(0) ); console.log('\nDelegation Statistics:'); console.log( 'Average Delegation:', (averageDelegation / BigInt(10 ** 18)).toString(), 'DEV' ); console.log( 'Largest Delegation:', (maxDelegation / BigInt(10 ** 18)).toString(), 'DEV' ); console.log( 'Smallest Delegation:', (minDelegation / BigInt(10 ** 18)).toString(), 'DEV' ); // Get network context const selectedCandidates = await api.query.parachainStaking.selectedCandidates(); console.log('\nNetwork Context:'); console.log('Total Selected Collators:', selectedCandidates.length); console.log( 'Delegating to Selected Collators:', delegations.filter((d) => selectedCandidates.some((c) => c.toString() === d.owner.toString()) ).length ); } else { console.log('\nNo delegator state found for this address'); } process.exit(0); } catch (error) { console.error('Error querying delegator state:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**enabledMarkingOffline**() - returns a boolean indicating whether or not the marking offline feature for inactive collators is enabled" === "Parameters" None === "Returns" `boolean` - Indicating whether or not the marking offline feature for inactive collators is enabled === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get marking offline status with the correct method name const isEnabled = await api.query.parachainStaking.enableMarkingOffline(); console.log('Marking Offline Feature Status:', isEnabled.toHuman()); process.exit(0); } catch (error) { console.error('Error querying marking offline status:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**inflationConfig**() - returns the inflation configuration" === "Parameters" None === "Returns" A JSON object that contains the minimum, ideal, and maximum inflation parameters in each of the following thresholds: expected, annual, and round. === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Query inflation configuration const inflationConfig = await api.query.parachainStaking.inflationConfig(); // Get current round info for context const round = await api.query.parachainStaking.round(); console.log('Current Round:', round.current.toString()); console.log('\nInflation Configuration (Human Readable):'); const config = inflationConfig.toHuman(); console.log(JSON.stringify(config, null, 2)); // Access the nested structure correctly const rawConfig = inflationConfig.toJSON(); console.log('\nDetailed Configuration Breakdown:'); // Expected rewards console.log('\nExpected Rewards:'); console.log('Min:', rawConfig.expect.min); console.log('Ideal:', rawConfig.expect.ideal); console.log('Max:', rawConfig.expect.max); // Annual inflation rates (divide by 10^7 to get percentage) console.log('\nAnnual Inflation Rates:'); console.log('Min:', (rawConfig.annual.min / 10_000_000).toFixed(2) + '%'); console.log( 'Ideal:', (rawConfig.annual.ideal / 10_000_000).toFixed(2) + '%' ); console.log('Max:', (rawConfig.annual.max / 10_000_000).toFixed(2) + '%'); // Round inflation rates console.log('\nRound Inflation Rates:'); console.log('Min:', (rawConfig.round.min / 10_000_000).toFixed(4) + '%'); console.log( 'Ideal:', (rawConfig.round.ideal / 10_000_000).toFixed(4) + '%' ); console.log('Max:', (rawConfig.round.max / 10_000_000).toFixed(4) + '%'); // Example calculations for 100 DEV with annual rates const exampleStake = 100n * BigInt(10 ** 18); // 100 DEV console.log('\nExample Annual Returns for 100 DEV stake:'); // Convert to BigInt for calculations const annualMin = (BigInt(rawConfig.annual.min) * exampleStake) / BigInt(10_000_000) / BigInt(10 ** 18); const annualIdeal = (BigInt(rawConfig.annual.ideal) * exampleStake) / BigInt(10_000_000) / BigInt(10 ** 18); const annualMax = (BigInt(rawConfig.annual.max) * exampleStake) / BigInt(10_000_000) / BigInt(10 ** 18); console.log('Min:', annualMin.toString(), 'DEV'); console.log('Ideal:', annualIdeal.toString(), 'DEV'); console.log('Max:', annualMax.toString(), 'DEV'); process.exit(0); } catch (error) { console.error('Error querying inflation configuration:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**nominatorState2**(AccountId20) - *deprecated as of runtime 1001* - use `delegatorState` instead" === "Parameters" - `AccountId20` - The account to query === "Returns" Deprecated as of runtime 1001* - use `delegatorState` instead === "Polkadot.js API Example" Deprecated as of runtime 1001* - use `delegatorState` instead ??? function "**palletVersion**() - returns the current pallet version" === "Parameters" None === "Returns" `u16` - current pallet version === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Query pallet version const version = await api.query.parachainStaking.palletVersion(); console.log('Parachain Staking Pallet Version:', version.toString()); process.exit(0); } catch (error) { console.error('Error querying pallet version:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**points**(u32) - returns the total points awarded to collators for block production in all rounds or for a given round" === "Parameters" - `u32` - a round number. If omitted, the data for the last three rounds will be returned === "Returns" - `u32` - total points awarded to collators in the given round === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get current round information const round = await api.query.parachainStaking.round(); const currentRound = round.current.toNumber(); // Query points for several recent rounds const roundsToCheck = 5; const rounds = Array.from( { length: roundsToCheck }, (_, i) => currentRound - i ); console.log('Current Round:', currentRound); // Get selected candidates for context const selectedCandidates = await api.query.parachainStaking.selectedCandidates(); console.log('Number of Selected Collators:', selectedCandidates.length); // Check each round for (const roundNumber of rounds) { console.log(`\nPoints for Round ${roundNumber}:`); const roundPoints = await api.query.parachainStaking.points(roundNumber); if (roundPoints.toNumber() === 0) { console.log('No points recorded for this round'); } else { console.log('Total Points:', roundPoints.toString()); // Get individual collator points for this round let collatorPoints = []; for (const collator of selectedCandidates) { const points = await api.query.parachainStaking.awardedPts( roundNumber, collator ); if (points.toNumber() > 0) { collatorPoints.push({ collator: collator.toString(), points: points.toNumber(), }); } } // Sort collators by points collatorPoints.sort((a, b) => b.points - a.points); // Display collator points if (collatorPoints.length > 0) { console.log('\nCollator Performance:'); collatorPoints.forEach(({ collator, points }) => { console.log(`Collator ${collator}: ${points} points`); }); // Calculate statistics const totalPoints = collatorPoints.reduce( (sum, { points }) => sum + points, 0 ); const averagePoints = totalPoints / collatorPoints.length; const maxPoints = collatorPoints[0].points; const minPoints = collatorPoints[collatorPoints.length - 1].points; console.log('\nRound Statistics:'); console.log('Active Collators:', collatorPoints.length); console.log('Average Points:', averagePoints.toFixed(2)); console.log('Highest Points:', maxPoints); console.log('Lowest Points:', minPoints); } } } process.exit(0); } catch (error) { console.error('Error querying points:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**round**() - returns the current round number, the first block of the current round, and the length of the round" === "Parameters" None === "Returns" Returns the current round number, the first block of the current round, and the length of the round === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Query round information const roundInfo = await api.query.parachainStaking.round(); console.log('Round Information:'); console.log('Current Round:', roundInfo.current.toString()); console.log('First Block of Round:', roundInfo.first.toString()); console.log('Round Length:', roundInfo.length.toString()); // Calculate some additional useful information const currentBlock = await api.rpc.chain.getBlock(); const currentBlockNumber = currentBlock.block.header.number.toNumber(); // Calculate blocks remaining in current round const blocksIntoRound = currentBlockNumber - roundInfo.first.toNumber(); const blocksRemaining = roundInfo.length.toNumber() - blocksIntoRound; console.log('\nAdditional Information:'); console.log('Current Block:', currentBlockNumber); console.log('Blocks Into Current Round:', blocksIntoRound); console.log('Blocks Remaining in Round:', blocksRemaining); process.exit(0); } catch (error) { console.error('Error querying round information:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**selectedCandidates**() - returns the collator candidates selected to be in the active set for the current round" === "Parameters" None === "Returns" A set of `AccountId20`s - collator candidates selected to be in the active set for the current round === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get current round for context const round = await api.query.parachainStaking.round(); console.log('Current Round:', round.current.toString()); // Query selected candidates const selectedCandidates = await api.query.parachainStaking.selectedCandidates(); console.log('\nSelected Candidates:'); console.log('Total Selected:', selectedCandidates.length); // Get detailed information for each candidate console.log('\nDetailed Candidate Information:'); for (const [index, candidate] of selectedCandidates.entries()) { const candidateInfo = await api.query.parachainStaking.candidateInfo(candidate); if (candidateInfo.isSome) { const info = candidateInfo.unwrap(); console.log(`\nCandidate #${index + 1}:`); console.log('Address:', candidate.toString()); console.log('Bond:', info.bond.toString(), 'Wei'); console.log( 'Bond in DEV:', (BigInt(info.bond) / BigInt(10 ** 18)).toString(), 'DEV' ); console.log('Delegation Count:', info.delegationCount.toString()); console.log('Status:', info.status.toString()); // Get recent points for context (last 3 rounds) const currentRound = round.current.toNumber(); let recentPoints = 0; console.log('Recent Points:'); for (let i = 0; i < 3; i++) { const roundPoints = await api.query.parachainStaking.awardedPts( currentRound - i, candidate ); console.log(` Round ${currentRound - i}: ${roundPoints.toString()}`); recentPoints += roundPoints.toNumber(); } console.log('Total Points (last 3 rounds):', recentPoints); } } // Calculate some statistics let totalBond = BigInt(0); let totalDelegations = 0; for (const candidate of selectedCandidates) { const candidateInfo = await api.query.parachainStaking.candidateInfo(candidate); if (candidateInfo.isSome) { const info = candidateInfo.unwrap(); totalBond += BigInt(info.bond); totalDelegations += info.delegationCount.toNumber(); } } console.log('\nCollective Statistics:'); console.log('Total Bonded:', totalBond.toString(), 'Wei'); console.log( 'Total Bonded in DEV:', (totalBond / BigInt(10 ** 18)).toString(), 'DEV' ); console.log( 'Average Bond in DEV:', ( totalBond / BigInt(selectedCandidates.length) / BigInt(10 ** 18) ).toString(), 'DEV' ); console.log( 'Average Delegations per Candidate:', (totalDelegations / selectedCandidates.length).toFixed(2) ); process.exit(0); } catch (error) { console.error('Error querying selected candidates:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**topDelegations**(AccountId20) - returns at the most the top 300 delegations for all collators or for a given collator's address" === "Parameters" - `AccountId20` - Address of the given collator. If no address is provided then the top 300 delegations for all collators is returned. === "Returns" Returns up to the top 300 delegations for a given collator, including the address of the delegator and the amount delegated === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Example collator address const collatorAddress = 'INSERT_COLLATOR_ADDRESS'; // Get collator info first const candidateInfo = await api.query.parachainStaking.candidateInfo(collatorAddress); console.log('Query Parameters:'); console.log('Collator address:', collatorAddress); if (candidateInfo.isSome) { const info = candidateInfo.unwrap(); console.log('\nCollator Information:'); console.log('Total delegations:', info.delegationCount.toString()); console.log('Self bond:', info.bond.toString(), 'Wei'); console.log( 'Self bond in DEV:', (BigInt(info.bond) / BigInt(10 ** 18)).toString(), 'DEV' ); } // Query top delegations const topDelegations = await api.query.parachainStaking.topDelegations(collatorAddress); if (topDelegations.isSome) { const delegations = topDelegations.unwrap(); console.log('\nTop Delegations:'); console.log('Total delegations found:', delegations.delegations.length); console.log( 'Total amount delegated:', delegations.total.toString(), 'Wei' ); console.log( 'Total amount delegated in DEV:', (BigInt(delegations.total) / BigInt(10 ** 18)).toString(), 'DEV' ); // Sort delegations by amount in descending order const sortedDelegations = [...delegations.delegations].sort( (a, b) => BigInt(b.amount) - BigInt(a.amount) ); // Display each delegation console.log('\nDelegation Details:'); sortedDelegations.forEach((delegation, index) => { console.log(`\nDelegation #${index + 1}:`); console.log('Delegator:', delegation.owner.toString()); console.log('Amount:', delegation.amount.toString(), 'Wei'); console.log( 'Amount in DEV:', (BigInt(delegation.amount) / BigInt(10 ** 18)).toString(), 'DEV' ); }); // Calculate statistics if (sortedDelegations.length > 0) { const amounts = sortedDelegations.map((d) => BigInt(d.amount)); const total = amounts.reduce((a, b) => a + b, BigInt(0)); const average = total / BigInt(sortedDelegations.length); const highest = amounts[0]; const lowest = amounts[amounts.length - 1]; const median = amounts[Math.floor(amounts.length / 2)]; console.log('\nDelegation Statistics:'); console.log( 'Average delegation:', (average / BigInt(10 ** 18)).toString(), 'DEV' ); console.log( 'Highest delegation:', (highest / BigInt(10 ** 18)).toString(), 'DEV' ); console.log( 'Median delegation:', (median / BigInt(10 ** 18)).toString(), 'DEV' ); console.log( 'Lowest delegation:', (lowest / BigInt(10 ** 18)).toString(), 'DEV' ); // Distribution analysis const totalDelegated = BigInt(delegations.total); console.log('\nStake Distribution:'); console.log( 'Top 5 delegators control:', ( (amounts.slice(0, 5).reduce((a, b) => a + b, BigInt(0)) * BigInt(100)) / totalDelegated ).toString() + '%' ); if (sortedDelegations.length >= 10) { console.log( 'Top 10 delegators control:', ( (amounts.slice(0, 10).reduce((a, b) => a + b, BigInt(0)) * BigInt(100)) / totalDelegated ).toString() + '%' ); } } // Check auto-compound settings const autoCompoundDelegations = await api.query.parachainStaking.autoCompoundingDelegations( collatorAddress ); console.log('\nAuto-compound Settings:'); console.log( 'Delegators with auto-compound:', autoCompoundDelegations.length ); } else { console.log('\nNo top delegations found for this collator'); } process.exit(0); } catch (error) { console.error('Error querying top delegations:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**total**() - returns the total capital locked in the staking pallet" === "Parameters" None === "Returns" `u128` - returns the total capital locked in the staking pallet === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get total staked amount const totalStaked = await api.query.parachainStaking.total(); console.log('Total Staked:'); console.log('Amount:', totalStaked.toString(), 'Wei'); console.log( 'Amount in DEV:', (BigInt(totalStaked) / BigInt(10 ** 18)).toString(), 'DEV' ); // Get some context information const selectedCandidates = await api.query.parachainStaking.selectedCandidates(); console.log('\nNetwork Context:'); console.log('Number of Selected Collators:', selectedCandidates.length); // Get total issuance for percentage calculation const totalIssuance = await api.query.balances.totalIssuance(); const percentageStaked = (BigInt(totalStaked) * BigInt(100)) / BigInt(totalIssuance); console.log('\nStaking Metrics:'); console.log( 'Total Issuance:', (BigInt(totalIssuance) / BigInt(10 ** 18)).toString(), 'DEV' ); console.log( 'Percentage of Total Supply Staked:', percentageStaked.toString() + '%' ); // Calculate average stake per collator const averageStakePerCollator = BigInt(totalStaked) / BigInt(selectedCandidates.length); console.log( 'Average Stake per Collator:', (averageStakePerCollator / BigInt(10 ** 18)).toString(), 'DEV' ); process.exit(0); } catch (error) { console.error('Error querying total staked:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**totalSelected**() - returns the total number of collator candidates that can be selected for the active set" === "Parameters" None === "Returns" `u32` - returns the total number of collator candidates that can be selected for the active set === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get total number of collators that can be selected const totalSelected = await api.query.parachainStaking.totalSelected(); console.log( 'Maximum Number of Collators that can be Selected:', totalSelected.toString() ); process.exit(0); } catch (error) { console.error('Error querying total selected:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ### Pallet Constants {: #constants } The parachain staking pallet includes the following read-only functions to obtain pallet constants: ??? function "**candidateBondLessDelay**() - returns the number of rounds that must be waited until a candidate's scheduled request to decrease their self bond can be executed" === "Parameters" None === "Returns" `u32` - returns the number of rounds that must be waited until a candidate's scheduled request to decrease their self bond can be executed === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the bond less delay constant const delay = await api.consts.parachainStaking.candidateBondLessDelay; console.log('Candidate Bond Less Delay:', delay.toString(), 'rounds'); process.exit(0); } catch (error) { console.error('Error querying candidate bond less delay:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**defaultBlocksPerRound**() - *deprecated as of runtime 1900* - returns the default number of blocks per round" === "Parameters" None === "Returns" *Deprecated as of runtime 1900* === "Polkadot.js API Example" *Deprecated as of runtime 1900* ??? function "**defaultCollatorCommission**() - *deprecated as of runtime 1900* - returns the default commission due to collators" === "Parameters" None === "Returns" *Deprecated as of runtime 1900* === "Polkadot.js API Example" *Deprecated as of runtime 1900* ??? function "**defaultParachainBondReservePercent**() - *deprecated as of runtime 1900* - returns the default percent of inflation set aside for the parachain bond account" === "Parameters" None === "Returns" *Deprecated as of runtime 1900* === "Polkadot.js API Example" *Deprecated as of runtime 1900* ??? function "**delegationBondLessDelay**() - returns the number of rounds that must be waited until a scheduled request to decrease a delegation can be executed" === "Parameters" None === "Returns" `u32` - returns the number of rounds that must be waited until a scheduled request to decrease a delegation can be executed === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the delegation bond less delay constant const delay = await api.consts.parachainStaking.delegationBondLessDelay; console.log('Delegation Bond Less Delay:', delay.toString(), 'rounds'); process.exit(0); } catch (error) { console.error('Error querying delegation bond less delay:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**leaveCandidatesDelay**() - returns the number of rounds that must be waited before a scheduled request for a candidate to leave the candidate pool can be executed" === "Parameters" None === "Returns" `u32` - returns the number of rounds that must be waited before a scheduled request for a candidate to leave the candidate pool can be executed === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the leaveCandidatesDelay constant from the parachainStaking module const leaveCandidatesDelay = await api.consts.parachainStaking.leaveCandidatesDelay; console.log( 'Leave Candidates Delay:', leaveCandidatesDelay.toString(), 'rounds' ); process.exit(0); } catch (error) { console.error('Error querying leave candidates delay:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**leaveDelegatorsDelay**() - returns the number of rounds that must be waited before a scheduled request for a delegator to leave the set of delegators can be executed" === "Parameters" None === "Returns" `u32` - returns the number of rounds that must be waited before a scheduled request for a delegator to leave the set of delegators can be executed === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the leaveDelegatorsDelay constant from the parachainStaking module const leaveDelegatorsDelay = await api.consts.parachainStaking.leaveDelegatorsDelay; console.log( 'Leave Delegators Delay:', leaveDelegatorsDelay.toString(), 'rounds' ); process.exit(0); } catch (error) { console.error('Error querying leave delegators delay:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**linearInflationThreshold**() - returns the total supply threshold at which inflation becomes linear instead of exponential" === "Parameters" None === "Returns" `Option` - returns the total supply threshold at which inflation becomes linear instead of exponential. When the total supply reaches this amount, inflation transitions from exponential to linear. Returns `Some(value)` if configured, or `None` if not set. Example values are approximately 1.2B DEV for Moonbase, 1.0B MOVR for Moonriver, and 1.2B GLMR for Moonbeam. === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API provider const wsProvider = new WsProvider('INSERT_WSS_ENDPOINT'); const api = await ApiPromise.create({ provider: wsProvider }); // Get the linear inflation threshold constant const linearInflationThreshold = api.consts.parachainStaking.linearInflationThreshold; console.log(`Linear Inflation Threshold: ${linearInflationThreshold.toHuman()}`); // Disconnect from the API await api.disconnect(); }; main().catch(console.error); ``` ??? function "**maxBottomDelegationsPerCandidate**() - returns the maximum number of bottom delegations per candidate" === "Parameters" None === "Returns" `u32` - returns the maximum number of bottom delegations per candidate === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the maxBottomDelegationsPerCandidate constant from the parachainStaking module const maxBottomDelegationsPerCandidate = await api.consts.parachainStaking.maxBottomDelegationsPerCandidate; console.log( 'Max Bottom Delegations Per Candidate:', maxBottomDelegationsPerCandidate.toString() ); process.exit(0); } catch (error) { console.error( 'Error querying max bottom delegations per candidate:', error ); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**maxCandidates**() - returns the maximum number of candidates allowed in the candidate pool" === "Parameters" None === "Returns" `u32` - returns the maximum number of candidates allowed in the candidate pool === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the maximum number of candidates allowed const maxCandidates = await api.consts.parachainStaking.maxCandidates; console.log('Maximum Allowed Candidates:', maxCandidates.toString()); process.exit(0); } catch (error) { console.error('Error querying max candidates:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**maxDelegationsPerDelegator**() - returns the maximum number of delegations per delegator" === "Parameters" None === "Returns" `u32` - returns the maximum number of delegations per delegator === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the maximum number of delegations per delegator const maxDelegations = await api.consts.parachainStaking.maxDelegationsPerDelegator; console.log( 'Maximum Delegations Per Delegator:', maxDelegations.toString() ); process.exit(0); } catch (error) { console.error('Error querying max delegations per delegator:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**maxOfflineRounds**() - returns the number of rounds that must pass before a collator that has stopped producing blocks is marked as inactive" === "Parameters" None === "Returns" `u32` - returns the number of rounds that must pass before a collator that has stopped producing blocks is marked as inactive === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the maximum number of offline rounds const maxOfflineRounds = await api.consts.parachainStaking.maxOfflineRounds; console.log('Maximum Offline Rounds:', maxOfflineRounds.toString()); process.exit(0); } catch (error) { console.error('Error querying max offline rounds:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**maxTopDelegationsPerCandidate**() - returns the maximum number of top delegations per candidate" === "Parameters" None === "Returns" `u32` - returns the maximum number of top delegations per candidate === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the maximum number of top delegations per candidate const maxTopDelegations = await api.consts.parachainStaking.maxTopDelegationsPerCandidate; console.log( 'Maximum Top Delegations Per Candidate:', maxTopDelegations.toString() ); process.exit(0); } catch (error) { console.error('Error querying max top delegations per candidate:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**minBlocksPerRound**() - returns the minimum number of blocks per round" === "Parameters" None === "Returns" `u32` - returns the minimum number of blocks per round === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the minimum number of blocks per round const minBlocksPerRound = await api.consts.parachainStaking.minBlocksPerRound; console.log('Minimum Blocks Per Round:', minBlocksPerRound.toString()); process.exit(0); } catch (error) { console.error('Error querying min blocks per round:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**minCandidateStk**() - returns the minimum stake required for a candidate to be a collator candidate" === "Parameters" None === "Returns" `u128` - returns the minimum stake required for a candidate to be a collator candidate === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the minimum candidate stake required const minCandidateStake = await api.consts.parachainStaking.minCandidateStk; console.log( 'Minimum Candidate Stake:', minCandidateStake.toString(), 'Wei' ); console.log( 'Minimum Candidate Stake in DEV:', (BigInt(minCandidateStake) / BigInt(10 ** 18)).toString() ); process.exit(0); } catch (error) { console.error('Error querying min candidate stake:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**minCollatorStk**() - *deprecated as of runtime 2400* - returns the minimum stake required for a candidate to be in the active set" === "Parameters" None === "Returns" *Deprecated as of runtime 2400* === "Polkadot.js API Example" *Deprecated as of runtime 2400* ??? function "**minDelegation**() - returns the minimum delegation amount" === "Parameters" None === "Returns" `u128` - returns the minimum delegation amount === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the minimum delegation amount const minDelegation = await api.consts.parachainStaking.minDelegation; console.log('Minimum Delegation Amount:', minDelegation.toString(), 'Wei'); console.log( 'Minimum Delegation Amount in DEV:', (BigInt(minDelegation) / BigInt(10 ** 18)).toString() ); process.exit(0); } catch (error) { console.error('Error querying min delegation amount:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**minDelegatorStk**() - *deprecated as of runtime 2500* - returns the minimum stake for an account to be a delegator" === "Parameters" None === "Returns" *Deprecated as of runtime 2500* === "Polkadot.js API Example" *Deprecated as of runtime 2500* ??? function "**minSelectedCandidates**() - returns the minimum number of selected candidates in the active set every round" === "Parameters" None === "Returns" `u32` - the minimum number of selected candidates in the active set every round === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the minimum number of selected candidates const minSelectedCandidates = await api.consts.parachainStaking.minSelectedCandidates; console.log( 'Minimum Selected Candidates:', minSelectedCandidates.toString() ); process.exit(0); } catch (error) { console.error('Error querying min selected candidates:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**revokeDelegationDelay**() - returns the number of rounds that must be waited before a scheduled request to revoke a delegation can be executed" === "Parameters" None === "Returns" `u32` - the number of rounds that must be waited before a scheduled request to revoke a delegation can be executed === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the revoke delegation delay const revokeDelegationDelay = await api.consts.parachainStaking.revokeDelegationDelay; console.log( 'Revoke Delegation Delay:', revokeDelegationDelay.toString(), 'rounds' ); process.exit(0); } catch (error) { console.error('Error querying revoke delegation delay:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` ??? function "**rewardPaymentDelay**() - returns the number of rounds that must be waited after which block authors are rewarded" === "Parameters" None === "Returns" `u32` - The number of rounds that must be waited after which block authors are rewarded === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Initialize the API const api = await ApiPromise.create({ provider: new WsProvider('wss://moonbase-alpha.public.blastapi.io'), }); try { // Get the reward payment delay const rewardPaymentDelay = await api.consts.parachainStaking.rewardPaymentDelay; console.log( 'Reward Payment Delay:', rewardPaymentDelay.toString(), 'rounds' ); process.exit(0); } catch (error) { console.error('Error querying reward payment delay:', error); process.exit(1); } }; // Execute the script main().catch((error) => { console.error('Script error:', error); process.exit(1); }); ``` --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/interfaces/ --- BEGIN CONTENT --- --- title: The Substrate Pallets on Moonbeam description: Substrate-based blockchains like Moonbeam utilize modular components to encapsulate specific functionalities. Explore these modules and their interfaces. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/interfaces/interoperability/ --- BEGIN CONTENT --- --- title: Low-Level Substrate Interfaces for XCM description: Leverage low-level Substrate interfaces for seamless interoperability via XCM, include interfaces for asset transfers and remote execution. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/interfaces/utility/ --- BEGIN CONTENT --- --- title: The Substrate Pallets on Moonbeam description: Implement essential utility functions with low-level Substrate interfaces for batching transactions and sending calls via derivative accounts. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/interfaces/utility/utility/ --- BEGIN CONTENT --- --- title: Utility Pallet description: Learn about the available extrinsics for the Utility Pallet on Moonbeam and how to interact with them using Polkadot.js Apps and the Polkadot.js API. keywords: utility, batch, substrate, pallet, moonbeam, polkadot categories: Substrate Toolkit --- # The Utility Pallet ## Introduction {: #introduction } Through Substrate's Utility Pallet, users on Moonbeam can include multiple calls into a single transaction through the two available batch extrinsics and use derivative accounts to send calls. This guide will provide an overview and examples of the extrinsics and getters for the pallet constants available in the Utility Pallet on Moonbeam. ## Derivative Accounts {: #derivative-accounts } Derivative accounts are accounts that are derived from another account using an index. This enables the derivative account to dispatch transactions and use the origin account to pay for transaction fees. Since the private key of this account is unknown, transactions must be initiated with the `asDerivative` extrinsic of this pallet. For example, Alice has a derivative account with an index of `0`. If she transfers any balance using the `asDerivative` function, Alice would still pay for transaction fees, but the funds being transferred will be withdrawn from the derivative account at index `0`. The derivation is done by calculating the Blake2 hash of `modlpy/utilisuba` + `originalAddress` + `index`. You can use a [script to calculate a derivative account](https://github.com/albertov19/PolkaTools/blob/main/calculateDerivedAddress.ts){target=\_blank} given an origin account and index. One use case of derivative accounts can be found in the XCM Transactor Pallet. The pallet allows users to perform remote cross-chain calls from an account derived from the Sovereign account, which enables the calls to be easily executed with a simple transaction. For more information, please refer to the [Using the XCM Transactor Pallet for Remote Executions](/builders/interoperability/xcm/remote-execution/substrate-calls/xcm-transactor-pallet/){target=_blank} guide. ## Utility Pallet Interface {: #utility-pallet-interface } ### Extrinsics {: #extrinsics } The Utility Pallet provides the following extrinsics (functions): ??? function "**asDerivative**(index, call) - sends a call through an indexed pseudonym of the sender" === "Parameters" - `index` - the indexed pseudonym of the sender - `call` - the encoded call data of the call === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const index = INSERT_INDEX; const call = 'INSERT_ENCODED_CALL_DATA'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.utility.asDerivative(index, call); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**batch**(calls) - sends a batch of calls to be dispatched. If a call fails, any successful calls up until that point will be processed, and a `BatchInterrupted` event will be emitted. If all calls are successful, then the `BatchCompleted` event is emitted. The number of calls must not exceed the [limit](#constants)" === "Parameters" - `calls` - an array that contains the encoded call data for each of the calls to be dispatched === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const calls = ['INSERT_ENCODED_CALL_DATA']; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.utility.batch(calls); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**batchAll**(calls) - sends a batch of calls to be dispatched and atomically executes them. If one of the calls fails, the entire transaction will roll back and fail. The number of calls must not exceed the [limit](#constants)" === "Parameters" - `calls` - an array that contains the encoded call data for each of the calls to be dispatched === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const calls = ['INSERT_ENCODED_CALL_DATA']; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.utility.batchAll(calls); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ??? function "**dispatchAs**(asOrigin, call) - dispatches a function call provided an origin and the call to be dispatched. The dispatch origin for this call must be Root" === "Parameters" - `asOrigin` - the dispatch origin - `call` - the encoded call data of the call to be dispatched === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const asOrigin = { System: 'Root' }; const call = 'INSERT_ENCODED_CALL_DATA'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.utility.dispatchAs(asOrigin, call); const txHash = await tx.signAndSend('INSERT_ACCOUNT_OR_KEYRING'); api.disconnect(); }; main(); ``` ### Pallet Constants {: #constants } The Utility Pallet includes the following read-only functions to obtain pallet constants: ??? function "**batchedCallsLimit**() - returns the limit on the number of batched calls" === "Parameters" None. === "Returns" The maximum number of calls that can be batched. ```js // If using Polkadot.js API and calling toJSON() on the query results 10922 ``` === "Polkadot.js API Example" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const batchedCallsLimit = api.consts.utility.batchedCallsLimit; }; main(); ``` ## Generating Encoded Call Data {: #generating-encoded-call-data } To use the extrinsics in the Utility Pallet, you'll need to generate the encoded call data of the call(s) that you're dispatching. You can do this using the Polkadot.js API. You'll assemble the call, and instead of signing and sending it, you'll call `method.toHex()` on the assembled call to get the encoded call data. For example, to generate the encoded call data of a simple transfer extrinsic, you can use the following code snippet: ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { const api = await ApiPromise.create({ provider: new WsProvider('INSERT_WSS_ENDPOINT'), }); const tx = api.tx.balances.transferAllowDeath('INSERT_ADDRESS', 'INSERT_AMOUNT'); const encodedCallData = tx.method.toHex(); }; main(); ``` You can then pass the `encodedCallData` value into the extrinsic that you're using. ## Using the Batch Extrinsics {: #using-the-batch-extrinsics } You can access the batch extrinsics using the Polkadot.js Apps interface or through the Polkadot.js API. This example will show you how to use the `batch` extrinsic with Polkadot.js Apps. If you're using the Polkadot.js API, you can access the Utility Pallet through the `api.tx.utility.batch` interface. For more information on batching transactions with the API, please refer to the [Polkadot.js API Library](/builders/substrate/libraries/polkadot-js-api/#batching-transactions){target=_blank} page. To get started, you can navigate to [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/extrinsics){target=\_blank} and connect to Moonbase Alpha. This example can also be adapted for Moonbeam or Moonriver. You can send any combination of calls, whether they're balance transfers, democracy actions, staking actions, or more. As a basic example, you can send two balance transfers at once. To get started, click on the **Developer** dropdown, select **Extrinsics**, and take the following steps: 1. Select the account to submit the `batch` extrinsic with 2. Choose **utility** from the **submit the following extrinsic** menu 3. Select the **batch** extrinsic 4. Fields for the first call should already appear, and to add a second call click on **Add item** 5. For the first call, select **balances** 6. Choose the **transfer** extrinsic 7. Enter the destination account to send the funds to 8. Enter an amount of DEV tokens to send in the **value** field, make sure you account for 18 decimals 9. For the second call, you can repeat steps 5 through 8 10. To send the calls at once, click on **Submit Transaction** ![Send batch transaction](/images/builders/substrate/interfaces/utility/utility/utility-1.webp) Next, you will need to enter your password and click on **Sign and Submit**. Then you can review the extrinsic on [Subscan](https://moonbase.subscan.io/){target=_blank} !!! note As a reference, you can [view the exact extrinsic for this example on Subscan](https://moonbase.subscan.io/extrinsic/2561364-6){target=\_blank}. If you take a look at the **Events** tab at the bottom of the extrinsic page, you should see several events, including two `balances (Transfer)` events, two `utility (ItemCompleted)` events, and a `utility (BatchCompleted)` event containing the details of the batch transaction. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/libraries/ --- BEGIN CONTENT --- --- title: Substrate Libraries description: Learn how to use JavaScript or Python Substrate libraries such as Polkadot.js and Py Substrate Interface to interact with the Substrate side of Moonbeam. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/libraries/polkadot-js-api/ --- BEGIN CONTENT --- --- title: How to use the Polkadot.js API description: Learn how to use the Polkadot.js API to interact with a Moonbeam node to get chain data and send transactions (extrinsics) via the Substrate side of Moonbeam. categories: Substrate Toolkit, Libraries and SDKs --- # Polkadot.js API Library ## Introduction {: #introduction } [Polkadot.js](https://wiki.polkadot.network/general/polkadotjs/){target=\_blank} is a collection of tools that allow you to interact with Polkadot and its parachains, such as Moonbeam. The [Polkadot.js API](https://polkadot.js.org/docs/api/){target=\_blank} is one component of Polkadot.js and is a library that allows application developers to query a Moonbeam node and interact with the node's Substrate interfaces using JavaScript, enabling you to read and write data to the network. You can use the Polkadot.js API to query on-chain data and send extrinsics from the Substrate side of Moonbeam. You can query Moonbeam's runtime constants, chain state, events, transaction (extrinsic) data, and more. Here you will find an overview of the available functionalities and some commonly used code examples to get you started on interacting with Moonbeam networks using the Polkadot.js API library. ## Checking Prerequisites {: #checking-prerequisites } Installing and using Polkadot.js API library requires Node.js to be installed. You need to install Node.js (for this example, you can use v16.x) and the npm package manager. You can download directly from [Node.js](https://nodejs.org/en/download/package-manager){target=\_blank} or in your terminal: === "Ubuntu" ```bash curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash - sudo apt install -y nodejs ``` === "MacOS" ```bash # You can use homebrew (https://docs.brew.sh/Installation) brew install node # Or you can use nvm (https://github.com/nvm-sh/nvm) nvm install node ``` You can verify that everything is installed correctly by querying the version for each package: ```bash node -v ``` ```bash npm -v ``` To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. ### Install Polkadot.js API {: #installing-polkadot.js-api-library } First, you need to install the Polkadot.js API library for your project through a package manager such as `yarn`. Install it in your project directory with the following command: === "npm" ```bash npm i @polkadot/api ``` === "yarn" ```bash yarn add @polkadot/api ``` The library also includes other core components like Keyring for account management, or some utilities that are used throughout this guide. ## Create an API Provider Instance {: #creating-an-API-provider-instance } Similar to [Ethereum API libraries](/builders/ethereum/libraries/){target=\_blank}, you must first instantiate an API instance of the Polkadot.js API. Create the `WsProvider` using the WebSocket endpoint of the Moonbeam network you wish to interact with. To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. === "Moonbeam" ```javascript // Import import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Construct API provider const wsProvider = new WsProvider('{{ networks.moonbeam.wss_url }}'); const api = await ApiPromise.create({ provider: wsProvider }); // Code goes here await api.disconnect(); } main(); ``` === "Moonriver" ```javascript // Import import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Construct API provider const wsProvider = new WsProvider('{{ networks.moonriver.wss_url }}'); const api = await ApiPromise.create({ provider: wsProvider }); // Code goes here await api.disconnect(); } main(); ``` === "Moonbase Alpha" ```javascript // Import import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Construct API provider const wsProvider = new WsProvider('{{ networks.moonbase.wss_url }}'); const api = await ApiPromise.create({ provider: wsProvider }); // Code goes here await api.disconnect(); } main(); ``` === "Moonbeam Dev Node" ```javascript // Import import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Construct API provider const wsProvider = new WsProvider('{{ networks.development.wss_url }}'); const api = await ApiPromise.create({ provider: wsProvider }); // Code goes here await api.disconnect(); } main(); ``` ### Metadata and Dynamic API Decoration {: #metadata-and-dynamic-api-decoration } Before diving into the details of performing different tasks via the Polkadot.js API library, it's useful to understand some of the basic workings of the library. When the Polkadot.js API connects to a node, one of the first things it does is retrieve the metadata and decorate the API based on the metadata information. The metadata effectively provides data in the form of: ```text api...
``` Where `` can be either: - `query` - for endpoints to read all the state queries - `tx` - for endpoints related to transactions - `rpc` - for endpoints specific to RPC calls - `consts` - for endpoints specific to runtime constants And therefore, none of the information contained in the `api.{query, tx, rpc, consts}..` endpoints are hard-coded in the API. This allows parachains like Moonbeam to have custom endpoints through its [pallets](/builders/substrate/interfaces/){target=\_blank} that can be directly accessed via the Polkadot.js API library. ## Query On-Chain Data on Moonbeam {: #querying-for-information } In this section, you will learn how to query for on-chain information using the Polkadot.js API library. ### Moonbeam Chain State Queries {: #state-queries } This category of queries retrieves information related to the current state of the chain. These endpoints are generally of the form `api.query..`, where the module and method decorations are generated through metadata. You can see a list of all available endpoints by examining the `api.query` object, for example via: ```javascript console.log(api.query); ``` Assuming you've [initialized the API](#creating-an-API-provider-instance), here is a code sample for retrieving basic account information given its address : ```javascript // Define wallet address const addr = 'INSERT_ADDRESS'; // Retrieve the last timestamp const now = await api.query.timestamp.now(); // Retrieve the account balance & current nonce via the system module const { nonce, data: balance } = await api.query.system.account(addr); console.log( `${now}: balance of ${balance.free} and a current nonce of ${nonce}` ); ``` ??? code "View the complete script" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Construct API provider const wsProvider = new WsProvider('INSERT_WSS_ENDPOINT'); const api = await ApiPromise.create({ provider: wsProvider }); // Define wallet address const addr = 'INSERT_ADDRESS'; // Retrieve the last timestamp via the timestamp module const now = await api.query.timestamp.now(); // Retrieve the account balance & current nonce via the system module const { nonce, data: balance } = await api.query.system.account(addr); console.log( `${now}: balance of ${balance.free} and a current nonce of ${nonce}` ); // Disconnect the API await api.disconnect(); }; main(); ``` ### Moonbeam RPC Queries {: #rpc-queries } The RPC calls provide the backbone for the transmission of data to and from the node. This means that all API endpoints such as `api.query`, `api.tx` or `api.derive` just wrap RPC calls, providing information in the encoded format as expected by the node. You can see a list of all available endpoints by examining the `api.rpc` object, for example via: ```javascript console.log(api.rpc); ``` The `api.rpc` interface follows the a similar format to `api.query`, for instance: ```javascript // Retrieve the chain name const chain = await api.rpc.system.chain(); // Retrieve the latest header const lastHeader = await api.rpc.chain.getHeader(); // Log the information console.log( `${chain}: last block #${lastHeader.number} has hash ${lastHeader.hash}` ); ``` ??? code "View the complete script" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Construct API provider const wsProvider = new WsProvider('INSERT_WSS_ENDPOINT'); const api = await ApiPromise.create({ provider: wsProvider }); // Retrieve the chain name const chain = await api.rpc.system.chain(); // Retrieve the latest header const lastHeader = await api.rpc.chain.getHeader(); // Log the information console.log( `${chain}: last block #${lastHeader.number} has hash ${lastHeader.hash}` ); // Disconnect the API await api.disconnect(); }; main(); ``` ### Query Subscriptions {: #query-subscriptions } The `rpc` API also provide endpoints for subscriptions. You can adapt the previous example to start using subscriptions to listen to new blocks. Note that you need to remove the API disconnect when using subscriptions, to avoid normal closures of the WSS connection. ```javascript // Retrieve the chain name const chain = await api.rpc.system.chain(); // Subscribe to the new headers await api.rpc.chain.subscribeNewHeads((lastHeader) => { console.log( `${chain}: last block #${lastHeader.number} has hash ${lastHeader.hash}` ); }); // Remove await api.disconnect()! ``` The general pattern for `api.rpc.subscribe*` functions is to pass a callback into the subscription function, and this will be triggered on each new entry as they are imported. Other calls under `api.query.*` can be modified in a similar fashion to use subscription, including calls that have parameters. Here is an example of how to subscribe to balance changes in an account: ```javascript // Define wallet address const addr = 'INSERT_ADDRESS'; // Subscribe to balance changes for a specified account await api.query.system.account(addr, ({ nonce, data: balance }) => { console.log( `Free balance is ${balance.free} with ${balance.reserved} reserved and a nonce of ${nonce}` ); }); // Remove await api.disconnect()! ``` ??? code "View the complete script" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Construct API provider const wsProvider = new WsProvider('INSERT_WSS_ENDPOINT'); const api = await ApiPromise.create({ provider: wsProvider }); // Retrieve the chain name const chain = await api.rpc.system.chain(); // Subscribe to the new headers await api.rpc.chain.subscribeNewHeads((lastHeader) => { console.log( `${chain}: last block #${lastHeader.number} has hash ${lastHeader.hash}` ); }); // Define wallet address const addr = 'INSERT_ADDRESS'; // Subscribe to balance changes for a specified account await api.query.system.account(addr, ({ nonce, data: balance }) => { console.log( `free balance is ${balance.free} with ${balance.reserved} reserved and a nonce of ${nonce}` ); // Handle API disconnect here if needed }); }; main(); ``` ## Create a Keyring for a Moonbeam Account {: #keyrings } The Keyring object is used for maintaining key pairs, and the signing of any data, whether it's a transfer, a message, or a contract interaction. ### Create a Keyring Instance {: #creating-a-keyring-instance } You can create an instance by just creating an instance of the Keyring class, and specifying the default type of wallet address used. For Moonbeam networks, the default wallet type should be `ethereum`. ```javascript // Import the keyring as required import Keyring from '@polkadot/keyring'; // Create a keyring instance const keyring = new Keyring({ type: 'ethereum' }); ``` ### Add an Account to a Keyring {: #adding-accounts } There are a number of ways to add an account to the keyring instance, including from the mnemonic phrase and from the shortform private key. === "From Mnemonic" ```javascript // Import the required packages import Keyring from '@polkadot/keyring'; import { u8aToHex } from '@polkadot/util'; import { mnemonicToLegacySeed, hdEthereum } from '@polkadot/util-crypto'; // Import Ethereum account from mnemonic const keyringECDSA = new Keyring({ type: 'ethereum' }); const mnemonic = 'INSERT_MNEMONIC'; // Define index of the derivation path and the derivation path const index = 0; const ethDerPath = "m/44'/60'/0'/0/" + index; console.log(`Mnemonic: ${mnemonic}`); console.log(`--------------------------\n`); // Extract Ethereum address from mnemonic const alice = keyringECDSA.addFromUri(`${mnemonic}/${ethDerPath}`); console.log(`Ethereum Derivation Path: ${ethDerPath}`); console.log(`Derived Ethereum Address from Mnemonic: ${alice.address}`); // Extract private key from mnemonic const privateKey = u8aToHex( hdEthereum(mnemonicToLegacySeed(mnemonic, '', false, 64), ethDerPath) .secretKey ); console.log(`Derived Private Key from Mnemonic: ${privateKey}`); ``` === "From Private Key" ```javascript // Import the required packages import Keyring from '@polkadot/keyring'; // Import Ethereum account from mnemonic const keyringECDSA = new Keyring({ type: 'ethereum' }); const privateKeyInput = 'INSERT_PK'; // Extract address from private key const alice = keyringECDSA.addFromUri(privateKeyInput); console.log(`Derived Address from provided Private Key: ${alice.address}`); ``` ## Dry Run API {: #dry-run-api } The Dry Run API is an easy and convenient way to test the integrity of a call without incurring any transaction fees. The Dry Run API can be accessed from the [Runtime Calls](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbeam.network#/runtime){target=\_blank} tab of the **Developer** section of Polkadot.js Apps. While primarily intended for the [testing of XCM messages](/builders/interoperability/xcm/send-execute-xcm/#test-an-xcm-message-with-the-dry-run-api){target=\_blank}, the Dry Run API can be used to test any arbitrary call. This method takes the origin and call data as parameters and returns an execution result and additional event data. ```javascript const testAccount = api.createType( 'AccountId20', '0x88bcE0b038eFFa09e58fE6d24fDe4b5Af21aa798' ); const callData = '0x030088bce0b038effa09e58fe6d24fde4b5af21aa79813000064a7b3b6e00d'; const callDataU8a = hexToU8a(callData); const result = await api.call.dryRunApi.dryRunCall( { system: { Signed: testAccount } }, callDataU8a ); ``` ??? code "View the complete script" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { hexToU8a } from '@polkadot/util'; const main = async () => { try { // Construct API provider const wsProvider = new WsProvider('INSERT_WSS_ENDPOINT'); const api = await ApiPromise.create({ provider: wsProvider }); console.log('Connected to the API. Preparing dry run call...'); // Create a test account (you should replace this with an actual account) const testAccount = api.createType( 'AccountId20', '0x88bcE0b038eFFa09e58fE6d24fDe4b5Af21aa798' ); // The call data (replace with your actual call data) const callData = '0x030088bce0b038effa09e58fe6d24fde4b5af21aa79813000064a7b3b6e00d'; // Your hex-encoded call data // Convert hex to Uint8Array const callDataU8a = hexToU8a(callData); // Perform the dry run call const result = await api.call.dryRunApi.dryRunCall( { system: { Signed: testAccount } }, // origin callDataU8a // call ); console.log( 'Dry run XCM result:', JSON.stringify(result.toJSON(), null, 2) ); // Disconnect the API await api.disconnect(); console.log('Disconnected from the API.'); } catch (error) { console.error('An error occurred:', error); } }; main().catch(console.error); ``` Upon calling the Dry Run API, the method will tell you whether the call would be successful and returns the event data that would be emitted if the call were actually submitted on chain. You can view the initial output of the `dryRunCall` below. ??? code "View the complete output" ```json Dry run XCM result: { "ok": { "executionResult": { "ok": { "actualWeight": null, "paysFee": "Yes" } }, "emittedEvents": [], "localXcm": null, // Additional data returned here // Omitted for clarity ``` ## Send Transactions on Moonbeam {: #transactions } Transaction endpoints are exposed on endpoints generally of the form `api.tx..`, where the module and method decorations are generated through metadata. These allow you to submit transactions for inclusion in blocks, be it transfers, interacting with pallets, or anything else Moonbeam supports. You can see a list of all available endpoints by examining the `api.tx` object, for example via: ```javascript console.log(api.tx); ``` ### Send a Transaction {: #sending-basic-transactions } The Polkadot.js API library can be used to send transactions to the network. For example, assuming you've [initialized the API](#creating-an-API-provider-instance) and a [keyring instance](#creating-a-keyring-instance), you can use the following snippet to send a basic transaction (this code sample will also retrieve the encoded calldata of the transaction as well as the transaction hash after submitting): ```javascript // Initialize wallet key pairs const alice = keyring.addFromUri('INSERT_ALICES_PRIVATE_KEY'); const bob = 'INSERT_BOBS_ADDRESS'; // Form the transaction const tx = await api.tx.balances.transferAllowDeath(bob, 12345n); // Retrieve the encoded calldata of the transaction const encodedCalldata = tx.method.toHex(); console.log(`Encoded calldata: ${encodedCallData}`); // Sign and send the transaction const txHash = await tx .signAndSend(alice); // Show the transaction hash console.log(`Submitted with hash ${txHash}`); ``` ??? code "View the complete script" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import Keyring from '@polkadot/keyring'; const main = async () => { // Construct API provider const wsProvider = new WsProvider('INSERT_WSS_ENDPOINT'); const api = await ApiPromise.create({ provider: wsProvider }); // Create a keyring instance (ECDSA) const keyring = new Keyring({ type: 'ethereum' }); // Initialize wallet key pairs const alice = keyring.addFromUri('INSERT_ALICES_PRIVATE_KEY'); const bob = 'INSERT_BOBS_ADDRESS'; // Form the transaction const tx = await api.tx.balances.transferAllowDeath(bob, BigInt(12345)); // Retrieve the encoded calldata of the transaction const encodedCalldata = tx.method.toHex(); console.log(`Encoded calldata: ${encodedCalldata}`); // Sign and send the transaction const txHash = await tx.signAndSend(alice); // Show the transaction hash console.log(`Submitted with hash ${txHash}`); // Disconnect the API await api.disconnect(); }; main(); ``` !!! note Prior to client v0.35.0, the extrinsic used to perform a simple balance transfer was the `balances.transfer` extrinsic. It has since been deprecated and replaced with the `balances.transferAllowDeath` extrinsic. Note that the `signAndSend` function can also accept optional parameters, such as the `nonce`. For example, `signAndSend(alice, { nonce: aliceNonce })`. You can use the [sample code from the State Queries](/builders/substrate/libraries/polkadot-js-api/#state-queries){target=\_blank} section to retrieve the correct nonce, including transactions in the mempool. ### Fee Information {: #fees } The transaction endpoint also offers a method to obtain weight information for a given `api.tx..`. To do so, you'll need to use the `paymentInfo` function after having built the entire transaction with the specific `module` and `method`. The `paymentInfo` function returns weight information in terms of `refTime` and `proofSize`, which can be used to determine the transaction fee. This is extremely helpful when crafting [remote execution calls via XCM](/builders/interoperability/xcm/remote-execution/){target=\_blank}. For example, assuming you've [initialized the API](#creating-an-API-provider-instance), the following snippet shows how you can get the weight information for a simple balance transfer between two accounts: ```javascript // Transaction to get weight information const tx = api.tx.balances.transferAllowDeath('INSERT_BOBS_ADDRESS', BigInt(12345)); // Get weight info const { partialFee, weight } = await tx.paymentInfo('INSERT_SENDERS_ADDRESS'); console.log(`Transaction weight: ${weight}`); console.log(`Transaction fee: ${partialFee.toHuman()}`); ``` ??? code "View the complete script" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const main = async () => { // Construct API provider const wsProvider = new WsProvider('INSERT_WSS_ENDPOINT'); const api = await ApiPromise.create({ provider: wsProvider }); // Transaction to get weight information const tx = api.tx.balances.transferAllowDeath('INSERT_BOBS_ADDRESS', BigInt(12345)); // Get weight info const { partialFee, weight } = await tx.paymentInfo('INSERT_SENDERS_ADDRESS'); console.log(`Transaction weight: ${weight}`); console.log(`Transaction fee: ${partialFee.toHuman()}`); // Disconnect the API await api.disconnect(); }; main(); ``` ### Transaction Events {: #transaction-events } Any transaction will emit events, as a bare minimum this will always be either a `system.ExtrinsicSuccess` or `system.ExtrinsicFailed` event for the specific transaction. These provide the overall execution result for the transaction, i.e. execution has succeeded or failed. Depending on the transaction sent, some other events may however be emitted, for instance for a balance transfer event, this could include one or more `balance.Transfer` events. The Transfer API page includes an [example code snippet](/learn/core-concepts/transfers-api/#monitor-all-balance-transfers-with-the-substrate-api){target=\_blank} for subscribing to new finalized block headers, and retrieving all `balance.Transfer` events. ### Batch Transactions {: #batching-transactions } The Polkadot.js API allows transactions to be batch processed via the `api.tx.utility.batch` method. The batched transactions are processed sequentially from a single sender. The transaction fee can be estimated using the `paymentInfo` helper method. For example, assuming you've [initialized the API](#creating-an-API-provider-instance), a [keyring instance](#creating-a-keyring-instance) and [added an account](#adding-accounts), the following example makes a couple of transfers and also uses the `api.tx.parachainStaking` module to schedule a request to decrease the bond of a specific collator candidate: ```javascript // Construct a list of transactions to batch const collator = 'INSERT_COLLATORS_ADDRESS'; const txs = [ api.tx.balances.transferAllowDeath('INSERT_BOBS_ADDRESS', BigInt(12345)), api.tx.balances.transferAllowDeath('INSERT_CHARLEYS_ADDRESS', BigInt(12345)), api.tx.parachainStaking.scheduleDelegatorBondLess(collator, BigInt(12345)), ]; // Estimate the fees as RuntimeDispatchInfo, using the signer (either // address or locked/unlocked keypair) const info = await api.tx.utility.batch(txs).paymentInfo(alice); console.log(`Estimated fees: ${info}`); // Construct the batch and send the transactions api.tx.utility.batch(txs).signAndSend(alice, ({ status }) => { if (status.isInBlock) { console.log(`included in ${status.asInBlock}`); // Disconnect API here! } }); ``` ??? code "View the complete script" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import Keyring from '@polkadot/keyring'; const main = async () => { // Construct API provider const wsProvider = new WsProvider('INSERT_WSS_ENDPOINT'); const api = await ApiPromise.create({ provider: wsProvider }); // Create a keyring instance (ECDSA) const keyring = new Keyring({ type: 'ethereum' }); // Initialize wallet key pairs const alice = keyring.addFromUri('INSERT_ALICES_PRIVATE_KEY'); // Construct a list of transactions to batch const collator = 'INSERT_COLLATORS_ADDRESS'; const txs = [ api.tx.balances.transferAllowDeath('INSERT_BOBS_ADDRESS', BigInt(12345)), api.tx.balances.transferAllowDeath('INSERT_CHARLEYS_ADDRESS', BigInt(12345)), api.tx.parachainStaking.scheduleDelegatorBondLess(collator, BigInt(12345)), ]; // Estimate the fees as RuntimeDispatchInfo, using the signer (either // address or locked/unlocked keypair) const info = await api.tx.utility.batch(txs).paymentInfo(alice); console.log(`Estimated fees: ${info}`); // Construct the batch and send the transactions api.tx.utility.batch(txs).signAndSend(alice, async ({ status }) => { if (status.isInBlock) { console.log(`Included in ${status.asInBlock}`); // Disconnect the API await api.disconnect(); } }); }; main(); ``` !!! note You can check out all of the available functions for the `parachainStaking` module by adding `console.log(api.tx.parachainStaking);` to your code. ## Substrate and Custom JSON-RPC Endpoints {: #substrate-and-custom-json-rpc-endpoints } RPCs are exposed as a method on a specific module. This means that once available, you can call any RPC via `api.rpc..(...params[])`. This also works for accessing Ethereum RPCs using the Polkadot.js API, in the form of `polkadotApi.rpc.eth.*`. Some of the methods available through the Polkadot.js API interface are also available as JSON-RPC endpoints on Moonbeam nodes. This section will provide some examples; you can check for a list of exposed RPC endpoints by calling `api.rpc.rpc.methods()` or the `rpc_methods` endpoint listed below. - **[`methods()`](https://polkadot.js.org/docs/substrate/rpc/#methods-rpcmethods){target=\_blank}** - **Interface** - `api.rpc.rpc.methods` - **JSON-RPC** - `rpc_methods` - **Returns** - The list of RPC methods that are exposed by the node ```bash curl --location --request POST 'https://rpc.api.moonbase.moonbeam.network' \ --header 'Content-Type: application/json' \ --data-raw '{ "jsonrpc":"2.0", "id":1, "method":"rpc_methods", "params": [] }' ``` - **[`getBlock(hash?: BlockHash)`](https://polkadot.js.org/docs/substrate/rpc/#getblockhash-blockhash-signedblock){target=\_blank}** - **Interface** - `api.rpc.chain.getBlock` - **JSON-RPC** - `chain_getBlock` - **Returns** - The header and body of a block as specified by the block hash parameter ```bash curl --location --request POST 'https://rpc.api.moonbase.moonbeam.network' \ --header 'Content-Type: application/json' \ --data-raw '{ "jsonrpc":"2.0", "id":1, "method":"chain_getBlock", "params": ["0x870ad0935a27ed8684048860ffb341d469e091abc2518ea109b4d26b8c88dd96"] }' ``` - **[`getFinalizedHead()`](https://polkadot.js.org/docs/substrate/rpc/#getfinalizedhead-blockhash){target=\_blank}** - **Interface** `api.rpc.chain.getFinalizedHead` - **JSON-RPC** `chain_getFinalizedHead` - **Returns** The block hash of the last finalized block in the canonical chain ```bash curl --location --request POST '{{ networks.moonbase.rpc_url }}' \ --header 'Content-Type: application/json' \ --data-raw '{ "jsonrpc":"2.0", "id":1, "method":"chain_getHeader", "params": [] }' ``` The [Consensus and Finality page](/learn/core-concepts/consensus-finality/){target=\_blank} has sample code for using the exposed custom and Substrate RPC calls to check the finality of a given transaction. ## Polkadot.js API Utility Functions {: #utilities } The Polkadot.js API also includes a number of utility libraries for computing commonly used cryptographic primitives and hash functions. The following example computes the deterministic transaction hash of a raw Ethereum legacy transaction by first computing its RLP ([Recursive Length Prefix](https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp/){target=\_blank}) encoding, then hashing the result with keccak256. ```javascript import { encode } from '@polkadot/util-rlp'; import { keccakAsHex } from '@polkadot/util-crypto'; import { numberToHex } from '@polkadot/util'; // Define the raw signed transaction const txData = { nonce: numberToHex(1), gasPrice: numberToHex(21000000000), gasLimit: numberToHex(21000), to: '0xc390cC49a32736a58733Cf46bE42f734dD4f53cb', value: numberToHex(1000000000000000000), data: '', v: '0507', r: '0x5ab2f48bdc6752191440ce62088b9e42f20215ee4305403579aa2e1eba615ce8', s: '0x3b172e53874422756d48b449438407e5478c985680d4aaa39d762fe0d1a11683', }; // Extract the values to an array var txDataArray = Object.keys(txData).map(function (key) { return txData[key]; }); // Calculate the RLP encoded transaction var encoded_tx = encode(txDataArray); // Hash the encoded transaction using keccak256 console.log(keccakAsHex(encoded_tx)); ``` You can check the respective [NPM repository page](https://www.npmjs.com/package/@polkadot/util-crypto/v/0.32.19){target=\_blank} for a list of available methods in the `@polkadot/util-crypto` library and their descriptions.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/libraries/py-substrate-interface/ --- BEGIN CONTENT --- --- title: How to use the Python Substrate Interface description: Learn the basics of how to use the Python Substrate Interface library to query chain data, send transactions, and more on Moonbeam networks. categories: Substrate Toolkit, Libraries and SDKs --- # Python Substrate Interface ## Introduction {: #introduction } [Python Substrate Interface](https://github.com/polkascan/py-substrate-interface){target=\_blank} library allows application developers to query a Moonbeam node and interact with the node's Polkadot or Substrate features using a native Python interface. Here you will find an overview of the available functionalities and some commonly used code examples to get you started on interacting with Moonbeam networks using Python Substrate Interface. ## Checking Prerequisites {: #checking-prerequisites } For the examples in this guide, you will need to have the following: - An account with funds. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} - To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank} - Have [`pip`](https://pypi.org/project/pip){target=\_blank} installed !!! note The examples in this guide assume you have a MacOS or Ubuntu 22.04-based environment and will need to be adapted accordingly for Windows. ### Installing Python Substrate Interface {: #installing-python-substrate-interface } You can install Python Substrate Interface library for your project through `pip`. Run the following command in your project directory: ```bash pip install substrate-interface ``` ## Creating an API Provider Instance {: #creating-an-API-provider-instance } Similar to ETH API libraries, you must first instantiate an API instance of Python Substrate Interface API. Create the `WsProvider` using the websocket endpoint of the Moonbeam network you wish to interact with. To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. === "Moonbeam" ```python # Imports from substrateinterface import SubstrateInterface # Construct the API provider ws_provider = SubstrateInterface( url="{{ networks.moonbeam.wss_url }}", ) ``` === "Moonriver" ```python # Imports from substrateinterface import SubstrateInterface # Construct the API provider ws_provider = SubstrateInterface( url="{{ networks.moonriver.wss_url }}", ) ``` === "Moonbase Alpha" ```python # Imports from substrateinterface import SubstrateInterface # Construct the API provider ws_provider = SubstrateInterface( url="{{ networks.moonbase.wss_url }}", ) ``` === "Moonbeam Dev Node" ```python # Import from substrateinterface import SubstrateInterface # Construct the API provider ws_provider = SubstrateInterface( url="{{ networks.development.wss_url }}", ) ``` ## Querying for Information {: #querying-for-information } In this section, you will learn how to query for on-chain information of Moonbeam networks using Python Substrate Interface library. ### Accessing Runtime Constants {: #accessing-runtime-constants } All runtime constants, such as `BlockWeights`, `DefaultBlocksPerRound` and `ExistentialDeposit`, are provided in the metadata. You can use the [`get_metadata_constants`](https://jamdottech.github.io/py-polkadot-sdk/reference/base/#substrateinterface.base.SubstrateInterface.get_metadata_constants){target=\_blank} method to see a list of available runtime constants within Moonbeam network's metadata. Runtime constants available in the metadata can be queried through the [`get_constant`](https://jamdottech.github.io/py-polkadot-sdk/reference/base/#substrateinterface.base.SubstrateInterface.get_constant){target=\_blank} method. ```python # Imports from substrateinterface import SubstrateInterface # Construct the API provider ws_provider = SubstrateInterface( url="{{ networks.moonbase.wss_url }}", ) # List of available runtime constants in the metadata constant_list = ws_provider.get_metadata_constants() print(constant_list) # Retrieve the Existential Deposit constant on Moonbeam, which is 0 constant = ws_provider.get_constant("Balances", "ExistentialDeposit") print(constant.value) ``` ### Retrieving Blocks and Extrinsics {: #retrieving-blocks-and-extrinsics } You can retrieve basic information about Moonbeam networks, such as blocks and extrinsics, using the Python Substrate Interface API. To retrieve a block, you can use the [`get_block`](https://jamdottech.github.io/py-polkadot-sdk/reference/base/#substrateinterface.base.SubstrateInterface.get_block){target=\_blank} method. You can also access extrinsics and their data fields inside a block object, which is simply a Python dictionary. To retrieve a block header, you can use the [`get_block_header`](https://jamdottech.github.io/py-polkadot-sdk/reference/base/#substrateinterface.base.SubstrateInterface.get_block_header){target=\_blank} method. ```python # Imports from substrateinterface import SubstrateInterface # Construct the API provider ws_provider = SubstrateInterface( url="{{ networks.moonbase.wss_url }}", ) # Retrieve the latest block block = ws_provider.get_block() # Retrieve the latest finalized block block = ws_provider.get_block_header(finalized_only=True) # Retrieve a block given its Substrate block hash block_hash = "0xa499d4ebccdabe31218d232460c0f8b91bd08f72aca25f9b25b04b6dfb7a2acb" block = ws_provider.get_block(block_hash=block_hash) # Iterate through the extrinsics inside the block for extrinsic in block["extrinsics"]: if "address" in extrinsic: signed_by_address = extrinsic["address"].value else: signed_by_address = None print( "\nPallet: {}\nCall: {}\nSigned by: {}".format( extrinsic["call"]["call_module"].name, extrinsic["call"]["call_function"].name, signed_by_address, ) ) ``` !!! note The block hash used in the above code sample is the Substrate block hash. The standard methods in Python Substrate Interface assume you are using the Substrate version of primitives, such as block or tx hashes. ### Subscribing to New Block Headers {: #subscribing-to-new-block-headers } You can also adapt the previous example to use a subscription based model to listen to new block headers. ```python # Imports from substrateinterface import SubstrateInterface # Construct the API provider ws_provider = SubstrateInterface( url="{{ networks.moonbase.wss_url }}", ) def subscription_handler(obj, update_nr, subscription_id): print(f"New block #{obj['header']['number']}") if update_nr > 10: return { "message": "Subscription will cancel when a value is returned", "updates_processed": update_nr, } result = ws_provider.subscribe_block_headers(subscription_handler) ``` ### Querying for Storage Information {: #querying-for-storage-information } You can use the [`get_metadata_storage_functions`](https://jamdottech.github.io/py-polkadot-sdk/reference/base/#substrateinterface.base.SubstrateInterface.get_metadata_storage_functions){target=\_blank} to see a list of available storage functions within Moonbeam network's metadata. Chain states that are provided in the metadata through storage functions can be queried through the [`query`](https://jamdottech.github.io/py-polkadot-sdk/reference/base/#substrateinterface.base.SubstrateInterface.query){target=\_blank} method. The Substrate system modules, such as `System`, `Timestamp`, and `Balances`, can be queried to provide basic information such as account nonce and balance. The available storage functions are read from the metadata dynamically, so you can also query for storage information on Moonbeam custom modules, such as `ParachainStaking` and `Democracy`, for state information that's specific to Moonbeam. ```python # Imports from substrateinterface import SubstrateInterface # Construct the API provider ws_provider = SubstrateInterface( url="{{ networks.moonbase.wss_url }}", ) # List of available storage functions in the metadata method_list = ws_provider.get_metadata_storage_functions() print(method_list) # Query basic account information account_info = ws_provider.query( module="System", storage_function="Account", params=["0x578002f699722394afc52169069a1FfC98DA36f1"], ) # Log the account nonce print(account_info.value["nonce"]) # Log the account free balance print(account_info.value["data"]["free"]) # Query candidate pool information from Moonbeam's Parachain Staking module candidate_pool_info = ws_provider.query( module="ParachainStaking", storage_function="CandidatePool", params=[] ) print(candidate_pool_info) ``` ## Signing and Transactions {: #signing-and-transactions } ### Creating a Keypair {: #creating-a-keypair } The keypair object in Python Substrate Interface is used in the signing of any data, whether it's a transfer, a message, or a contract interaction. You can create a keypair instance from the shortform private key or from the mnemonic. For Moonbeam networks, you also need to specify the `KeypairType` to be `KeypairType.ECDSA`. ```python # Imports from substrateinterface import Keypair, KeypairType # Define the shortform private key privatekey = bytes.fromhex("INSERT_PRIVATE_KEY_WITHOUT_0X_PREFIX") # Define the account mnemonic mnemonic = "INSERT_MNEMONIC" # Generate the keypair from shortform private key keypair = Keypair.create_from_private_key(privatekey, crypto_type=KeypairType.ECDSA) # Generate the keypair from mnemonic keypair = Keypair.create_from_mnemonic(mnemonic, crypto_type=KeypairType.ECDSA) ``` ### Forming and Sending a Transaction {: #forming-and-sending-a-transaction } The [`compose_call`](https://jamdottech.github.io/py-polkadot-sdk/reference/base/#substrateinterface.base.SubstrateInterface.compose_call){target=\_blank} method can be used to compose a call payload which can be used as an unsigned extrinsic or a proposal. Then the payload can be signed using a keypair through the [`create_signed_extrinsic`](https://jamdottech.github.io/py-polkadot-sdk/reference/base/#substrateinterface.base.SubstrateInterface.create_signed_extrinsic){target=\_blank} method. The signed extrinsic can then be submitted using the [`submit_extrinsic`](https://jamdottech.github.io/py-polkadot-sdk/reference/base/#substrateinterface.base.SubstrateInterface.submit_extrinsic){target=\_blank} method. This method will also return an `ExtrinsicReceipt` object which contains information about the on-chain execution of the extrinsic. If you need to examine the receipt object, you can set the `wait_for_inclusion` to `True` when submitting the extrinsic to wait until the extrinsic is successfully included into the block. The following sample code will show a complete example for sending a transaction. ```python # Imports from substrateinterface import SubstrateInterface, Keypair, KeypairType from substrateinterface.exceptions import SubstrateRequestException # Construct the API provider ws_provider = SubstrateInterface( url="{{ networks.moonbase.wss_url }}", ) # Define the shortform private key of the sending account privatekey = bytes.fromhex("INSERT_PRIVATE_KEY_WITHOUT_0X_PREFIX") # Generate the keypair keypair = Keypair.create_from_private_key(privatekey, crypto_type=KeypairType.ECDSA) # Form a transaction call call = ws_provider.compose_call( call_module="Balances", call_function="transfer_allow_death", call_params={ "dest": "0x44236223aB4291b93EEd10E4B511B37a398DEE55", "value": 1 * 10**18, }, ) # Form a signed extrinsic extrinsic = ws_provider.create_signed_extrinsic(call=call, keypair=keypair) # Submit the extrinsic try: receipt = ws_provider.submit_extrinsic(extrinsic, wait_for_inclusion=True) print( "Extrinsic '{}' sent and included in block '{}'".format( receipt.extrinsic_hash, receipt.block_hash ) ) except SubstrateRequestException as e: print("Failed to send: {}".format(e)) ``` ### Offline Signing {: #offline-signing } You can sign transaction payloads or any arbitrary data using a keypair object through the [`sign`](https://jamdottech.github.io/py-polkadot-sdk/reference/keypair/#substrateinterface.keypair.Keypair.sign){target=\_blank} method. This can be used for offline signing of transactions. 1. First, generate the signature payload on an online machine: ```python # Imports from substrateinterface import SubstrateInterface # Construct the API provider ws_provider = SubstrateInterface( url="{{ networks.moonbase.wss_url }}", ) # Construct a transaction call call = ws_provider.compose_call( call_module="Balances", call_function="transfer_allow_death", call_params={ "dest": "0x44236223aB4291b93EEd10E4B511B37a398DEE55", "value": 1 * 10**18, }, ) # Generate the signature payload signature_payload = ws_provider.generate_signature_payload(call=call) ``` 2. On an offline machine, create a keypair with the private key of the sending account, and sign the signature payload: ```python # Imports from substrateinterface import Keypair, KeypairType # Define the signature payload from the offline machine signature_payload = "INSERT_SIGNATURE_PAYLOAD" # Define the shortform private key of the sender account privatekey = bytes.fromhex("INSERT_PRIVATE_KEY_WITHOUT_0X_PREFIX") # Generate the keypair from shortform private key keypair = Keypair.create_from_private_key(privatekey, crypto_type=KeypairType.ECDSA) # Sign the signature_payload signature = keypair.sign(signature_payload) ``` 3. On an online machine, create a keypair with the public key of the sending account, and submit the extrinsic with the generated signature from the offline machine: ```python # Imports from substrateinterface import SubstrateInterface, Keypair, KeypairType # Construct the API provider ws_provider = SubstrateInterface( url="{{ networks.moonbase.wss_url }}", ) # Define the signature from the offline machine signature_payload = "INSERT_SIGNATURE_PAYLOAD" # Construct a keypair with the Ethereum style wallet address of the sending account keypair = Keypair(public_key="INSERT_ADDRESS_WITHOUT_0X", crypto_type=KeypairType.ECDSA) # Construct the same transaction call that was signed call = ws_provider.compose_call( call_module="Balances", call_function="transfer_allow_death", call_params={ "dest": "0x44236223aB4291b93EEd10E4B511B37a398DEE55", "value": 1 * 10**18, }, ) # Construct the signed extrinsic with the generated signature extrinsic = ws_provider.create_signed_extrinsic( call=call, keypair=keypair, signature=signature ) # Submit the signed extrinsic result = ws_provider.submit_extrinsic(extrinsic=extrinsic) # Print the execution result print(result.extrinsic_hash) ``` ## Custom RPC Requests {: #custom-rpc-requests } You can also make custom RPC requests with the [`rpc_request`](https://jamdottech.github.io/py-polkadot-sdk/reference/base/#substrateinterface.base.SubstrateInterface.rpc_request){target=\_blank} method. This is particularly useful for interacting with Moonbeam's [Ethereum JSON-RPC](/builders/ethereum/json-rpc/eth-rpc/){target=\_blank} endpoints or Moonbeam's [custom RPC](/builders/ethereum/json-rpc/moonbeam-custom-api/){target=\_blank} endpoints. The [Consensus and Finality page](/learn/core-concepts/consensus-finality/#checking-tx-finality-with-substrate-libraries){target=\_blank} has examples for using the custom RPC calls through Python Substrate Interface to check the finality of a transaction given its transaction hash.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/builders/substrate/libraries/sidecar/ --- BEGIN CONTENT --- --- title: Using Substrate API Sidecar with Moonbeam description: Learn how to use Sidecar, a Substrate-based REST service, with Moonbeam-based networks to access blocks, account balances, compute gas used, and more. categories: Substrate Toolkit, Libraries and SDKs --- # Using Substrate API Sidecar with Moonbeam ## Introduction {: #introduction } Substrate API Sidecar allows applications to access blocks, account balance, and other information of Substrate-based blockchains through a REST API. This can be useful for exchanges, wallets or other types of applications that need to keep track of account balance and other state changes on a Moonbeam network. This page will describe how to install and run a Substrate API Sidecar for Moonbeam, and the commonly used API endpoints. ## Installing and Running Substrate API Sidecar {: #installing-and-running-substrate-api-sidecar } There are multiple ways of installing and running the Substrate API Sidecar. This guide will describe the steps for installing and running it locally through NPM. For running Substrate API Sidecar through Docker, or building and running it from source, please refer to the [Substrate API Sidecar Github Repository](https://github.com/paritytech/substrate-api-sidecar#readme). ### Checking Prerequisites {: #checking-prerequisites } Running this service locally through NPM requires Node.js to be installed. You need to install Node.js (for this example, you can use v16.x) and the npm package manager. You can download directly from [Node.js](https://nodejs.org/en/download/package-manager){target=\_blank} or in your terminal: === "Ubuntu" ```bash curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash - sudo apt install -y nodejs ``` === "MacOS" ```bash # You can use homebrew (https://docs.brew.sh/Installation) brew install node # Or you can use nvm (https://github.com/nvm-sh/nvm) nvm install node ``` You can verify that everything is installed correctly by querying the version for each package: ```bash node -v ``` ```bash npm -v ``` ### Installing the Substrate API Sidecar {: #installing-the-substrate-api-sidecar } To install the Substrate API Sidecar service locally in the current directory, run this from the command line: ```bash npm install @substrate/api-sidecar@{{ networks.moonbase.substrate_api_sidecar.stable_version }} ``` !!! note If the current folder does not already have a Node.js project structure, you need to manually create the `node_modules` directory by typing `mkdir node_modules`. Substrate API Sidecar v{{ networks.moonbase.substrate_api_sidecar.stable_version }} is the current stable version that has been tested to work with Moonbeam networks. You can verify the installation was successful by typing from the installation directory root: ```bash node_modules/.bin/substrate-api-sidecar --version ``` ## Setting up the Substrate API Sidecar {: #setting-up-the-substrate-api-sidecar } In the terminal that Sidecar will run, export the environmental variable for the WS endpoint of the network. Examples: === "Moonbeam" ```bash export SAS_SUBSTRATE_URL=wss://wss.api.moonbeam.network ``` === "Moonriver" ```bash export SAS_SUBSTRATE_URL=wss://wss.api.moonriver.moonbeam.network ``` === "Moonbase Alpha" ```bash export SAS_SUBSTRATE_URL=wss://wss.api.moonbase.moonbeam.network ``` === "Moonbeam Dev Node" ```bash export SAS_SUBSTRATE_URL=ws://127.0.0.1:9944 ``` Please reference the [Public Endpoints](/builders/get-started/endpoints/) page for a full list of Moonbeam network endpoints. After setting the environmental variable, you can use the `echo` command to check that the environmental variable has been set correctly, by typing: ```bash echo $SAS_SUBSTRATE_URL ``` And it should display the network endpoint you have just set. ## Generating the Types Bundle {: #generating-the-types-bundle } Moonbeam introduces custom types that differ from the standard Substrate types. For API clients like Substrate API Sidecar to properly understand and decode these custom types, you must provide Substrate API Sidecar with the corresponding custom types bundle for the respective network you're interacting with. Generating and associating the custom types bundle with Substrate API Sidecar is quick. First, ensure that you installed [Parity's `generate-types-bundle` package](https://github.com/paritytech/generate-type-bundle){target=\_blank}: ```bash npm install -g @substrate/generate-type-bundle ``` Then, navigate to the following directory within your project: ```bash cd ./node_modules/@substrate/api-sidecar/build/src/ ``` Then, run the following command to generate the types bundle for the respective network: === "Moonbeam" ```bash generate-type-bundle -p . -s moonbeam ``` === "Moonriver" ```bash generate-type-bundle -p . -s moonriver ``` === "Moonbase Alpha" ```bash generate-type-bundle -p . -s moonbase ``` Note that running subsequent commands will overwrite the existing `typesBundle.json.` You'll then need to set the `SAS_SUBSTRATE_TYPES_BUNDLE` environment variable as shown below. If you've renamed the `typesBundle.json,` ensure you use the correct file name. ```bash export SAS_SUBSTRATE_TYPES_BUNDLE="./typesBundle.json" ``` After setting the environment variable, you can verify that you set it correctly by using the following `echo` command: ```bash echo $SAS_SUBSTRATE_TYPES_BUNDLE ``` ## Running Substrate API Sidecar {: #running-substrate-api-sidecar } Navigate back to the root directory of the project: ```bash cd ../../../../.. ``` With the network endpoint environmental variable set, and from the installation directory root, run: ```bash node_modules/.bin/substrate-api-sidecar ``` If the installation and configuration are successful, you should see this output in the console:
node_modules/.bin/substrate-api-sidecar
v0.42.1: Pulling from moonbeamfoundation/moonbeam
SAS:
📦 LOG:
✅ LEVEL: "info"
✅ JSON: false
✅ FILTER_RPC: false
✅ STRIP_ANSI: false
✅ WRITE: false
✅ WRITE_PATH: "/temp/node_modules/@substrate/api-sidecar/build/src/logs"
✅ WRITE_MAX_FILE_SIZE: 5242880
✅ WRITE_MAX_FILES: 5
📦 SUBSTRATE:
✅ URL: "wss://wss.api.moonbeam.network"
✅ TYPES_BUNDLE: undefined
✅ TYPES_CHAIN: undefined
✅ TYPES_SPEC: undefined
✅ TYPES: undefined
📦 EXPRESS:
✅ BIND_HOST: "127.0.0.1"
✅ PORT: 8080
✅ KEEP_ALIVE_TIMEOUT: 5000
2024-05-07 11:29:54 info: Version: 18.0.0
2024-05-07 11:29:55 warn: API/INIT: RPC methods not decorated: eth_getBlockReceipts, moon_isBlockFinalized, moon_isTxFinalized
2024-05-07 11:29:55 warn: API/INIT: moonbeam/3300: Not decorating unknown runtime apis: 0xd0399cd053adda2b/1, 0xa33d43f58731ad84/2, 0xba8173bf23b2e6f8/1
2024-05-07 11:29:55 info: Connected to chain Moonbeam on the moonbeam client at wss://wss.api.moonbeam.network
2024-05-07 11:29:55 info: Listening on http://127.0.0.1:8080/
2024-05-07 11:29:55 info: Check the root endpoint (http://127.0.0.1:8080) to see the available endpoints for the current node
## Substrate API Sidecar Endpoints {: #substrate-api-sidecar-endpoints } Some of the commonly used Substrate API Sidecar endpoints include: - **GET /blocks​/head** — Get the most recently finalized block. The optional parameter `finalized` can be set to `false` to the get the newest known block, which may not be finalized - **GET /blocks/head/header** — Get the most recently finalized block header. The optional parameter `finalized` can be set to `false` to the get the newest known block header, which may not be finalized - **GET /blocks/{blockId}** — Get a block by its height or hash - **GET /accounts/{accountId}/balance-info** — Get balance information for an account - **GET /node/version** — Get information about the Substrates node's implementation and versioning - **GET /runtime/metadata** — Get the runtime metadata in decoded, JSON form. For a full list of API endpoints available on Substrate API Sidecar, please refer to the [official documentation](https://paritytech.github.io/substrate-api-sidecar/dist). ## EVM Field Mapping in Block JSON Object {: #evm-fields-mapping-in-block-json-object } Substrate API Sidecar returns Moonbeam blocks as a JSON object. Information related to EVM execution of Moonbeam transactions is under the `extrinsics` top level field, where individual extrinsics are organized numerically as nested JSON objects. The nesting structure is as following: ```text RESPONSE JSON Block Object: |--extrinsics |--{extrinsic_number} |--method |--pallet: "ethereum" |--method: "transact" |--signature |--nonce |--args |--transaction |--{transaction_type} |--hash |--events |--{event_number} |--method |--pallet: "ethereum" |--method: "Executed" |--data |--0 |--1 |--2 |--3 ... ``` Moonbeam EVM transactions can be identify by the `method` field under the current extrinsic object, where it is set to: ```text {extrinsic_number}.method.pallet = "ethereum" {extrinsic_number}.method.method = "transact" ``` ### Transaction Types and Payload {: #transaction-types-and-payload } The Moonbeam EVM currently supports three transaction standards: `legacy`, `eip1559`, and `eip2930`. These correspond to the `transaction type` field in the above JSON object diagram. For each transaction type, the transaction payload contains the following fields: === "EIP1559" ```text ... |--eip1559 |--chainId |--nonce |--maxPriorityFeePerGas |--maxFeePerGas |--gasLimit |--action |--value |--input |--accessList |--oddYParity |--r |--s ... ``` === "Legacy" ```text ... |--legacy |--nonce |--gasPrice |--gasLimit |--action |--value |--input |--signature ... ``` === "EIP2930" ```text ... |--eip2930 |--chainId |--nonce |--gasPrice |--gasLimit |--action |--value |--input |--accessList |--oddYParity |--r |--s ... ``` For more information on the new [EIP1559](https://eips.ethereum.org/EIPS/eip-1559){target=\_blank} and [EIP2930](https://eips.ethereum.org/EIPS/eip-2930){target=\_blank} transaction types and what each field means, please refer to the respective official Ethereum proposal specs. ### Transaction Field Mappings {: #transaction-field-mappings } To obtain the EVM sender address, recipient address, and EVM hash of any EVM transaction type, check the `events` field under the current extrinsic object, and identify the event where the `method` field is set to: ```text {event_number}.method.pallet: "ethereum" {event_number}.method.method: "Executed" ``` The EVM field mappings are then summarized as the following: === "EIP1559" | EVM Field | Block JSON Field | |:------------------------:|:----------------------------------------------------------------------------:| | Chain ID | `extrinsics[extrinsic_number].args.transaction.eip1559.chainId` | | Nonce | `extrinsics[extrinsic_number].args.transaction.eip1559.nonce` | | Max priority fee per gas | `extrinsics[extrinsic_number].args.transaction.eip1559.maxPriorityFeePerGas` | | Max fee per gas | `extrinsics[extrinsic_number].args.transaction.eip1559.maxFeePerGas` | | Gas limit | `extrinsics[extrinsic_number].args.transaction.eip1559.gasLimit` | | Access list | `extrinsics[extrinsic_number].args.transaction.eip1559.accessList` | | Signature | `extrinsics[extrinsic_number].args.transaction.eip1559.oddYParity/r/s` | | Sender address | `extrinsics[extrinsic_number].events[event_number].data[0]` | | Recipient address | `extrinsics[extrinsic_number].events[event_number].data[1]` | | EVM hash | `extrinsics[extrinsic_number].events[event_number].data[2]` | | EVM execution status | `extrinsics[extrinsic_number].events[event_number].data[3]` | === "Legacy" | EVM Field | Block JSON Field | |:--------------------:|:----------------------------------------------------------------:| | Nonce | `extrinsics[extrinsic_number].args.transaction.legacy.nonce` | | Gas price | `extrinsics[extrinsic_number].args.transaction.legacy.gasPrice` | | Gas limit | `extrinsics[extrinsic_number].args.transaction.legacy.gasLimit` | | Value | `extrinsics[extrinsic_number].args.transaction.legacy.value` | | Signature | `extrinsics[extrinsic_number].args.transaction.legacy.signature` | | Sender address | `extrinsics[extrinsic_number].events[event_number].data[0]` | | Recipient address | `extrinsics[extrinsic_number].events[event_number].data[1]` | | EVM hash | `extrinsics[extrinsic_number].events[event_number].data[2]` | | EVM execution status | `extrinsics[extrinsic_number].events[event_number].data[3]` | === "EIP2930" | EVM Field | Block JSON Field | |:--------------------:|:----------------------------------------------------------------------:| | Chain ID | `extrinsics[extrinsic_number].args.transaction.eip2930.chainId` | | Nonce | `extrinsics[extrinsic_number].args.transaction.eip2930.nonce` | | Gas price | `extrinsics[extrinsic_number].args.transaction.eip2930.gasPrice` | | Gas limit | `extrinsics[extrinsic_number].args.transaction.eip2930.gasLimit` | | Value | `extrinsics[extrinsic_number].args.transaction.eip2930.value` | | Access list | `extrinsics[extrinsic_number].args.transaction.eip2930.accessList` | | Signature | `extrinsics[extrinsic_number].args.transaction.eip2930.oddYParity/r/s` | | Sender address | `extrinsics[extrinsic_number].events[event_number].data[0]` | | Recipient address | `extrinsics[extrinsic_number].events[event_number].data[1]` | | EVM hash | `extrinsics[extrinsic_number].events[event_number].data[2]` | | EVM execution status | `extrinsics[extrinsic_number].events[event_number].data[3]` | !!! note For Substrate transactions, the "Nonce" and "Signature" fields are under `extrinsics[extrinsic_number]`. For EVM transactions, the "Nonce" and "Signature" fields are under `extrinsics[extrinsic_number].args.transaction[transaction_type]`, leaving the "Nonce" and "Signature" under `extrinsics[extrinsic_number]` to be `null`. A successfully executed EVM transaction will return either `succeed: "Stopped"` or `succeed: "Returned"` under the "EVM Execution Status" field. ### ERC-20 Token Transfers {: #erc-20-token-transfers } Events emitted by smart contracts such as an ERC-20 token contract deployed on Moonbeam can be decoded from Sidecar block JSON objects. The nesting structure is as following: ```text RESPONSE JSON Block Object: |--extrinsics |--{extrinsic_number} |--method |--pallet: "ethereum" |--method: "transact" |--signature: |--nonce: |--args |--transaction |--{transaction_type} |--hash |--events |--{event_number} |--method |--pallet: "evm" |--method: "Log" |--data |--0 |-- address |-- topics |--0 |--1 |--2 |-- data ... ... ``` Moonbeam ERC-20 token transfers will emit the [`Transfer`](https://eips.ethereum.org/EIPS/eip-20){target=\_blank} event which can be decoded as the following: | Tx Information | Block JSON Field | |:-----------------------:|:---------------------------------------------------------------------:| | ERC-20 contract address | `extrinsics[extrinsic_number].events[event_number].data[0].address` | | Event signature hash | `extrinsics[extrinsic_number].events[event_number].data[0].topics[0]` | | Sender address | `extrinsics[extrinsic_number].events[event_number].data[0].topics[1]` | | Recipient address | `extrinsics[extrinsic_number].events[event_number].data[0].topics[2]` | | Amount | `extrinsics[extrinsic_number].events[event_number].data[0].data` | Other events emitted by EVM smart contracts can be decoded in a similar fashion, but the content of the topics and data fields will change depending on the definition of the specific event. !!! note The amount transferred is given in Wei and in hexadecimal format. ## Sample Code for Monitoring Native Token Transfers { #sample-code-for-monitoring-native-token-transfers } The [Transfers API page](/learn/core-concepts/transfers-api/#using-substrate-api-sidecar){target=\_blank} has a code snippet demonstrating how to use Substrate API Sidecar to retrieve and decode native token transfers sent with both Substrate and Ethereum APIs on Moonbeam networks. You can reference that as a starting point to build out backends that utilize Sidecar to listen to transfers on Moonbeam networks. ## Calculating Transaction Fees {: #calculating-transaction-fees } For more detailed information and sample code on how to calculate the transaction fees of Moonbeam transactions using Substrate Sidecar API, please check the [Calculating Transaction Fees on Moonbeam](/learn/core-concepts/tx-fees/){target=\_blank} page.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/core-concepts/balances/ --- BEGIN CONTENT --- --- title: Account Balances description: A description of the main differences that Ethereum developers need to understand in terms of account balances on Moonbeam and how they differ from Ethereum. categories: Basics --- # Moonbeam Account Balances ## Introduction {: #introduction } While Moonbeam strives to be compatible with Ethereum's Web3 API and EVM, there are some important Moonbeam differences that developers should know and understand in terms of account balances. One of the design goals of Moonbeam is to create an environment that is as close as possible to Ethereum, and to offer a set of Web3 RPC endpoints that are compatible with Ethereum. However, Moonbeam is also a Substrate based chain, which means that it exposes Substrate RPCs, and that it has integral functionality that is powered by Substrate such as Staking, Governance, and other features which are not part of the Ethereum API. Moonbeam [unified accounts](/learn/core-concepts/unified-accounts/){target=\_blank} are one way that Moonbeam achieves Ethereum compatibility, by changing the underlying account type in the protocol to be Ethereum-like (H160 or 20 byte addresses starting with `0x`). Unified accounts are used by both the Substrate and Ethereum APIs, and map to the same underlying data storage on the blockchain. Nevertheless, there are important differences that users coming from Ethereum should understand when using Moonbeam accounts via the Ethereum API. This guide will outline some of these main differences and what to expect when using Moonbeam for the first time. ## Ethereum Account Balances {: #ethereum-account-balances } An account on Ethereum is an entity with a token balance (Ether or ETH in this case). Account-holders can send Ether transactions on Ethereum and accounts can be controlled by either users (with the private key for signing) or smart contracts. Therefore, Ethereum has two main types of accounts: user-owned and contract-owned. No matter the type, an Ethereum account has a single balance field that represents the number of Wei owned by this address, where Wei is a denomination of ETH (1 x 10^18 Wei per ETH). ![Ethereum balances diagram](/images/learn/core-concepts/balances/balances-1.webp) ## Moonbeam Account Balances {: #moonbeam-account-balances } An account on Moonbeam is also an entity with a token balance (the token will depend on the network). Like on Ethereum, account holders can send token transactions on the Moonbeam Network they are connected to. In addition, accounts can be controlled by users (with the private key for signing) or smart contracts. As with Ethereum, there are two main types of accounts: user-owned and contract owned. However, on Moonbeam, within both account types, there are also [proxy accounts](https://wiki.polkadot.network/learn/learn-proxies/){target=\_blank}, which can perform a limited number of actions on behalf of another account. In terms of balances, all of Moonbeam account types have five (5) different [balance types](https://wiki.polkadot.network/learn/learn-accounts/#balance-types){target=\_blank}: - **Free** — refers to the balance that can be used (not locked/frozen) from the Substrate API. The concept of `free` balance depends on the action to be executed. For example, voting in democracy will not subtract the allocated balance to the vote from `free` balance, but token holders won't be able to transfer that balance - **Reducible** — refers to the balance that can be used (not locked/frozen) through the Ethereum API on Moonbeam. For example, this is the balance displayed by MetaMask. It is the real spendable balance, accounting for all democracy locks (displayed as transferable in Polkadot.js Apps) - **Reserved** — refers to the balance held due to on-chain requirements, and that can be freed by performing some on-chain action. For example, bonds for creating a proxy account or setting an on-chain identity are shown as `reserved balance`. These funds are **not** transferable or accessible via the Ethereum API until they are freed - **Misc frozen** — represents a balance that the `free` balance may not drop below when withdrawing funds, except for transaction fee payment. For example, funds being used to vote on a governance proposal are shown as `misc frozen`. These funds are **not** transferable or accessible via the Ethereum API until they are freed - **Fee frozen** — represents a balance that the `free` balance may not drop below when specifically paying for transaction fees. These funds are **not** transferable or accessible via the Ethereum API until they are freed ![Moonbeam balances diagram](/images/learn/core-concepts/balances/balances-2.webp) ### Calculating Your Transferable Balance {: #calculating-your-transferable-balance } An account's transferable or spendable balance can be calculated as the free balance minus the maximum of `0` or the difference between frozen and reserved tokens: ```text Transferable = free - max(0, frozen - reserved ) ``` Here are two examples of calculating transferable balances: An account has `1000` free tokens, `200` frozen tokens, and `50` reserved tokens. The transferable balance is calculated as: ```text Transferable = 1000 - max(0, 200 - 50) = 1000 - 150 = 850 ``` If the frozen tokens are less than the reserved tokens, with `1000` free tokens, `100` frozen tokens, and `150` reserved tokens, the transferable balance would be: ```text Transferable = 1000 - max(0, 100 - 150) = 1000 - 0 = 1000 ``` ### Retrieve Your Balance {: #retrieve-your-balance } You can check on your balances, including your free (or transferable) and reserved balances (if exists), using the [Polkadot.js API](/builders/substrate/libraries/polkadot-js-api/){target=\_blank}. !!! note To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const wsProvider = new WsProvider('wss://wss.api.moonbase.moonbeam.network'); const main = async () => { const polkadotApi = await ApiPromise.create({ provider: wsProvider, }); const balances = await polkadotApi.query.system.account('INSERT_ADDRESS'); console.log(balances.toHuman()); }; main(); ``` You can also retrieve your balance locks using the Polkadot.js API. ```js import { ApiPromise, WsProvider } from '@polkadot/api'; const wsProvider = new WsProvider('wss://wss.api.moonbase.moonbeam.network'); const main = async () => { const polkadotApi = await ApiPromise.create({ provider: wsProvider, }); const locks = await polkadotApi.query.balances.locks('INSERT_ADDRESS'); console.log(locks.toHuman()); }; main(); ``` ## Main Differences {: #main-differences } The main difference between account balances on Ethereum and Moonbeam lies in the concept of locked and reserved balance on Moonbeam. These are tokens that are still owned by that account, but they are not spendable (yet). From the Ethereum's API perspective, an account might show that it has a certain balance (called `reducible` balance). However, after an on-chain action, this value might increase (or decrease) without an actual balance transfer. It is important to note that the account and behavior differences described here apply to account balances with the base asset (GLMR, MOVR) only and the balances of that asset that aren't interacting with smart contracts. As soon as a Moonbeam account balance is interacting with smart contracts, the behavior will be the same as Ethereum behavior. For example, if you wrap MOVR on Moonriver there is no way for the underlying balance to change via staking or governance actions, because that is part of the storage of the contract. In this case the reducible balance of that account has been committed to the wrapped MOVR smart contract and can't be modified by Substrate actions. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/core-concepts/consensus-finality/ --- BEGIN CONTENT --- --- title: Consensus & Finality description: The main differences that Ethereum developers should understand in terms of consensus and finality on Moonbeam and how it differs from Ethereum. categories: Basics --- # Moonbeam Consensus & Finality ## Introduction {: #introduction } While Moonbeam strives to be compatible with Ethereum's Web3 API and EVM, there are some important Moonbeam differences that developers should know and understand in terms of consensus and finality. In short, consensus is a way for different parties to agree on a shared state. As blocks are created, nodes in the network must decide which block will represent the next valid state. Finality defines when that valid state cannot be altered or reversed. Ethereum began by using a consensus protocol based on [Proof-of-Work (PoW)](https://ethereum.org/en/developers/docs/consensus-mechanisms/pow){target=\_blank}, which provides probabilistic finality. However, in 2022, Ethereum switched to [Proof-of-Stake (PoS)](https://ethereum.org/en/developers/docs/consensus-mechanisms/pos){target=\_blank}, which provides deterministic finality, and no longer uses PoW. In contrast, Moonbeam uses a hybrid consensus protocol based on Delegated Proof-of-Stake (DPoS), which also provides deterministic finality. DPoS is an evolution of Polkadot's [Nominated Proof of Stake (NPoS)](https://docs.polkadot.com/polkadot-protocol/architecture/polkadot-chain/pos-consensus/){target=\_blank} concept, that puts more power into the hands of token holders by allowing delegators to choose which collator candidate they want to support and in what magnitude. This guide will outline some of these main differences around consensus and finality, and what to expect when using Moonbeam for the first time. ## Ethereum Consensus and Finality {: #ethereum-consensus-and-finality } Ethereum currently uses a PoS consensus protocol, in which validators stake ETH in the network and are responsible for producing blocks and checking the validity of new blocks. The timing of block production is fixed and is divided into 12 second slots and 32 slot epochs. One validator per slot is randomly selected to produce a block and broadcast it to the network. There is a randomly selected committee of validators per slot that is responsible for determining the validity of the block. The greater the stake in the network, the greater the chance the validator will be chosen to produce or validate a block. Finality is deterministic in Ethereum's PoS consensus protocol and is achieved through "checkpoint" blocks. Validators agree on the state of a block at particular checkpoint blocks, which are always the first block in an epoch, and if two-thirds of the validators agree, the block is finalized. Block finality can be reverted; however, there are strong economic incentives in place so validators do not attempt to collude to revert a block. You can find out more information in Vitalik's [On Settlement Finality](https://blog.ethereum.org/2016/05/09/on-settlement-finality){target=\_blank} blog, under the Finality in Casper section. ## Moonbeam Consensus and Finality {: #moonbeam-consensus-and-finality } In Polkadot, there are collators and validators. [Collators](https://wiki.polkadot.network/learn/learn-collator/){target=\_blank} maintain parachains (in this case, Moonbeam) by collecting transactions from users and producing state transition proofs for the relay chain [validators](https://wiki.polkadot.network/learn/learn-validator/){target=\_blank}. The collator set (nodes that produce blocks) is selected based on the [stake they have in the network](/learn/features/consensus/){target=\_blank}. For finality, Polkadot and Kusama rely on [GRANDPA](https://docs.polkadot.com/polkadot-protocol/architecture/polkadot-chain/pos-consensus/#finality-gadget-grandpa){target=\_blank}. GRANDPA provides deterministic finality for any given transaction (block). In other words, when a block or transaction is marked as final, it can't be reverted except via on-chain governance or forking. Moonbeam follows this deterministic finality. ## Main Differences Between PoS and DPoS {: #main-differences } In terms of consensus, Moonbeam is based on Delegated Proof-of-Stake, while Ethereum relies on a standard Proof-of-Stake system, which is slightly different. Although both mechanisms rely on the use of stake to validate and create new blocks, there are some key differences. With PoS on Ethereum, validators are selected to produce and validate blocks based on their own stake in the network. As long as a validator has placed a validator deposit, they can be selected to produce and validate blocks. However, as previously mentioned, the greater the stake in the network, the higher the chances a validator has to be selected to produce and validate blocks. On the other hand, with DPoS on Moonbeam, collators become eligible to produce blocks based on their own stake plus their delegated stake in the network. Any token holder can choose to delegate their stake to a collator candidate. The top collator candidates by stake, including delegations, join the active set. The number of candidates in the active set is subject to [governance](/learn/features/governance/){target=\_blank}. Once in the active set, collators are randomly selected to produce blocks using the [Nimbus Consensus Framework](/learn/features/consensus/){target=\_blank}. It is important to note that once a collator is in the active set, their total stake does not impact their chances of being selected to produce blocks. In terms of finality, blocks on Ethereum can take quite a bit longer to finalize than on Moonbeam due to the checkpoint finality system it uses. In Ethereum, validators determine finality at checkpoint blocks, which are always the first block in an epoch. Since an epoch has 32 slots and each slot is 12 seconds, it'll take at least 384 seconds, or 6.4 minutes for a block to be finalized. Moonbeam does not use checkpoint blocks and instead relies on Polkadot's GRANDPA finality gadget, where the finality process is completed in parallel to block production. In addition, the finality process incorporates the blockchain's structure, which allows the relay chain validators to vote on the highest block that they think is valid. In this scenario, the vote would apply to all of the blocks leading up to the one that is finalized, which speeds up the finalization process. After a block has been included in the relay chain, a block can be finalized within one block on Moonbeam. ## Check Transaction Finality with Ethereum RPC Endpoints {: #check-tx-finality-with-ethereum-rpc-endpoints } Although the finality gadgets differ, you can use the same, fairly simple strategy to check for transaction finality on both Ethereum and Moonbeam: 1. You ask the network for the hash of the latest finalized block 2. You retrieve the block number using the hash 3. You compare it with the block number of your transaction. If your transaction was included in a previous block, it is finalized 4. As a safety check, retrieve the block by number and verify that the given transaction hash is in the block The snippets below follow this strategy to check transaction finality. It uses the `finalized` option for the [default block parameter](https://ethereum.org/en/developers/docs/apis/json-rpc/#default-block){target=\_blank} to get the latest finalized block. To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. !!! note The code snippets presented in the following sections are not meant for production environments. Please make sure you adapt it for each use-case. === "Ethers.js" ```js import { ethers } from 'ethers'; // Define the transaction hash to check finality const txHash = 'INSERT_TX_HASH'; // Define the RPC of the provider for Moonbeam // This can be adapted for Moonriver or Moonbase Alpha const providerRPC = { moonbeam: { name: 'moonbeam', rpc: 'INSERT_RPC_API_ENDPOINT', chainId: 1284, } }; // Define the Web3 provider const web3Provider = new ethers.JsonRpcProvider(providerRPC.moonbeam.rpc, { chainId: providerRPC.moonbeam.chainId, name: providerRPC.moonbeam.name, }); const main = async () => { // Get the last finalized block const finalizedBlockHeader = await web3Provider.getBlock('finalized'); const finalizedBlockNumber = finalizedBlockHeader.number; // Get the transaction receipt of the given transaction hash const txReceipt = await web3Provider.getTransactionReceipt(txHash); // If block number of receipt is not null, compare it against finalized head if (txReceipt) { const txBlockNumber = txReceipt.blockNumber; // As a safety check, get given block to check if transaction is included const txBlock = await web3Provider.getBlock(txBlockNumber); console.log(`Current finalized block number is ${finalizedBlockNumber}`); console.log( `Your transaction in block ${txBlockNumber} is finalized? ${ finalizedBlockNumber >= txBlockNumber }` ); console.log( `Your transaction is indeed in block ${txBlockNumber}? ${txBlock.transactions.includes( txHash )}` ); } else { console.log( 'Your transaction has not been included in the canonical chain' ); } }; main(); ``` === "Web3.js" ```js import { Web3 } from 'web3'; // Define the transaction hash to check finality const txHash = 'INSERT_TX_HASH'; // Define the Web3 provider for Moonbeam // This can be adapted for Moonriver or Moonbase Alpha const web3Provider = new Web3('INSERT_RPC_API_ENDPOINT'); const main = async () => { // Get the last finalized block const finalizedBlockHeader = await web3Provider.eth.getBlock('finalized'); const finalizedBlockNumber = finalizedBlockHeader.number; // Get the transaction receipt of the given transaction hash const txReceipt = await web3Provider.eth.getTransactionReceipt(txHash); // If block number of receipt is not null, compare it against finalized head if (txReceipt) { const txBlockNumber = txReceipt.blockNumber; // As a safety check, get given block to check if transaction is included const txBlock = await web3Provider.eth.getBlock(txBlockNumber); console.log(`Current finalized block number is ${finalizedBlockNumber}`); console.log( `Your transaction in block ${txBlockNumber} is finalized? ${ finalizedBlockNumber >= txBlockNumber }` ); console.log( `Your transaction is indeed in block ${txBlockNumber}? ${txBlock.transactions.includes( txHash )}` ); } else { console.log( 'Your transaction has not been included in the canonical chain' ); } }; main(); ``` === "Web3.py" ```py from web3 import Web3 # Define the transaction hash to check finality tx_hash = "INSERT_TX_HASH" # Define the Web3 provider for Moonbeam # This can be adapted for Moonriver or Moonbase Alpha web3_provider = Web3(Web3.HTTPProvider("INSERT_RPC_API_ENDPOINT")) if __name__ == "__main__": # Get the latest finalized block finalized_block_header = web3_provider.eth.get_block("finalized") finalized_block_number = finalized_block_header.number # Get the transaction receipt of the given transaction hash tx_receipt = web3_provider.eth.get_transaction_receipt(tx_hash) # If block number of receipt is not null, compare it against finalized head if tx_receipt is not None: tx_block_number = tx_receipt.blockNumber # As a safety check, get given block to check if transaction is included tx_block = web3_provider.eth.get_block(tx_block_number) is_in_block = False for tx in tx_block.transactions: if tx_hash == web3_provider.to_hex(tx): is_in_block = True print(f"Current finalized block number is { str(finalized_block_number) }") print( f"Your transaction in block { str(tx_block_number) } is finalized? { str(finalized_block_number >= tx_block_number) }" ) print( f"Your transaction is indeed in block { str(tx_block_number) }? { is_in_block }" ) else: print("Your transaction has not been included in the canonical chain") ``` ## Check Transaction Finality with Moonbeam RPC Endpoints {: #check-tx-finality-with-moonbeam-rpc-endpoints } Moonbeam has added support for two custom RPC endpoints, `moon_isBlockFinalized` and `moon_isTxFinalized`, that can be used to check whether an on-chain event is finalized. These methods are a bit more straightforward, as you don't need to compare block numbers to ensure your transaction is finalized. For more information, you can go to the [Finality RPC Endpoints](/builders/ethereum/json-rpc/moonbeam-custom-api/#rpc-methods){target=\_blank} section of the Moonbeam Custom API page. You can modify the scripts from the Ethereum RPC section above to use `moon_isBlockFinalized` and `moon_isTxFinalized`. To do this, you can make custom calls to the Substrate JSON-RPC using the `send` method of both [Web3.js](https://web3js.readthedocs.io){target=\_blank} and [Ethers.js](https://docs.ethers.org/v6){target=\_blank}. Custom RPC requests are also possible using [Web3.py](https://web3py.readthedocs.io){target=\_blank} with the `make_request` method. You'll need to pass in the method name and the parameters to the custom request, which you can find on the [Moonbeam Custom API](/builders/ethereum/json-rpc/moonbeam-custom-api/){target=\_blank} page. ???+ code "moon_isBlockFinalized" === "Ethers.js" ```js import { ethers } from 'ethers'; // Define the block hash to check finality const blockHash = 'INSERT_BLOCK_HASH'; // Define the RPC of the provider for Moonbeam // This can be adapted for Moonriver or Moonbase Alpha const providerRPC = { moonbeam: { name: 'moonbeam', rpc: 'INSERT_RPC_API_ENDPOINT', chainId: 1284, }, }; // Define the Web3 provider const web3Provider = new ethers.JsonRpcProvider(providerRPC.moonbeam.rpc, { chainId: providerRPC.moonbeam.chainId, name: providerRPC.moonbeam.name, }); // Define the function for the custom web3 request const customWeb3Request = async (web3Provider, method, params) => { try { return await web3Provider.send(method, params); } catch (error) { throw new Error(error.body); } }; const main = async () => { // Check if the block has been finalized const isFinalized = await customWeb3Request( web3Provider, 'moon_isBlockFinalized', [blockHash] ); console.log(`Block is finalized? ${isFinalized}`); }; main(); ``` === "Web3.js" ```js import { Web3 } from 'web3'; // Define the block hash to check finality const blockHash = 'INSERT_BLOCK_HASH'; // Define the Web3 provider for Moonbeam // This can be adapted for Moonriver or Moonbase Alpha const web3Provider = new Web3('INSERT_RPC_API_ENDPOINT'); // Define the function for the custom Web3 request const customWeb3Request = async (web3Provider, method, params) => { try { return await requestPromise(web3Provider, method, params); } catch (error) { throw new Error(error); } }; // In Web3.js you need to return a promise const requestPromise = async (web3Provider, method, params) => { return new Promise((resolve, reject) => { web3Provider.send( { jsonrpc: '2.0', id: 1, method, params, }, (error, result) => { if (error) { reject(error.message); } else { if (result.error) { reject(result.error.message); } resolve(result); } } ); }); }; const main = async () => { // Check if the block has been finalized const isFinalized = await customWeb3Request( web3Provider.currentProvider, 'moon_isBlockFinalized', [blockHash] ); console.log(JSON.stringify(isFinalized)); console.log(`Block is finalized? ${isFinalized.result}`); }; main(); ``` === "Web3.py" ```py from web3 import Web3 # Define the block hash to check finality block_hash = 'INSERT_BLOCK_HASH' # Set the RPC_address for Moonbeam # This can also be adapted for Moonriver or Moonbase Alpha RPC_address = 'INSERT_RPC_API_ENDPOINT' # Define the Web3 provider web3_provider = Web3(Web3.HTTPProvider(RPC_address)) # Asynchronous JSON-RPC API request def custom_web3_request(method, params): response = web3_provider.provider.make_request(method, params) return response if __name__ == "__main__": # Check if the block has been finalized is_finalized = custom_web3_request( 'moon_isBlockFinalized', [block_hash]) print( f'Block is finalized? { is_finalized["result"] }') ``` ??? code "moon_isTxFinalized" === "Ethers.js" ```js import { ethers } from 'ethers'; // Define the transaction hash to check finality const txHash = 'INSERT_TRANSACTION_HASH'; // Define the RPC of the provider for Moonbeam // This can be adapted for Moonriver or Moonbase Alpha const providerRPC = { moonbeam: { name: 'moonbeam', rpc: 'INSERT_RPC_API_ENDPOINT', chainId: 1284, }, }; // Define the Web3 provider const web3Provider = new ethers.JsonRpcProvider(providerRPC.moonbeam.rpc, { chainId: providerRPC.moonbeam.chainId, name: providerRPC.moonbeam.name, }); // Define the function for the custom web3 request const customWeb3Request = async (web3Provider, method, params) => { try { return await web3Provider.send(method, params); } catch (error) { throw new Error(error.body); } }; const main = async () => { // Check if the transaction has been finalized const isFinalized = await customWeb3Request( web3Provider, 'moon_isTxFinalized', [txHash] ); console.log(`Transaction is finalized? ${isFinalized}`); }; main(); ``` === "Web3.js" ```js import Web3 from 'web3'; // Define the transaction hash to check finality const txHash = 'INSERT_TRANSACTION_HASH'; // Define the Web3 provider for Moonbeam // This can be adapted for Moonriver or Moonbase Alpha const web3Provider = new Web3('INSERT_RPC_API_ENDPOINT'); // Define the function for the custom Web3 request const customWeb3Request = async (web3Provider, method, params) => { try { return await requestPromise(web3Provider, method, params); } catch (error) { throw new Error(error); } }; // In Web3.js you need to return a promise const requestPromise = async (web3Provider, method, params) => { return new Promise((resolve, reject) => { web3Provider.send( { jsonrpc: '2.0', id: 1, method, params, }, (error, result) => { if (error) { reject(error.message); } else { if (result.error) { reject(result.error.message); } resolve(result); } } ); }); }; const main = async () => { // Check if the transaction has been finalized const isFinalized = await customWeb3Request( web3Provider.currentProvider, 'moon_isTxFinalized', [txHash] ); console.log(JSON.stringify(isFinalized)); console.log(`Transaction is finalized? ${isFinalized}`); }; main(); ``` === "Web3.py" ```py from web3 import Web3 # Define the transaction hash to check finality tx_hash = 'INSERT_BLOCK_HASH' # Set the RPC_address for Moonbeam # This can also be adapted for Moonriver or Moonbase Alpha RPC_address = 'INSERT_RPC_API_ENDPOINT' # Define the Web3 provider web3_provider = Web3(Web3.HTTPProvider(RPC_address)) # Asynchronous JSON-RPC API request def custom_web3_request(method, params): response = web3_provider.provider.make_request(method, params) return response if __name__ == "__main__": # Check if the transaction has been finalized is_finalized = custom_web3_request( 'moon_isTxFinalized', [tx_hash]) print( f'Transaction is finalized? { is_finalized["result"] }') ``` ## Check Transaction Finality with Substrate RPC Endpoints {: #check-tx-finality-with-substrate-rpc-endpoints } Using the following three RPC requests from the Substrate JSON-RPC, you can fetch the current finalized block and compare it with the block number of the transaction you want to check finality for: - `chain_getFinalizedHead` - the first request gets the block hash of the last finalized block - `chain_getHeader` - the second request gets the block header for a given block hash - `eth_getTransactionReceipt` - this retrieves the transaction receipt given the transaction hash The [Polkadot.js API package](/builders/substrate/libraries/polkadot-js-api/){target=\_blank} and [Python Substrate Interface package](/builders/substrate/libraries/py-substrate-interface/){target=\_blank} provide developers with a way to interact with Substrate chains using JavaScript and Python. You can find more information about Polkadot.js and the Substrate JSON-RPC in the [official Polkadot.js documentation site](https://polkadot.js.org/docs/substrate/rpc){target=\_blank}, and more about Python Substrate Interface in the [official PySubstrate documentation site](https://jamdottech.github.io/py-polkadot-sdk/){target=\_blank}. === "Polkadot.js" ```js import { ApiPromise, WsProvider } from '@polkadot/api'; import { types } from 'moonbeam-types-bundle'; // Define the transaction hash to check finality const txHash = 'INSERT_TX_HASH'; // Define the provider for Moonbeam // This can be adapted for Moonriver or Moonbase Alpha const wsProvider = new WsProvider('INSERT_WSS_API_ENDPOINT'); const main = async () => { // Create the provider using Moonbeam types const polkadotApi = await ApiPromise.create({ provider: wsProvider, typesBundle: types, }); await polkadotApi.isReady; // Get the latest finalized block of the Substrate chain const finalizedHeadHash = ( await polkadotApi.rpc.chain.getFinalizedHead() ).toJSON(); // Get finalized block header to retrieve number const finalizedBlockHeader = ( await polkadotApi.rpc.chain.getHeader(finalizedHeadHash) ).toJSON(); // Get the transaction receipt of the given tx hash const txReceipt = ( await polkadotApi.rpc.eth.getTransactionReceipt(txHash) ).toJSON(); // You can not verify if the tx is in the block because polkadotApi.rpc.eth.getBlockByNumber // does not return the list of tx hashes // If block number of receipt is not null, compare it against finalized head if (txReceipt) { console.log( `Current finalized block number is ${finalizedBlockHeader.number}` ); console.log( `Your transaction in block ${txReceipt.blockNumber} is finalized? ${ finalizedBlockHeader.number >= txReceipt.blockNumber }` ); } else { console.log( 'Your transaction has not been included in the canonical chain' ); } polkadotApi.disconnect(); }; main(); ``` === "py-substrate-interface" ```py from substrateinterface import SubstrateInterface # Define the Ethereum transaction hash to check finality tx_hash = "INSERT_TX_HASH" # Point API provider to Moonbeam # This can be adapted for Moonriver or Moonbase Alpha moonbeam_API_provider = SubstrateInterface( url="INSERT_WSS_API_ENDPOINT", ) if __name__ == "__main__": # Get the latest finalized block header of the chain finalized_block_header = moonbeam_API_provider.get_block_header(finalized_only=True) # Get the finalized block number from the block header finalized_block_number = finalized_block_header["header"]["number"] # Get the transaction receipt of the given transaction hash through a # custom RPC request tx_receipt = moonbeam_API_provider.rpc_request( "eth_getTransactionReceipt", [tx_hash] ) # Check if tx_receipt is null if tx_receipt is None: print("The transaction hash cannot be found in the canonical chain.") else: # Get the block number of the transaction tx_block_number = int(tx_receipt["result"]["blockNumber"], 16) # Get the transaction block through a custom RPC request tx_block = moonbeam_API_provider.rpc_request( "eth_getBlockByNumber", [tx_block_number, False] ) print(f"Current finalized block number is { str(finalized_block_number) }") print( f"Your transaction in block { str(tx_block_number) } is finalized? { str(finalized_block_number >= tx_block_number) }" ) print( f'Your transaction is indeed in block { str(tx_block_number) }? { str(tx_hash in tx_block["result"]["transactions"]) }' ) ```
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/core-concepts/ --- BEGIN CONTENT --- --- title: Core Concepts description: Dive into some of the core concepts and their key differences between Moonbeam, an Ethereum-compatible blockchain, and Ethereum itself. dropdown_description: Learn about the fundamentals of Moonbeam template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/core-concepts/security/ --- BEGIN CONTENT --- --- title: Security Considerations description: A description of the main differences that Ethereum developers need to understand in terms of security considerations when developing on Moonbeam. categories: Basics --- # Security Considerations ## Introduction {: #introduction } When developing smart contracts on Moonbeam, there are some security considerations to be aware of that do not apply when developing on Ethereum. Moonbeam has several [precompiled contracts](/builders/ethereum/precompiles/){target=\_blank}, which are Solidity interfaces that enable developers to access Substrate-based functionality through the Ethereum API, but circumventing the EVM. Although the precompiled contracts are designed to improve the developer experience, there can be some unintended consequences that must be considered. This guide will outline and provide examples of some security considerations to be cognizant of when developing on Moonbeam. ## Arbitrary Code Execution {: #arbitrary-code-execution } Arbitrary code execution in Solidity is the ability to execute code and call functions of other contracts using an arbitrary number of arguments of any type. A smart contract allows arbitrary execution of another contract when it allows a user to influence its own `call()` and pass in arbitrary call data and/or the `call()`s target. The [`call()` function](https://solidity-by-example.org/call){target=\_blank} is made available through the [address data type in Solidity](https://docs.soliditylang.org/en/latest/types.html#address){target=\_blank}. When the `call()` function is invoked, the target contract is called using the arbitrary call data. Arbitrary code execution follows the pattern in the diagram below when **Contract A** allows a user to influence its call to **Contract B**. ![Arbitrary code execution](/images/learn/core-concepts/security/security-1.webp) As previously mentioned, one major concern of arbitrarily executing code on Moonbeam is that Moonbeam has precompile contracts that can be called, which can be used to get around some protections that are typically available on Ethereum. To safely use arbitrary code execution on Moonbeam, you should consider the following, which **only applies to contracts that allow arbitrary code execution**: - Moonbeam [precompiled contracts](/builders/ethereum/precompiles/){target=\_blank} such as the Native ERC-20 precompile, XC-20 precompiles, and XCM-related precompiles allow users to manage and transfer assets without requiring access to the EVM. Instead, these actions are done using native Substrate code. So, if your contract holds native tokens or XC-20s and allows arbitrary code execution, these precompiles can be used to drain the balance of the contract, bypassing any security checks that are normally enforced by the EVM - Setting the value attribute of the transaction object to a fixed amount when using the `call()` function (for example, `call{value: 0}(...)`) can be bypassed by calling the native asset precompile and specifying an amount to transfer in the encoded call data - Allowing users that consume your contract to pass in arbitrary call data that will execute any function on the target contract, especially if the contract being targeted is a precompile, is **not** safe. To be safe, you can hard code the function selector for a safe function that you want to allow to be executed - Blacklisting target contracts (including precompiles) in the function that executes arbitrary call data is **not** considered safe, as other precompiles might be added in the future. Providing whitelisted target contracts in the function that executes the arbitrary call data is considered safe, assuming that the contracts being called are not precompiles, or that in the case they are, the contract making the call does not hold the native token or any XC-20 In the following sections, you'll learn about each of these security considerations through examples. ### Precompiles Can Override a Set Value {: #setting-a-value } On Ethereum, a smart contract that allows for arbitrary code execution could force the value of a call to be a specific amount (for example, `{value: 0}`), guaranteeing that only that amount of native currency would be sent with the transaction. Whereas on Moonbeam, the [native ERC-20 precompile contract](/builders/ethereum/precompiles/ux/erc20/){target=\_blank} enables you to interact with the native currency on Moonbeam as an ERC-20 through the Substrate API. As a result, you can transfer the Moonbeam native asset from a smart contract by setting the `value` of a call, as well as through the native ERC-20 precompile. If you set the `value` of an arbitrary call, it can be overridden by targeting the [native ERC-20 precompile contract](/builders/ethereum/precompiles/ux/erc20/){target=\_blank} and passing in call data to transfer the native asset. Since ERC-20s and XC-20s are not native assets, setting the value attribute doesn't provide any protection for these types of assets on Ethereum or Moonbeam. For example, if you have a contract that allows arbitrary code execution and you pass it encoded call data that transfers the balance of a contract to another address, you could essentially drain the given contract of its balance. To get the encoded call data, you can use any of the [ABI encoding functions outlined in the Solidity docs](https://docs.soliditylang.org/en/latest/units-and-global-variables.html#abi-encoding-and-decoding-functions){target=\_blank}, including `abi.encodeWithSelector` as seen in the following function: ```solidity function getBytes(address _erc20Contract, address _arbitraryCallContract, address _to) public view returns (bytes memory) { // Load ERC-20 interface of contract IERC20 erc20 = IERC20(_erc20Contract); // Get amount to transfer uint256 amount = erc20.balanceOf(_arbitraryCallContract); // Build the encoded call data return abi.encodeWithSelector(IERC20.transfer.selector, _to, amount); } ``` Once you have the encoded call data, you could make an arbitrary call to the [native ERC-20 precompile contract](/builders/ethereum/precompiles/ux/erc20/){target=\_blank}, set the value of the call to `0`, and pass in the call data in bytes: ```solidity function makeArbitraryCall(address _target, bytes calldata _bytes) public { // Value: 0 does not protect against native ERC-20 precompile calls or XCM precompiles (bool success,) = _target.call{value: 0}(_bytes); require(success); } ``` The value of `0` will be overridden by the amount to be transferred as specified in the encoded call data, which in this example is the balance of the contract. ### Whitelisting Safe Function Selectors {: #whitelisting-function-selectors } By whitelisting a specific function selector, you can control what functions can be executed and ensure only functions that are considered safe and do not call precompiles are allowed to be called. To get the function selector to whitelist, you can [keccack256 hash](https://emn178.github.io/online-tools/keccak_256.html){target=\_blank} the signature of the function. Once you have the whitelisted function selector, you can use inline assembly to get the function selector from the encoded call data and compare the two selectors using the [require function](https://docs.soliditylang.org/en/v0.8.17/control-structures.html#panic-via-assert-and-error-via-require){target=\_blank}. If the function selector from the encoded call data matches the whitelisted function selector, you can make the call. Otherwise, an exception will be thrown. ```solidity function makeArbitraryCall(address _target, bytes calldata _bytes) public { // Get the function selector from the encoded call data bytes4 selector; assembly { selector := calldataload(_bytes.offset) } // Ensure the call data calls an approved and safe function require(selector == INSERT_WHITELISTED_FUNCTION_SELECTOR); // Arbitrary call (bool success,) = _target.call(_bytes); require(success); } ``` ### Whitelisting Safe Contracts {: #whitelisting-safe-contracts} By whitelisting a specific target contract address in the function that can execute arbitrary call data, you can ensure that the call is considered safe, as the EVM will enforce that only whitelisted contracts can be called. This assumes that the contracts being called are not precompiles. If they are precompiles, you'll want to make sure that the contract making the call does not hold the native token or any XC-20. Blacklisting contracts from arbitrary code execution is not considered safe, as other precompiles might be added in the future. To whitelist a given contract, you can use the [require function](https://docs.soliditylang.org/en/v0.8.17/control-structures.html#panic-via-assert-and-error-via-require){target=\_blank}, which will compare the target contract address to the whitelisted contract address. If the addresses match, the call can be executed. Otherwise, an exception will be thrown. ```solidity function makeArbitraryCall(address _target, bytes calldata _bytes) public { // Ensure the contract address is safe require(_target == INSERT_CONTRACT_ADDRESS); // Arbitrary call (bool success,) = _target.call(_bytes); require(success); } ``` ## Precompiles Can Bypass Sender vs Origin Checks {: #bypass-sender-origin-checks } The transaction origin, or `tx.origin`, is the address of the externally owned account (EOA) the transaction originated from. Whereas the `msg.sender` is the address that has initiated the current call. The `msg.sender` can be an EOA or a contract. The two can be different values if one contract calls another contract, as opposed to directly calling a contract from an EOA. In this case, the `msg.sender` will be the calling contract and the `tx.origin` will be the EOA that initially called the calling contract. For example, if Alice calls a function in contract A that then calls a function in contract B, when looking at the call to contract B, the `tx.origin` is Alice and the `msg.sender` is contract A. !!! note As a [best practice](https://consensysdiligence.github.io/smart-contract-best-practices/development-recommendations/solidity-specific/tx-origin/){target=\_blank}, `tx.origin` should not be used for authorization. Instead, you should use `msg.sender`. You can use the [require function](https://docs.soliditylang.org/en/v0.8.17/control-structures.html#panic-via-assert-and-error-via-require){target=\_blank} to compare the `tx.origin` and `msg.sender`. If they are the same address, you're ensuring that only EOAs can call the function. If the `msg.sender` is a contract address, an exception will be thrown. ```solidity function transferFunds(address payable _target) payable public { require(tx.origin == msg.sender); _target.call{value: msg.value}; } ``` On Ethereum, you can use this check to ensure that a given contract function can only be called once by an EOA. This is because on Ethereum, EOAs can only interact with a contract once per transaction. However, **this is not the case** on Moonbeam, as EOAs can interact with a contract multiple times at once by using precompiled contracts, such as the [batch](/builders/ethereum/precompiles/ux/batch/){target=\_blank} and [call permit](/builders/ethereum/precompiles/ux/call-permit/){target=\_blank} precompiles. With the batch precompile, users can perform multiple calls to a contract atomically. The caller of the batch function will be the `msg.sender` and `tx.origin`, enabling multiple contract interactions at once. With the call permit precompile, if a user wants to interact with a contract multiple times in one transaction, they can do so by signing a permit for each contract interaction and dispatching all of the permits in a single function call. This will only bypass the `tx.origin == msg.sender` check if the dispatcher is the same account as the permit signer. Otherwise, the `msg.sender` will be the permit signer and the `tx.origin` will be the dispatcher, causing an exception to be thrown. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/core-concepts/transfers-api/ --- BEGIN CONTENT --- --- title: Transfer & Monitor Balances on Moonbeam description: A description of the main differences that developers need to understand in terms of the different balance transfers available on Moonbeam compared to Ethereum. categories: Basics --- # Balance Transfers on Moonbeam ## Introduction {: #introduction } While Moonbeam strives to be compatible with Ethereum's Web3 API and EVM, there are some important Moonbeam differences that developers should know and understand in terms of balance transfers of the base network token (for example, GLMR and MOVR). Token holders have two ways of initiating a balance transfer on Moonbeam. On the one hand, users can use the Ethereum API via apps like MetaMask, MathWallet, or any other tools that use the Ethereum JSON-RPC. On the other hand, users can use the Substrate API via the Polkadot.js Apps website or directly using the Substrate RPC. Developers need to be aware that token holders can leverage both APIs to transfer the base-layer network token. Note that these comments do not apply to transfers of other assets, like ERC-20 based assets in the Moonriver or Moonbeam EVMs. Transfers of these assets are only done via the Ethereum APIs since these are smart contract interactions. This guide will outline some of the main differences between both APIs for base-layer network token balance transfers and what to expect when using Moonbeam for the first time. ## Ethereum Transfers {: #ethereum-transfers } A simple balance transfer using the Ethereum API relies on the `eth_sendRawTransaction` JSON-RPC. This can be done directly from one account to another or via a smart contract. There are different strategies to listen for transfers or balance changes on Ethereum, which are not covered in this documentation. But they are all focused on different strategies using the Ethereum JSON-RPC. ## Moonbeam Transfers {: #moonbeam-transfers } As stated before, Moonbeam enables token holders to execute base-layer network token transfers via both the Ethereum and Substrate API. There are multiple scenarios to trigger token transfers on Moonbeam. Consequently, to monitor all transfers, **you should use the Polkadot.js SDK** (Substrate API). Before going over the different scenarios, there are two different elements associated with a block: - **Extrinsic** — refers to state changes that originated outside of the system itself. The most common form of extrinsic is a transaction. They are ordered by execution - **Events** — refers to logs generated from the extrinsic. There can be multiple events per extrinsic. They are ordered by execution The different transfer scenarios are: - **Substrate transfer** — it will create an extrinsic, either `balances.transferAllowDeath` or `balances.transferKeepAlive`. It will trigger **one** `balances.Transfer` event - **Substrate feature** — some native Substrate features can create extrinsic that would send tokens to an address. For example, [Treasury](/learn/features/treasury/){target=\_blank} can create an extrinsic such as `treasury.proposeSend`, which will trigger **one or multiple** `balances.Transfer` events - **Ethereum transfer** — it will create an `ethereum.transact` extrinsic with an empty input. It will trigger **one** `balances.Transfer` event - **Ethereum transfers via smart contracts** — it will create an `ethereum.transact` extrinsic with some data as input. It will trigger **one or multiple** `balances.Transfer` events All the scenarios described above will effectively transfer base-layer network tokens. The easiest way to monitor them all is to rely on the `balances.Transfer` event. ## Monitor Native Token Balance Transfers {: #monitor-transfers } The following code samples will demonstrate how to listen to both types of native token transfers, sent via the Substrate or Ethereum API, using either the [Polkadot.js API library](https://polkadot.js.org/docs/api/start/){target=\_blank} or [Substrate API Sidecar](https://github.com/paritytech/substrate-api-sidecar){target=\_blank}. The following code snippets are for demo purposes only and should not be used without modification and further testing in a production environment. ### Using Polkadot.js API {: #using-polkadotjs-api } The [Polkadot.js API package](https://polkadot.js.org/docs/api/start/){target=\_blank} provides developers a way to interact with Substrate chains using JavaScript. The following code snippet uses [`subscribeFinalizedHeads`](https://polkadot.js.org/docs/substrate/rpc/#subscribefinalizedheads-header){target=\_blank} to subscribe to new finalized block headers, loops through extrinsics fetched from the block, and retrieves the events of each extrinsic. Then, it checks if any event corresponds to a `balances.Transfer` event. If so, it will extract the `from`, `to`, `amount`, and the `tx hash` of the transfer and display it on the console. Note that the `amount` is shown in the smallest unit (Wei). You can find all the available information about Polkadot.js and the Substrate JSON-RPC on their [official documentation site](https://polkadot.js.org/docs/substrate/rpc){target=\_blank}. ```ts import { typesBundlePre900 } from 'moonbeam-types-bundle'; import { ApiPromise, WsProvider } from '@polkadot/api'; // This script will listen to all GLMR transfers (Substrate & Ethereum) and extract the tx hash // It can be adapted for Moonriver or Moonbase Alpha const main = async () => { // Define the provider for Moonbeam const wsProvider = new WsProvider('wss://wss.api.moonbeam.network'); // Create the provider using Moonbeam types const polkadotApi = await ApiPromise.create({ provider: wsProvider, typesBundle: typesBundlePre900 as any, }); // Subscribe to finalized blocks await polkadotApi.rpc.chain.subscribeFinalizedHeads( async (lastFinalizedHeader) => { const [{ block }, records] = await Promise.all([ polkadotApi.rpc.chain.getBlock(lastFinalizedHeader.hash), polkadotApi.query.system.events.at(lastFinalizedHeader.hash), ]); block.extrinsics.forEach((extrinsic, index) => { const { method: { args, method, section }, } = extrinsic; const isEthereum = section == 'ethereum' && method == 'transact'; // Gets the transaction object const tx = args[0] as any; // Convert to the correct Ethereum Transaction format const ethereumTx = isEthereum && ((tx.isLegacy && tx.asLegacy) || (tx.isEip1559 && tx.asEip1559) || (tx.isEip2930 && tx.asEip2930)); // Check if the transaction is a transfer const isEthereumTransfer = ethereumTx && ethereumTx.input.length === 0 && ethereumTx.action.isCall; // Retrieve all events for this extrinsic const events = records.filter( ({ phase }) => phase.isApplyExtrinsic && phase.asApplyExtrinsic.eq(index) ); // This hash will only exist if the transaction was executed through Ethereum. let ethereumHash = ''; if (isEthereum) { // Search for Ethereum execution events.forEach(({ event }) => { if (event.section == 'ethereum' && event.method == 'Executed') { ethereumHash = event.data[2].toString(); } }); } // Search if it is a transfer events.forEach(({ event }) => { if (event.section == 'balances' && event.method == 'Transfer') { const from = event.data[0].toString(); const to = event.data[1].toString(); const balance = (event.data[2] as any).toBigInt(); const substrateHash = extrinsic.hash.toString(); console.log( `Transfer from ${from} to ${to} of ${balance} (block #${lastFinalizedHeader.number})` ); console.log(` - Triggered by extrinsic: ${substrateHash}`); if (isEthereum) { console.log( ` - Ethereum (isTransfer: ${isEthereumTransfer}) hash: ${ethereumHash}` ); } } }); }); } ); }; main(); ``` In addition, you can find more sample code snippets related to more specific cases around balance transfers on this [GitHub page](https://gist.github.com/crystalin/b2ce44a208af60d62b5ecd1bad513bce){target=\_blank}. ### Using Substrate API Sidecar {: #using-substrate-api-sidecar } Developers can also retrieve Moonbeam blocks and monitor transactions sent via both the Substrate and Ethereum APIs using [Substrate API Sidecar](https://github.com/paritytech/substrate-api-sidecar){target=\_blank}, a REST API service for interacting with blockchains built with the Substrate framework. The following code snippet uses the Axios HTTP client to query the [Sidecar endpoint `/blocks/head`](https://paritytech.github.io/substrate-api-sidecar/dist){target=\_blank} for the latest finalized block and then decodes the block for the `from`, `to`, `value`, `tx hash`, and `transaction status` of native token transfers at both the EVM and Substrate API level. ```js import axios from 'axios'; // This script will decode all native token transfers (Substrate & Ethereum) in a given Sidecar block, and extract the tx hash. It can be adapted for any Moonbeam network. // Endpoint to retrieve the latest block const endpoint = 'http://127.0.0.1:8080/blocks/head'; async function main() { try { // Retrieve the block from the Sidecar endpoint const response = await axios.get(endpoint); // Retrieve the block height of the current block console.log('Block Height: ' + response.data.number); // Iterate through all extrinsics in the block response.data.extrinsics.forEach((extrinsic) => { // Retrieve Ethereum Transfers if ( extrinsic.method.pallet === 'ethereum' && extrinsic.method.method === 'transact' ) { // Get the value for any of the three EIP transaction standards supported const value = (extrinsic.args.transaction.legacy && extrinsic.args.transaction.legacy.value) || (extrinsic.args.transaction.eip1559 && extrinsic.args.transaction.eip1559.value) || (extrinsic.args.transaction.eip2930 && extrinsic.args.transaction.eip2930.value); // Iterate through the events to get transaction details extrinsic.events.forEach((event) => { if ( event.method.pallet === 'ethereum' && event.method.method === 'Executed' ) { console.log('From: ' + event.data[0]); console.log('To: ' + event.data[1]); console.log('Tx Hash: ' + event.data[2]); console.log('Value: ' + value); // Check the execution status if (event.data[3].succeed) { console.log('Status: Success'); } else { console.log('Status: Failed'); } } }); } // Retrieve Substrate Transfers if ( extrinsic.method.pallet === 'balances' && (extrinsic.method.method === 'transferKeepAlive' || extrinsic.method.method === 'transferAllowDeath') ) { // Iterate through the events to get transaction details extrinsic.events.forEach((event) => { if ( event.method.pallet === 'balances' && event.method.method === 'Transfer' ) { console.log('From: ' + event.data[0]); console.log('To: ' + event.data[1]); console.log('Tx Hash: ' + extrinsic.hash); console.log('Value: ' + event.data[2]); // Check the execution status if (extrinsic.success) { console.log('Status: Success'); } else { console.log('Status: Failed'); } } }); } }); } catch (err) { console.log(err); } } main(); ``` You can reference the [Substrate API Sidecar page](/builders/substrate/libraries/sidecar/) for information on installing and running your own Sidecar service instance, as well as more details on how to decode Sidecar blocks for Moonbeam transactions. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/core-concepts/tx-fees/ --- BEGIN CONTENT --- --- title: Calculating Transaction Fees description: Learn about the transaction fee model used in Moonbeam and the differences compared to Ethereum that developers should be aware of. categories: Basics --- # Calculating Transaction Fees on Moonbeam ## Introduction {: #introduction } Similar to [the Ethereum and Substrate APIs for sending transfers](/learn/core-concepts/transfers-api/){target=\_blank} on Moonbeam, the Substrate and EVM layers on Moonbeam also have distinct transaction fee models that developers should be aware of when they need to calculate and keep track of transaction fees for their transactions. For starters, Ethereum transactions consume gas units based on their computational complexity and data storage requirements. On the other hand, Substrate transactions use the concept of "weight" to determine fees. In this guide, you'll learn how to calculate the transaction fees for both Substrate and Ethereum transactions. In terms of Ethereum transactions, you'll also learn about the key differences between how transaction fees are calculated on Moonbeam and Ethereum. ### Key Differences with Ethereum {: #key-differences-with-ethereum} There are some key differences between the transaction fee model on Moonbeam and the one on Ethereum that developers should be mindful of when developing on Moonbeam: - The [dynamic fee mechanism](https://forum.moonbeam.network/t/proposal-status-idea-dynamic-fee-mechanism-for-moonbeam-and-moonriver/241){target=\_blank} resembles that of [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559){target=\_blank} but the implementation is different - The amount of gas used in Moonbeam's transaction fee model is mapped from the transaction's Substrate extrinsic `refTime` component of the transaction weight via a fixed factor of `{{ networks.moonbase.tx_weight_to_gas_ratio }}` and `proofSize` component of the transaction weight via a fixed factor of `{{ xcm.generic_weights.proof_size.weight_per_gas }}`. The transaction weight vector is then multiplied with the unit gas price to calculate the transaction fee. This fee model means it can potentially be significantly cheaper to send transactions such as basic balance transfers via the Ethereum API than the Substrate API. - The EVM is designed to solely have capacity for gas and Moonbeam requires additional metrics outside of gas. In particular, Moonbeam needs the ability to record proof size, which is the amount of storage required on Moonbeam for a relay chain validator to verify a state transition. When the capacity limit for proof size has been reached for the current block, which is 25% of the block limit, an "Out of Gas" error will be thrown. This can happen even if there is remaining *legacy* gas in the gasometer. This additional metric also impacts refunds. Refunds are based on the more consumed resource after the execution. In other words, if more proof size has been consumed proportionally than legacy gas, the refund will be calculated using proof size - Moonbeam has implemented a new mechanism defined in [MBIP-5](https://github.com/moonbeam-foundation/moonbeam/blob/master/MBIPS/MBIP-5.md){target=\_blank} that limits block storage and increases gas usage for transactions that result in an increase in storage ## Overview of MBIP-5 {: #overview-of-mbip-5 } MBIP-5 introduced changes to Moonbeam's fee mechanism that account for storage growth on the network, which deviates from the way Ethereum handles fees. By raising the gas needed to execute transactions that increase chain state and by establishing a block storage limit, it controls storage growth. This impacts contract deployments that add to the chain state, transactions that create new storage entries, and precompiled contract calls that result in the creation of new accounts. The block storage limit prevents transactions in a single block from collectively increasing the storage state by more than the limit. The limit for each network is as follows: === "Moonbeam" ```text {{ networks.moonbeam.mbip_5.block_storage_limit }}KB ``` === "Moonriver" ```text {{ networks.moonriver.mbip_5.block_storage_limit }}KB ``` === "Moonbase Alpha" ```text {{ networks.moonbase.mbip_5.block_storage_limit }}KB ``` To determine the amount of gas for storage in bytes, there is a ratio that is defined as: ```text Ratio = Block Gas Limit / (Block Storage Limit * 1024 Bytes) ``` The block gas limit for each network is as follows: === "Moonbeam" ```text {{ networks.moonbeam.gas_block }} ``` === "Moonriver" ```text {{ networks.moonriver.gas_block }} ``` === "Moonbase Alpha" ```text {{ networks.moonbase.gas_block }} ``` Knowing the block gas and storage limits, the ratio of gas to storage is computed as follows: === "Moonbeam" ```text Ratio = {{ networks.moonbeam.gas_block_numbers_only }} / ({{ networks.moonbeam.mbip_5.block_storage_limit }} * 1024) Ratio = {{ networks.moonbeam.mbip_5.gas_storage_ratio }} ``` === "Moonriver" ```text Ratio = {{ networks.moonriver.gas_block_numbers_only }} / ({{ networks.moonriver.mbip_5.block_storage_limit }} * 1024) Ratio = {{ networks.moonriver.mbip_5.gas_storage_ratio }} ``` === "Moonbase Alpha" ```text Ratio = {{ networks.moonbase.gas_block_numbers_only }} / ({{ networks.moonbase.mbip_5.block_storage_limit }} * 1024) Ratio = {{ networks.moonbase.mbip_5.gas_storage_ratio }} ``` Then, you can take the storage growth in bytes for a given transaction and multiply it by the gas-to-storage growth ratio to determine how many units of gas to add to the transaction. For example, if you execute a transaction that increases the storage by {{ networks.moonbase.mbip_5.example_storage }} bytes, the following calculation is used to determine the units of gas to add: === "Moonbeam" ```text Additional Gas = {{ networks.moonbeam.mbip_5.example_storage }} * {{ networks.moonbeam.mbip_5.gas_storage_ratio }} Additional Gas = {{ networks.moonbeam.mbip_5.example_addtl_gas }} ``` === "Moonriver" ```text Additional Gas = {{ networks.moonriver.mbip_5.example_storage }} * {{ networks.moonriver.mbip_5.gas_storage_ratio }} Additional Gas = {{ networks.moonriver.mbip_5.example_addtl_gas }} ``` === "Moonbase Alpha" ```text Additional Gas = {{ networks.moonbase.mbip_5.example_storage }} * {{ networks.moonbase.mbip_5.gas_storage_ratio }} Additional Gas = {{ networks.moonbase.mbip_5.example_addtl_gas }} ``` To see how this MBIP differentiates Moonbeam from Ethereum firsthand, you can estimate the gas for two different contract interactions on both networks: one that modifies an item in the chain state and one that doesn't. For example, you can use a greeting contract that allows you to store a name and then use the name to say "Hello". ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract SayHello { mapping(address => string) public addressToName; constructor(string memory _name) { addressToName[msg.sender] = _name; } // Store a name associated to the address of the sender function setName(string memory _name) public { addressToName[msg.sender] = _name; } // Use the name in storage associated to the sender function sayHello() external view returns (string memory) { return string(abi.encodePacked("Hello ", addressToName[msg.sender])); } } ``` You can deploy this contract on both Moonriver and Ethereum, or on Moonbeam's TestNet, Moonbase Alpha, and Ethereum's TestNet, Sepolia. The above contract has already been deployed to Moonbase Alpha and Sepolia. You can feel free to access these contracts at the following addresses: === "Moonbase Alpha" ```text 0xDFF8E772A9B212dc4FbA19fa650B440C5c7fd7fd ``` === "Sepolia" ```text 0x8D0C059d191011E90b963156569A8299d7fE777d ``` Next, you can use the `eth_estimateGas` method to check the gas estimate for calling the `setName` and `sayHello` functions on each network. To do so, you'll need the bytecode for each transaction, which includes the function selector, and for the `setName` function, the name to be set. This example bytecode sets the name to "Chloe": === "Set Name" ```text 0xc47f00270000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000543686c6f65000000000000000000000000000000000000000000000000000000 ``` === "Say Hello" ```text 0xef5fb05b ``` Now, you can use the following curl commands on Moonbase Alpha to return the gas estimate: === "Set Name" ```sh curl {{ networks.moonbase.rpc_url }} -H "Content-Type:application/json;charset=utf-8" -d \ '{ "jsonrpc": "2.0", "id": 1, "method": "eth_estimateGas", "params":[{ "to": "0xDFF8E772A9B212dc4FbA19fa650B440C5c7fd7fd", "data": "0xc47f00270000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000543686c6f65000000000000000000000000000000000000000000000000000000" }] }' ``` === "Say Hello" ```sh curl {{ networks.moonbase.rpc_url }} -H "Content-Type:application/json;charset=utf-8" -d \ '{ "jsonrpc": "2.0", "id": 1, "method": "eth_estimateGas", "params":[{ "to": "0xDFF8E772A9B212dc4FbA19fa650B440C5c7fd7fd", "data": "0xef5fb05b" }] }' ``` Then on Sepolia, you can use the same bytecode for the `data` and modify the RPC URL and contract address to target the contract deployed to Sepolia: === "Set Name" ```sh curl https://sepolia.publicgoods.network -H "Content-Type:application/json;charset=utf-8" -d \ '{ "jsonrpc": "2.0", "id": 1, "method": "eth_estimateGas", "params":[{ "to": "0x8D0C059d191011E90b963156569A8299d7fE777d", "data": "0xc47f00270000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000543686c6f65000000000000000000000000000000000000000000000000000000" }] }' ``` === "Say Hello" ```sh curl https://sepolia.publicgoods.network -H "Content-Type:application/json;charset=utf-8" -d \ '{ "jsonrpc": "2.0", "id": 1, "method": "eth_estimateGas", "params":[{ "to": "0x8D0C059d191011E90b963156569A8299d7fE777d", "data": "0xef5fb05b" }] }' ``` At the time of writing, the gas estimates for both networks are as follows: === "Moonbase Alpha" | Method | Gas Estimate | |:----------:|:------------:| | `setName` | 45977 | | `sayHello` | 25938 | === "Sepolia" | Method | Gas Estimate | |:----------:|:------------:| | `setName` | 21520 | | `sayHello` | 21064 | You'll see that on Sepolia, the gas estimates for both calls are very similar, whereas on Moonbase Alpha, there is a noticeable difference between the calls and that the `setName` call, which modifies the storage, uses more gas than the `sayHello` call. ## Ethereum API Transaction Fees {: #ethereum-api-transaction-fees } To calculate the fee incurred on a Moonbeam transaction sent via the Ethereum API, the following formula can be used: === "EIP-1559" ```text GasPrice = BaseFee + MaxPriorityFeePerGas < MaxFeePerGas ? BaseFee + MaxPriorityFeePerGas : MaxFeePerGas; Transaction Fee = (GasPrice * TransactionWeight) / {{ networks.moonbase.tx_weight_to_gas_ratio }} ``` === "Legacy" ```text Transaction Fee = (GasPrice * TransactionWeight) / {{ networks.moonbase.tx_weight_to_gas_ratio }} ``` === "EIP-2930" ```text Transaction Fee = (GasPrice * TransactionWeight) / {{ networks.moonbase.tx_weight_to_gas_ratio }} ``` !!! note EIP-1559 transaction fees on Moonbeam are calculated using the previous block's base fee. The following sections describe in more detail each of the components needed to calculate the transaction fee. ### Base Fee {: #base-fee} The `BaseFee` is the minimum amount charged to send a transaction and is a value set by the network itself. It was introduced in [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559){target=\_blank}. Moonbeam has its own [dynamic fee mechanism](https://forum.moonbeam.network/t/proposal-status-idea-dynamic-fee-mechanism-for-moonbeam-and-moonriver/241){target=\_blank} for calculating the base fee, which is adjusted based on block congestion. As of runtime 2300, the dynamic fee mechanism has been rolled out to all of the Moonbeam-based networks. The minimum gas price for each network is as follows: === "Moonbeam" | Variable | Value | |:-----------------:|:------------------------------------------:| | Minimum Gas Price | {{ networks.moonbeam.min_gas_price }} Gwei | === "Moonriver" | Variable | Value | |:-----------------:|:------------------------------------------:| | Minimum Gas Price | {{ networks.moonriver.min_gas_price }} Gwei | === "Moonbase Alpha" | Variable | Value | |:-----------------:|:------------------------------------------:| | Minimum Gas Price | {{ networks.moonbase.min_gas_price }} Gwei | To calculate the dynamic base fee, the following calculation is used: === "Moonbeam" ```text BaseFee = NextFeeMultiplier * 31250000000 / 10^18 ``` === "Moonriver" ```text BaseFee = NextFeeMultiplier * 312500000 / 10^18 ``` === "Moonbase Alpha" ```text BaseFee = NextFeeMultiplier * 31250000 / 10^18 ``` The value of `NextFeeMultiplier` can be retrieved from the Substrate Sidecar API, via the following endpoint: ```text GET /pallets/transaction-payment/storage/nextFeeMultiplier?at={blockId} ``` The pallets endpoints for Sidecar returns data relevant to a pallet, such as data in a pallet's storage. You can read more about the pallets endpoint in the [official Sidecar documentation](https://paritytech.github.io/substrate-api-sidecar/dist/#operations-tag-pallets){target=\_blank}. The data at hand that's required from storage is the `nextFeeMultiplier`, which can be found in the `transaction-payment` pallet. The stored `nextFeeMultiplier` value can be read directly from the Sidecar storage schema. Read as a JSON object, the relevant nesting structure is as follows: ```text RESPONSE JSON Storage Object: |--at |--hash |--height |--pallet |--palletIndex |--storageItem |--keys |--value ``` The relevant data will be stored in the `value` key of the JSON object. This value is a fixed point data type, hence the real value is found by dividing the `value` by `10^18`. This is why [the calculation of `BaseFee`](#ethereum-api-transaction-fees) includes such an operation. ### GasPrice, MaxFeePerGas, and MaxPriorityFeePerGas {: #gasprice-maxfeepergas-maxpriorityfeepergas } The `GasPrice` is used to specify the gas price of legacy transactions prior to [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559){target=\_blank}. The `MaxFeePerGas` and `MaxPriorityFeePerGas` were both introduced in EIP-1559 alongside the `BaseFee`. The `MaxFeePerGas` defines the maximum fee permitted to be paid per unit of gas and is the sum of the `BaseFee` and the `MaxPriorityFeePerGas`. The `MaxPriorityFeePerGas` is the maximum priority fee configured by the sender of a transaction that is used to incentivize the prioritization of a transaction in a block. Although Moonbeam is Ethereum-compatible, it is also a Substrate-based chain at its core, and priorities work differently in Substrate than in Ethereum. In Substrate, transactions are not prioritized by gas price. To address this, Moonbeam uses a modified prioritization system that reprioritizes Substrate transactions using an Ethereum-first solution. A Substrate transaction still goes through the validity process, where it is assigned transaction tags, longevity, and a priority. The original priority is then overwritten with a new priority based on the transaction's fee per gas, which is derived from the transaction's tip and weight. If the transaction is an Ethereum transaction, the priority is set according to the priority fee. It's important to note that priority is not the sole component responsible for determining the order of transactions in a block. Other components, such as the longevity of a transaction, also play a role in the sorting process. The values of `GasPrice`, `MaxFeePerGas` and `MaxPriorityFeePerGas` for the applicable transaction types can be read from the block JSON object according to the structure described in [the Sidecar API page](/builders/substrate/libraries/sidecar/#evm-fields-mapping-in-block-json-object){target=\_blank}. The data for an Ethereum transaction in a particular block can be extracted from the following block endpoint: ```text GET /blocks/{blockId} ``` The paths to the relevant values have also been truncated and reproduced below: === "EIP1559" | EVM Field | Block JSON Field | |:--------------------:|:----------------------------------------------------------------------------:| | MaxFeePerGas | `extrinsics[extrinsic_number].args.transaction.eip1559.maxFeePerGas` | | MaxPriorityFeePerGas | `extrinsics[extrinsic_number].args.transaction.eip1559.maxPriorityFeePerGas` | === "Legacy" | EVM Field | Block JSON Field | |:---------:|:---------------------------------------------------------------:| | GasPrice | `extrinsics[extrinsic_number].args.transaction.legacy.gasPrice` | === "EIP2930" | EVM Field | Block JSON Field | |:---------:|:----------------------------------------------------------------:| | GasPrice | `extrinsics[extrinsic_number].args.transaction.eip2930.gasPrice` | ### Transaction Weight {: #transaction-weight} `TransactionWeight` is a Substrate mechanism used to measure the execution time a given transaction takes to be executed within a block. A transaction's weight is a vector of two components: `refTime` and `proofSize`. `refTime` refers to the amount of computational time that can be used for execution. `proofSize` refers to the size of the PoV (Proof of Validity) of the Moonbeam block that gets submitted to the Polkadot Relay Chain for validation. Since both `refTime` and `proofSize` are integral components of determining a weight, it is impossible to obtain an accurate weight value with just one of these values. For all transactions types, `TransactionWeight` can be retrieved under the event of the relevant extrinsic where the `method` field is set to: ```text pallet: "system", method: "ExtrinsicSuccess" ``` And then `TransactionWeight` is mapped to the following two fields of the block JSON object. `proofSize` is mapped as follows: ```text extrinsics[extrinsic_number].events[event_number].data[0].weight.proof_size ``` And `refTime` is mapped as follows: ```text extrinsics[extrinsic_number].events[event_number].data[0].weight.ref_time ``` ### Fee History Endpoint {: #eth-feehistory-endpoint } Moonbeam networks implement the [`eth_feeHistory`](https://www.alchemy.com/docs/node/ethereum/ethereum-api-endpoints/eth-fee-history){target_blank} JSON-RPC endpoint as a part of the support for EIP-1559. `eth_feeHistory` returns a collection of historical gas information from which you can reference and calculate what to set for the `MaxFeePerGas` and `MaxPriorityFeePerGas` fields when submitting EIP-1559 transactions. The following curl example will return the gas information of the last 10 blocks starting from the latest block on the respective Moonbeam network using `eth_feeHistory`: === "Moonbeam" ```sh curl --location \ --request POST '{{ networks.moonbeam.rpc_url }}' \ --header 'Content-Type: application/json' \ --data-raw '{ "jsonrpc": "2.0", "id": 1, "method": "eth_feeHistory", "params": ["0xa", "latest"] }' ``` === "Moonriver" ```sh curl --location \ --request POST '{{ networks.moonriver.rpc_url }}' \ --header 'Content-Type: application/json' \ --data-raw '{ "jsonrpc": "2.0", "id": 1, "method": "eth_feeHistory", "params": ["0xa", "latest"] }' ``` === "Moonbase Alpha" ```sh curl --location \ --request POST '{{ networks.moonbase.rpc_url }}' \ --header 'Content-Type: application/json' \ --data-raw '{ "jsonrpc": "2.0", "id": 1, "method": "eth_feeHistory", "params": ["0xa", "latest"] }' ``` === "Moonbeam Dev Node" ```sh curl --location \ --request POST '{{ networks.development.rpc_url }}' \ --header 'Content-Type: application/json' \ --data-raw '{ "jsonrpc": "2.0", "id": 1, "method": "eth_feeHistory", "params": ["0xa", "latest"] }' ``` ### Sample Code for Calculating Transaction Fees {: #sample-code } The following code snippet uses the [Axios HTTP client](https://axios-http.com){target=\_blank} to query the [Sidecar endpoint `/blocks/head`](https://paritytech.github.io/substrate-api-sidecar/dist/#operations-tag-blocks){target=\_blank} for the latest finalized block. It then calculates the transaction fees of all transactions in the block according to the transaction type (for Ethereum API: legacy, EIP-1559 or EIP-2930 standards, and for Substrate API), as well as calculating the total transaction fees in the block. !!! note EIP-1559 transaction fees on Moonbeam are calculated using the previous block's base fee. The following code sample is for demo purposes only and should not be used without modification and further testing in a production environment. You can use the following snippet for any Moonbeam-based network, but you'll need to modify the `baseFee` accordingly. You can refer back to the [Base Fee](#base-fee) section to get the calculation for each network. ```js import axios from 'axios'; // This script calculates the transaction fees of all transactions in a block // according to the transaction type (for Ethereum API: legacy, EIP-1559 or // EIP-2930 standards, and Substrate API) using the dynamic fee mechanism. // It also calculates the total fees in the block // Endpoint to retrieve the latest block const endpointBlock = 'http://127.0.0.1:8080/blocks/head'; // Endpoint to retrieve the latest nextFeeMultiplier const endpointPallet = 'http://127.0.0.1:8080/pallets/transaction-payment/storage/nextFeeMultiplier?at='; // Endpoint to retrieve the node client's information const endpointNodeVersion = 'http://127.0.0.1:8080/node/version'; // Define the minimum base fee for each network const baseFee = { moonbeam: 31250000000n, moonriver: 312500000n, moonbase: 31250000n, }; async function main() { try { // Create a variable to sum the transaction fees in the whole block let totalFees = 0n; // Find which Moonbeam network the Sidecar is pointing to const responseClient = await axios.get(endpointNodeVersion); const network = responseClient.data.clientImplName; // Retrieve the block from the Sidecar endpoint const responseBlock = await axios.get(endpointBlock); // Retrieve the block height of the current block console.log('Block Height: ' + responseBlock.data.number); // Use the previous block's base fee to match the on-chain data // Find the block's nextFeeMultiplier const prevBlock = Number(responseBlock.data.number) - 1; const responsePallet = await axios.get(endpointPallet + prevBlock); // Iterate through all extrinsics in the block responseBlock.data.extrinsics.forEach((extrinsic) => { // Create an object to store transaction information let transactionData = new Object(); // Set the network field transactionData['network'] = network; // Filter for Ethereum Transfers if ( extrinsic.method.pallet === 'ethereum' && extrinsic.method.method === 'transact' ) { // Iterate through the events to get non type specific parameters extrinsic.events.forEach((event) => { if ( event.method.pallet === 'ethereum' && event.method.method === 'Executed' ) { // Get Transaction Hash transactionData['hash'] = event.data[2]; } if ( event.method.pallet === 'system' && event.method.method === 'ExtrinsicSuccess' ) { // Add correction weight if needed to Transaction Weight! transactionData['weight'] = BigInt(event.data[0].weight.refTime); } }); // Get the transaction type and type specific parameters and compute the // transaction fee if (extrinsic.args.transaction.legacy) { transactionData['txType'] = 'legacy'; transactionData['gasPrice'] = BigInt( extrinsic.args.transaction.legacy.gasPrice ); transactionData['txFee'] = (transactionData['gasPrice'] * transactionData['weight']) / 25000n; } else if (extrinsic.args.transaction.eip1559) { transactionData['txType'] = 'eip1599'; transactionData['maxFeePerGas'] = BigInt( extrinsic.args.transaction.eip1559.maxFeePerGas ); transactionData['maxPriorityFeePerGas'] = BigInt( extrinsic.args.transaction.eip1559.maxPriorityFeePerGas ); // Update based on the network you're getting tx fees for transactionData['baseFee'] = (BigInt(responsePallet.data.value) * baseFee.moonbeam) / BigInt('1000000000000000000'); // Gas price dependes on the MaxFeePerGas and MaxPriorityFeePerGas set transactionData['gasPrice'] = transactionData['baseFee'] + transactionData['maxPriorityFeePerGas'] < transactionData['maxFeePerGas'] ? transactionData['baseFee'] + transactionData['maxPriorityFeePerGas'] : transactionData['maxFeePerGas']; transactionData['txFee'] = (transactionData['gasPrice'] * transactionData['weight']) / 25000n; } else if (extrinsic.args.transaction.eip2930) { transactionData['txType'] = 'eip2930'; transactionData['gasPrice'] = BigInt( extrinsic.args.transaction.eip2930.gasPrice ); transactionData['txFee'] = (transactionData['gasPrice'] * transactionData['weight']) / 25000n; } // Increment totalFees totalFees += transactionData['txFee']; // Display the tx information to console console.log(transactionData); } // Filter for Substrate transactions, check if the extrinsic has a // 'TransactionFeePaid' event else { extrinsic.events.forEach((event) => { if ( event.method.pallet === 'transactionPayment' && event.method.method === 'TransactionFeePaid' ) { transactionData['txType'] = 'substrate'; transactionData['txFee'] = event.data[1]; transactionData['tip'] = event.data[1]; } if ( event.method.pallet === 'system' && event.method.method === 'ExtrinsicSuccess' ) { transactionData['weight'] = event.data[0].weight.refTime; } }); } }); // Output the total amount of fees in the block console.log('Total fees in block: ' + totalFees); } catch (err) { console.log(err); } } main(); ``` ## Substrate API Transaction Fees {: #substrate-api-transaction-fees } This section of the guide assumes you are interacting with Moonbeam blocks via [the Substrate API Sidecar](/builders/substrate/libraries/sidecar/){target=\_blank} service. There are other ways of interacting with Moonbeam blocks, such as using [the Polkadot.js API library](/builders/substrate/libraries/polkadot-js-api/){target=\_blank}. The logic is identical once the blocks are retrieved. You can reference the [Substrate API Sidecar page](/builders/substrate/libraries/sidecar/){target=\_blank} for information on installing and running your own Sidecar service instance, as well as more details on how to decode Sidecar blocks for Moonbeam transactions. **Note that the information in this section assumes you are running version {{ networks.moonbase.substrate_api_sidecar.stable_version }} of the Substrate Sidecar REST API.** All the information around fee data for transactions sent via the Substrate API can be extracted from the following block endpoint: ```text GET /blocks/{blockId} ``` The block endpoints will return data relevant to one or more blocks. You can read more about the block endpoints on the [official Sidecar documentation](https://paritytech.github.io/substrate-api-sidecar/dist/#operations-tag-blocks){target=\_blank}. Read as a JSON object, the relevant nesting structure is as follows: ```text RESPONSE JSON Block Object: ... |--number |--extrinsics |--{extrinsic_number} |--method |--signature |--nonce |--args |--tip |--hash |--info |--era |--events |--{event_number} |--method |--pallet: "transactionPayment" |--method: "TransactionFeePaid" |--data |--0 |--1 |--2 ... ``` The object mappings are summarized as follows: | Tx Information | Block JSON Field | |:------------------:|:-----------------------------------------------------------:| | Fee paying account | `extrinsics[extrinsic_number].events[event_number].data[0]` | | Total fees paid | `extrinsics[extrinsic_number].events[event_number].data[1]` | | Tip | `extrinsics[extrinsic_number].events[event_number].data[2]` | The transaction fee related information can be retrieved under the event of the relevant extrinsic where the `method` field is set to: ```text pallet: "transactionPayment", method: "TransactionFeePaid" ``` And then the total transaction fee paid for this extrinsic is mapped to the following field of the block JSON object: ```text extrinsics[extrinsic_number].events[event_number].data[1] ```
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/core-concepts/unified-accounts/ --- BEGIN CONTENT --- --- title: Unified Accounts description: Moonbeam replaced the default Substrate account system with native support for the Ethereum-based H160 accounts and ECDSA keys. Find out more information! categories: Basics --- # Unified Accounts ## Introduction {: #introduction } As Moonbeam is designed to be an Ethereum-compatible parachain on Polkadot, the underlying account system replaces the default Substrate-style accounts and keys with Ethereum-style accounts and keys. As a result, you can interact with your Moonbeam account using [MetaMask](/tokens/connect/metamask/){target=\_blank} and Ethereum tools you may already be familiar with, such as [Remix](/builders/ethereum/dev-env/remix/){target=\_blank} and [Hardhat](/builders/ethereum/dev-env/hardhat/){target=\_blank}. You can also interact with your Moonbeam account using Polkadot.js Apps as it natively supports H160 addresses and ECDSA keys. For more information on this integration, you can check out the [Interacting with Moonbeam Using Polkadot.js Apps](/tokens/connect/polkadotjs/){target=\_blank} guide. ## Substrate EVM Compatible Blockchain {: #substrate-evm-compatible-blockchain } Any parachain in the Polkadot ecosystem can offer a full EVM implementation, which provides the possibility of executing Solidity-based smart contracts with minimal to no changes. Substrate makes this integration possible - just plug the [EVM pallet](https://docs.rs/pallet-evm/2.0.1/pallet_evm){target=\_blank} into your runtime for EVM support, and the [Ethereum Pallet with Frontier](https://github.com/polkadot-evm/frontier){target=\_blank} to have Ethereum RPC compatibility. The availability of these open-source modules that Moonbeam has developed with Parity has led multiple parachains to offer Ethereum compatibility on their chains. But there is an important catch. With the configuration described above, a user, for example, Alice, can have an Ethereum-style address (H160 format), which is 40+2 hex-characters long, in a Substrate based chain. This address matches a private key, which can be used to sign transactions in the Ethereum side of the chain. Furthermore, the address is mapped into a storage slot inside the Substrate Balance pallet to a Substrate-style address (H256 format). However, Alice only knows the private key of the H160 address, and not of the mapped version. Therefore, she is unable to send transactions with her H256 address and is limited only to do read-only operations through Substrate’s API. As a consequence, Alice needs another H256 address matching a different private key to be able to operate in the Substrate side of the chain, which include, among others, staking, balances, and governance. The following diagram illustrates this configuration. ![Old account system diagram](/images/learn/core-concepts/unified-accounts/unified-accounts-1.webp) This can creates friction and a poor user experience for Alice. First, she has to move tokens to her H160 mapped H256 address to be able to make transactions and deploy contracts through the EVM. Second, she also needs to hold a balance in her other H256 address (which she has a different private key for) to use Substrate-based features. So in short, Alice needs a minimum of two private keys to have the best of both worlds. ## Moonbeam Unified Accounts {: #moonbeam-unified-accounts } Moonbeam’s focus is to create a fully Ethereum-compatible environment on Polkadot with the best user experience possible. This extends beyond the base Ethereum feature set, with additional features such as on-chain governance, staking, and cross-chain integrations. With unified accounts, a user, for example, Bob, will only need a single H160 address, with its corresponding private key, to do everything we mentioned above, including both EVM and Substrate functions. The diagram for this new configuration looks as follows. ![New account system diagram](/images/learn/core-concepts/unified-accounts/unified-accounts-2.webp) That is it, Bob only holds one private key that matches one address. He does not need to move balances between 2 different accounts and is able to access all the features with a single account and private key. We have standardized this single account to conform to the Ethereum-style H160 address and ECDSA key standards. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/dapp-directory/ --- BEGIN CONTENT --- --- title: List your Dapp on the Moonbeam DApp Directory description: Follow this tutorial to learn how to list your Moonbeam or Moonriver project or update a current listing on the Moonbeam Foundation DApp Directory. dropdown_description: Explore the DApp Directory and listing process categories: Reference --- # How to List your Project on the Moonbeam DApp Directory ## Introduction to the Moonbeam DApp Directory {: #introduction-to-state-of-the-dapps } The Moonbeam ecosystem comprises two distinct production networks: Moonbeam and Moonriver. Each network has its own dedicated [DApp Directory](https://apps.moonbeam.network/moonbeam/app-dir){target=\_blank}, maintained by the Moonbeam Foundation. These directories categorize projects spanning from DeFi to NFTs to gaming, providing users with comprehensive access to diverse applications. You'll supply core project details like name, description, and relevant links when adding your project. Depending on your project type, you may include additional data such as on-chain stats and token information. Despite the distinction between the Moonbeam and Moonriver DApp directories, the submission process remains the same. To list your project on the DApp Directory, you must submit a pull request to the [Moonbeam Foundation's App Directory Data repository on GitHub](https://github.com/moonbeam-foundation/app-directory-data){target=\_blank}. This guide outlines the necessary data and formatting specifics for your submission. ![The Moonbeam DApp Directory home page](/images/learn/dapps-list/directory-1.webp) ## Overview of the Project Data {: #overview-project-data } There are four main sources of data that are used for a project's listing in the Moonbeam DApp Directory: - **Core Project Data** - core project data such as descriptions, logos, and screenshots. This data also includes IDs used to query data from external platforms - **Active Users and Transaction Volume** - on-chain data based on smart contract activity for all of the contracts associated with the project. Data is discovered via the use of contract labeling in Moonscan, which is then indexed by Web3Go and consumed by the DApp Directory - **TVL Data** - TVL data for the protocol, sourced from the project's listing on DefiLlama - **Project Token Information** - token information, which is sourced from the project's listing on CoinGecko ## Prerequisites for Using External Data Sources {: #configuring-external-data-sources } Before pulling data from the mentioned sources, certain prerequisites must be fulfilled. However, it's worth noting that these steps may not apply to all project types. For instance, in the case of wallets, where there are no smart contracts, the DApp Directory is currently unable to display user and transaction activity data. ### Configure the Data Source for Active Users and Transaction Volume {: #configure-active-users } For projects that have smart contracts deployed on Moonbeam or Moonriver, it is important that those contracts can be linked to the DApp Directory project data. The end-to-end flow for linking smart contract activity to the DApp Directory is as follows: 1. The smart contract owner fills in the [form to label contracts on Moonscan](https://moonscan.io/contactus?id=5){target=\_blank} 2. The contracts become labeled in Moonscan 3. Periodically, the entire list of labeled contracts is exported and transmitted to Web3Go to be ingested 4. Every hour, Web3Go loads smart contract activity within Moonbeam and Moonriver and runs a job to index this data by the labels To get your project's smart contracts properly labeled on [Moonscan](https://moonscan.io){target=\_blank}, please refer to Web3Go's documentation on the [Labeling Structure](https://dinlol.gitbook.io/moonscan-smart-contract-label-for-projects/labeling-structure){target=\_blank} and [How to Submit Contract Information](https://dinlol.gitbook.io/moonscan-smart-contract-label-for-projects/how-to-submit-contract-information){target=\_blank} on Moonscan. Once you've labeled your smart contracts and are ready to submit your project to the DApp Directory, configuring the Directory to utilize your smart contract data becomes straightforward. You'll only need the **Project** component of your labeled contracts. Consider the following example project with two smart contracts: a Comptroller and a Router recently updated to a new version. | Project | Contract Name | Contract Version | Resulting Label | |:----------:|:-------------:|:----------------:|:--------------------------:| | My Project | Comptroller | V1 | My Project: Comptroller V1 | | My Project | Router | V2 | My Project: Router V2 | To submit your project to the Moonbeam DApp Directory, ensure you have your **Project** name ready, identified here as `My Project`. If you're ready to add your project to the DApp Directory, skip to the [How to Submit Your Project Listing](#how-to-submit-your-project-listing) section. ### Configure the Data Source for TVL {: #configure-tvl } If the project represents a DeFi protocol with TVL (whereby value is locked in the protocol's smart contract), it is possible to display TVL in the Moonbeam DApp Directory. TVL data is pulled from [DefiLlama](https://defillama.com){target=\_blank}, so you must list your project there. To get your project listed, please refer to DefiLlama's documentation on [How to list a DeFi project](https://docs.llama.fi/list-your-project/submit-a-project){target=\_blank}. After listing your project, you can easily configure the DApp Directory to pull data from DefiLlama. To do so, you'll need the DefiLlama identifier, which you can find in the URL for your protocol's page. For example, the URL for Moonwell's page is `https://defillama.com/protocol/moonwell`, so the identifier is `moonwell`. If you have the identifier and are ready to submit your project to the Moonbeam DApp Directory, skip to the [How to Submit Your Project Listing](#how-to-submit-your-project-listing) section. ### Configure the Data Source for Project Token Information {: #project-token-information } If a project has a token, it is possible to display the name of the token, current price, and contract in the DApp Directory. However, the data is pulled from [CoinGecko](https://www.coingecko.com){target=\_blank}, so the project's token must be listed there. If your token is not listed there, you can complete [CoinGecko's Request Form](https://support.coingecko.com/hc/en-us/requests/new){target=\_blank} to initiate the listing process. Assuming your project's token is listed there, you must obtain the CoinGecko **API ID** value. You can find the **API ID** value in the **Information** section of the token's page on CoinGecko. For example, the **API ID** on [Moonwell's token page](https://www.coingecko.com/en/coins/moonwell){target=\_blank} is `moonwell-artemis`. If you have the CoinGecko ID and are ready to submit your project to the Moonbeam DApp Directory, you can continue to the next section. ## How to Submit Your Project Listing {: #how-to-submit-your-project-listing } As mentioned, you must submit a pull request to the Moonbeam Foundation's GitHub repository that holds the DApp Directory's data. Before getting started, it's worth noting that to expedite the review process, the GitHub user who submits the pull request is recommended to be a major contributor to the project's GitHub so that the Moonbeam Foundation can quickly verify that they represent the project. You can check out the [Review Process](#review-process) section for more information. To begin, you have two options for adding your project information to the [`app-directory-data` repository on GitHub](https://github.com/moonbeam-foundation/app-directory-data){targe\_blank}. You can utilize [GitHub's browser-based editor](https://github.dev/moonbeam-foundation/app-directory-data){target=\_blank}, which offers a user-friendly interface. ![The app-directory-data repository loaded on GitHub's browser-based editor](/images/learn/dapps-list/directory-2.webp) Or you can clone the repository locally and make modifications using your preferred code editor, in which you can use the following command to clone the repository: ```bash git clone https://github.com/moonbeam-foundation/app-directory-data.git ``` Once you've cloned the project, you can create a new branch to which you will add all of your changes. To do this on the browser-based editor, take the following steps: 1. Click on the current branch name in the bottom left corner 2. A menu will appear at the top of the page. Enter the name of your branch 3. Click **Create new branch...** ![Create a new branch on GitHub's browser-based editor](/images/learn/dapps-list/directory-3.webp) The page will reload, and your branch name will now be displayed in the bottom left corner. ### Projects with Deployments on Moonbeam and Moonriver {: #projects-with-deployments } If a project is deployed to both Moonbeam and Moonriver, there are two different options available: - Create a separate project structure for each deployment - Use a single project structure and modify the project data file for both projects Separate project structures should be used if: - The two deployments have distinct representations in DefiLlama (i.e., two distinct identifiers) - The project has two different tokens, one native to Moonbeam and one native to Moonriver Otherwise, either option may be used. ### Set Up the Folder Structure for Your Project {: #set-up-the-file-structure } All configurations for each project listed in the DApp Directory are stored in the `projects` folder. To get started, you must have a name that uniquely and properly identifies your project. Using your project name, you can take the following steps: 1. Create a new directory for your project using your unique project name 2. In your project directory, you'll need to create: 1. A project data file is a JSON file that defines all your project data and contains references to the images stored in the `logos` and `screenshots` folders. The list of fields you can use to define your data, with descriptions, is outlined in the next section. The file must be named using your unique project name 2. A `logos` folder where your project logo images are stored 3. (Optional) A `screenshots` folder where screenshots for the project are stored ??? code "Example folder structure" ```text my-project ├── my-project.json ├── logos │ ├── my-project-logo-small.jpeg │ └── my-project-logo-full.jpeg └── screenshots ├── my-project-screenshot1-small.jpeg ├── my-project-screenshot1-full.jpeg ├── my-project-screenshot2-small.jpeg └── my-project-screenshot2-full.jpeg ``` ![The file structure displayed on GitHub's browser-based editor](/images/learn/dapps-list/directory-4.webp) With the foundational file structure in place, you're ready to populate the necessary information for your project submission. ### Add Information to the Project Data File {: #add-information } Your project's data file is where you'll add all the information for your project. The file permits the following top-level properties: |
Property
| Type | Description | |:--------------------------------------:|:-----------------------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| | `id` | String | Unique identifier for the dApp in the Moonbeam DApp Directory. It should be a unique, human-readable string representing this project. E.g., `my-project` | | `slug` | String | Identifier used in certain third-party sources. In particular, if the project is listed in DefiLlama, this value should be set to the DefiLlama identifier. See the [Configure the Data Source for TVL](#configure-tvl) section for more information | | `name` | String | The project name as it will appear in the DApp Directory. E.g., `My Project` | | `category` | String | The category the project should be associated with. A project can only have one category, and it corresponds to the category list in the left-hand nav of the DApp Directory. See the [Category and Tags](#category-and-tags) section for the accepted list of values | | `coinGeckoId` | String | If the project has a token listed on CoinGecko, this property should have the **API ID** value corresponding to the given token. See the [Configure the Data Source for Project Token Information](#project-token-information) section for more information | | `chains` | Array of Strings | List of Moonbeam ecosystem chains on which the project is deployed. Valid values are currently `moonbeam` and `moonriver` | | `web3goIDs` | Array of Strings | List of Web3Go identifiers for a given dApp. The identifiers should correspond to the **Project** component of the smart contract labels set up in Moonscan. Generally, there should only be one value in the array. See the [Configure the Data Source for Active Users and Transaction Volume](#configure-active-users) section for more information | | `logo` | Map of Strings to JSON objects | Map of logo image files associated with this project and stored in the `logos` directory. See the [Logos](#logos) section for more information | | `shortDescription` | String | A short description of the project used in the display card when browsing dapps in the directory. This should be kept to under 80 characters | | `description` | String | A longer description used in the project detail page. Markdown or similar formatting cannot be used. Line breaks can be used using `\r\n`. The text should be limited to a few paragraphs | | `tags` | Array of Strings | A list of applicable [tags](#category-and-tags) for this project. Tag values will show up in the project details. See the [Category and Tags](#category-and-tags) section for the accepted list of values | | `contracts` | Array of contract JSON objects | List of contracts for the project. Currently, this is used only for token contracts. The list of smart contracts which make up the protocol is externally sourced from Moonscan. See the [Contracts](#contracts) section for more information | | `urls` | Map of Strings (names) to Strings (URLs) | Mapping of URLs for websites and socials associated with the project. See the [URLs](#urls) section for the accepted list of properties | | `screenshots` | Array of Maps of Strings (size) to image JSON objects | List of screenshot image files associated with this project and stored in the `screenshots` directory. See the [Screenshots](#screenshots) section for more information | | `projectCreationDate` | int | The date the project was created. Used for sorting purposes in the DApp Directory | ??? code "Example project data file" ```json { "id": "moonwell", "slug": "moonwell", "name": "Moonwell", "category": "lending", "coinGeckoId": "moonwell-artemis", "chains": [ "moonbeam" ], "web3goIDs": [ "Moonwell Artemis" ], "logo": { "small": { "fileName": "moonwell-logo-small.jpeg", "width": 40, "height": 40, "mimeType": "image/jpeg" }, "large": { "fileName": "moonwell-logo-large.jpeg", "width": 400, "height": 400, "mimeType": "image/jpeg" }, "full": { "fileName": "moonwell-logo-full.jpeg", "width": 3000, "height": 3000, "mimeType": "image/jpeg" } }, "shortDescription": "Lending, borrowing, and DeFi protocol built on Moonbeam and Moonriver", "description": "Moonwell is an open lending, borrowing, and decentralized finance protocol built on Moonbeam and Moonriver. Moonwell’s composable design can accommodate a full range of DeFi applications in the greater Polkadot and Kusama (DotSama) ecosystem.\r\n\r\nOur first deployment will be on Kusama’s Moonriver, the sister network of Polkadot’s Moonbeam. Moonriver is where new products are expected to be incubated and developed prior to being deployed on Moonbeam.", "tags": [ "Lending", "DeFi" ], "contracts": [ { "contract": "0x511ab53f793683763e5a8829738301368a2411e3", "chain": "moonbeam", "name": "WELL Token" } ], "urls": { "website": "https://moonwell.fi/", "try": "https://moonwell.fi/", "twitter": "https://twitter.com/MoonwellDeFi", "medium": "https://moonwell.medium.com/", "telegram": "https://t.me/moonwellfichat", "github": "https://github.com/moonwell-open-source", "discord": "https://discord.gg/moonwellfi" }, "screenshots": [ { "small": { "fileName": "moonwell-screenshot-small1.png", "width": 429, "height": 200, "mimeType": "image/png" }, "full": { "fileName": "moonwell-screenshot-full1.png", "width": 514, "height": 300, "mimeType": "image/png" } }, { "small": { "fileName": "moonwell-screenshot-small2.png", "width": 429, "height": 200, "mimeType": "image/png" }, "full": { "fileName": "moonwell-screenshot-full2.png", "width": 1716, "height": 800, "mimeType": "image/png" } }, { "small": { "fileName": "moonwell-screenshot-small3.png", "width": 429, "height": 200, "mimeType": "image/png" }, "full": { "fileName": "moonwell-screenshot-full3.png", "width": 1054, "height": 637, "mimeType": "image/png" } }, { "small": { "fileName": "moonwell-screenshot-small4.png", "width": 429, "height": 200, "mimeType": "image/png" }, "full": { "fileName": "moonwell-screenshot-full4.png", "width": 1365, "height": 436, "mimeType": "image/png" } } ], "projectCreationDate": 1644828523000 } ``` #### Category and Tags {: #category-and-tags } A category is the primary classification for a project. A project can be categorized under only one category, but it can have multiple tags. Ensure you carefully select the most applicable category for your project to ensure it is easily found. Any secondary classifications can be included as a tag. The currently supported values for `category` are: ```text - Bridges - DAO - DEX - DeFi - Gaming - Lending - NFTs - Other - Social - Wallets ``` The currently supported values for `tag` are: ```text - Bridges - DAO - DEX - DeFi - DePIN - Developer Tools - Explorers - Files - GLMR Grants - Gaming - Infrastructure - IoT - Lending - MOVR Grants - Messaging - NFT - NFT Marketplaces - On-ramp - Other - Social - Tool - VPN - Wallets - ZeroTrust ``` #### URLs {: #urls } The `urls` property name/value pairs are used so a project can provide links to their website, socials, etc. The following table lists the supported `urls` properties: | Property Name | Description | Example | |:-------------:|:------------------------------------------------------------------------------------------------------------------:|:-----------------------------------------------:| | `website` | The main website for the project | https://moonbeam.network/ | | `try` | URL a user should visit if they want to try out the dApp. Typically, this page will have a link to launch the dApp | https://moonbeam.network/ | | `twitter` | The project's Twitter profile | https://twitter.com/MoonbeamNetwork | | `medium` | The project's Medium site | https://medium.com/moonbeam-network | | `telegram` | The project's Telegram | https://t.me/Moonbeam_Official | | `github` | The project's GitHub repository | https://github.com/moonbeam-foundation/moonbeam | | `discord` | The project's Discord | https://discord.com/invite/PfpUATX | The format of the property name/value pairs should follow the JSON standard, for example: ```json "urls": { "website": "https://moonbeam.network/", "try": "https://docs.moonbeam.network/", "twitter": "https://twitter.com/MoonbeamNetwork" } ``` #### Logos {: #logos } The `logos` property of the main project data file is a map of image sizes (i.e., `small`, `large`, `full`) to corresponding image JSON objects. The image JSON object contains the display properties for the given image. The following table lists the properties of the image JSON object: | Property | Type | Description | |:----------:|:------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------:| | `fileName` | String | The name of the image file (unqualified) stored in the `logos` directory | | `width` | int | The width of the logo image in pixels | | `height` | int | The height of the logo image in pixels | | `mimeType` | String | The standard [MIME type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/MIME_types){target=\_blank} of the file. E.g., `"image/jpeg"` | Currently, only the `small` size is utilized, and the dimensions for small logos should be 40x40 pixels. Here is an example showing the structure of the `logo` property that supplies `small` and `full` logos: ```json "logo": { "small": { "fileName": "my-project-logo-small.jpeg", "width": 40, "height": 40, "mimeType": "image/jpeg" }, "full": { "fileName": "my-project-logo-full.jpeg", "width": 3000, "height": 3000, "mimeType": "image/jpeg" } } ``` #### Screenshots {: #screenshots } The `screenshots` property of the main project data file is an array of maps. Each map in the array is for a specific screenshot. However, different-sized images for each screenshot should be supplied so that different sizes can be used in different contexts (e.g., thumbnails vs full-sized images). Thus, for each screenshot, there is a map of image sizes (i.e., `small`, `large`, `full`) to corresponding image JSON objects. The image JSON object contains the display properties for the given image. The following table lists the properties of the image JSON object: | Property | Type | Description | |:----------:|:------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------:| | `fileName` | String | The name of the image file (unqualified) stored in the `screenshots` directory | | `width` | int | The width of the logo image in pixels | | `height` | int | The height of the logo image in pixels | | `mimeType` | String | The standard [MIME type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/MIME_types){target=\_blank} of the file. E.g., `"image/jpeg"` | Here is an example showing the structure of the `screenshot` property for two screenshots (`screenshot1` and `screenshot2`): ```json "screenshots": [ { "small": { "fileName": "my-project-screenshot1-small.png", "width": 429, "height": 200, "mimeType": "image/png" }, "full": { "fileName": "my-project-screenshot1-full.png", "width": 514, "height": 300, "mimeType": "image/png" } }, { "small": { "fileName": "my-project-screenshot2-small.png", "width": 429, "height": 200, "mimeType": "image/png" }, "full": { "fileName": "my-project-screenshot2-full.png", "width": 1716, "height": 800, "mimeType": "image/png" } } ] ``` #### Contracts {: #contracts } A list of contracts for the project. Currently, this is used only for token contracts. The smart contracts that make up the protocol are sourced from [Moonscan](https://moonscan.io){target=\_blank} based on tagging, so they do not need to be listed here. If you have not properly labeled your contracts or are unsure if they are labeled according to the Moonbeam community standard, please refer to the [Configure the Data Source for Active Users and Transaction Volume](#configure-active-users) section. The following table lists the properties found in the contract JSON object: | Property | Type | Description | |:----------:|:------:|:-----------------------------------------------------------------------------:| | `contract` | String | The address for the smart contract | | `chain` | String | The chain on which the contract is deployed (i.e., `moonbeam` or `moonriver`) | | `name` | String | The name of the contract | Here is a `contracts` array with a single smart contract for the WGLMR token: ```json "contracts": [ { "contract": "0xAcc15dC74880C9944775448304B263D191c6077F", "chain": "moonbeam", "name": "Wrapped GLMR Token" } ] ``` ### Submit a Pull Request {: #submit-a-pull-request } After you've populated the project data file and added your logos and screenshots, you should be ready to submit your pull request. ![All of the project files added on GitHub's browser-based editor](/images/learn/dapps-list/directory-5.webp) From the web-based editor, take the following steps to commit your changes to the `app-directory-data` repository: 1. Click on the **Source Control** tab, which should show you how many pages have been added or changed 2. Review the files under the **Changes** section. Click the **+** button next to **Changes**, or as you review each file, click the **+** button next to the file name to add them to the list of **Staged Changes** ![Staging the changed files on GitHub's browser-based editor](/images/learn/dapps-list/directory-6.webp) All of your files should now be under the **Staged Changes** section. All you have to commit and push the changes are: 1. Enter a descriptive commit message, such as "Add My Project", making sure to use your actual project name 2. Click **Commit & Push** ![Committing the staged files on GitHub's browser-based editor](/images/learn/dapps-list/directory-7.webp) Now that you've committed the changes, you'll need to head over to the [`app-directory-data` repository](https://github.com/moonbeam-foundation/app-directory-data){target=\_blank} and open a pull request against the `develop` branch: 1. At the top of the repository page, click **Compare and Pull** button displayed on the banner, or 2. If the banner is not there anymore, you'll need to select your branch from the branches dropdown 3. Click the **Contribute** dropdown 4. Click the **Open pull request** button ![The main page of the app-directory-data repository on GitHub](/images/learn/dapps-list/directory-8.webp) You'll be taken to the **Comparing changes** page, where you'll need to: 1. Make sure that you are merging your branch into the `develop` branch, which is the **base** branch 2. Add a title 3. Add a description of the changes 4. Click **Create pull request** ![Submit a pull request on the Comparing changes page of the app-directory-data repository on GitHub](/images/learn/dapps-list/directory-9.webp) ### The Review Process {: #review-process } Submitted pull requests will be reviewed bi-weekly by the Moonbeam Foundation. During the review, and especially for new projects, the Foundation may have to verify that the GitHub user who created the pull request is a contributor and/or represents the specific project. One way projects can expedite this process is if the submitter's GitHub account is also a major contributor to the project itself on GitHub. Alternatively, teams should leave a note in the pull request comments indicating how we can get in touch with project team members to verify. A comment will be added to the pull request if any changes are requested. After your pull request has been approved, it will be merged, and your project will be added to the Moonbeam DApp Directory! ## How to Update Your Project Listing {: #how-to-update-your-project-listing } As your project evolves, you may need to update your project's listing or images related to your listing. You can create a new branch for your changes, find and modify your existing project's data from the root `projects` directory, and make the desired changes. If you are no longer using a logo or screenshot, please remember to remove it from the `logos` or `screenshots` directory. Once your changes have been made, you must follow the same instructions in the [Submit a Pull Request](#submit-a-pull-request) section so the changes can be [reviewed](#review-process) by the Moonbeam Foundation. Please note that pull requests are reviewed on a bi-weekly basis, so if the update is urgent, you can create a [forum post](https://forum.moonbeam.network){target=\_blank} asking for assistance. ## DApp Directory API {: #dapp-directory-api } The DApp Directory also features a queryable API that you can use to integrate data from Moonbeam's DApp Directory into your application. The API is public and currently does not require authentication. The base URL for the API is as follows: ```bash https://apps.moonbeam.network/api/ds/v1/app-dir/ ``` ### Query a Project {: #query-a-project} You can retrieve all the information for a particular project by appending `/projects/INSERT_PROJECT_NAME` to the base URL. If you need clarification on the project name, you can omit the project name as shown below to retrieve data for every listed project and find the project in the response. ```bash https://apps.moonbeam.network/api/ds/v1/app-dir/projects ``` Here's an example of querying the API for StellaSwap, which returns the project description, social media information, user counts, relevant smart contract addresses, market data, images, and more. ```bash https://apps.moonbeam.network/api/ds/v1/app-dir/projects/stellaswap ``` You can visit the query URL directory in the browser, using a tool like Postman, or directly from the command line with Curl as follows: ```bash curl -H "Content-Type: application/json" -X GET 'https://apps.moonbeam.network/api/ds/v1/app-dir/projects/stellaswap' ``` ??? code "API Response to Querying StellaSwap" ```json { "project":{ "currentTx":{ "moonbeam":2883079 }, "web3goIDs":[ "StellaSwap" ], "name":"StellaSwap", "currentTVL":{ "moonbeam":5046832.23328 }, "currentUsers":{ "moonbeam":52455 }, "coinGeckoId":"stellaswap", "shortDescription":"The leading DEX and DeFi gateway on Moonbeam", "id":"stellaswap", "featured":true, "tags":[ "DEX", "DeFi" ], "tvlChange7d":{ "moonbeam":-1.61482567543498 }, "urls":{ "telegram":"https://t.me/stellaswap", "website":"https://stellaswap.com/", "try":"https://stellaswap.com/", "twitter":"https://twitter.com/StellaSwap", "github":"https://github.com/stellaswap", "medium":"https://stellaswap.medium.com/" }, "web3goContracts":[ { "name":"StellaSwap: stDOT Oracle Master", "chain":"moonbeam", "contract":"0x3b23f0675ffc45153eca239664ccaefc5e816b9c" }, { "name":"StellaSwap: stDOT Token", "chain":"moonbeam", "contract":"0xbc7e02c4178a7df7d3e564323a5c359dc96c4db4" }, { "name":"StellaSwap: stDOT Controller", "chain":"moonbeam", "contract":"0x002d34d6a1b4a8e665fec43fd5d923f4d7cd254f" }, { "name":"StellaSwap: stDOT Proxy Admin", "chain":"moonbeam", "contract":"0xe8a5c0039226269313c89c093a6c3524c4d39fa4" }, { "name":"StellaSwap: madUSDC GLMR V2", "chain":"moonbeam", "contract":"0x2ad0e92461df950e2b1c72e2f7a865c81eaa3ce6" }, { "name":"StellaSwap: Dual ETH - GLMR Rewarder V1", "chain":"moonbeam", "contract":"0x2ba130297d1966e077c2fb5e4b434e8802925277" }, { "name":"StellaSwap: BCMC Rewarder V1", "chain":"moonbeam", "contract":"0x18e75887aa81e113636e18d5a78e3ff93787ec88" }, { "name":"StellaSwap: Pulsar Position Manager V1", "chain":"moonbeam", "contract":"0x1ff2adaa387dd27c22b31086e658108588eda03a" }, { "name":"StellaSwap: DualETH Pool LP Token V1", "chain":"moonbeam", "contract":"0xa3ee3a0a36dc915fdc93062e4b386df37d00217e" }, { "name":"StellaSwap: Interlay Rewarder V1", "chain":"moonbeam", "contract":"0x3a7572220afaddc31a72a520642111776d92b2d2" }, { "name":"StellaSwap: Router V1", "chain":"moonbeam", "contract":"0xd0a01ec574d1fc6652edf79cb2f880fd47d34ab1" }, { "name":"StellaSwap: xStella - GLMR Rewarder 2nd V1", "chain":"moonbeam", "contract":"0xb4dba7fe6fcc613963d64204fcf789e9e376679a" }, { "name":"StellaSwap: GLMR Rewarder First V1", "chain":"moonbeam", "contract":"0x69f9d134991e141c4244f397514ba05d67861cc0" }, { "name":"StellaSwap: CELER Rewarder 0 V1", "chain":"moonbeam", "contract":"0xbebd88782a1145b71df3f4986ef7686154ce01d9" }, { "name":"StellaSwap: MATICILO V1", "chain":"moonbeam", "contract":"0xfffa340944ff32f50c7935e2b5d22a7c3393b313" }, { "name":"StellaSwap: ETHmad - GLMR V1", "chain":"moonbeam", "contract":"0x9fe074a56ffa7f4079c6190be6e8452911b7e349" }, { "name":"StellaSwap: STELLA Token", "chain":"moonbeam", "contract":"0x0e358838ce72d5e61e0018a2ffac4bec5f4c88d2" }, { "name":"StellaSwap: SFL - 4pool Wormhole V1", "chain":"moonbeam", "contract":"0xb1bc9f56103175193519ae1540a0a4572b1566f6" }, { "name":"StellaSwap: BICO Trusted Forwarder V1", "chain":"moonbeam", "contract":"0x3d08ce1f9609bb02f47192ff620634d9eb0e7b56" }, { "name":"StellaSwap: Gass Refund V1", "chain":"moonbeam", "contract":"0xee42d4861b56b32776e6fe9a2fe122af0e3f4a33" }, { "name":"StellaSwap: xcDOT - GLMR V1", "chain":"moonbeam", "contract":"0xe76215efea540ea87a2e1a4bf63b1af6942481f3" }, { "name":"StellaSwap: 4pool LP V1", "chain":"moonbeam", "contract":"0xda782836b65edc4e6811c7702c5e21786203ba9d" }, { "name":"StellaSwap: SFL LP V1", "chain":"moonbeam", "contract":"0xa0aa99f71033378864ed6e499eb03612264e319a" }, { "name":"StellaSwap: SFL - 4pool V1", "chain":"moonbeam", "contract":"0x422b5b7a15fb12c518aa29f9def640b4773427f8" }, { "name":"StellaSwap: Acala - GLMR Rewarder V1", "chain":"moonbeam", "contract":"0x9de8171bebfa577d6663b594c60841fe096eff97" }, { "name":"StellaSwap: Zap V1", "chain":"moonbeam", "contract":"0x01834cf26717f0351d9762cc9cca7dc059d140df" }, { "name":"StellaSwap: GLMR Rewarder for UST - GLMR V1", "chain":"moonbeam", "contract":"0xc85ddcff71200f9673137e2f93ce504bdbf7db4e" }, { "name":"StellaSwap: xStella Token", "chain":"moonbeam", "contract":"0x06a3b410b681c82417a906993acefb91bab6a080" }, { "name":"StellaSwap: ETHmad - GLMR V2", "chain":"moonbeam", "contract":"0xa6ec79c97e533e7bddb00898e22c6908742e039b" }, { "name":"StellaSwap: WBTC - USDT Contract V1", "chain":"moonbeam", "contract":"0xcae51da6dceacd84f79df4b88d9f92035d1479e9" }, { "name":"StellaSwap: AVAXILO V1", "chain":"moonbeam", "contract":"0x96bef4719ae7c053113292e6aa7fc36e62b243e8" }, { "name":"StellaSwap: Swap For Gas V1", "chain":"moonbeam", "contract":"0xb64dee2d182fed3dd6c273303fb08f11808c9c23" }, { "name":"StellaSwap: Farming Centre V1", "chain":"moonbeam", "contract":"0x0d4f8a55a5b2583189468ca3b0a32d972f90e6e5" }, { "name":"StellaSwap: FTMILO V1", "chain":"moonbeam", "contract":"0x096352f7ea415a336b41fc48b33142eff19a8ad8" }, { "name":"StellaSwap: Acala Rewarder V1", "chain":"moonbeam", "contract":"0xb7b5d3659ad213478bc8bfb94d064d0efdda8f7c" }, { "name":"StellaSwap: USDC Rewarder V1", "chain":"moonbeam", "contract":"0xa52123adc0bc5c4c030d1ff4f5dad966366a646c" }, { "name":"StellaSwap: Vault V1", "chain":"moonbeam", "contract":"0x54e2d14df9348b3fba7e372328595b9f3ae243fe" }, { "name":"StellaSwap: CELER Rewarder 1 V1", "chain":"moonbeam", "contract":"0x70cbd76ed57393e0cd81e796de850080c775d24f" }, { "name":"StellaSwap: Stella Timelock V1", "chain":"moonbeam", "contract":"0xc6f73b028cd3154a5bb87f49aa43aa259a6522fb" }, { "name":"StellaSwap: GLMR - MAI Vault V1", "chain":"moonbeam", "contract":"0x3a82f4da24f93a32dc3c2a28cfa9d6e63ec28531" }, { "name":"StellaSwap: UST - GLMR V1", "chain":"moonbeam", "contract":"0x556d9c067e7a0534564d55f394be0064993d2d3c" }, { "name":"StellaSwap: SFL - axlUSDC - 4pool V1", "chain":"moonbeam", "contract":"0xa1ffdc79f998e7fa91ba3a6f098b84c9275b0483" }, { "name":"StellaSwap: Stable Router V1", "chain":"moonbeam", "contract":"0xb0dfd6f3fddb219e60fcdc1ea3d04b22f2ffa9cc" }, { "name":"StellaSwap: ATOM - GLMR Rewarder New V1", "chain":"moonbeam", "contract":"0x5aa224966e302424ec13a4f51b80bcfc205984b6" }, { "name":"StellaSwap: CELR Rewarder V1", "chain":"moonbeam", "contract":"0x05ad30253f0b20be35d84253d6aca8bd7ec0c66c" }, { "name":"StellaSwap: Router V3", "chain":"moonbeam", "contract":"0xe6d0ed3759709b743707dcfecae39bc180c981fe" }, { "name":"StellaSwap: xStella - GLMR Rewarder V1", "chain":"moonbeam", "contract":"0x896135ff51debe8083a2e03f9d44b1d3c77a0324" }, { "name":"StellaSwap: XStella - MAI Vault V1", "chain":"moonbeam", "contract":"0x3756465c5b1c1c4cee473880c9726e20875284f1" }, { "name":"StellaSwap: ATOM - USDC Rewarder New V1", "chain":"moonbeam", "contract":"0x5546e272c67fac10719f1223b1c0212fa3e41a8f" }, { "name":"StellaSwap: SFL - athUSDC - 4pool V1", "chain":"moonbeam", "contract":"0x715d7721fa7e8616ae9d274704af77857779f6f0" }, { "name":"StellaSwap: IDO Locker V1", "chain":"moonbeam", "contract":"0x4b1381b5b959a8ba7f44414c7d758e53d500a8a9" }, { "name":"StellaSwap: Locker V1", "chain":"moonbeam", "contract":"0x8995066b7f1fb3abe3c88040b677d03d607a0b58" }, { "name":"StellaSwap: ATOM - USDC - GLMR Rewarder V1", "chain":"moonbeam", "contract":"0xe06e720aaed5f5b817cb3743108ae0a12fe69e9b" }, { "name":"StellaSwap: Mistake in Rewarder V1", "chain":"moonbeam", "contract":"0x168ceb7e49c21e3f37820a34590171214a765f5f" }, { "name":"StellaSwap: LP 4pool - Wormhole V1", "chain":"moonbeam", "contract":"0xb326b5189aa42acaa3c649b120f084ed8f4dcaa6" }, { "name":"StellaSwap: Farms V1", "chain":"moonbeam", "contract":"0xedfb330f5fa216c9d2039b99c8ce9da85ea91c1e" }, { "name":"StellaSwap: Factory V1", "chain":"moonbeam", "contract":"0x68a384d826d3678f78bb9fb1533c7e9577dacc0e" }, { "name":"StellaSwap: anyETH-madETH Pool", "chain":"moonbeam", "contract":"0xb86271571c90ad4e0c9776228437340b42623402" }, { "name":"StellaSwap: Dual Farms V2", "chain":"moonbeam", "contract":"0xf3a5454496e26ac57da879bf3285fa85debf0388" }, { "name":"StellaSwap: CELER Rewarder 01 - 02 V1", "chain":"moonbeam", "contract":"0x713f76076283fcd81babe06c76ff51485edf9d5e" }, { "name":"StellaSwap: SCNFT Token", "chain":"moonbeam", "contract":"0x5f23a6a0b6b90fdeeb4816afbfb2ec0408fda59e" }, { "name":"StellaSwap: ATOM - GLMR - GLMR Rewarder V1", "chain":"moonbeam", "contract":"0xe60c41de5537418fde05b804df077397dfa84d75" }, { "name":"StellaSwap: Timelock Main V1", "chain":"moonbeam", "contract":"0x9a8693c6f7bf0f44e885118f3f83e2cdb4e611b8" }, { "name":"StellaSwap: MAI - B4P - Wormhole V1", "chain":"moonbeam", "contract":"0xf0a2ae65342f143fc09c83e5f19b706abb37414d" }, { "name":"StellaSwap: LP Token V1", "chain":"moonbeam", "contract":"0x7b17122b941d2173192c7d8d68faabdc88421326" }, { "name":"StellaSwap: Multisig V1", "chain":"moonbeam", "contract":"0x4300e09284e3bb4d9044ddab31efaf5f3301daba" }, { "name":"StellaSwap: Router V2", "chain":"moonbeam", "contract":"0x70085a09d30d6f8c4ecf6ee10120d1847383bb57" }, { "name":"StellaSwap: DOTxc - GLMR V1", "chain":"moonbeam", "contract":"0x505b0a5458dd12605b84bb2928dd2bc5b44993b9" }, { "name":"StellaSwap: SFL - MAI - 4pool V1", "chain":"moonbeam", "contract":"0x7fbe3126c03444d43fc403626ec81e3e809e6b46" }, { "name":"StellaSwap: xStella - USDC Rewarder V1", "chain":"moonbeam", "contract":"0xfa16d5b8bf03677945f0a750c8d2a30001b2fa93" }, { "name":"StellaSwap: madUSDC - GLMR V1", "chain":"moonbeam", "contract":"0x9200cb047a9c4b34a17ccf86334e3f434f948301" } ], "slug":"stellaswap", "createdAt":1699292612617, "tvlChange1d":{ "moonbeam":-0.748278690902012 }, "logo":{ "small":{ "width":36, "fileName":"stellaswap-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":510, "fileName":"stellaswap-logo-large.jpeg", "mimeType":"image/jpeg", "height":510 }, "full":{ "width":3000, "fileName":"stellaswap-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "chains":[ "moonbeam" ], "usersChange7d":{ "moonbeam":-17.2727272727273 }, "marketData":{ "symbol":"stella", "marketCap":808908, "marketCapRank":2865, "priceChangePercentage1y":-43.01356, "currentPrice":0.01729378, "priceChangePercentage14d":-17.23772, "contracts":{ "moonbeam":"0x0e358838ce72d5e61e0018a2ffac4bec5f4c88d2" }, "priceChangePercentage60d":-39.75633, "priceChangePercentage30d":-26.13934, "priceChangePercentage24h":-4.63782, "priceChangePercentage200d":-74.57003, "marketCapChangePercentage24h":-4.62971, "priceChange24h":-0.0008410608839097, "marketCapChange24h":-39268.122562502, "priceChangePercentage7d":-7.91278 }, "projectCreationDate":1644828523000, "contracts":[ { "chain":"moonbeam", "contract":"0x0e358838ce72d5e61e0018a2ffac4bec5f4c88d2" } ], "updatedAt":1722544694830, "category":"dex", "description":"StellaSwap is one of the first automated market-making (AMM), decentralized exchange (DEX) for the Moonbeam parachain network. The unique value proposition of StellaSwap is that we're committed in establishing a strong foundation with our native token, STELLA, as a governance token, diverse farms, a built in bridge and user-centered service. \r\n\r\nStellaSwap's main objective is to create a broader range of network effects to address the issues of liquidity in the DeFi space, instead of limiting ourselves to a single solution like many DEXs are doing now. This manifests itself in the diverse product suite of StellaSwap that will be explained in more details. Our products are structured in such a way that facilitates decentralized governance of STELLA holders, while continuing to innovate on the collective foundations by design.", "usersChange1d":{ "moonbeam":-6.18556701030928 } } } ``` ### Query a Category {: #query-a-category} You can also query the API by [category](#category-and-tags). For example, you can retrieve information about all NFT projects with the following query: ```bash https://apps.moonbeam.network/api/ds/v1/app-dir/projects?category=nfts ``` ??? code "API Response to Querying NFT projects" ```json { "projects":[ { "urls":{ "telegram":"https://t.me/nfts2me", "website":"https://nfts2me.com/", "try":"https://nfts2me.com/", "twitter":"https://twitter.com/nfts2me", "medium":"https://nfts2me.medium.com/", "discord":"https://nfts2me.com/discord/" }, "slug":"nfts2me", "createdAt":1699292617117, "logo":{ "small":{ "width":36, "fileName":"nfts2me-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":512, "fileName":"nfts2me-logo-large.jpeg", "mimeType":"image/jpeg", "height":512 }, "full":{ "width":3000, "fileName":"nfts2me-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"NFTs2Me", "chains":[ "moonbeam" ], "defiLLamaTvlExist":false, "projectCreationDate":1673608509000, "shortDescription":"NFTs2Me is a toolkit for creating and managing NFT projects.", "contracts":[ { "chain":"moonbeam", "contract":"0x2269bCeB3f4e0AA53D2FC43B1B7C5C5D13B119a5" } ], "updatedAt":1722498896566, "category":"nfts", "description":"NFTs2Me is a tool for creating and managing NFT projects. It includes features such as an art generator, delayed reveal, minting widget, token gating, and support for multiple blockchain platforms. It also offers customization options, an affiliate system, automatic logo and banner generation, and support for redeemable NFTs. It is user-friendly and suitable for those new to the world of NFTs.\n\nIn addition to these features, NFTs2Me also offers a minting widget and free IPFS hosting to make it simple to mint and store your NFTs securely and efficiently. The minting widget allows you to easily create and mint new NFTs, while the free IPFS hosting provides a secure and decentralized way to store your NFTs.", "id":"nfts2me", "tags":[ "NFT", "Tool" ] }, { "urls":{ "telegram":"https://t.me/rmrkapp", "website":"https://singular.app/", "try":"https://singular.app/", "twitter":"https://twitter.com/RmrkSingular", "discord":"https://discord.gg/TjB6v5AGZz" }, "slug":"singular-app", "createdAt":1699292616171, "logo":{ "small":{ "width":36, "fileName":"singular-app-logo-small.png", "mimeType":"image/png", "height":36 }, "large":{ "width":400, "fileName":"singular-app-logo-large.png", "mimeType":"image/png", "height":400 }, "full":{ "width":3000, "fileName":"singular-app-logo-full.png", "mimeType":"image/png", "height":3000 } }, "name":"Singular App", "chains":[ "moonbeam" ], "defiLLamaTvlExist":false, "projectCreationDate":1686240710000, "shortDescription":"The home of NFTs by @RmrkApp. Create and trade your nestable, equippable, soulbound, and multi-asset NFTs with us - no coding required.", "contracts":[ ], "updatedAt":1722498914806, "category":"nfts", "description":"Singular is an NFT 2.0 marketplace that allows users to buy, sell, and trade both regular and advanced NFTs. Users can create and/or connect a wallet, browse digital items, and securely conduct transactions using blockchain technology.", "id":"singular-app", "tags":[ "NFT Marketplaces" ] }, { "urls":{ "telegram":"https:/t.me/metacourtgg", "website":"https://www.metacourt.gg/", "try":"https://www.metacourt.gg/", "twitter":"https://twitter.com/metacourtgg", "medium":"https://metacourtgg.medium.com/", "discord":"https://discord.gg/9AnnfKCb39" }, "slug":"metacourt", "createdAt":1699292616238, "logo":{ "small":{ "width":36, "fileName":"metacourt-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":512, "fileName":"metacourt-logo-large.jpeg", "mimeType":"image/jpeg", "height":512 }, "full":{ "width":3000, "fileName":"metacourt-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"Metacourt", "chains":[ "moonbeam" ], "defiLLamaTvlExist":false, "projectCreationDate":1663756794000, "shortDescription":"Metacourt created NFTdeals for anyone who wants to become an influencer and trade their social media", "contracts":[ ], "updatedAt":1722498888422, "category":"nfts", "description":"Influencer accelerator for anyone who wants to become an influencer in the space. We allow selling your social media through NFTs and joining influencer marketing campaigns.", "id":"metacourt", "tags":[ "NFT Marketplaces" ] }, { "urls":{ "telegram":"https://t.me/tofuNFT", "website":"https://tofunft.com/", "try":"https://tofunft.com/", "twitter":"https://twitter.com/tofuNFT", "medium":"https://medium.com/tofunftofficial", "discord":"https://discord.com/invite/3wFUTZmTm7" }, "slug":"tofunft", "createdAt":1699292615874, "logo":{ "small":{ "width":36, "fileName":"tofunft-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":400, "fileName":"tofunft-logo-large.jpeg", "mimeType":"image/jpeg", "height":400 }, "full":{ "width":3000, "fileName":"tofunft-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"tofuNFT", "chains":[ "moonbeam", "moonriver" ], "defiLLamaTvlExist":false, "projectCreationDate":1644828523000, "shortDescription":"The largest multichain NFT marketplace", "contracts":[ ], "updatedAt":1722498924881, "category":"nfts", "description":"tofuNFT.com is an NFT marketplace focused on GameFi and collectibles, rebranded from SCV’s NFT market. Enjoy exploring & trading with your buddies!", "id":"tofunft", "tags":[ "NFT Marketplaces", "NFT" ] }, { "urls":{ "website":"https://d-book.io", "try":"https://d-book.io", "twitter":"https://twitter.com/dbook_io" }, "slug":"d-book.io", "createdAt":1699292617021, "logo":{ "small":{ "width":129, "fileName":"d-book.io-logo-small.png", "mimeType":"image/png", "height":36 }, "large":{ "width":129, "fileName":"d-book.io-logo-large.png", "mimeType":"image/png", "height":36 }, "full":{ "width":3000, "fileName":"d-book.io-logo-full.png", "mimeType":"image/png", "height":3000 } }, "name":"D-book.io", "chains":[ "moonbeam" ], "defiLLamaTvlExist":false, "projectCreationDate":1682016612000, "shortDescription":"Buğra Ayan is a speaker,and university lecturer in Turkey who founded the Web3 Association Turkey.", "contracts":[ { "chain":"moonbeam", "contract":"0x8d4BA02D0973749ad7c646DcaAa60BDC66F6F6D2" } ], "updatedAt":1722498866417, "category":"nfts", "description":"We are an NFT Book Platform that connects authors and the decentralized world, aiming for a transformation ecosystem.", "id":"d-book.io", "tags":[ "NFT Marketplaces", "NFT" ] }, { "urls":{ "telegram":"https://t.me/BcmHuntGroup", "website":"https://bcmhunt.com/", "try":"https://bcmhunt.com/", "twitter":"https://twitter.com/bcmhunt", "medium":"https://medium.com/bcmhunt", "discord":"https://discord.com/invite/Ee9aJ287J2" }, "slug":"blockchain-monster-hunt", "createdAt":1699292616780, "logo":{ "small":{ "width":36, "fileName":"blockchain-monster-hunt-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":510, "fileName":"blockchain-monster-hunt-logo-large.jpeg", "mimeType":"image/jpeg", "height":510 }, "full":{ "width":3000, "fileName":"blockchain-monster-hunt-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"Blockchain Monster Hunt", "chains":[ "moonbeam" ], "defiLLamaTvlExist":false, "projectCreationDate":1644828523000, "shortDescription":"The First Multichain NFT Monster Hunt", "contracts":[ ], "updatedAt":1722498855937, "category":"nfts", "description":"Blockchain Monster Hunt (BCMH) is the world’s first multi-chain game that runs entirely on the blockchain itself. Inspired by Pokémon-GO,BCMH allows players to continuously explore brand new places on the blockchain to hunt and battle monsters. Each block on the blockchain is a unique digital space where a limited number of monsters (of the same DNA gene and rarity) may exist. Players and collectors can hunt or battle for a chance to capture these unique monsters and to earn coins.", "id":"blockchain-monster-hunt", "tags":[ "NFT", "Gaming", "GLMR Grants" ] }, { "urls":{ "website":"https://speedboat.studio/", "try":"https://speedboat.studio/", "twitter":"https://twitter.com/Speedboat_STDO", "medium":"https://medium.com/@speedboat_studio", "discord":"https://discord.gg/y7TQbtEWSV" }, "slug":"speedboat.studio", "createdAt":1699292616328, "logo":{ "small":{ "width":36, "fileName":"speedboat.studio-logo-small.png", "mimeType":"image/png", "height":36 }, "large":{ "width":190, "fileName":"speedboat.studio-logo-large.png", "mimeType":"image/png", "height":190 }, "full":{ "width":3000, "fileName":"speedboat.studio-logo-full.png", "mimeType":"image/png", "height":3000 } }, "name":"Speedboat", "chains":[ "moonbeam" ], "defiLLamaTvlExist":false, "projectCreationDate":1657584952000, "shortDescription":"Your no-code Web3 toolkit", "contracts":[ ], "updatedAt":1722498916466, "category":"nfts", "description":"Speedboat is a Web3 toolkit for everyone. Built on the idea that NFTs are not just expensive JPEGs, but programmable experiences.", "id":"speedboat.studio", "tags":[ "NFT", "Tool" ] }, { "urls":{ "telegram":"https://t.me/+qGh0InPSPc1iMTNk", "website":"https://www.glmrapes.com/", "try":"https://www.glmrapes.com/", "twitter":"https://twitter.com/GLMRApes", "discord":"https://discord.com/invite/glmrapes" }, "web3goContracts":[ { "name":"GLMR Apes: GLMR Ape", "chain":"moonbeam", "contract":"0x8fbe243d898e7c88a6724bb9eb13d746614d23d6" }, { "name":"GLMR Apes: GLMR Jungle", "chain":"moonbeam", "contract":"0xcb13945ca8104f813992e4315f8ffefe64ac49ca" } ], "currentTx":{ "moonbeam":7830 }, "slug":"glmr-apes", "web3goIDs":[ "GLMR Apes" ], "createdAt":1699292616827, "logo":{ "small":{ "width":47, "fileName":"glmr-apes-logo-small.png", "mimeType":"image/png", "height":36 }, "large":{ "width":528, "fileName":"glmr-apes-logo-large.png", "mimeType":"image/png", "height":408 }, "full":{ "width":3000, "fileName":"glmr-apes-logo-full.png", "mimeType":"image/png", "height":3000 } }, "name":"GLMR APES", "chains":[ "moonbeam" ], "defiLLamaTvlExist":false, "usersChange7d":{ "moonbeam":-66.6666666666667 }, "currentUsers":{ "moonbeam":1531 }, "projectCreationDate":1644828523000, "shortDescription":"The first NFT collection on GLMR by & for the community", "contracts":[ ], "updatedAt":1722547408370, "category":"nfts", "description":"GLIMMER APES is the first NFT collection on GLMR by & for the community. The longer you’re bonding with GLMR Apes and the friendlier their behavior. Join the troops as soon as possible to become an EARLY APE, take part in our giveaways and games and land in the GLMR APE VIP CLUB.", "id":"glmr-apes", "tags":[ "NFT", "Gaming" ], "usersChange1d":{ "moonbeam":0 } }, { "urls":{ "website":"https://snakesoldiers.com", "try":"https://snakesoldiers.com", "twitter":"https://twitter.com/snakesoldiers", "github":"https://github.com/steven2308/snake-soldiers-contracts", "medium":"https://medium.com/@snakesoldiers/emoting-to-influence-the-hatch-df3eab7e45b8", "discord":"http://discord.gg/A6zQSz4YU4" }, "slug":"snake-soldiers", "createdAt":1699292616971, "logo":{ "small":{ "width":36, "fileName":"snake-soldiers-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":400, "fileName":"snake-soldiers-logo-large.jpeg", "mimeType":"image/jpeg", "height":400 }, "full":{ "width":3000, "fileName":"snake-soldiers-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"Snake Soldiers", "chains":[ "moonbeam" ], "defiLLamaTvlExist":false, "projectCreationDate":1691439275000, "shortDescription":"NFT game collection divided in 3 categories: Generals, Commanders and Soldiers🐍. Built on Moonbeam", "contracts":[ { "chain":"moonbeam", "contract":"0x3ab955216BdD76f51fbe02A3fe237D6612BBD09F" } ], "updatedAt":1722498915320, "category":"nfts", "description":"Snake Soldiers is an NFT collection with a supply of at most 5k units, all unique and distributed among 3 ranks. Each snake will be usable inside a play to own game, where snakes will be the main characters, necessary to interact with the SerpenTerra ecosystem. This metaverse will be based on the RMRK 2.0 standard, making forward compatible and giving super powers to the NFTs.", "id":"snake-soldiers", "tags":[ "NFT" ] }, { "urls":{ "telegram":"https://t.me/+LqmDOeGUQdRmYjVh%60%60", "website":"https://omni-x.io", "try":"https://omni-x.io", "twitter":"https://twitter.com/omnix_nft", "github":"https://github.com/Omni-X-NFT", "discord":"https://discord.gg/omni-x" }, "slug":"omni-x", "createdAt":1699292617077, "logo":{ "small":{ "width":36, "fileName":"omni-x-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":107, "fileName":"omni-x-logo-large.jpeg", "mimeType":"image/jpeg", "height":108 }, "full":{ "width":3000, "fileName":"omni-x-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"Omni-X", "chains":[ "moonbeam" ], "defiLLamaTvlExist":false, "projectCreationDate":1673811786000, "shortDescription":"The first natively omnichain NFT platform", "contracts":[ ], "updatedAt":1722498898538, "category":"nfts", "description":"Omni X is an omnichain NFT protocol and marketplace that connects communities, creators, and enthusiasts across multiple blockchains. \n\nWe provide tooling for creating ONFT collections, bridging regular NFTs to ONFTs and grant access to unparalleled liquidity that allows users to buy and sell NFTs from any blockchain to any other blockchain.", "id":"omni-x", "tags":[ "NFT Marketplaces", "Infrastructure" ] }, { "urls":{ "website":"https://www.publicpressure.io/", "try":"https://www.publicpressure.io/", "twitter":"https://twitter.com/jointhepressure", "discord":"https://discord.gg/publicpressure" }, "slug":"publicpressure", "createdAt":1702283744356, "logo":{ "small":{ "width":36, "fileName":"publicpressure-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":400, "fileName":"publicpressure-logo-large.jpeg", "mimeType":"image/jpeg", "height":400 }, "full":{ "width":3000, "fileName":"publicpressure-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"Public Pressure", "chains":[ "moonriver" ], "defiLLamaTvlExist":false, "projectCreationDate":1651597275000, "shortDescription":"Support your favorite artists, own their music, get rewarded.", "contracts":[ ], "updatedAt":1722498907699, "category":"nfts", "description":"We are the web3 music platform powered by artists, labels and fans", "id":"publicpressure", "tags":[ "NFT Marketplaces" ] }, { "currentTx":{ "moonbeam":8409 }, "web3goIDs":[ "Moonbeans" ], "name":"Moonbeans", "currentUsers":{ "moonbeam":1134 }, "coinGeckoId":"moonbeans", "shortDescription":"Galactic Co-Op & Profit sharing NFT platform and soon to be Metaverse", "id":"moonbeans", "tags":[ "NFT Marketplaces" ], "urls":{ "website":"https://moonbeans.io/", "twitter":"https://twitter.com/moonbeansio", "github":"https://github.com/m00nbeans", "discord":"https://discord.com/invite/qqE9aBPzQ9", "telegram":"https://t.me/moonbeansio", "try":"https://moonbeans.io/", "medium":"https://medium.com/@MoonBeans" }, "web3goContracts":[ { "name":"Moonbeans: Beanie Distributor V2", "chain":"moonbeam", "contract":"0xda6367c6510d8f2d20a345888f9dff3eb3226b02" }, { "name":"Moonbeans: Marketplace V9", "chain":"moonbeam", "contract":"0x683724817a7d526d6256aec0d6f8ddf541b924de" }, { "name":"Moonbeans: Storefront Ownership V1", "chain":"moonbeam", "contract":"0x971dfedd548f2269e515957404cbbee1f507cd01" } ], "slug":"moonbeans", "createdAt":1699292615978, "logo":{ "small":{ "width":36, "fileName":"moonbeans-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":400, "fileName":"moonbeans-logo-large.jpeg", "mimeType":"image/jpeg", "height":400 }, "full":{ "width":3000, "fileName":"moonbeans-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "chains":[ "moonbeam", "moonriver" ], "defiLLamaTvlExist":false, "usersChange7d":{ "moonbeam":0 }, "marketData":{ "symbol":"beans", "marketCap":0, "priceChangePercentage1y":-62.22489, "currentPrice":0.062264, "priceChangePercentage14d":-13.93552, "contracts":{ }, "priceChangePercentage60d":-44.93764, "priceChangePercentage30d":-33.587, "priceChangePercentage24h":-0.05451, "priceChangePercentage200d":-83.0363, "marketCapChangePercentage24h":0, "priceChange24h":-0.0000339560550113, "marketCapChange24h":0, "priceChangePercentage7d":-5.36696 }, "projectCreationDate":1644828523000, "contracts":[ { "chain":"moonbeam", "contract":"0x65b09ef8c5a096c5fd3a80f1f7369e56eb932412" }, { "chain":"moonriver", "contract":"0xC2392DD3e3fED2c8Ed9f7f0bDf6026fcd1348453" } ], "updatedAt":1722548296818, "category":"nfts", "description":"Moonbeans is a fully functional NFT marketplace launched on October 8th 2021, after releasing 465 Beanies into the Moonriver network to wreak havoc. The platform is still in beta, but has been performing incredibly well. With minimal fees for artists, traders, and project developers, Moonbeans aims to grow and aid the Moonrver network as a whole to develop, learn, and earn. With multiple collections now live (Beanies, Damned Pirates Society), minting (RivrMaids), Moonbeans is the heart of the Moonriver NFT ecosystem.", "usersChange1d":{ "moonbeam":0 } }, { "urls":{ "telegram":"https://t.me/blocsport", "website":"https://blocsport.one/", "try":"https://blocsport.one/", "twitter":"https://twitter.com/blocsport1", "medium":"https://blocsport1.medium.com/" }, "slug":"blocsport-one", "createdAt":1699292616637, "logo":{ "small":{ "width":36, "fileName":"blocsport-one-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":400, "fileName":"blocsport-one-logo-large.jpeg", "mimeType":"image/jpeg", "height":400 }, "full":{ "width":3000, "fileName":"blocsport-one-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"Blocsport.one", "chains":[ "moonriver" ], "defiLLamaTvlExist":false, "projectCreationDate":1644828523000, "shortDescription":"Web 3.0 metaverse, smart sports money, athlete NFT launchpad & assets tokenization", "contracts":[ ], "updatedAt":1722498857332, "category":"nfts", "description":"Blocsport.one is a Swiss sports tech company founded in 2019 that is transforming the sports business by building a transparent and reliable sports ecosystem uniting athletes, clubs, and fans based on blockchain. Company owns NFTdeals.io exclusive marketplace and has the biometric-enabled football scouting DApp live. Blocsport.one helps the young promising athletes get the money and exposure for their career development, which is nobody else doing in the world.", "id":"blocsport-one", "tags":[ "NFT" ] }, { "urls":{ "telegram":"https://t.me/mintverse", "website":"https://www.mintverse.com/", "try":"https://www.mintverse.com/", "twitter":"https://twitter.com/mintverse_", "medium":"https://medium.com/mintverse", "discord":"https://discord.com/invite/mhhnbvAaq9" }, "slug":"mintverse", "createdAt":1702283733666, "logo":{ "small":{ "width":36, "fileName":"mintverse-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":400, "fileName":"mintverse-logo-large.jpeg", "mimeType":"image/jpeg", "height":400 }, "full":{ "width":3000, "fileName":"mintverse-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"Mintverse", "chains":[ "moonbeam" ], "defiLLamaTvlExist":false, "projectCreationDate":1651597514000, "shortDescription":"Mint, Explore & Trade Liquid NFT Assets Across Multiple Chains", "contracts":[ ], "updatedAt":1722498889300, "category":"nfts", "description":"Comprehensive NFT Aggregation Marketplace with a 0% trading fee", "id":"mintverse", "tags":[ "NFT Marketplaces" ] }, { "urls":{ "telegram":"https://t.me/rmrkapp", "website":"https://upgradooor.app", "try":"https://upgradooor.app", "twitter":"https://x.com/rmrkapp", "github":"https://github.com/rmrk-team", "medium":"https://medium.com/rmrkapp" }, "slug":"upgradooor", "createdAt":1699292616895, "logo":{ "small":{ "width":36, "fileName":"upgradooor-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":512, "fileName":"upgradooor-logo-large.jpeg", "mimeType":"image/jpeg", "height":512 }, "full":{ "width":3000, "fileName":"upgradooor-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"Upgradooor", "chains":[ "moonbeam", "moonriver" ], "defiLLamaTvlExist":false, "projectCreationDate":1692259742000, "shortDescription":"Upgrade your NFT 1.0 collections to NFT 2.0 by wrapping them into advanced functionality", "contracts":[ ], "updatedAt":1722498927244, "category":"nfts", "description":"As a collection issuer, use Upgradooor to initialize the process of upgrading your collection to NFT 2.0 if you are currently using ERC721.\n\nAs a holder, once the collection owner initiates the process, you can wrap any NFT you hold in that collection and instantly turn it into an equippable, multi-asset, composable NFT with no added risk.\n\nYou can always unwrap at will, and all the changes will still wait for you when you decide to re-claim the 2.0 wrapper again.\n\nUpgrading allows you to:\n\n- add more assets (outputs) to a legacy NFT, preventing needless airdrop spam\n- airdrop NFTs into the NFT itself, preventing detachment of context, and saving tremendous amounts of gas by letting people transfer just the parent NFT\n- define equippable settings and even achieve compatibility with other collections, for cross collection equippables and thus cross collection royalties and commissions\n- see your NFTs on Singular, and use GBM auctions as a unique and novel listing mechanic", "id":"upgradooor", "tags":[ "NFT", "Tool" ] }, { "urls":{ "telegram":"https://t.me/moonfit_official_community", "website":"https://moonfit.xyz/", "try":"https://moonfit.xyz/", "twitter":"https://twitter.com/MoonFitOfficial", "discord":"https://discord.gg/hStdUVtHXp" }, "slug":"moonfit", "createdAt":1702283734897, "logo":{ "small":{ "width":36, "fileName":"moonfit-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":400, "fileName":"moonfit-logo-large.jpeg", "mimeType":"image/jpeg", "height":400 }, "full":{ "width":3000, "fileName":"moonfit-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"MoonFit", "chains":[ "moonbeam" ], "defiLLamaTvlExist":false, "projectCreationDate":1654692249000, "shortDescription":"Web3 & NFT Lifestyle App That Pays You Anytime You Burn Calories", "contracts":[ ], "updatedAt":1722498891201, "category":"nfts", "description":"MoonFit is a Web3 Lifestyle App that promotes active living by rewarding users with tokens and NFTs anytime they burn calories through physical activities.", "id":"moonfit", "tags":[ "NFT", "Gaming" ] }, { "urls":{ "telegram":"https://t.me/rmrkapp", "website":"https://rmrk.app/", "try":"https://rmrk.app/", "twitter":"https://twitter.com/rmrkapp", "discord":"https://discord.com/invite/bV9kQbVC99" }, "slug":"rmrk", "createdAt":1699292615938, "logo":{ "small":{ "width":36, "fileName":"rmrk-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":400, "fileName":"rmrk-logo-large.jpeg", "mimeType":"image/jpeg", "height":400 }, "full":{ "width":3000, "fileName":"rmrk-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"RMRK", "chains":[ "moonbeam" ], "defiLLamaTvlExist":false, "marketData":{ "symbol":"rmrk", "marketCap":5985029, "marketCapRank":1602, "priceChangePercentage1y":-64.99216, "currentPrice":0.62974, "priceChangePercentage14d":-24.26661, "contracts":{ "moonbeam":"0x524d524b4c9366be706d3a90dcf70076ca037ae3" }, "priceChangePercentage60d":-51.72181, "priceChangePercentage30d":-30.11256, "priceChangePercentage24h":-2.58554, "priceChangePercentage200d":-75.55551, "marketCapChangePercentage24h":-2.50147, "priceChange24h":-0.01671434617594, "marketCapChange24h":-153554.8536219, "priceChangePercentage7d":-1.5052 }, "coinGeckoId":"rmrk", "projectCreationDate":1644828523000, "shortDescription":"Creators of NFTs 2.0 via ERC6059, ERC6220, ERC5773, EIP6381, and EIP6454.\nNFT equippables, future compatibility, reputation, and token balances.", "contracts":[ ], "updatedAt":1722548302467, "category":"nfts", "description":"With the RMRK NFT Building Block System\nOur ERC NFT standards allow you to unlock the true potential of NFTs.\nTailored to work with each other, these EVM smart contracts will help you create your NFT projects of varying complexity.", "id":"rmrk", "tags":[ "NFT", "Infrastructure" ] }, { "urls":{ "website":"https://www.mynft.com/", "try":"https://bridge.mynft.com/home", "twitter":"https://twitter.com/mynft" }, "slug":"mynft", "createdAt":1699292616578, "logo":{ "small":{ "width":36, "fileName":"mynft-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":400, "fileName":"mynft-logo-large.jpeg", "mimeType":"image/jpeg", "height":400 }, "full":{ "width":3000, "fileName":"mynft-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"myNFT", "chains":[ "moonbeam" ], "defiLLamaTvlExist":false, "projectCreationDate":1644828523000, "shortDescription":"The marketplace that puts the power back in your hands", "contracts":[ ], "updatedAt":1722498895020, "category":"nfts", "description":"myNFT is the marketplace that puts the power back in your hands. It is a creative workshop, a trading platform and a discovery engine, helping you tell your story and share your passions, on your own terms. myNFT is built on decentralized technologies empowering you to create, trade, and discover. myNFT is built by Perpetual Altruism, a leader in the NFT space and the creator of charitable NFT publisher Cryptograph and the GBM auction system. Perpetual Altruism is backed by prominent investors and creators and is also the recipient of grants from the Web3 Foundation and the Moonbeam network for their work on the decentralized internet, which powers myNFT.", "id":"mynft", "tags":[ "NFT Marketplaces", "GLMR Grants", "MOVR Grants" ] }, { "urls":{ "website":"https://readl.co/", "try":"https://readl.co/", "twitter":"https://twitter.com/readl_co", "medium":"https://medium.com/@readlnetwork", "discord":"https://discord.gg/XPTENepHqY" }, "slug":"readl", "createdAt":1702283745749, "logo":{ "small":{ "width":36, "fileName":"readl-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":512, "fileName":"readl-logo-large.jpeg", "mimeType":"image/jpeg", "height":512 }, "full":{ "width":3000, "fileName":"readl-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"Readl", "chains":[ "moonriver" ], "defiLLamaTvlExist":false, "projectCreationDate":1655885161000, "shortDescription":"Bringing the publishing industry to web3", "contracts":[ ], "updatedAt":1722498910044, "category":"nfts", "description":"Readl is the protocol that provides publishers and storytellers with the infrastructure to publish their content on the blockchain, while providing a user-friendly platform to enjoy any story, in any format.", "id":"readl", "tags":[ "NFT Marketplaces", "MOVR Grants" ] }, { "urls":{ "telegram":"https://t.me/rmrkapp", "website":"https://emotes.app", "try":"https://emotes.app", "twitter":"https://x.com/rmrkapp", "github":"https://github.com/rmrk-team", "medium":"https://medium.com/rmrkapp" }, "slug":"emotes.app", "createdAt":1699292616951, "logo":{ "small":{ "width":36, "fileName":"emotes.app-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":512, "fileName":"emotes.app-logo-large.jpeg", "mimeType":"image/jpeg", "height":512 }, "full":{ "width":3000, "fileName":"emotes.app-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"Emotes.app", "chains":[ "moonbeam" ], "defiLLamaTvlExist":false, "projectCreationDate":1692254489000, "shortDescription":"React on anyone's NFT - throw 💩 at those apes, give a 🤗 to those Pudgies!", "contracts":[ ], "updatedAt":1722498871347, "category":"nfts", "description":"Emotes.app is a RMRK mini-app which allows you to send emotes / reactions to anyone's NFT. It utilizes RMRK's ERC7009 and is trivial to integrate into any project wanting to take advantage of the community's reactions to their NFTs.\n\nUse it to direct storylines, affect NFT egg hatching, or just do relative price comparison when influencers like one NFTs and dislike another!", "id":"emotes.app", "tags":[ "NFT", "Social" ] }, { "urls":{ "telegram":"https://twitter.com/PolkaPets", "website":"https://www.polkapet.world/", "try":"https://www.polkapet.world/", "twitter":"https://twitter.com/PolkaPets", "medium":"https://polkapetworld.medium.com/" }, "slug":"polkapet-world", "createdAt":1702283743596, "logo":{ "small":{ "width":36, "fileName":"polkapet-world-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":400, "fileName":"polkapet-world-logo-large.jpeg", "mimeType":"image/jpeg", "height":400 }, "full":{ "width":3000, "fileName":"polkapet-world-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"PolkaPets", "chains":[ "moonriver" ], "defiLLamaTvlExist":false, "marketData":{ "priceChangePercentage60d":1206.42918, "symbol":"pets", "marketCap":0, "priceChangePercentage30d":619.39533, "priceChangePercentage200d":135.91624, "priceChangePercentage1y":355.00061, "currentPrice":0.00515699, "priceChangePercentage14d":-15.30948, "contracts":{ "moonriver":"0x1e0f2a75be02c025bd84177765f89200c04337da" }, "priceChangePercentage7d":749.62625 }, "coinGeckoId":"polkapet-world", "projectCreationDate":1651157216000, "shortDescription":"Welcome to PolkaPet World", "contracts":[ ], "updatedAt":1722548303208, "category":"nfts", "description":"An immersive NFT collection created in partnership with the biggest and best PolkaDot projects ", "id":"polkapet-world", "tags":[ "NFT" ] }, { "urls":{ "website":"https://www.moonarines.com/", "try":"https://www.moonarines.com/", "discord":"https://discord.gg/bXhSyW8htW" }, "slug":"moonarines", "createdAt":1702283733870, "logo":{ "small":{ "width":36, "fileName":"moonarines-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":400, "fileName":"moonarines-logo-large.jpeg", "mimeType":"image/jpeg", "height":400 }, "full":{ "width":3000, "fileName":"moonarines-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"Moonarines", "chains":[ "moonriver" ], "defiLLamaTvlExist":false, "projectCreationDate":1654792422000, "shortDescription":"Be part of the conquest of the digital space", "contracts":[ ], "updatedAt":1722498889804, "category":"nfts", "description":"The Moonarines are unique NFT characters starting soon on the Moonriver Network!\nWith the Moonarines, the NFT owners will be taken to an unforgettable adventure to explore the Cryptoverse!", "id":"moonarines", "tags":[ "NFT" ] }, { "urls":{ "telegram":"https://t.me/NFTrade", "website":"https://nftrade.com/", "try":"https://nftrade.com/", "twitter":"https://twitter.com/NFTradeOfficial", "medium":"https://medium.com/@NFTrade", "discord":"https://discord.com/invite/SESqfsyw8k" }, "slug":"nftrade", "createdAt":1699292616005, "logo":{ "small":{ "width":36, "fileName":"nftrade-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":400, "fileName":"nftrade-logo-large.jpeg", "mimeType":"image/jpeg", "height":400 }, "full":{ "width":3000, "fileName":"nftrade-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"NFTrade", "chains":[ "moonbeam", "moonriver" ], "defiLLamaTvlExist":false, "marketData":{ "symbol":"nftd", "marketCap":234018, "marketCapRank":3653, "priceChangePercentage1y":-65.38449, "currentPrice":0.00502075, "priceChangePercentage14d":-7.09922, "contracts":{ }, "priceChangePercentage60d":-27.37596, "priceChangePercentage30d":-14.12267, "priceChangePercentage24h":-2.22137, "priceChangePercentage200d":-56.66993, "marketCapChangePercentage24h":-2.16658, "priceChange24h":-0.00011406326237191, "marketCapChange24h":-5182.473845666, "priceChangePercentage7d":-6.88049 }, "coinGeckoId":"nftrade", "projectCreationDate":1644828523000, "shortDescription":"Create, Buy, Sell, Swap and Farm NFTs", "contracts":[ ], "updatedAt":1722548304198, "category":"nfts", "description":"NFTrade is a multi-chain platform for NFT creation and trading. Seamlessly launch, mint, and swap non-fungible tokens. Earn digital collectibles. NFTrade places you at the heart of the NFT economy. Create, Buy, Sell, Swap and Farm NFTs. All chains, All NFTs, One Platform.", "id":"nftrade", "tags":[ "NFT Marketplaces", "MOVR Grants" ] }, { "urls":{ "website":"https://www.pipcards.com/", "try":"https://www.pipcards.com/", "twitter":"https://twitter.com/pipcards", "discord":"https://discord.com/invite/hnSC7QjTHj" }, "slug":"pipcards", "createdAt":1699292616371, "logo":{ "small":{ "width":36, "fileName":"pipcards-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":400, "fileName":"pipcards-logo-large.jpeg", "mimeType":"image/jpeg", "height":400 }, "full":{ "width":3000, "fileName":"pipcards-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"PIP Cards", "chains":[ "moonriver" ], "defiLLamaTvlExist":false, "projectCreationDate":1651149583000, "shortDescription":"Post-generated NFT playing card decks", "contracts":[ ], "updatedAt":1722498904704, "category":"nfts", "description":"PIPS is a first-of-its-kind NFT generative playing card project that will enable NFT holders to generate an entire deck of custom cards to be used cross-chain.", "id":"pipcards", "tags":[ "NFT", "Gaming" ] }, { "urls":{ "website":"https://bithotel.io/", "twitter":"https://twitter.com/playbithotel", "github":"https://github.com/BitHotelOrg/bithotel-token-contracts", "discord":"https://discord.gg/RFFZNwxY9n", "telegram":"https://t.me/bithotelcommunity", "try":"https://bithotel.io/", "medium":"https://medium.com/@bithotelnftgame" }, "slug":"bit-hotel", "createdAt":1702283710425, "logo":{ "small":{ "width":36, "fileName":"bit-hotel-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":500, "fileName":"bit-hotel-logo-large.jpeg", "mimeType":"image/jpeg", "height":500 }, "full":{ "width":3000, "fileName":"bit-hotel-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"Bit Hotel", "chains":[ "moonbeam" ], "defiLLamaTvlExist":false, "projectCreationDate":1658743551000, "shortDescription":"Bit Hotel is a Social-first Play 2 Earn NFT Gaming Metaverse set in a Pixel-art Hotel.", "contracts":[ { "chain":"moonbeam", "contract":"Not deployed yet" }, { "chain":"moonriver", "contract":"Not deployed yet" } ], "updatedAt":1722498854706, "category":"nfts", "description":"In Bit Hotel users can compete to earn Bit Hotel tokens and acquire native NFTs. These NFTs have in-game utilities and consist of characters, hotel rooms, furniture and other assets that have their own unique perks. With over 250k Hotel Guests cross-channel, this nostalgic Hotel metaverse is taking people back to their 8bit upbringing.", "id":"bit-hotel", "tags":[ "NFT", "Gaming" ] }, { "tvlChange7d":{ "moonriver":0.00190215150271202 }, "urls":{ "website":"https://www.moonbeamdao.com/", "try":"https://www.moonbeamdao.com/", "twitter":"https://twitter.com/moonbeam_dao", "medium":"https://medium.com/@moonbeamdao", "discord":"https://discord.gg/AevrFzwZjk" }, "web3goContracts":[ { "name":"MoonDAO: MDAO Token", "chain":"moonbeam", "contract":"0xc6342eab8b7cc405fc35eba7f7401fc400ac0709" } ], "currentTx":{ "moonbeam":972 }, "slug":"moondao", "web3goIDs":[ "MoonDAO" ], "createdAt":1699292616416, "tvlChange1d":{ "moonriver":-0.0349944884006391 }, "logo":{ "small":{ "width":25, "fileName":"moondao-logo-small.png", "mimeType":"image/png", "height":36 }, "large":{ "width":330, "fileName":"moondao-logo-large.png", "mimeType":"image/png", "height":475 }, "full":{ "width":3000, "fileName":"moondao-logo-full.png", "mimeType":"image/png", "height":3000 } }, "name":"MoonDAO", "chains":[ "moonbeam" ], "currentTVL":{ "moonriver":76.75665 }, "currentUsers":{ "moonbeam":229 }, "projectCreationDate":1648347145000, "shortDescription":"The first & only community art dao on moonbeam", "contracts":[ ], "updatedAt":1722547637377, "category":"nfts", "description":"MoonDao is the first community Art Collection DAO on the Moonbeam network!\n\nWe aim to utilize input from our community to select high-end NFT’s. These NFT’s will be acquired with the MoonDao treasury and stored in the MoonDao Vault.\n\nMoon ownership grants access to DAO voting rights, future events, and additional holder perks outlined below. Welcome to the moon, we hope you stay.\n\n", "id":"moondao", "tags":[ "NFT", "DAO" ] }, { "urls":{ "telegram":"https://t.me/raresama", "website":"https://raresama.com/", "try":"https://raresama.com/", "twitter":"https://twitter.com/RaresamaNFT", "discord":"https://discord.com/channels/938592318380982303/1010237900685840405" }, "slug":"raresama", "createdAt":1699292615958, "logo":{ "small":{ "width":36, "fileName":"raresama-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":400, "fileName":"raresama-logo-large.jpeg", "mimeType":"image/jpeg", "height":400 }, "full":{ "width":3000, "fileName":"raresama-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"Raresama", "chains":[ "moonbeam" ], "defiLLamaTvlExist":false, "projectCreationDate":1662528828000, "shortDescription":"Discover amazing Rare digital artwork", "contracts":[ ], "updatedAt":1722498909462, "category":"nfts", "description":"Raresama brings the magic of owning a piece of artwork to your fingertips. Create or browse NFT art collections and enjoy a diverse mix of artists, genres, styles and movements.", "id":"raresama", "tags":[ "NFT Marketplaces" ] }, { "urls":{ "telegram":"https://gal.xyz/telegram", "website":"https://galxe.com/", "try":"https://galxe.com/", "twitter":"https://twitter.com/Galxe", "medium":"https://blog.galxe.com/", "discord":"https://gal.xyz/discord" }, "slug":"galxe", "createdAt":1699292616277, "logo":{ "small":{ "width":36, "fileName":"galxe-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":400, "fileName":"galxe-logo-large.jpeg", "mimeType":"image/jpeg", "height":400 }, "full":{ "width":3000, "fileName":"galxe-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"Galxe", "chains":[ "moonbeam" ], "defiLLamaTvlExist":false, "projectCreationDate":1659868871000, "shortDescription":"Create Impactful Experiences With #Web3 Credentials. (Formerly Project Galaxy) ", "contracts":[ ], "updatedAt":1722498876438, "category":"nfts", "description":"Galxe is the leading Web3 credential data network in the world. A collaborative credential infrastructure enabling brands and developers to engage communities and build robust products in Web3.", "id":"galxe", "tags":[ "NFT", "Social", "Tool" ] }, { "urls":{ "telegram":"http://t.me/MoonsamaNFT", "website":"https://moonsama.com/", "try":"https://moonsama.com/", "twitter":"https://twitter.com/MoonsamaNFT", "discord":"discord.gg/moonsama" }, "slug":"moonsama", "createdAt":1702283735408, "logo":{ "small":{ "width":36, "fileName":"moonsama-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":512, "fileName":"moonsama-logo-large.jpeg", "mimeType":"image/jpeg", "height":512 }, "full":{ "width":3000, "fileName":"moonsama-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"Moonsama", "chains":[ "moonriver", "moonbeam" ], "defiLLamaTvlExist":false, "projectCreationDate":1651156798000, "shortDescription":"Let's build the multiverse", "contracts":[ ], "updatedAt":1722498892389, "category":"nfts", "description":"Moonsama’s protocol for bi-directional bridging of on-chain digital assets and off-chain applications. This is how we connect web2.0 games, metaverses and blockchains. It enables new games, development and community fun from across the Kusamaverse and beyond!", "id":"moonsama", "tags":[ "NFT", "Gaming" ] }, { "urls":{ "website":"https://smartstamp.com/", "try":"https://smartstamp.com/", "discord":"https://discord.gg/kajPqvZY" }, "slug":"smartstamp", "createdAt":1699292617058, "logo":{ "small":{ "width":36, "fileName":"smartstamp-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":436, "fileName":"smartstamp-logo-large.jpeg", "mimeType":"image/jpeg", "height":436 }, "full":{ "width":3000, "fileName":"smartstamp-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"SmartStamp", "chains":[ "moonbeam", "moonriver" ], "defiLLamaTvlExist":false, "projectCreationDate":1675081766000, "shortDescription":"SmartStamp is the pioneering new standard in identification and authentication for the art world.", "contracts":[ ], "updatedAt":1722498915044, "category":"nfts", "description":"Developed over more than a decade, SmartStamp’s app uses patented AI technology that is designed to read and record artworks’ surface characteristics– offering artists, collectors, institutions, and all arts and culture stakeholders a way to securely and immutably link physical objects to their digital fingerprints on the blockchain. Using the SmartStamp app is as simple as taking a picture, making the groundbreaking security and timestamping power of blockchain technology accessible to anyone who can use a smartphone.", "id":"smartstamp", "tags":[ "NFT" ] }, { "urls":{ "telegram":"https://t.me/yusernetwork", "website":"https://yuser.network/", "try":"https://yuser.network/", "twitter":"https://twitter.com/yuser", "medium":"https://medium.com/yuser", "discord":"https://discord.com/invite/uRRxnfAjhY" }, "slug":"yuser", "createdAt":1699292616605, "logo":{ "small":{ "width":36, "fileName":"yuser-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":512, "fileName":"yuser-logo-large.jpeg", "mimeType":"image/jpeg", "height":512 }, "full":{ "width":3000, "fileName":"yuser-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"Yuser", "chains":[ "moonriver" ], "defiLLamaTvlExist":false, "projectCreationDate":1644828523000, "shortDescription":"The first NFT social networking app- by creators, for creators", "contracts":[ ], "updatedAt":1722498932483, "category":"nfts", "description":"Yuser’s mission is to build an ecosystem of interconnected applications that put power back into the hands of users by giving them full control over their content, data, and personal networks. Developers can connect via an API to instantly gain access to millions of users and incentivize them to try their product by paying them with a token.", "id":"yuser", "tags":[ "NFT Marketplaces", "GLMR Grants", "MOVR Grants" ] }, { "urls":{ "telegram":"https://t.me/cryptosoots", "website":"https://raregems.io/my#", "try":"https://raregems.io/my#", "twitter":"https://twitter.com/RareGems_io" }, "slug":"rare-gems", "createdAt":1702283745336, "logo":{ "small":{ "width":36, "fileName":"rare-gems-logo-small.png", "mimeType":"image/png", "height":36 }, "large":{ "width":360, "fileName":"rare-gems-logo-large.png", "mimeType":"image/png", "height":360 }, "full":{ "width":3000, "fileName":"rare-gems-logo-full.png", "mimeType":"image/png", "height":3000 } }, "name":"Rare Gems", "chains":[ "moonriver", "moonbeam" ], "defiLLamaTvlExist":false, "projectCreationDate":1652705611000, "shortDescription":"Multichain NFT marketplace.", "contracts":[ ], "updatedAt":1722498909205, "category":"nfts", "description":"Multichain NFT marketplace\nCreated by \n@cryptosoots", "id":"rare-gems", "tags":[ "NFT Marketplaces" ] }, { "urls":{ "telegram":"https://t.me/rmrkapp", "website":"https://wizard.rmrk.dev", "try":"https://wizard.rmrk.dev", "twitter":"https://x.com/rmrkapp", "github":"https://github.com/rmrk-team", "medium":"https://medium.com/rmrkapp" }, "slug":"rmrk-wizard", "createdAt":1699292616919, "logo":{ "small":{ "width":36, "fileName":"rmrk-wizard-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":512, "fileName":"rmrk-wizard-logo-large.jpeg", "mimeType":"image/jpeg", "height":512 }, "full":{ "width":3000, "fileName":"rmrk-wizard-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"RMRK Wizard", "chains":[ "moonbeam", "moonriver" ], "defiLLamaTvlExist":false, "projectCreationDate":1692255253000, "shortDescription":"A no-code-but-code wizard UI for building NFTs 2.0", "contracts":[ ], "updatedAt":1722498911520, "category":"nfts", "description":"A simple UI to put together NFT 2.0 legos created by the RMRK.app team. Use this tool to get started developing advanced NFT collections by picking from a set of functions you need, and the tool will compose code for you which only needs final tweaks before being deployed!", "id":"rmrk-wizard", "tags":[ "NFT", "Tool", "Developer Tools" ] }, { "urls":{ "telegram":"https://t.me/evelonapp", "website":"https://platform.evelon.app/", "try":"https://www.evelon.app/", "twitter":"https://twitter.com/EvelonApp" }, "slug":"evelon-app", "createdAt":1699292616145, "logo":{ "small":{ "width":36, "fileName":"evelon-app-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":512, "fileName":"evelon-app-logo-large.jpeg", "mimeType":"image/jpeg", "height":512 }, "full":{ "width":3000, "fileName":"evelon-app-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"Evelon.App", "chains":[ "moonbeam" ], "defiLLamaTvlExist":false, "projectCreationDate":1690486894000, "shortDescription":"Transform the way you create and bring to life your own unique DNFTs, with the revolutionary platform that combines cutting-edge AI technology.", "contracts":[ ], "updatedAt":1722498873048, "category":"nfts", "description":"Evelon is a no code platform that allows you to create and deploy dynamic NFTs with ease. This project is a game changer in the world of NFTs and image generation. Evelon uses AI to generate high-quality images, making it possible to create NFTs with unique visuals that are both dynamic and engaging.", "id":"evelon-app", "tags":[ "NFT", "Tool" ] }, { "urls":{ "website":"https://mintlabz.io/", "try":"https://app.mintlabz.io/", "twitter":"https://twitter.com/mintlabz", "medium":"https://blog.mintlabz.io/", "discord":"https://discord.com/invite/BRF2PEetea" }, "slug":"mintlabz", "createdAt":1712311518649, "logo":{ "small":{ "width":36, "fileName":"mintlabz-logo-small.png", "mimeType":"image/png", "height":36 }, "large":{ "width":400, "fileName":"mintlabz-logo-large.png", "mimeType":"image/png", "height":400 }, "full":{ "width":3000, "fileName":"mintlabz-logo-full.png", "mimeType":"image/png", "height":3000 } }, "name":"Mintlabz", "chains":[ "moonbeam" ], "defiLLamaTvlExist":false, "projectCreationDate":1712189524, "shortDescription":"MintLabz is a complete crosschain NFT solution at zero cost.", "contracts":[ ], "updatedAt":1722498889042, "category":"nfts", "description":"MintLabz aims to establish a digital NFT minting platform for third party projects to create NFT collections with utilities to reward the NFT holder. Our mission is to become the number one choice for providing complete cross-chain NFT solutions to B2B customers.", "id":"mintlabz", "tags":[ "nfts" ] }, { "urls":{ "telegram":"https://t.me/golempark", "website":"https://golempark.com", "try":"https://golempark.com", "twitter":"https://twitter.com/golempark", "discord":"https://discord.gg/rNvtdHN8q7" }, "slug":"golem-park", "createdAt":1699292617039, "logo":{ "small":{ "width":36, "fileName":"golem-park-logo-small.png", "mimeType":"image/png", "height":36 }, "large":{ "width":512, "fileName":"golem-park-logo-large.png", "mimeType":"image/png", "height":512 }, "full":{ "width":3000, "fileName":"golem-park-logo-full.png", "mimeType":"image/png", "height":3000 } }, "name":"Golem Park", "chains":[ "moonbeam" ], "defiLLamaTvlExist":false, "projectCreationDate":1676839105000, "shortDescription":"Golem Park is holders friendly NFT collection. P2E blockchain game, $GP Token, Staking Pools & more", "contracts":[ { "chain":"moonbeam", "contract":"0x74746524f5A31F08e0528FaA704C2c5d8d116506" } ], "updatedAt":1722498878088, "category":"nfts", "description":"First Time In Crypto History Token Burning Campaign!\n30% Of Total Token Supply Will Be Burned In 30 Days.\n\nAfter Minting We Are Going To Release Deflationary $GP Token & 50% Of Total Supply Will Be Distributed To All $GP NFT Holders, 1 NFT = 5 000 000 Tokens. Then 30 Days Each Day We'll Burn 1% Of Total Token Supply To Ensure Token Price Will Go UP!\n\nWorld Of Golems is a decentralized Play-To-Earn blockchain game.\nOnce You Become Golem Park NFT Holder You Will Be Able To Participate in the WoG Game, Own Countries And Display Your Message On Them.\n\nThe Leaderboard Shows Of TOP 5 Wealthiest Countries & Every Month Owners Of These Countries Will Be Rewarded With $GLMR.", "id":"golem-park", "tags":[ "NFT" ] }, { "urls":{ "telegram":"https://t.me/rarible", "website":"https://rarible.com/", "try":"https://rarible.com/", "twitter":"https://x.com/rarible", "discord":"https://discord.com/invite/rarible" }, "slug":"rarible", "createdAt":1722498909701, "logo":{ "small":{ "width":429, "fileName":"rarible-small.png", "mimeType":"image/png", "height":121 }, "large":{ "width":858, "fileName":"rarible-medium.png", "mimeType":"image/png", "height":242 }, "full":{ "width":1716, "fileName":"rarible-large.png", "mimeType":"image/png", "height":485 } }, "name":"Rarible", "chains":[ "moonbeam" ], "shortDescription":"Rarible - NFT Marketplace for Brands, Communities and Traders", "projectCreationDate":1721872843, "contracts":[ ], "updatedAt":1722498909701, "category":"nfts", "description":"Discover, sell and buy NFTs on Rarible! Our aggregated NFT marketplace for Ethereum NFTs and Polygon NFTs powers brands, collections and creator marketplaces.", "id":"rarible", "featured":false, "tags":[ "NFT" ] }, { "urls":{ "website":"https://neoncrisis.io/", "try":"https://neoncrisis.io/", "twitter":"https://twitter.com/NeonCrisisNFT", "discord":"https://discord.gg/MVVjT9k9eD" }, "slug":"neoncrisis-io", "createdAt":1702283737907, "logo":{ "small":{ "width":36, "fileName":"neoncrisis-io-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":319, "fileName":"neoncrisis-io-logo-large.jpeg", "mimeType":"image/jpeg", "height":319 }, "full":{ "width":3000, "fileName":"neoncrisis-io-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"Neon Crisis", "chains":[ "moonriver" ], "defiLLamaTvlExist":false, "projectCreationDate":1654792548000, "shortDescription":"6,008 heroes on the $MOVR network. A $RMRK powered metaverse featuring battle simulations, equipables, and more!", "contracts":[ ], "updatedAt":1722498896060, "category":"nfts", "description":"", "id":"neoncrisis-io", "tags":[ "NFT", "Gaming" ] }, { "urls":{ "telegram":"https://t.me/xp_network", "website":"https://xp.network/", "try":"https://xp.network/", "twitter":"https://twitter.com/xpnetwork_", "discord":"https://discord.com/invite/g3vkcsmd38" }, "slug":"xp-network", "createdAt":1699292615205, "logo":{ "small":{ "width":36, "fileName":"xp-network-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":400, "fileName":"xp-network-logo-large.jpeg", "mimeType":"image/jpeg", "height":400 }, "full":{ "width":3000, "fileName":"xp-network-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"XP Network", "chains":[ "moonbeam" ], "defiLLamaTvlExist":false, "projectCreationDate":1673327644000, "shortDescription":"A powerful NFT bridge trusted by all major blockchains ", "contracts":[ ], "updatedAt":1722498932103, "category":"nfts", "description":"We build software tools that enable experienced developers and non-coding blockchain community members to move their assets seamlessly and intuitively between versatile distributed ledgers. By doing so, we encourage unlimited growth of exchange and trade between otherwise isolated ecosystems. We enable them to enrich each other technologically with insights and discoveries. To gain access to new, previously inaccessible markets with users hungry for fresh ideas and technologies to invest in.", "id":"xp-network", "tags":[ "NFT", "Bridges" ] }, { "urls":{ "website":"https://www.damnedpiratessociety.io/", "try":"https://www.damnedpiratessociety.io/", "twitter":"https://twitter.com/TheDPSproject", "discord":"https://discord.com/invite/TheDamnedPiratesSociety" }, "web3goContracts":[ { "name":"Damned Pirates Society: DPSArtifact Token", "chain":"moonriver", "contract":"0xcd84ddadc45a25b02e1a6a5520171487a98e6155" }, { "name":"Damned Pirates Society: DPS Token", "chain":"moonriver", "contract":"0xb6e9e605aa159017173caa6181c522db455f6661" }, { "name":"Damned Pirates Society: DSPFlagship Token", "chain":"moonriver", "contract":"0x3822063a3f1aad3fd0b894e2a8f238ccca7c2d00" }, { "name":"Damned Pirates Society: DSPVoyage Token", "chain":"moonriver", "contract":"0x7b2e778453ab3a0d946c4620fb38a0530a434e15" }, { "name":"Damned Pirates Society: DOUBLOON Token", "chain":"moonriver", "contract":"0xe413a631e8a9a10958d9b7c64157449eae7c2064" } ], "currentTx":{ "moonriver":20402 }, "slug":"damned-pirates-society", "web3goIDs":[ "Damned Pirates Society" ], "createdAt":1699292616058, "logo":{ "small":{ "width":36, "fileName":"damned-pirates-society-logo-small.jpeg", "mimeType":"image/jpeg", "height":36 }, "large":{ "width":400, "fileName":"damned-pirates-society-logo-large.jpeg", "mimeType":"image/jpeg", "height":400 }, "full":{ "width":3000, "fileName":"damned-pirates-society-logo-full.jpeg", "mimeType":"image/jpeg", "height":3000 } }, "name":"Damned Pirates Society", "chains":[ "moonriver" ], "defiLLamaTvlExist":false, "currentUsers":{ "moonriver":2000 }, "projectCreationDate":1644828523000, "shortDescription":"Eclectic pirate-based NFT project with utility", "contracts":[ ], "updatedAt":1722547421801, "category":"nfts", "description":"A long time ago the Fortune’s Grasp was carrying families to settle on The Islands and start a new life. In the middle of their voyage they encountered a fearsome maelstrom. The Captain and his crew worked tirelessly to keep the ship afloat. Badly damaged, the Ship limped to the edges of the storm. It was taking on water and the cries of terrified children could be heard above the crashing waves. Another ship appeared on the horizon, it’s light glowing brightly against the dark night. The Captain of the Fortune’s Grasp ordered his crew to evacuate the families, but the fifty crew members ignored the Captain, abandoning ship, taking all means of escape with them. The Captain, left on the sinking ship, cursed the cowardly crew for damning those innocent souls to the watery depths. Those Forsaken Fifty were marked with The Black Spot, doomed to row the high seas until the Reaper came to claim his mutinous crew to serve on the Ship Of The Damned. However, if they could convince another soul to take their place at the oars, protection would be offered by those Pirates who’ve cheated the Reaper before. Those who’ve served and survived are welcome in the Damned Pirates Society.\r\n\r\nThe Damned Pirate Society is an Profile Picture NFT with inbuilt utility. Stake your Pirate for Treasure Maps(TMAP) and save these for your Doubloon farming voyages on our upcoming, skill based gamified contracts.", "id":"damned-pirates-society", "tags":[ "NFT", "Gaming", "GLMR Grants" ] } ], "count":40 } ``` Below are all possible categories and their respective parameters for querying the API. Ensure you query the API with the parameter formatted exactly as shown in lowercase. | Category | API Parameter | |:--------:|:-------------:| | Bridges | `bridges` | | DAO | `dao` | | DEX | `dex` | | DeFi | `defi` | | Gaming | `gaming` | | Lending | `lending` | | NFTs | `nfts` | | Other | `other` | | Social | `social` | | Wallets | `wallets` | ### Query a Chain {: #query-a-chain} The following queries can be used to query all of the listed projects on Moonbeam or Moonriver. Note that Moonbase Alpha is not a supported network in the DApp Directory. === "Moonbeam" ```bash https://apps.moonbeam.network/api/ds/v1/app-dir/projects?chain=moonbeam ``` === "Moonriver" ```bash https://apps.moonbeam.network/api/ds/v1/app-dir/projects?chain=moonriver ```
You are responsible for checking and validating the accuracy and truthfulness of all content. You are also responsible for doing your own diligence to understand the applicable risks present, including selection, performance, security, accuracy, or use of any third-party information. All information contained herein is subject to modification without notice.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/features/consensus/ --- BEGIN CONTENT --- --- title: Moonbeam's Nimbus Consensus Framework description: Learn about all the parts of Moonbeam's Nimbus consensus framework and how it works as part of Polkadot's shared security model. categories: Basics --- # Nimbus Parachain Consensus Framework ## Introduction {: #introduction } Polkadot relies on a [hybrid consensus model](https://docs.polkadot.com/polkadot-protocol/architecture/polkadot-chain/pos-consensus/). In such a scheme, the block finality gadget and the block production mechanism are separate. Consequently, parachains only have to worry about producing blocks and rely on the relay chain to validate the state transitions. At a parachain level, block producers are called [collators](https://wiki.polkadot.network/learn/learn-collator/). They maintain parachains (such as Moonbeam) by collecting transactions from users and offering blocks to the relay chain [validators](https://wiki.polkadot.network/learn/learn-validator/). However, parachains might find the following problems they need to solve in a trustless and decentralized matter (if applicable): - Amongst all of the nodes in the network, which ones are allowed to author blocks? - If multiple nodes are allowed, will they be eligible at the same time? Only one? Maybe a few? Enter Nimbus. Nimbus is a framework for building slot-based consensus algorithms on [Cumulus](https://github.com/paritytech/polkadot-sdk/tree/master/cumulus)-based parachains. It strives to provide standard implementations for the logistical parts of such consensus engines and helpful traits for implementing the elements (filters) that researchers and developers want to customize. These filters can be customizable to define what a block authorship slot is and can be composed, so block authorship is restricted to a subset of collators in multiple steps. For example, Moonbeam uses a two-layer approach. The first layer comprises the parachain staking filter, which helps select an active collator pool among all collator candidates using a staked-based ranking. The second layer adds another filter which narrows down the number of collators to a subset for each slot. Notice that Nimbus can only answer which collator(s) are eligible to produce a parachain block in the next available slot. It is the [Cumulus](https://docs.polkadot.com/develop/parachains/#cumulus) consensus mechanism that marks this parachain block as best, and ultimately the [BABE](https://docs.polkadot.com/polkadot-protocol/architecture/polkadot-chain/pos-consensus/#babe) and [GRANDPA](https://docs.polkadot.com/polkadot-protocol/architecture/polkadot-chain/pos-consensus/#grandpa-finality-gadget) hybrid consensus model (of the relay chain) that will include this parachain block in the relay chain and finalize it. Once any relay chain forks are resolved at a relay chain level, that parachain block is deterministically finalized. The following two sections go over the filtering strategy currently used on Moonbeam. ## Parachain Staking Filtering {: #parachain-staking-filtering } Collators can join the candidate pool by simply bonding some tokens via an extrinsic. Once in the pool, token holders can add to the candidate's stake via delegation (also referred to as staking), that is, at a parachain level. Parachain staking is the first of the two Nimbus filters applied to the candidate pool. It selects the top {{ networks.moonbase.staking.max_candidates }} candidates in terms of tokens staked in the network, which includes the candidate's bond and delegations from token holders. This filtered pool is called selected candidates, and selected candidates are renewed every round (which lasts {{ networks.moonbase.staking.round_blocks }} blocks). For a given round, the following diagram describes the parachain staking filtering: ![Nimbus Parachain Staking Filter](/images/learn/features/consensus/consensus-1.webp) From this pool, another filter is applied to retrieve a subset of eligible candidates for the next block authoring slot. If you want to learn more about staking, visit our [staking documentation](/learn/features/staking/). ## Fixed Size Subset Filtering {: #fixed-size-subset-filtering } Once the parachain staking filter is applied and the selected candidates are retrieved, a second filter is applied on a block by block basis and helps narrow down the selected candidates to a smaller number of eligible collators for the next block authoring slot. In broad terms, this second filter picks a pseudo-random subset of the previously selected candidates. The eligibility ratio, a tunable parameter, defines the size of this subset. A high eligibility ratio results in fewer chances for the network to skip a block production slot, as more collators will be eligible to propose a block for a specific slot. However, only a certain number of validators are assigned to a parachain, meaning that most of these blocks will not be backed by a validator. For those that are, a higher number of backed blocks means that it might take longer for the relay chain to solve any possible forks and return a finalized block. Moreover, this might create an unfair advantage for certain collators that might be able to get their proposed block faster to relay chain validators, securing a higher portion of block rewards (if any). A lower eligibility ratio might provide faster block finalization times and a fairer block production distribution amongst collators. However, if the eligible collators are not able to propose a block (for whatever reason), the network will skip a block, affecting its stability. Once the size of the subset is defined, collators are randomly selected using a source of entropy. Currently, an internal coin-flipping algorithm is implemented, but this will later be migrated to use [Verifiable random function](https://docs.polkadot.com/polkadot-protocol/parachain-basics/randomness/){target=\_blank}. Consequently, a new subset of eligible collators is selected for every relay chain block. For a given round and a given block `XYZ`, the following diagram describes the fixed-size subset filtering: ![Nimbus Parachain Staking Filter](/images/learn/features/consensus/consensus-2.webp) ## Why Nimbus? {: #why-nimbus } You might ask yourself: but why Nimbus? Initially, it was not envisioned when Moonbeam was being developed. As Moonbeam progressed, the necessity for a more customizable but straightforward parachain consensus mechanism became clear, as the available methods presented some drawbacks or technical limitations. With Nimbus, writing a parachain consensus engine is as easy as writing a pallet! This simplicity and flexibility is the main value it adds. Some technical benefits of Nimbus are considered in the following sections. ### Weight and Extra Execution {: #weight-and-extra-execution } Nimbus puts the author-checking execution in a [Substrate pallet](https://docs.polkadot.com/develop/parachains/customize-parachain/overview/). At first glance, you might think this adds a higher execution load to a single block compared to doing this check off-chain. But consider this from a validator’s perspective The validators will also have to check the author. By putting the author-checking execution logic in a pallet, the execution time can be benchmarked and quantified with weights. If this execution time is not accounted for, there is the risk of a block exceeding the relay chain Wasm execution limit (currently 0.5 seconds). In practice, this check will be fast and will most likely not push execution time over the limit. But from a theoretical perspective, accounting for its weight is better for implementation purposes. ### Reusability {: #reusability } Another benefit of moving the author-checking execution to a pallet, rather than a custom executor, is that one single executor can be reused for any consensus that can be expressed in the Nimbus framework. That is slot-based, signature-sealed algorithms. For example, the [relay-chain provided consensus](https://github.com/paritytech/polkadot-sdk/blob/master/cumulus/client/consensus/relay-chain/src/lib.rs), [AuRa](https://crates.io/crates/sc-consensus-aura) and [BABE](https://crates.io/crates/sc-consensus-babe) each have their own custom executor. With Nimbus, these consensus mechanisms can reuse the same executor. The power of reusability is evidenced by the Nimbus implementation of AuRa in less than 100 lines of code. ### Hot-Swapping Consensus {: #hot-swapping-consensus } Teams building parachains may want to change, tune, or adjust their consensus algorithm from time to time. Without nimbus, swapping consensus would require a client upgrade and hard fork. With the Nimbus framework, writing a consensus engine is as easy as writing a [Substrate pallet](https://docs.polkadot.com/develop/parachains/customize-parachain/make-custom-pallet/). Consequently, swapping consensus is as easy as upgrading a pallet. Nonetheless, hot swapping is still bounded by consensus engines (filters) that fit within Nimbus, but it might be helpful for teams that are yet confident on what consensus they want to implement in the long run. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/features/eth-compatibility/ --- BEGIN CONTENT --- --- title: Ethereum Compatibility description: Transitioning from Ethereum to Moonbeam? Here's a brief overview of the key components and key differences of Moonbeam's Ethereum compatibility. categories: Basics --- # Ethereum Compatibility Moonbeam bridges the Ethereum and Polkadot ecosystems, offering developers the familiarity of Ethereum's tooling and infrastructure while leveraging Polkadot's scalability and interoperability. This documentation overviews Moonbeam's Ethereum compatibility features and highlights its key components. It also covers some critical differences between Moonbeam and Ethereum so Ethereum developers know what to expect. ## Key Components {: #key-components } ### EVM Compatibility {: #evm } Moonbeam incorporates a fully compatible EVM to execute smart contracts in Solidity or other EVM-compatible languages. This enables developers to deploy existing Ethereum smart contracts on Moonbeam with minimal modifications. Learn more: - [Moonbeam's Ethereum-compatibility architecture](/learn/platform/technology/#ethereum-compatibility-architecture){target=\_blank} ### Ethereum-style Accounts {: #ethereum-style-accounts } Moonbeam employs H160 Ethereum-style accounts and ECDSA keys, ensuring compatibility with existing Ethereum wallets and facilitating a smooth end-user experience. This is possible due to Moonbeam's unified accounts system, which modifies the underlying Substrate account system to use Ethereum accounts by default. Learn more: - [Moonbeam's unified accounts system](/learn/core-concepts/unified-accounts/){target=\_blank} ### JSON-RPC Support {: #json-rpc-support } Moonbeam offers full JSON-RPC compatibility with Ethereum, allowing developers to interact with Moonbeam nodes using familiar Ethereum tools and libraries. This compatibility extends to methods for account management, transaction submission, smart contract deployment, and event monitoring. In addition to standard Ethereum RPC methods, Moonbeam supports non-standard Debug and Trace modules, providing developers with enhanced debugging and tracing capabilities for smart contract execution. The Debug module allows developers to inspect internal state transitions and execution traces, enabling efficient debugging of complex smart contracts. The Trace module provides detailed transaction traces, including opcode-level execution information and gas consumption, facilitating performance analysis and optimization. Learn more: - [Supported Ethereum RPC methods](/builders/ethereum/json-rpc/eth-rpc/){target=\_blank} - [Subscribe to events with Ethereum JSON-RPC methods](/builders/ethereum/json-rpc/pubsub/){target=\_blank} - [Debug and trace transactions with non-standard RPC methods](/builders/ethereum/json-rpc/debug-trace/){target=\_blank} ### Ethereum Developer Tools and Libraries {: #ethereum-dev-tools } With the underlying support for Ethereum JSON-RPC methods, Moonbeam leverages Ethereum's rich ecosystem of developer libraries and environments. With seamless integration of popular Ethereum libraries and development environments, developers can leverage their existing knowledge and tooling to build and deploy decentralized applications (DApps) on Moonbeam. Learn more: - [Ethereum libraries](/builders/ethereum/libraries/){target=\_blank} - [Ethereum development environments](/builders/ethereum/libraries/){target=\_blank} ### Precompiled Contracts {: #precompiled-contracts } Moonbeam provides precompiled contracts that allow Ethereum smart contracts to seamlessly access Substrate functionality. These precompiled contracts expose Substrate features such as on-chain governance, staking, and identity management to Ethereum-based DApps on Moonbeam. This integration ensures that Ethereum developers can harness the full potential of Moonbeam's features, expanding the possibilities for dApp development on Moonbeam. In addition, developers can leverage Ethereum MainNet precompiles seamlessly within their smart contracts on Moonbeam. These precompiled contracts, widely used on the Ethereum network, offer optimized and efficient execution of common cryptographic operations and complex computations. By supporting Ethereum MainNet precompiles, Moonbeam ensures compatibility with Ethereum-based dApps while enabling developers to utilize familiar tools and libraries to build on its platform. Learn more: - [Overview of the precompiled contracts on Moonbeam](/builders/ethereum/precompiles/overview/){target=\_blank} ### Ethereum Token Standards {: #ethereum-token-standards } Moonbeam supports Ethereum token standards, allowing developers to deploy and interact with tokens that adhere to popular standards such as ERC-20, ERC-721, and ERC-1155. By supporting these standards, Moonbeam enables developers to deploy existing Ethereum tokens without modification. Due to Moonbeam's native interoperability, ERC-20s can be sent cross-chain to other chains within the Polkadot ecosystem via Cross-Consensus Messaging (XCM). Learn more: - [Create common OpenZeppelin contracts such as ERC-20, ERC-721, and ERC-1155 tokens](/builders/ethereum/dev-env/openzeppelin/contracts/){target=\_blank} - [XCM-enabled ERC-20s](/builders/interoperability/xcm/xc20/overview/#local-xc20s){target=\_blank} (also referred to as local XC-20s) ## Key Differences {: #key-differences } ### Consensus Mechanisms {: #consensus-mechanisms } Moonbeam uses a Delegated Proof-of-Stake (DPoS) consensus mechanism, where token holders in the network can delegate candidates to become block producers, known as _collators_. On the other hand, Ethereum uses a Proof-of-Stake (PoS) system in which validators are selected based on their stake in the network to produce and validate blocks. Learn more: - [Differences between PoS and DPoS](/learn/core-concepts/consensus-finality/#main-differences){target=_blank} ### Finality {: #finality } Moonbeam and Ethereum have different finality processes. On Ethereum, there is a checkpoint system where validators determine finality at checkpoint blocks, which takes at least 6.4 minutes for a block to be finalized. Moonbeam relies on Polkadot's [GRANDPA](https://docs.polkadot.com/polkadot-protocol/architecture/polkadot-chain/pos-consensus/#finality-gadget-grandpa){target=\_blank} finality gadget, which expedites finality by completing the process parallel to block production and allowing relay chain validators to vote on the highest block, finalizing all blocks leading up to that block. Learn more: - [Consensus and finality on Moonbeam](/learn/core-concepts/consensus-finality/){target=_blank} ### Proxy Accounts {: #proxy-accounts } On both Moonbeam and Ethereum, accounts can be controlled by two main types of accounts: Externally Owned Accounts (EOA) or smart contracts. However, on Moonbeam, within both account types, there are also proxy accounts, which can perform a limited number of actions on behalf of another account. Learn more: - [An overview of proxy accounts](https://wiki.polkadot.network/learn/learn-proxies/){target=\_blank} - [How to set up a proxy account](/tokens/manage/proxy-accounts/){target=\_blank} ### Account Balances {: #account-balances } Balances on Ethereum are fairly straightforward; if an account holds tokens, that account has a token balance. On Moonbeam, different balance types exist to support various Substrate functionality. There are five types: free, reducible, reserved, miscellaneous frozen, and fee frozen. When using Ethereum tools, accounts show the reducible balance and don't include locked or frozen balances. Learn more: - [Moonbeam account balances](/learn/core-concepts/balances/){target=_blank} ### Balance Transfers {: #balance-transfers } Since Moonbeam is a Substrate-based chain, balance transfers of the native asset (GLMR, MOVR, and DEV) can occur through the Ethereum and Substrate APIs. Like Ethereum, transfers sent through the Ethereum API rely on the `eth_sendRawTransaction`. Transfers sent through the Substrate API are done using the Balances Pallet, a built-in module in the Substrate framework that provides functionality for managing accounts and balances. Learn more: - [Balance transfers on Moonbeam](/learn/core-concepts/transfers-api/){target=_blank} ### Transaction Fees {: #transaction-fees } Moonbeam and Ethereum calculate transaction fees differently due to variations in their underlying architectures and consensus mechanisms. The fundamental difference in how transaction fees are calculated is that Ethereum uses a gas-based fee system, and Moonbeam uses a weight-based system that maps to the gas used. Moonbeam also implements additional metrics in the underlying gas calculations, including proof size and storage costs. Learn more: - [Calculating transaction fees on Moonbeam](/learn/core-concepts/tx-fees/){target=\_blank} --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/features/governance/ --- BEGIN CONTENT --- --- title: Governance description: As a Polkadot parachain, Moonbeam uses an on-chain governance system, allowing for a stake-weighted vote on public referenda. categories: Governance, Basics --- # Governance on Moonbeam ## Introduction {: #introduction } The goal of Moonbeam’s governance mechanism is to advance the protocol according to the desires of the community. In that shared mission, the governance process seeks to include all token holders. Any and all changes to the protocol must go through a referendum so that all token holders, weighted by stake, can have input on the decision. Governance forums like the [Moonbeam Community Forum](https://forum.moonbeam.network){target=\_blank} and [Polkassembly](https://moonbeam.polkassembly.io/opengov){target=\_blank} enable open discussion and allow proposals to be refined based on community input. Autonomous enactments and [forkless upgrades](https://docs.polkadot.com/develop/parachains/maintenance/runtime-upgrades/#forkless-upgrades){target=\_blank} unite the community towards a shared mission to advance the protocol. With the rollout of OpenGov (originally referred to as Gov2), the second phase of governance in Polkadot, several modifications have been introduced to the governance process. You can read the [OpenGov: What is Polkadot Gov2](https://moonbeam.network/news/opengov-what-is-polkadot-gov2){target=\_blank} blog post, which provides an overview of all of the changes made in OpenGov. As of runtime 2400, all Moonbeam networks use OpenGov as their governance system. ## Principles {: #principles } Guiding "soft" principles for engagement with Moonbeam's governance process include: - Being inclusive to token holders that want to engage with Moonbeam and that are affected by governance decisions - Favoring token holder engagement, even with views contrary to our own, versus a lack of engagement - A commitment to openness and transparency in the decision-making process - Working to keep the greater good of the network above personal gain - Acting at all times as a moral agent that considers the consequences of action (or inaction) from a moral standpoint - Being patient and generous in our interactions with other token holders, but not tolerating abusive or destructive language, actions, and behavior, and abiding by [Moonbeam’s Code of Conduct](https://github.com/moonbeam-foundation/code-of-conduct){target=\_blank} These points were heavily inspired by Vlad Zamfir’s writings on governance. Refer to his articles, especially the [How to Participate in Blockchain Governance in Good Faith (and with Good Manners)](https://medium.com/@Vlad_Zamfir/how-to-participate-in-blockchain-governance-in-good-faith-and-with-good-manners-bd4e16846434){target=\_blank} Medium article. ## On-Chain Governance Mechanics {: #on-chain-governance-mechanics } The "hard" governance process for Moonbeam will be driven by an on-chain process that allows the majority of tokens on the network to determine the outcomes of key decisions around the network. These decision points come in the form of stake-weighted voting on proposed referenda. Some of the main components of this governance model include: - **Referenda** — a stake-based voting scheme where each referendum is tied to a specific proposal for a change to the Moonbeam system including values for key parameters, code upgrades, or changes to the governance system itself - **Voting** — referenda will be voted on by token holders on a stake-weighted basis. Referenda which pass are subject to delayed enactment so that people who disagree with the direction of the decision have time to exit the network - **Council & Technical Committee Governance V1** — a group of community members who have special voting rights within the system. With the deprecation and removal of Governance v1, both of these committees were dissolved as of the [runtime 2800 release](https://forum.moonbeam.network/t/runtime-rt2801-schedule/1616/4){target=\_blank} - **OpenGov Technical Committee** — a group of community members who can add certain proposals to the Whitelisted Track For more details on how these Substrate frame pallets implement on-chain governance, you can checkout the [Walkthrough of Polkadot’s Governance](https://polkadot.com/blog/a-walkthrough-of-polkadots-governance){target=\_blank} blog post and the [Polkadot Governance Wiki](https://wiki.polkadot.network/learn/learn-polkadot-opengov/){target=\_blank}. ## Governance v2: OpenGov {: #opengov } This section will cover everything you need to know about OpenGov on Moonbeam. ### General Definitions {: #general-definitions-gov2 } - **Proposal** — an action or item, defined by the preimage hash, being proposed by a token holder and open for consideration and discussion by token holders - **Referendum** — a proposal that is up for token-holder voting. Each referendum is tied to a specific proposal for a change to the Moonbeam system including values for key parameters, code upgrades, or changes to the governance system itself - **Preimage hash** — hash of the proposal to be enacted. The first step to make a proposal is to submit a preimage. The hash is just its identifier. The proposer of the preimage can be different than the user that proposes that preimage as a formal proposal - **Preimage deposit** — amount of tokens that the proposer needs to bond when submitting a preimage. It is calculated as the sum of a base deposit per network plus a fee per byte of the preimage being proposed - **Origin** - an authorization-based dispatch source for an operation, which is used to determine the Track that a referendum is posted under - **Track** - an Origin-specific pipeline that outlines the life cycle of proposals. Currently, there are five Tracks: | Origin Track | Description | Referendum Examples | |:-------------------:|:--------------------------------------------------------------------------------:|:--------------------------------------------------------------------:| | Root | Highest privilege | Runtime upgrades, Technical Committee management | | Whitelisted | Proposals to be whitelisted by the Technical Committee before being dispatched | Fast-tracked operations | | General Admin | For general on-chain decisions | Changes to XCM fees, Orbiter program, Staking parameters, Registrars | | Emergency Canceller | For cancellation of a referendum. Decision Deposit is refunded | Wrongly constructed referendum | | Emergency Killer | For killing of bad/malicious referendum. Decision Deposit is slashed | Malicious referendum | | Fast General Admin | For faster general on-chain decisions | HRMP channel management | Tracks have different criteria parameters that are proportional to their level of Origin class. For example, more dangerous and privileged referenda will have more safeguards, higher thresholds, and longer consideration periods for approval. Please refer to the [Governance Parameters](#governance-parameters-v2) section for more information. - **Voting** — a mechanism for token holders to support (Aye), oppose (Nay), or remain neutral (Abstain) on a proposal. For Aye and Nay, the voting weight is determined by both the number of tokens locked and the lock duration (Conviction). Abstain votes do not receive additional weighting - **Conviction** — the time that token holders voluntarily lock their tokens when voting; the longer they are locked, the more weight their vote has - **Lock balance** — the number of tokens that a user commits to a vote (note, this is not the same as a user's total account balance) Moonbeam uses the concept of voluntary locking, which allows token holders to increase their voting power by locking tokens for a longer period of time. Specifying no Lock Period means a user's vote is valued at 10% of their lock balance. Specifying a greater Conviction increases voting power. For each increase in Conviction (vote multiplier), the Lock Periods double - **Approval** — minimum "Aye" votes as a percentage of overall Conviction-weighted votes needed for approval - **Support** — the minimum portion of Aye and Abstain votes (ignoring conviction) needed as a percentage of the total active supply for a proposal to pass. Nay votes do not count toward Support - **Lead-in Period** — the initial proposal voting and discussion period. At this stage, proposals are in an undecided state until they pass some criteria for the given Track. The criteria include: - **Prepare Period** — the minimum time the referendum needs to wait before it can progress to the next phase after submission - **Capacity** — limit for the number of referenda on a given Track that can be decided at once - **Decision Deposit** — the minimum deposit amount required for a referendum to progress to the decision phase after the end of the Lead-in Period. Since each Track has a defined Capacity, this deposit is larger than the submission deposit, and its goal is to mitigate spam - **Decide Period** - token holders continue to vote on the referendum. If a referendum does not pass by the end of the period, it will be rejected, and the Decision Deposit will be refunded - **Confirm Period** - a period of time within the Decide Period where the referendum needs to have maintained enough Approval and Support to be approved and move to the Enactment Period - **Enactment Period** - a specified time, which is defined at the time the proposal was created, that an approved referendum waits before it can be dispatched. There is a minimum amount of time for each Track - **Vote Delegation** — a voter can give their voting power, including Conviction voting, to another token holder (delegate), who may be more knowledgeable and able to make specific decisions - **Multirole Delegation** — the ability to delegate voting power on a Track-by-Track basis, where a token holder can specify different delegates for each Track ### Governance Parameters {: #governance-parameters-v2 } === "Moonbeam" | Variable | Value | |:---------------------------:|:----------------------------------------------------------:| | Preimage base deposit | {{ networks.moonbeam.preimage.base_deposit }} GLMR | | Preimage deposit per byte | {{ networks.moonbeam.preimage.byte_deposit }} GLMR | | Proposal Submission Deposit | {{ networks.moonbeam.governance.submission_deposit }} GLMR | === "Moonriver" | Variable | Value | |:---------------------------:|:-----------------------------------------------------------:| | Preimage base deposit | {{ networks.moonriver.preimage.base_deposit }} MOVR | | Preimage deposit per byte | {{ networks.moonriver.preimage.byte_deposit }} MOVR | | Proposal Submission Deposit | {{ networks.moonriver.governance.submission_deposit }} MOVR | === "Moonbase Alpha" | Variable | Value | |:---------------------------:|:---------------------------------------------------------:| | Preimage base deposit | {{ networks.moonbase.preimage.base_deposit }} DEV | | Preimage deposit per byte | {{ networks.moonbase.preimage.byte_deposit }} DEV | | Proposal Submission Deposit | {{ networks.moonbase.governance.submission_deposit }} DEV | #### General Parameters by Track {: #general-parameters-by-track } === "Moonbeam" | Track | Track ID | Capacity | Decision
Deposit | |:----------------------:|:--------:|:-----------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------:| | Root | 0 | {{ networks.moonbeam.governance.tracks.root.max_deciding }} proposals | {{ networks.moonbeam.governance.tracks.root.decision_deposit }} GLMR | | Whitelisted | 1 | {{ networks.moonbeam.governance.tracks.whitelisted.max_deciding }} proposals | {{ networks.moonbeam.governance.tracks.whitelisted.decision_deposit }} GLMR | | General Admin | 2 | {{ networks.moonbeam.governance.tracks.general_admin.max_deciding }} proposals | {{ networks.moonbeam.governance.tracks.general_admin.decision_deposit }} GLMR | | Emergency
Canceller | 3 | {{ networks.moonbeam.governance.tracks.canceller.max_deciding }} proposals | {{ networks.moonbeam.governance.tracks.canceller.decision_deposit }} GLMR | | Emergency
Killer | 4 | {{ networks.moonbeam.governance.tracks.killer.max_deciding }} proposals | {{ networks.moonbeam.governance.tracks.killer.decision_deposit }} GLMR | | Fast General Admin | 5 | {{ networks.moonbeam.governance.tracks.fast_general_admin.max_deciding }} proposals | {{ networks.moonbeam.governance.tracks.fast_general_admin.decision_deposit }} GLMR | === "Moonriver" | Track | Track ID | Capacity | Decision
Deposit | |:----------------------:|:--------:|:------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------:| | Root | 0 | {{ networks.moonriver.governance.tracks.root.max_deciding }} proposals | {{ networks.moonriver.governance.tracks.root.decision_deposit }} MOVR | | Whitelisted | 1 | {{ networks.moonriver.governance.tracks.whitelisted.max_deciding }} proposals | {{ networks.moonriver.governance.tracks.whitelisted.decision_deposit }} MOVR | | General Admin | 2 | {{ networks.moonriver.governance.tracks.general_admin.max_deciding }} proposals | {{ networks.moonriver.governance.tracks.general_admin.decision_deposit }} MOVR | | Emergency
Canceller | 3 | {{ networks.moonriver.governance.tracks.canceller.max_deciding }} proposals | {{ networks.moonriver.governance.tracks.canceller.decision_deposit }} MOVR | | Emergency
Killer | 4 | {{ networks.moonriver.governance.tracks.killer.max_deciding }} proposals | {{ networks.moonriver.governance.tracks.killer.decision_deposit }} MOVR | | Fast General Admin | 5 | {{ networks.moonriver.governance.tracks.fast_general_admin.max_deciding }} proposals | {{ networks.moonriver.governance.tracks.fast_general_admin.decision_deposit }} MOVR | === "Moonbase Alpha" | Track | Track ID | Capacity | Decision
Deposit | |:----------------------:|:--------:|:-----------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------:| | Root | 0 | {{ networks.moonbase.governance.tracks.root.max_deciding }} proposals | {{ networks.moonbase.governance.tracks.root.decision_deposit }} DEV | | Whitelisted | 1 | {{ networks.moonbase.governance.tracks.whitelisted.max_deciding }} proposals | {{ networks.moonbase.governance.tracks.whitelisted.decision_deposit }} DEV | | General Admin | 2 | {{ networks.moonbase.governance.tracks.general_admin.max_deciding }} proposals | {{ networks.moonbase.governance.tracks.general_admin.decision_deposit }} DEV | | Emergency
Canceller | 3 | {{ networks.moonbase.governance.tracks.canceller.max_deciding }} proposals | {{ networks.moonbase.governance.tracks.canceller.decision_deposit }} DEV | | Emergency
Killer | 4 | {{ networks.moonbase.governance.tracks.killer.max_deciding }} proposals | {{ networks.moonbase.governance.tracks.killer.decision_deposit }} DEV | | Fast General Admin | 5 | {{ networks.moonbase.governance.tracks.fast_general_admin.max_deciding }} proposals | {{ networks.moonbase.governance.tracks.fast_general_admin.decision_deposit }} DEV | #### Period Parameters by Track {: #period-parameters-by-track } === "Moonbeam" | Track | Prepare
Period | Decide
Period | Confirm
Period | Minimum
Enactment Period | |:----------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| | Root | {{ networks.moonbeam.governance.tracks.root.prepare_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.root.prepare_period.time }}) | {{ networks.moonbeam.governance.tracks.root.decision_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.root.decision_period.time }}) | {{ networks.moonbeam.governance.tracks.root.confirm_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.root.confirm_period.time }}) | {{ networks.moonbeam.governance.tracks.root.min_enactment_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.root.min_enactment_period.time }}) | | Whitelisted | {{ networks.moonbeam.governance.tracks.whitelisted.prepare_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.whitelisted.prepare_period.time }}) | {{ networks.moonbeam.governance.tracks.whitelisted.decision_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.whitelisted.decision_period.time }}) | {{ networks.moonbeam.governance.tracks.whitelisted.confirm_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.whitelisted.confirm_period.time }}) | {{ networks.moonbeam.governance.tracks.whitelisted.min_enactment_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.whitelisted.min_enactment_period.time }}) | | General Admin | {{ networks.moonbeam.governance.tracks.general_admin.prepare_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.general_admin.prepare_period.time }}) | {{ networks.moonbeam.governance.tracks.general_admin.decision_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.general_admin.decision_period.time }}) | {{ networks.moonbeam.governance.tracks.general_admin.confirm_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.general_admin.confirm_period.time }}) | {{ networks.moonbeam.governance.tracks.general_admin.min_enactment_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.general_admin.min_enactment_period.time }}) | | Emergency
Canceller | {{ networks.moonbeam.governance.tracks.canceller.prepare_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.canceller.prepare_period.time }}) | {{ networks.moonbeam.governance.tracks.canceller.decision_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.canceller.decision_period.time }}) | {{ networks.moonbeam.governance.tracks.canceller.confirm_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.canceller.confirm_period.time }}) | {{ networks.moonbeam.governance.tracks.canceller.min_enactment_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.canceller.min_enactment_period.time }}) | | Emergency
Killer | {{ networks.moonbeam.governance.tracks.killer.prepare_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.killer.prepare_period.time }}) | {{ networks.moonbeam.governance.tracks.killer.decision_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.killer.decision_period.time }}) | {{ networks.moonbeam.governance.tracks.killer.confirm_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.killer.confirm_period.time }}) | {{ networks.moonbeam.governance.tracks.killer.min_enactment_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.killer.min_enactment_period.time }}) | | Fast General Admin | {{ networks.moonbeam.governance.tracks.fast_general_admin.prepare_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.fast_general_admin.prepare_period.time }}) | {{ networks.moonbeam.governance.tracks.fast_general_admin.decision_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.fast_general_admin.decision_period.time }}) | {{ networks.moonbeam.governance.tracks.fast_general_admin.confirm_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.fast_general_admin.confirm_period.time }}) | {{ networks.moonbeam.governance.tracks.fast_general_admin.min_enactment_period.blocks }} blocks
({{ networks.moonbeam.governance.tracks.fast_general_admin.min_enactment_period.time }}) | === "Moonriver" | Track | Prepare
Period | Decide
Period | Confirm
Period | Minimum
Enactment Period | |:----------------------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| | Root | {{ networks.moonriver.governance.tracks.root.prepare_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.root.prepare_period.time }}) | {{ networks.moonriver.governance.tracks.root.decision_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.root.decision_period.time }}) | {{ networks.moonriver.governance.tracks.root.confirm_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.root.confirm_period.time }}) | {{ networks.moonriver.governance.tracks.root.min_enactment_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.root.min_enactment_period.time }}) | | Whitelisted | {{ networks.moonriver.governance.tracks.whitelisted.prepare_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.whitelisted.prepare_period.time }}) | {{ networks.moonriver.governance.tracks.whitelisted.decision_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.whitelisted.decision_period.time }}) | {{ networks.moonriver.governance.tracks.whitelisted.confirm_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.whitelisted.confirm_period.time }}) | {{ networks.moonriver.governance.tracks.whitelisted.min_enactment_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.whitelisted.min_enactment_period.time }}) | | General Admin | {{ networks.moonriver.governance.tracks.general_admin.prepare_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.general_admin.prepare_period.time }}) | {{ networks.moonriver.governance.tracks.general_admin.decision_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.general_admin.decision_period.time }}) | {{ networks.moonriver.governance.tracks.general_admin.confirm_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.general_admin.confirm_period.time }}) | {{ networks.moonriver.governance.tracks.general_admin.min_enactment_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.general_admin.min_enactment_period.time }}) | | Emergency
Canceller | {{ networks.moonriver.governance.tracks.canceller.prepare_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.canceller.prepare_period.time }}) | {{ networks.moonriver.governance.tracks.canceller.decision_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.canceller.decision_period.time }}) | {{ networks.moonriver.governance.tracks.canceller.confirm_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.canceller.confirm_period.time }}) | {{ networks.moonriver.governance.tracks.canceller.min_enactment_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.canceller.min_enactment_period.time }}) | | Emergency
Killer | {{ networks.moonriver.governance.tracks.killer.prepare_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.killer.prepare_period.time }}) | {{ networks.moonriver.governance.tracks.killer.decision_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.killer.decision_period.time }}) | {{ networks.moonriver.governance.tracks.killer.confirm_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.killer.confirm_period.time }}) | {{ networks.moonriver.governance.tracks.killer.min_enactment_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.killer.min_enactment_period.time }}) | | Fast General Admin | {{ networks.moonriver.governance.tracks.fast_general_admin.prepare_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.fast_general_admin.prepare_period.time }}) | {{ networks.moonriver.governance.tracks.fast_general_admin.decision_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.fast_general_admin.decision_period.time }}) | {{ networks.moonriver.governance.tracks.fast_general_admin.confirm_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.fast_general_admin.confirm_period.time }}) | {{ networks.moonriver.governance.tracks.fast_general_admin.min_enactment_period.blocks }} blocks
({{ networks.moonriver.governance.tracks.fast_general_admin.min_enactment_period.time }}) | === "Moonbase Alpha" | Track | Prepare
Period | Decide
Period | Confirm
Period | Minimum
Enactment Period | |:----------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| | Root | {{ networks.moonbase.governance.tracks.root.prepare_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.root.prepare_period.time }}) | {{ networks.moonbase.governance.tracks.root.decision_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.root.decision_period.time }}) | {{ networks.moonbase.governance.tracks.root.confirm_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.root.confirm_period.time }}) | {{ networks.moonbase.governance.tracks.root.min_enactment_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.root.min_enactment_period.time }}) | | Whitelisted | {{ networks.moonbase.governance.tracks.whitelisted.prepare_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.whitelisted.prepare_period.time }}) | {{ networks.moonbase.governance.tracks.whitelisted.decision_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.whitelisted.decision_period.time }}) | {{ networks.moonbase.governance.tracks.whitelisted.confirm_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.whitelisted.confirm_period.time }}) | {{ networks.moonbase.governance.tracks.whitelisted.min_enactment_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.whitelisted.min_enactment_period.time }}) | | General Admin | {{ networks.moonbase.governance.tracks.general_admin.prepare_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.general_admin.prepare_period.time }}) | {{ networks.moonbase.governance.tracks.general_admin.decision_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.general_admin.decision_period.time }}) | {{ networks.moonbase.governance.tracks.general_admin.confirm_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.general_admin.confirm_period.time }}) | {{ networks.moonbase.governance.tracks.general_admin.min_enactment_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.general_admin.min_enactment_period.time }}) | | Emergency
Canceller | {{ networks.moonbase.governance.tracks.canceller.prepare_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.canceller.prepare_period.time }}) | {{ networks.moonbase.governance.tracks.canceller.decision_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.canceller.decision_period.time }}) | {{ networks.moonbase.governance.tracks.canceller.confirm_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.canceller.confirm_period.time }}) | {{ networks.moonbase.governance.tracks.canceller.min_enactment_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.canceller.min_enactment_period.time }}) | | Emergency
Killer | {{ networks.moonbase.governance.tracks.killer.prepare_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.killer.prepare_period.time }}) | {{ networks.moonbase.governance.tracks.killer.decision_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.killer.decision_period.time }}) | {{ networks.moonbase.governance.tracks.killer.confirm_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.killer.confirm_period.time }}) | {{ networks.moonbase.governance.tracks.killer.min_enactment_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.killer.min_enactment_period.time }}) | | Fast General Admin | {{ networks.moonbase.governance.tracks.fast_general_admin.prepare_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.fast_general_admin.prepare_period.time }}) | {{ networks.moonbase.governance.tracks.fast_general_admin.decision_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.fast_general_admin.decision_period.time }}) | {{ networks.moonbase.governance.tracks.fast_general_admin.confirm_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.fast_general_admin.confirm_period.time }}) | {{ networks.moonbase.governance.tracks.fast_general_admin.min_enactment_period.blocks }} blocks
({{ networks.moonbase.governance.tracks.fast_general_admin.min_enactment_period.time }}) | !!! note As of runtime 3000, [asynchronous backing](https://wiki.polkadot.network/learn/learn-async-backing/){target=\_blank} has been enabled on all Moonbeam networks. As a result, the target block time was reduced from 12 seconds to 6 seconds, which may break some timing-based assumptions. #### Support and Approval Parameters by Track {: #support-and-approval-parameters-by-track } === "Moonbeam" | Track | Approval Curve | Approval Parameters | Support Curve | Support Parameters | |:----------------------:|:--------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:-------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| | Root | Reciprocal | {{ networks.moonbeam.governance.tracks.root.min_approval.time0 }}: {{ networks.moonbeam.governance.tracks.root.min_approval.percent0 }}%
{{ networks.moonbeam.governance.tracks.root.min_approval.time1 }}: {{ networks.moonbeam.governance.tracks.root.min_approval.percent1 }}%
{{ networks.moonbeam.governance.tracks.root.min_approval.time2 }}: {{ networks.moonbeam.governance.tracks.root.min_approval.percent2 }}% | Linear | {{ networks.moonbeam.governance.tracks.root.min_support.time0 }}: {{ networks.moonbeam.governance.tracks.root.min_support.percent0 }}%
{{ networks.moonbeam.governance.tracks.root.min_support.time1 }}: {{ networks.moonbeam.governance.tracks.root.min_support.percent1 }}% | | Whitelisted | Reciprocal | {{ networks.moonbeam.governance.tracks.whitelisted.min_approval.time0 }}: {{ networks.moonbeam.governance.tracks.whitelisted.min_approval.percent0 }}%
{{ networks.moonbeam.governance.tracks.whitelisted.min_approval.time1 }}: {{ networks.moonbeam.governance.tracks.whitelisted.min_approval.percent1 }}%
{{ networks.moonbeam.governance.tracks.whitelisted.min_approval.time2 }}: {{ networks.moonbeam.governance.tracks.whitelisted.min_approval.percent2 }}% | Reciprocal | {{ networks.moonbeam.governance.tracks.whitelisted.min_support.time0 }}: {{ networks.moonbeam.governance.tracks.whitelisted.min_support.percent0 }}%
{{ networks.moonbeam.governance.tracks.whitelisted.min_support.time1 }}: {{ networks.moonbeam.governance.tracks.whitelisted.min_support.percent1 }}%
{{ networks.moonbeam.governance.tracks.whitelisted.min_support.time2 }}: {{ networks.moonbeam.governance.tracks.whitelisted.min_support.percent2 }}% | | General Admin | Reciprocal | {{ networks.moonbeam.governance.tracks.general_admin.min_approval.time0 }}: {{ networks.moonbeam.governance.tracks.general_admin.min_approval.percent0 }}%
{{ networks.moonbeam.governance.tracks.general_admin.min_approval.time1 }}: {{ networks.moonbeam.governance.tracks.general_admin.min_approval.percent1 }}%
{{ networks.moonbeam.governance.tracks.general_admin.min_approval.time2 }}: {{ networks.moonbeam.governance.tracks.general_admin.min_approval.percent2 }}% | Reciprocal | {{ networks.moonbeam.governance.tracks.general_admin.min_support.time0 }}: {{ networks.moonbeam.governance.tracks.general_admin.min_support.percent0 }}%
{{ networks.moonbeam.governance.tracks.general_admin.min_support.time1 }}: {{ networks.moonbeam.governance.tracks.general_admin.min_support.percent1 }}%
{{ networks.moonbeam.governance.tracks.general_admin.min_support.time2 }}: {{ networks.moonbeam.governance.tracks.general_admin.min_support.percent2 }}% | | Emergency
Canceller | Reciprocal | {{ networks.moonbeam.governance.tracks.canceller.min_approval.time0 }}: {{ networks.moonbeam.governance.tracks.canceller.min_approval.percent0 }}%
{{ networks.moonbeam.governance.tracks.canceller.min_approval.time1 }}: {{ networks.moonbeam.governance.tracks.canceller.min_approval.percent1 }}%
{{ networks.moonbeam.governance.tracks.canceller.min_approval.time2 }}: {{ networks.moonbeam.governance.tracks.canceller.min_approval.percent2 }}% | Reciprocal | {{ networks.moonbeam.governance.tracks.canceller.min_support.time0 }}: {{ networks.moonbeam.governance.tracks.canceller.min_support.percent0 }}%
{{ networks.moonbeam.governance.tracks.canceller.min_support.time1 }}: {{ networks.moonbeam.governance.tracks.canceller.min_support.percent1 }}%
{{ networks.moonbeam.governance.tracks.canceller.min_support.time2 }}: {{ networks.moonbeam.governance.tracks.canceller.min_support.percent2 }}% | | Emergency
Killer | Reciprocal | {{ networks.moonbeam.governance.tracks.killer.min_approval.time0 }}: {{ networks.moonbeam.governance.tracks.killer.min_approval.percent0 }}%
{{ networks.moonbeam.governance.tracks.killer.min_approval.time1 }}: {{ networks.moonbeam.governance.tracks.killer.min_approval.percent1 }}%
{{ networks.moonbeam.governance.tracks.killer.min_approval.time2 }}: {{ networks.moonbeam.governance.tracks.killer.min_approval.percent2 }}% | Reciprocal | {{ networks.moonbeam.governance.tracks.killer.min_support.time0 }}: {{ networks.moonbeam.governance.tracks.killer.min_support.percent0 }}%
{{ networks.moonbeam.governance.tracks.killer.min_support.time1 }}: {{ networks.moonbeam.governance.tracks.killer.min_support.percent1 }}%
{{ networks.moonbeam.governance.tracks.killer.min_support.time2 }}: {{ networks.moonbeam.governance.tracks.killer.min_support.percent2 }}% | | Fast General Admin | Reciprocal | {{ networks.moonbeam.governance.tracks.fast_general_admin.min_approval.time0 }}: {{ networks.moonbeam.governance.tracks.fast_general_admin.min_approval.percent0 }}%
{{ networks.moonbeam.governance.tracks.fast_general_admin.min_approval.time1 }}: {{ networks.moonbeam.governance.tracks.fast_general_admin.min_approval.percent1 }}%
{{ networks.moonbeam.governance.tracks.fast_general_admin.min_approval.time2 }}: {{ networks.moonbeam.governance.tracks.fast_general_admin.min_approval.percent2 }}% | Reciprocal | {{ networks.moonbeam.governance.tracks.fast_general_admin.min_support.time0 }}: {{ networks.moonbeam.governance.tracks.fast_general_admin.min_support.percent0 }}%
{{ networks.moonbeam.governance.tracks.fast_general_admin.min_support.time1 }}: {{ networks.moonbeam.governance.tracks.fast_general_admin.min_support.percent1 }}%
{{ networks.moonbeam.governance.tracks.fast_general_admin.min_support.time2 }}: {{ networks.moonbeam.governance.tracks.fast_general_admin.min_support.percent2 }}% | === "Moonriver" | Track | Approval Curve | Approval Parameters | Support Curve | Support Parameters | |:----------------------:|:--------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:-------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| | Root | Reciprocal | {{ networks.moonriver.governance.tracks.root.min_approval.time0 }}: {{ networks.moonriver.governance.tracks.root.min_approval.percent0 }}%
{{ networks.moonriver.governance.tracks.root.min_approval.time1 }}: {{ networks.moonriver.governance.tracks.root.min_approval.percent1 }}%
{{ networks.moonriver.governance.tracks.root.min_approval.time2 }}: {{ networks.moonriver.governance.tracks.root.min_approval.percent2 }}% | Linear | {{ networks.moonriver.governance.tracks.root.min_support.time0 }}: {{ networks.moonriver.governance.tracks.root.min_support.percent0 }}%
{{ networks.moonriver.governance.tracks.root.min_support.time1 }}: {{ networks.moonriver.governance.tracks.root.min_support.percent1 }}% | | Whitelisted | Reciprocal | {{ networks.moonriver.governance.tracks.whitelisted.min_approval.time0 }}: {{ networks.moonriver.governance.tracks.whitelisted.min_approval.percent0 }}%
{{ networks.moonriver.governance.tracks.whitelisted.min_approval.time1 }}: {{ networks.moonriver.governance.tracks.whitelisted.min_approval.percent1 }}%
{{ networks.moonriver.governance.tracks.whitelisted.min_approval.time2 }}: {{ networks.moonriver.governance.tracks.whitelisted.min_approval.percent2 }}% | Reciprocal | {{ networks.moonriver.governance.tracks.whitelisted.min_support.time0 }}: {{ networks.moonriver.governance.tracks.whitelisted.min_support.percent0 }}%
{{ networks.moonriver.governance.tracks.whitelisted.min_support.time1 }}: {{ networks.moonriver.governance.tracks.whitelisted.min_support.percent1 }}%
{{ networks.moonriver.governance.tracks.whitelisted.min_support.time2 }}: {{ networks.moonriver.governance.tracks.whitelisted.min_support.percent2 }}% | | General Admin | Reciprocal | {{ networks.moonriver.governance.tracks.general_admin.min_approval.time0 }}: {{ networks.moonriver.governance.tracks.general_admin.min_approval.percent0 }}%
{{ networks.moonriver.governance.tracks.general_admin.min_approval.time1 }}: {{ networks.moonriver.governance.tracks.general_admin.min_approval.percent1 }}%
{{ networks.moonriver.governance.tracks.general_admin.min_approval.time2 }}: {{ networks.moonriver.governance.tracks.general_admin.min_approval.percent2 }}% | Reciprocal | {{ networks.moonriver.governance.tracks.general_admin.min_support.time0 }}: {{ networks.moonriver.governance.tracks.general_admin.min_support.percent0 }}%
{{ networks.moonriver.governance.tracks.general_admin.min_support.time1 }}: {{ networks.moonriver.governance.tracks.general_admin.min_support.percent1 }}%
{{ networks.moonriver.governance.tracks.general_admin.min_support.time2 }}: {{ networks.moonriver.governance.tracks.general_admin.min_support.percent2 }}% | | Emergency
Canceller | Reciprocal | {{ networks.moonriver.governance.tracks.canceller.min_approval.time0 }}: {{ networks.moonriver.governance.tracks.canceller.min_approval.percent0 }}%
{{ networks.moonriver.governance.tracks.canceller.min_approval.time1 }}: {{ networks.moonriver.governance.tracks.canceller.min_approval.percent1 }}%
{{ networks.moonriver.governance.tracks.canceller.min_approval.time2 }}: {{ networks.moonriver.governance.tracks.canceller.min_approval.percent2 }}% | Reciprocal | {{ networks.moonriver.governance.tracks.canceller.min_support.time0 }}: {{ networks.moonriver.governance.tracks.canceller.min_support.percent0 }}%
{{ networks.moonriver.governance.tracks.canceller.min_support.time1 }}: {{ networks.moonriver.governance.tracks.canceller.min_support.percent1 }}%
{{ networks.moonriver.governance.tracks.canceller.min_support.time2 }}: {{ networks.moonriver.governance.tracks.canceller.min_support.percent2 }}% | | Emergency
Killer | Reciprocal | {{ networks.moonriver.governance.tracks.killer.min_approval.time0 }}: {{ networks.moonriver.governance.tracks.killer.min_approval.percent0 }}%
{{ networks.moonriver.governance.tracks.killer.min_approval.time1 }}: {{ networks.moonriver.governance.tracks.killer.min_approval.percent1 }}%
{{ networks.moonriver.governance.tracks.killer.min_approval.time2 }}: {{ networks.moonriver.governance.tracks.killer.min_approval.percent2 }}% | Reciprocal | {{ networks.moonriver.governance.tracks.killer.min_support.time0 }}: {{ networks.moonriver.governance.tracks.killer.min_support.percent0 }}%
{{ networks.moonriver.governance.tracks.killer.min_support.time1 }}: {{ networks.moonriver.governance.tracks.killer.min_support.percent1 }}%
{{ networks.moonriver.governance.tracks.killer.min_support.time2 }}: {{ networks.moonriver.governance.tracks.killer.min_support.percent2 }}% | | Fast General Admin | Reciprocal | {{ networks.moonriver.governance.tracks.fast_general_admin.min_approval.time0 }}: {{ networks.moonriver.governance.tracks.fast_general_admin.min_approval.percent0 }}%
{{ networks.moonriver.governance.tracks.fast_general_admin.min_approval.time1 }}: {{ networks.moonriver.governance.tracks.fast_general_admin.min_approval.percent1 }}%
{{ networks.moonriver.governance.tracks.fast_general_admin.min_approval.time2 }}: {{ networks.moonriver.governance.tracks.fast_general_admin.min_approval.percent2 }}% | Reciprocal | {{ networks.moonriver.governance.tracks.fast_general_admin.min_support.time0 }}: {{ networks.moonriver.governance.tracks.fast_general_admin.min_support.percent0 }}%
{{ networks.moonriver.governance.tracks.fast_general_admin.min_support.time1 }}: {{ networks.moonriver.governance.tracks.fast_general_admin.min_support.percent1 }}%
{{ networks.moonriver.governance.tracks.fast_general_admin.min_support.time2 }}: {{ networks.moonriver.governance.tracks.fast_general_admin.min_support.percent2 }}% | === "Moonbase Alpha" | Track | Approval Curve | Approval Parameters | Support Curve | Support Parameters | |:----------------------:|:--------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:-------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| | Root | Reciprocal | {{ networks.moonbase.governance.tracks.root.min_approval.time0 }}: {{ networks.moonbase.governance.tracks.root.min_approval.percent0 }}%
{{ networks.moonbase.governance.tracks.root.min_approval.time1 }}: {{ networks.moonbase.governance.tracks.root.min_approval.percent1 }}%
{{ networks.moonbase.governance.tracks.root.min_approval.time2 }}: {{ networks.moonbase.governance.tracks.root.min_approval.percent2 }}% | Linear | {{ networks.moonbase.governance.tracks.root.min_support.time0 }}: {{ networks.moonbase.governance.tracks.root.min_support.percent0 }}%
{{ networks.moonbase.governance.tracks.root.min_support.time1 }}: {{ networks.moonbase.governance.tracks.root.min_support.percent1 }}% | | Whitelisted | Reciprocal | {{ networks.moonbase.governance.tracks.whitelisted.min_approval.time0 }}: {{ networks.moonbase.governance.tracks.whitelisted.min_approval.percent0 }}%
{{ networks.moonbase.governance.tracks.whitelisted.min_approval.time1 }}: {{ networks.moonbase.governance.tracks.whitelisted.min_approval.percent1 }}%
{{ networks.moonbase.governance.tracks.whitelisted.min_approval.time2 }}: {{ networks.moonbase.governance.tracks.whitelisted.min_approval.percent2 }}% | Reciprocal | {{ networks.moonbase.governance.tracks.whitelisted.min_support.time0 }}: {{ networks.moonbase.governance.tracks.whitelisted.min_support.percent0 }}%
{{ networks.moonbase.governance.tracks.whitelisted.min_support.time1 }}: {{ networks.moonbase.governance.tracks.whitelisted.min_support.percent1 }}%
{{ networks.moonbase.governance.tracks.whitelisted.min_support.time2 }}: {{ networks.moonbase.governance.tracks.whitelisted.min_support.percent2 }}% | | General Admin | Reciprocal | {{ networks.moonbase.governance.tracks.general_admin.min_approval.time0 }}: {{ networks.moonbase.governance.tracks.general_admin.min_approval.percent0 }}%
{{ networks.moonbase.governance.tracks.general_admin.min_approval.time1 }}: {{ networks.moonbase.governance.tracks.general_admin.min_approval.percent1 }}%
{{ networks.moonbase.governance.tracks.general_admin.min_approval.time2 }}: {{ networks.moonbase.governance.tracks.general_admin.min_approval.percent2 }}% | Reciprocal | {{ networks.moonbase.governance.tracks.general_admin.min_support.time0 }}: {{ networks.moonbase.governance.tracks.general_admin.min_support.percent0 }}%
{{ networks.moonbase.governance.tracks.general_admin.min_support.time1 }}: {{ networks.moonbase.governance.tracks.general_admin.min_support.percent1 }}%
{{ networks.moonbase.governance.tracks.general_admin.min_support.time2 }}: {{ networks.moonbase.governance.tracks.general_admin.min_support.percent2 }}% | | Emergency
Canceller | Reciprocal | {{ networks.moonbase.governance.tracks.canceller.min_approval.time0 }}: {{ networks.moonbase.governance.tracks.canceller.min_approval.percent0 }}%
{{ networks.moonbase.governance.tracks.canceller.min_approval.time1 }}: {{ networks.moonbase.governance.tracks.canceller.min_approval.percent1 }}%
{{ networks.moonbase.governance.tracks.canceller.min_approval.time2 }}: {{ networks.moonbase.governance.tracks.canceller.min_approval.percent2 }}% | Reciprocal | {{ networks.moonbase.governance.tracks.canceller.min_support.time0 }}: {{ networks.moonbase.governance.tracks.canceller.min_support.percent0 }}%
{{ networks.moonbase.governance.tracks.canceller.min_support.time1 }}: {{ networks.moonbase.governance.tracks.canceller.min_support.percent1 }}%
{{ networks.moonbase.governance.tracks.canceller.min_support.time2 }}: {{ networks.moonbase.governance.tracks.canceller.min_support.percent2 }}% | | Emergency
Killer | Reciprocal | {{ networks.moonbase.governance.tracks.killer.min_approval.time0 }}: {{ networks.moonbase.governance.tracks.killer.min_approval.percent0 }}%
{{ networks.moonbase.governance.tracks.killer.min_approval.time1 }}: {{ networks.moonbase.governance.tracks.killer.min_approval.percent1 }}%
{{ networks.moonbase.governance.tracks.killer.min_approval.time2 }}: {{ networks.moonbase.governance.tracks.killer.min_approval.percent2 }}% | Reciprocal | {{ networks.moonbase.governance.tracks.killer.min_support.time0 }}: {{ networks.moonbase.governance.tracks.killer.min_support.percent0 }}%
{{ networks.moonbase.governance.tracks.killer.min_support.time1 }}: {{ networks.moonbase.governance.tracks.killer.min_support.percent1 }}%
{{ networks.moonbase.governance.tracks.killer.min_support.time2 }}: {{ networks.moonbase.governance.tracks.killer.min_support.percent2 }}% | | Fast General Admin | Reciprocal | {{ networks.moonbase.governance.tracks.fast_general_admin.min_approval.time0 }}: {{ networks.moonbase.governance.tracks.fast_general_admin.min_approval.percent0 }}%
{{ networks.moonbase.governance.tracks.fast_general_admin.min_approval.time1 }}: {{ networks.moonbase.governance.tracks.fast_general_admin.min_approval.percent1 }}%
{{ networks.moonbase.governance.tracks.fast_general_admin.min_approval.time2 }}: {{ networks.moonbase.governance.tracks.fast_general_admin.min_approval.percent2 }}% | Reciprocal | {{ networks.moonbase.governance.tracks.fast_general_admin.min_support.time0 }}: {{ networks.moonbase.governance.tracks.fast_general_admin.min_support.percent0 }}%
{{ networks.moonbase.governance.tracks.fast_general_admin.min_support.time1 }}: {{ networks.moonbase.governance.tracks.fast_general_admin.min_support.percent1 }}%
{{ networks.moonbase.governance.tracks.fast_general_admin.min_support.time2 }}: {{ networks.moonbase.governance.tracks.fast_general_admin.min_support.percent2 }}% | #### Conviction Multiplier {: #conviction-multiplier-v2 } The Conviction multiplier is related to the number of Enactment Periods the tokens will be locked for after the referenda is enacted (if approved). Consequently, the longer you are willing to lock your tokens, the stronger your vote will be weighted. You also have the option of not locking tokens at all, but vote weight is drastically reduced (tokens are still locked during the duration of the referendum). If you were to vote 1000 tokens with a 6x Conviction, your weighted vote would be 6000 units. That is, 1000 locked tokens multiplied by the Conviction, which in this scenario would be 6. On the other hand, if you decided you didn't want to have your tokens locked after enactment, you could vote your 1000 tokens with a 0.1x Conviction. In this case, your weighted vote would only be 100 units. The Conviction multiplier values for each network are: === "Moonbeam" | Lock Periods After Enactment | Conviction Multiplier | Approx. Lock Time | |:----------------------------:|:---------------------:|:--------------------------------------------------------------:| | 0 | 0.1 | None | | 1 | 1 | {{networks.moonbeam.conviction.lock_period.conviction_1}} day | | 2 | 2 | {{networks.moonbeam.conviction.lock_period.conviction_2}} days | | 4 | 3 | {{networks.moonbeam.conviction.lock_period.conviction_3}} days | | 8 | 4 | {{networks.moonbeam.conviction.lock_period.conviction_4}} days | | 16 | 5 | {{networks.moonbeam.conviction.lock_period.conviction_5}} days | | 32 | 6 | {{networks.moonbeam.conviction.lock_period.conviction_6}} days | === "Moonriver" | Lock Periods After Enactment | Conviction Multiplier | Approx. Lock Time | |:----------------------------:|:---------------------:|:---------------------------------------------------------------:| | 0 | 0.1 | None | | 1 | 1 | {{networks.moonriver.conviction.lock_period.conviction_1}} day | | 2 | 2 | {{networks.moonriver.conviction.lock_period.conviction_2}} days | | 4 | 3 | {{networks.moonriver.conviction.lock_period.conviction_3}} days | | 8 | 4 | {{networks.moonriver.conviction.lock_period.conviction_4}} days | | 16 | 5 | {{networks.moonriver.conviction.lock_period.conviction_5}} days | | 32 | 6 | {{networks.moonriver.conviction.lock_period.conviction_6}} days | === "Moonbase Alpha" | Lock Periods After Enactment | Conviction Multiplier | Approx. Lock Time | |:----------------------------:|:---------------------:|:--------------------------------------------------------------:| | 0 | 0.1 | None | | 1 | 1 | {{networks.moonbase.conviction.lock_period.conviction_1}} day | | 2 | 2 | {{networks.moonbase.conviction.lock_period.conviction_2}} days | | 4 | 3 | {{networks.moonbase.conviction.lock_period.conviction_3}} days | | 8 | 4 | {{networks.moonbase.conviction.lock_period.conviction_4}} days | | 16 | 5 | {{networks.moonbase.conviction.lock_period.conviction_5}} days | | 32 | 6 | {{networks.moonbase.conviction.lock_period.conviction_6}} days | !!! note The lock time approximations are based upon regular {{ networks.moonriver.block_time }}-second block times. Block production may vary and thus the displayed lock times should not be deemed exact. ### Roadmap of a Proposal {: #roadmap-of-a-proposal-v2 } Before a proposal is submitted, the author of the proposal can submit their proposal idea to the designated Democracy Proposals section of the [Moonbeam Governance discussion forum](https://forum.moonbeam.network/c/governance/2){target=\_blank} for feedback from the community for at least five days. From there, the author can make adjustments to the proposal based on the feedback they've collected. Once the author is ready, they can submit their proposal on-chain. To do so, first, they need to submit the preimage of the proposal. The submitter needs to bond a fee to store the preimage on-chain. The bond is returned once the submitter unnotes the preimage. Next, they can submit the actual proposal and pay the Submission Deposit, which is enough to cover the on-chain storage cost of the proposal. Then the Lead-in Period begins and the community can begin voting "Aye" or "Nay" on the proposal by locking tokens. In order for the referendum to advance and move out of the Lead-in Period to the Decide period, the following criteria must be met: - The referendum must wait the duration of the Prepare Period, which allows for adequate time to discuss the proposal before it progresses to the next phase - There is enough Capacity in the chosen Track - A Decision Deposit has been made that meets the minimum requirements for the Track If a referendum meets the above criteria, it moves to the Decide Period and takes up one of the spots in its designated Track. In the Decide Period, voting continues and the referendum has a set amount of days to reach the Approval and Support requirements needed for it to progress to the Confirm Period. Once in the Confirm Period, a referendum must continuously meet the Approval and Support requirements for the duration of the period. If a referendum fails to meet the requirements at any point, it is returned to the Decide Period. If the referendum meets the Approval and Support requirements again, it can progress to the Confirm Period again and the Decide Period will be delayed until the end of the Confirm Period. If the Decide Period ends and not enough Approval and Support was received, the referendum will be rejected and the Decision Deposit will be returned. The proposal can be proposed again at any time. If a referendum continuously receives enough Approval and Support during the Confirm Period, it will be approved and move to the Enactment Period. It will wait the duration of the Enactment Period before it gets dispatched. The happy path for a proposal is shown in the following diagram: ![A happy path diagram of the proposal roadmap in OpenGov.](/images/learn/features/governance/proposal-roadmap.webp) ### Proposal Example Walkthrough A proposal (with its preimage) is submitted for the General Admin Track on Moonriver would have the following characteristics: - The Approval curve starts at {{ networks.moonriver.governance.tracks.general_admin.min_approval.percent0 }}% on {{ networks.moonriver.governance.tracks.general_admin.min_approval.time0 }}, goes to {{ networks.moonriver.governance.tracks.general_admin.min_approval.percent1 }}% on {{ networks.moonriver.governance.tracks.general_admin.min_approval.time1 }} - The Support curve starts at {{ networks.moonriver.governance.tracks.general_admin.min_support.percent0 }}% on {{ networks.moonriver.governance.tracks.general_admin.min_support.time0 }}, goes to {{ networks.moonriver.governance.tracks.general_admin.min_support.percent1 }}% on {{ networks.moonriver.governance.tracks.general_admin.min_support.time1 }} - A referendum starts the Decide Period with 0% "Aye" votes (nobody voted in the Lead-in Period) - Token holders begin to vote and the Approval increases to a value above {{ networks.moonriver.governance.tracks.general_admin.min_approval.percent1 }}% by {{ networks.moonriver.governance.tracks.general_admin.min_approval.time1 }} - If the Approval and Support thresholds are met for the duration of the Confirm Period ({{ networks.moonriver.governance.tracks.general_admin.confirm_period.blocks }} blocks, approximately {{ networks.moonriver.governance.tracks.general_admin.confirm_period.time }}), the referendum is approved - If the Approval and Support thresholds are not met during the Decision Period, the proposal is rejected. Note that the thresholds need to be met for the duration of the Confirm Period. Consequently, if they are met but the Decision Period expires before the completion of the Confirm Period, the proposal is rejected The Approval and Support percentages can be calculated using the following: === "Approval" ```text Approval = 100 * ( Total Conviction-weighted "Aye" votes / Total Conviction-weighted votes ) ``` === "Support" ```text Support = 100 * ( Total Aye + Abstain votes, ignoring conviction / Total supply ) ``` ### Proposal Cancellations {: #proposal-cancellations } In the event that a proposal already in the voting stage is found to have an issue, it may be necessary to prevent its approval. These instances may involve malicious activity or technical issues that make the changes impossible to implement due to recent upgrades to the network. Cancellations must be voted on by the network to be executed. Cancellation proposals are faster than a typical proposal because they must be decided before the enactment of the proposal they seek to cancel, but they follow the same process as other referenda. There is a cancellation Origin for use against referenda that contain an unforeseen problem, called the Emergency Canceller. The Emergency Canceller Origin and the Root Origin are allowed to cancel referenda. Regardless of the Origin, if a proposal is cancelled, it gets rejected and the Decision Deposit gets refunded. In addition, there is a Kill Origin, which is for bad referenda intending to harm the network, called Emergency Killer. The Emergency Killer Origin and the Root Origin have the ability to kill referenda. In this case, a proposal is cancelled and the Decision Deposit is slashed, meaning the deposit amount is burned regardless of the Origin. ### Rights of the OpenGov Technical Committee {: #rights-of-the-opengov-technical-committee } On Polkadot, the Technical Committee from Governance v1 was replaced with the Fellowship, which is a "mostly self-governing expert body with a primary goal of representing humans who embody and contain the technical knowledge base of the Kusama and/or Polkadot networks and protocol," according to [Polkadot's wiki](https://wiki.polkadot.network/general/web3-and-polkadot/#fellowship){target=\_blank}. For Moonbeam's implementation of OpenGov, instead of the Fellowship, there is a community OpenGov Technical Committee that has very similar power to that of the Fellowship. Their power in governance resides in their ability to whitelist a proposal. OpenGov Technical Committee members may only vote to whitelist a proposal if whitelisting that proposal would protect against a security vulnerability to the network. The passing threshold of the OpenGov Technical Committee members on whether to whitelist a proposal is determined by governance. As such, the OpenGov Technical Committee has very limited power over the network. Its purpose is to provide technical review of urgent security issues that are proposed by token holders. While still subject to governance, the idea behind the Whitelist track is that it will have different parameters to make it faster for proposals to pass. The Whitelist Track parameters, including approval, support, and voting, are determined by the Moonriver or Moonbeam token holders through governance and cannot be changed by the OpenGov Technical Committee. The OpenGov Technical Committee is made up of members of the community who have technical knowledge and expertise in Moonbeam-based networks. ### Related Guides on OpenGov {: #try-it-out } For related guides on submitting and voting on referenda on Moonbeam with OpenGov, please check the following guides: - [How to Submit a Proposal](/tokens/governance/proposals/){target=\_blank} - [How to Vote on a Proposal](/tokens/governance/voting/){target=\_blank} - [Interact with the Preimages Precompiled Contract (Solidity Interface)](/builders/ethereum/precompiles/features/governance/preimage/){target=\_blank} - [Interact with the Referenda Precompiled Contract (Solidity Interface)](/builders/ethereum/precompiles/features/governance/referenda/){target=\_blank} - [Interact with the Conviction Voting Precompiled Contract (Solidity Interface)](/builders/ethereum/precompiles/features/governance/conviction-voting/){target=\_blank} --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/features/ --- BEGIN CONTENT --- --- title: Features description: Learn about some of the main features on Moonbeam, including Ethereum compatibility, interoperability, the consensus framework, staking, governance, and more. dropdown_description: Explore core features template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/features/randomness/ --- BEGIN CONTENT --- --- title: Randomness description: Learn about the sources of VRF randomness on Moonbeam, the request and fulfillment process, and some security considerations when using on-chain randomness. categories: Basics --- # Randomness on Moonbeam ## Introduction {: #introduction } Randomness is necessary for a variety of blockchain applications to create unbiased, unpredictable, and unique outcomes. However, obtaining a reliable source of randomness is a challenge. Computers are deterministic, meaning given the same input, the same output will always be produced. Therefore, random values generated by computers are referred to as pseudo-random as they appear to be statistically random, but given the same input, the output can easily be repeated. Moonbeam utilizes verifiable random functions (VRF) to generate randomness that can be verified on-chain. A VRF is a cryptographic function that takes some input and produces random values, along with a proof of authenticity that they were generated by the submitter. The proof can be verified by anyone to ensure that the random values were generated correctly. There are two available sources of randomness that provide random inputs based on block producers' VRF keys and past randomness results: [local VRF](#local-vrf) and [BABE epoch randomness](#babe-epoch-randomness). Local VRF is determined directly within Moonbeam using the collator of the block's VRF key and the last block's VRF output. On the other hand, [BABE](https://docs.polkadot.com/polkadot-protocol/architecture/polkadot-chain/pos-consensus/#block-production-babe){target=\_blank} epoch randomness is based on all the VRF produced by the relay chain validators during a complete [epoch](https://wiki.polkadot.network/general/glossary/#epoch){target=\_blank}. You can interact with and request on-chain randomness using the Randomness Precompile contract, a Solidity interface that enables smart contract developers to access the randomness functionality through the Ethereum API. For more information, please check out the [Interacting with the Randomness Precompile](/builders/ethereum/precompiles/features/randomness/){target=\_blank} guide. You can also take a look at the [Randomness Pallet](/builders/substrate/interfaces/features/randomness/){target=\_blank}, which can be used to obtain current randomness requests and results. ## General Definitions {: #general-definitions } - **Epoch** - a time duration in the BABE protocol that is broken into smaller time slots. Slots are discrete units of time six seconds in length. On Polkadot, one epoch lasts approximately 2,400 slots or 4 hours. On Kusama, one epoch lasts approximately 600 slots or 1 hour. - **Deposit** - an amount of funds required to request random words. There is one deposit per request. Once the request has been fulfilled, the deposit will be returned to the account that requested the randomness - **Block expiration delay** - the number of blocks that must pass before a local VRF request expires and can be purged - **Epoch expiration delay** - the number of epochs that must pass before a BABE request expires and can be purged - **Minimum block delay** - the minimum number of blocks before a request can be fulfilled for local VRF requests - **Maximum block delay** - the maximum number of blocks before a request can be fulfilled for local VRF requests - **Maximum random words** - the maximum number of random words being requested - **Epoch fulfillment delay** - the delay in epochs before a request can be fulfilled for a BABE request ## Quick Reference {: #quick-reference } === "Moonbeam" | Variable | Value | |:-----------------------:|:---------------------------------------------------------------------------------------------:| | Deposit | {{ networks.moonbeam.randomness.req_deposit_amount.glmr }} GLMR | | Block expiration delay | {{ networks.moonbeam.randomness.block_expiration }} blocks | | Epoch expiration delay | {{ networks.moonbeam.randomness.epoch_expiration }} epochs | | Minimum block delay | {{ networks.moonbeam.randomness.min_vrf_blocks_delay }} blocks | | Maximum block delay | {{ networks.moonbeam.randomness.max_vrf_blocks_delay }} blocks | | Maximum random words | {{ networks.moonbeam.randomness.max_random_words }} words | | Epoch fulfillment delay | {{ networks.moonbeam.randomness.epoch_fulfillment_delay }} epochs (following the current one) | === "Moonriver" | Variable | Value | |:-----------------------:|:----------------------------------------------------------------------------------------------:| | Deposit | {{ networks.moonriver.randomness.req_deposit_amount.movr }} MOVR | | Block expiration delay | {{ networks.moonriver.randomness.block_expiration }} blocks | | Epoch expiration delay | {{ networks.moonriver.randomness.epoch_expiration }} epochs | | Minimum block delay | {{ networks.moonriver.randomness.min_vrf_blocks_delay }} blocks | | Maximum block delay | {{ networks.moonriver.randomness.max_vrf_blocks_delay }} blocks | | Maximum random words | {{ networks.moonriver.randomness.max_random_words }} words | | Epoch fulfillment delay | {{ networks.moonriver.randomness.epoch_fulfillment_delay }} epochs (following the current one) | === "Moonbase Alpha" | Variable | Value | |:-----------------------:|:---------------------------------------------------------------------------------------------:| | Deposit | {{ networks.moonbase.randomness.req_deposit_amount.dev }} DEV | | Block expiration delay | {{ networks.moonbase.randomness.block_expiration }} blocks | | Epoch expiration delay | {{ networks.moonbase.randomness.epoch_expiration }} epochs | | Minimum block delay | {{ networks.moonbase.randomness.min_vrf_blocks_delay }} blocks | | Maximum block delay | {{ networks.moonbase.randomness.max_vrf_blocks_delay }} blocks | | Maximum random words | {{ networks.moonbase.randomness.max_random_words }} words | | Epoch fulfillment delay | {{ networks.moonbase.randomness.epoch_fulfillment_delay }} epochs (following the current one) | ## Local VRF {: #local-vrf } Local VRF randomness is generated on a block-by-block basis at the beginning of the block using the previous block's VRF output along with the public key of the current block author's VRF key. The generated randomness result is stored and used to fulfill all randomness requests for the current block. You can request local VRF randomness using the [`requestLocalVRFRandomWords` method](/builders/ethereum/precompiles/features/randomness/#:~:text=requestLocalVRFRandomWords){target=\_blank} of the [Randomness Precompile](/builders/ethereum/precompiles/features/randomness/){target=\_blank}. If your contract could have concurrent requests open, you can use the `requestId` returned from the `requestLocalVRFRandomWords` method to track which response is associated with which randomness request. ## BABE Epoch Randomness {: #babe-epoch-randomness } BABE epoch randomness is based on a hash of the VRF values from the blocks produced in the relay chain epoch before last. On Polkadot, an [epoch lasts for roughly 4 hours](https://wiki.polkadot.network/learn/learn-cryptography/#vrf){target=\_blank}, and on Kusama, an [epoch lasts for roughly 1 hour](https://guide.kusama.network/docs/maintain-polkadot-parameters#periods-of-common-actions-and-attributes){target=\_blank}. The hashing is completed on the relay chain, and as such, it is not possible for a collator on Moonbeam to influence the randomness value unless they are also a validator on the relay chain and were responsible for producing the last output included in an epoch. The randomness remains constant during an epoch. If a collator skips block production, the next eligible collator can fulfill the request using the same random value. You can request BABE epoch randomness using the [`requestRelayBabeEpochRandomWords` method](/builders/ethereum/precompiles/features/randomness/#:~:text=requestRelayBabeEpochRandomWords){target=\_blank} of the [Randomness Precompile](/builders/ethereum/precompiles/features/randomness/){target=\_blank}. In order to generate unique randomness, a different salt must be provided to the `requestRelayBabeEpochRandomWords` function. At the beginning of each relay chain epoch change, the randomness from one epoch ago is read from the relay chain state proof and used to fulfill all randomness requests that are due in the current block. ## Request & Fulfill Process {: #request-and-fulfill-process } In general, the request and fulfill process for randomness is as follows: 1. Pay the deposit required to request random words 2. Request the randomness either using the local VRF or BABE epoch source of randomness. When requesting randomness you'll need to specify a few things: - a refund address where any excess fees will be sent to - the amount of fees which will be set aside to pay for fulfillment. If the specified amount is not enough you can always increase the request fees later, or if it's more than enough you'll be refunded the excess fees to the specified address after fulfillment - a unique salt that will be used to generate different random words - the number of random words you would like to request - for local VRF, the delay period in blocks, which is used to increase unpredictability. It must be between the [minimum and maximum number of blocks](#quick-reference) as listed above. For BABE epoch randomness, you do not need to specify a delay but can fulfill the request after the [epoch delay](#quick-reference) has passed 3. Wait for the delay period to pass 4. Fulfill the randomness request, which triggers the random words to be computed using the current block's randomness result and the given salt. This can manually be done by anyone using the fee that was initially set aside for the request 5. For fulfilled requests, the random words are returned and the cost of execution will be refunded from the request fee to the address that initiated the fulfillment. Then any excess fees and the request deposit are transferred to the specified refund address If a request expires it can be purged by anyone. When this happens, the request fee is paid out to the address that initiated the purge and the deposit is returned to the original requester. The happy path for a randomness request is shown in the following diagram: ![Randomness request happy path diagram](/images/learn/features/randomness/randomness-1.webp) ## Security Considerations {: #security-considerations } A method with the ability to call your `fulfillRandomness` method directly could spoof a VRF response with any random value, so it's critical that it can only be directly called by the `RandomnessConsumer.sol` contract's `rawFulfillRandomness` method. For your users to trust that your contract's random behavior is free from malicious interference, it's best if you can write it so that all behaviors implied by a VRF response are executed *during* your `fulfillRandomness` method. If your contract must store the response (or anything derived from it) and use it later, you must ensure that any user-significant behavior which depends on that stored value cannot be manipulated by a subsequent VRF request. Similarly, the collators have some influence over the order in which VRF responses appear on the blockchain, so if your contract could have multiple VRF requests in flight simultaneously, you must ensure that the order in which the VRF responses arrive cannot be used to manipulate your contract's user-significant behavior. Since the output of the random words generated for `requestLocalVRFRandomWords` is dependent on the collator producing the block at fulfillment, the collator could skip its block, forcing the fulfillment to be executed by a different collator and therefore generating a different VRF. However, such an attack would incur the cost of losing the block reward to the collator. It is also possible for a collator to be able to predict some of the possible outcome of the VRF if the delay between the request and the fulfillment is too short. It is for this reason that you can choose to provide a higher delay. Since the output of the random words generated for `requestRelayBabeEpochRandomWords` is dependent on the relay chain validator producing the blocks during an epoch, it is possible for the last validator of an epoch to choose between two possible VRF outputs by skipping the production of a block. However, such an attack would incur the cost of losing the block reward to the validator. It is not possible for a parachain collator to predict or influence the output of the relay chain VRF, not to censor the fulfillment, as long as there is one honest collator. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/features/staking/ --- BEGIN CONTENT --- --- title: Staking description: Moonbeam provides staking features where token holders delegate collator candidates with their tokens and earn rewards. categories: Basics, Staking --- # Staking on Moonbeam ## Introduction {: #introduction } Moonbeam uses a block production mechanism based on [Polkadot's Proof-of-Stake model](https://docs.polkadot.com/polkadot-protocol/architecture/polkadot-chain/pos-consensus/){target=\_blank}, where there are collators and validators. [Collators](https://wiki.polkadot.network/learn/learn-collator/){target=\_blank} maintain parachains (in this case, Moonbeam) by collecting transactions from users and producing state transition proofs for the relay chain [validators](https://wiki.polkadot.network/learn/learn-validator/){target=\_blank}. The candidates in the active set of collators (nodes that produce blocks) are selected based on their stake in the network. And here is where staking comes in. Collator candidates (and token holders if they delegate) have a stake in the network. The top N candidates by staked amount are chosen to produce blocks with a valid set of transactions, where N is a configurable parameter. Part of each block reward goes to the collators that produced the block, who then share it with the delegators considering their percental contributions towards the collator's stake. In such a way, network members are incentivized to stake tokens to improve the overall security. Since staking is done at a protocol level through the staking interface, if you choose to delegate, the collators you delegate to do not have access to your tokens. To easily manage staking related actions, you can visit the [Moonbeam Network DApp](https://apps.moonbeam.network){target=\_blank} and use the network tabs at the top of the page to easily switch between Moonbeam networks. To learn how to use the DApp, you can check out the [How to Stake MOVR Tokens](https://moonbeam.network/news/how-to-stake-movr-tokens-on-moonriver-and-earn-staking-rewards){target=\_blank} guide or [video tutorial](https://www.youtube.com/watch?v=8GwetYmzEJM){target=\_blank}, both of which can be adapted for the Moonbeam and the Moonbase Alpha TestNet. ## General Definitions {: #general-definitions } Some important parameters to understand in relation to the staking system on Moonbeam include: - **Round** — a specific number of blocks around which staking actions are enforced. For example, new delegations are enacted when the next round starts. When bonding less or revoking delegations, funds are returned after a specified number of rounds - **Candidates** - node operators that are eligible to become block producers if they can acquire enough stake to be in the active set - **Collators** — active set of candidates that are selected to be block producers. They collect transactions from users and produce state transition proofs for the relay chain to validate - **Delegators** — token holders who stake tokens, vouching for specific collator candidates. Any user that holds a minimum amount of tokens as [free balance](https://wiki.polkadot.network/learn/learn-accounts/#balance-types) can become a delegator - **Minimum delegation per candidate** — minimum amount of tokens to delegate candidates once a user is in the set of delegators - **Maximum delegators per candidate** — maximum number of delegators, by staked amount, that a candidate can have which are eligible to receive staking rewards - **Maximum delegations** — maximum number of candidates a delegator can delegate - **Exit delay** - an exit delay is the amount of rounds before a candidate or delegator can execute a scheduled request to decrease or revoke a bond, or leave the set of candidates or delegators - **Reward payout delay** - a certain amount of rounds must pass before staking rewards are distributed automatically to the free balance - **Reward pool** - a portion of the annual inflation that is set aside for collators and delegators - **Collator commission** - default fixed percent a collator takes off the top of the due staking rewards. Not related to the reward pool - **Delegator rewards** — the aggregate delegator rewards distributed over all eligible delegators, taking into account the relative size of stakes ([read more](/learn/features/staking/#reward-distribution)) - **Auto-compounding** - a setting that automatically applies a percentage of a delegator's rewards to their total amount delegated - **Slashing** — a mechanism to discourage collator misbehavior, where typically the collator and their delegators get slashed by losing a percentage of their stake. Currently, there is no slashing but this can be changed through governance. Collators who produce blocks that are not finalized by the relay chain won't receive rewards ## Quick Reference {: #quick-reference } === "Moonbeam" | Variable | Value | |:--------------------------------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------:| | Round duration | {{ networks.moonbeam.staking.round_blocks }} blocks ({{ networks.moonbeam.staking.round_hours }} hours) | | Minimum delegation per candidate | {{ networks.moonbeam.staking.min_del_stake }} GLMR | | Maximum delegators per candidate | {{ networks.moonbeam.staking.max_del_per_can }} | | Maximum delegations | {{ networks.moonbeam.staking.max_del_per_del }} | | Reward payout delay | {{ networks.moonbeam.delegator_timings.rewards_payouts.rounds }} rounds ({{ networks.moonbeam.delegator_timings.rewards_payouts.hours }} hours) | | Add or increase delegation | takes effect in the next round (funds are withdrawn immediately) | | Decrease delegation delay | {{ networks.moonbeam.delegator_timings.del_bond_less.rounds }} rounds ({{ networks.moonbeam.delegator_timings.del_bond_less.hours }} hours) | | Revoke delegations delay | {{ networks.moonbeam.delegator_timings.revoke_delegations.rounds }} rounds ({{ networks.moonbeam.delegator_timings.revoke_delegations.hours }} hours) | | Leave delegators delay | {{ networks.moonbeam.delegator_timings.leave_delegators.rounds }} rounds ({{ networks.moonbeam.delegator_timings.leave_delegators.hours }} hours) | === "Moonriver" | Variable | Value | |:--------------------------------:|:-------------------------------------------------------------------------------------------------------------------------------------------------------:| | Round duration | {{ networks.moonriver.staking.round_blocks }} blocks ({{ networks.moonriver.staking.round_hours }} hours) | | Minimum delegation per candidate | {{ networks.moonriver.staking.min_del_stake }} MOVR | | Maximum delegators per candidate | {{ networks.moonriver.staking.max_del_per_can }} | | Maximum delegations | {{ networks.moonriver.staking.max_del_per_del }} | | Reward payout delay | {{ networks.moonriver.delegator_timings.rewards_payouts.rounds }} rounds ({{ networks.moonriver.delegator_timings.rewards_payouts.hours }} hours) | | Add or increase delegation | takes effect in the next round (funds are withdrawn immediately) | | Decrease delegation delay | {{ networks.moonriver.delegator_timings.del_bond_less.rounds }} rounds ({{ networks.moonriver.delegator_timings.del_bond_less.hours }} hours) | | Revoke delegations delay | {{ networks.moonriver.delegator_timings.revoke_delegations.rounds }} rounds ({{ networks.moonriver.delegator_timings.revoke_delegations.hours }} hours) | | Leave delegators delay | {{ networks.moonriver.delegator_timings.leave_delegators.rounds }} rounds ({{ networks.moonriver.delegator_timings.leave_delegators.hours }} hours) | === "Moonbase Alpha" | Variable | Value | |:--------------------------------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------:| | Round duration | {{ networks.moonbase.staking.round_blocks }} blocks ({{ networks.moonbase.staking.round_hours }} hours) | | Minimum delegation per candidate | {{ networks.moonbase.staking.min_del_stake }} DEV | | Maximum delegators per candidate | {{ networks.moonbase.staking.max_del_per_can }} | | Maximum delegations | {{ networks.moonbase.staking.max_del_per_del }} | | Reward payout delay | {{ networks.moonbase.delegator_timings.rewards_payouts.rounds }} rounds ({{ networks.moonbase.delegator_timings.rewards_payouts.hours }} hours) | | Add or increase delegation | takes effect in the next round (funds are withdrawn immediately) | | Decrease delegation delay | {{ networks.moonbase.delegator_timings.del_bond_less.rounds }} rounds ({{ networks.moonbase.delegator_timings.del_bond_less.hours }} hours) | | Revoke delegations delay | {{ networks.moonbase.delegator_timings.revoke_delegations.rounds }} rounds ({{ networks.moonbase.delegator_timings.revoke_delegations.hours }} hours) | | Leave delegators delay | {{ networks.moonbase.delegator_timings.leave_delegators.rounds }} rounds ({{ networks.moonbase.delegator_timings.leave_delegators.hours }} hours) | !!! note As of runtime 3000, [asynchronous backing](https://wiki.polkadot.network/learn/learn-async-backing/){target=\_blank} has been enabled on all Moonbeam networks. As a result, the target block time was reduced from 12 seconds to 6 seconds, which may break some timing-based assumptions. To learn how to get the current value of any of the parameters around staking, check out the [Retrieving Staking Parameters](/tokens/staking/stake/#retrieving-staking-parameters){target=\_blank} section of the [How to Stake your Tokens](/tokens/staking/stake/){target=\_blank} guide. If you're looking for candidate or collator-specific requirements and information, you can take a look at the [Collators](/node-operators/networks/collators/requirements/#bonding-requirements){target=\_blank} guide. ## Resources for Selecting a Collator {: #resources-for-selecting-a-collator} There are a few resources you can check out to help you select a collator to delegate: === "Moonbeam" | Variable | Value | |:----------------------------:|:-------------------------------------------------------------------------------:| | Stake GLMR Dashboard | [Stake GLMR](https://stakeglmr.com){target=\_blank} | | Collators Leaderboard | [Moonscan](https://moonbeam.moonscan.io/collators){target=\_blank} | | Collator Dashboard | [DappLooker](https://dapplooker.com/dashboard/moonbeam-collator-dashboard-91){target=\_blank} | === "Moonriver" | Variable | Value | |:----------------------------:|:--------------------------------------------------------------------------------:| | Stake MOVR Dashboard | [Stake MOVR](https://stakemovr.com){target=\_blank} | | Collators Leaderboard | [Moonscan](https://moonriver.moonscan.io/collators){target=\_blank} | | Collator Dashboard | [DappLooker](https://dapplooker.com/dashboard/moonriver-collator-dashboard-28){target=\_blank} | === "Moonbase Alpha" | Variable | Value | |:------------------:|:--------------------------------------------------------------------------------:| | List of candidates | [Moonbase Alpha Subscan](https://moonbase.subscan.io/validator){target=\_blank} | !!! note The DappLooker Collator dashboard for Moonriver is experimental beta software and may not accurately reflect collator performance. Be sure to do your own research before delegating to a collator. ### General Tips {: #general-tips } - To optimize your staking rewards, you should generally choose a collator with a lower total amount bonded. In that case, your delegation amount will represent a larger portion of the collator’s total stake and you will earn proportionally higher rewards. However, there is a higher risk of the collator being kicked out of the active set and not earning rewards at all - The minimum bond for each collator tends to increase over time, so if your delegation is close to the minimum, there is a higher chance you might fall below the minimum and not receive rewards - Spreading delegations between multiple collators is more efficient in terms of rewards, but only recommended if you have enough to stay above the minimum bond of each collator - You can consider collator performance by reviewing the number of blocks each collator has produced recently - You can set up auto-compounding which will automatically restake a specified percentage of your delegation rewards ## Reward Distribution {: #reward-distribution } Rewards for collators and their delegators are calculated at the start of every round for their work prior to the [reward payout delay](#quick-reference). For example, on Moonriver the rewards are calculated for the collators work from {{ networks.moonriver.delegator_timings.rewards_payouts.rounds }} rounds ago. The calculated rewards are then paid out on a block-by-block basis starting at the second block of the round. For every block, one collator will be chosen to receive their entire reward payout from the prior round, along with their delegators, until all rewards have been paid out for that round. For example, if there are {{ networks.moonriver.staking.max_candidates }} collators who produced blocks in the prior round, all of the collators and their delegators will be paid by block {{ networks.moonriver.staking.paid_out_block }} of the new round. You can choose to auto-compound your delegation rewards so you no longer have to manually delegate rewards. If you choose to set up auto-compounding, you can specify the percentage of rewards to be auto-compounded. These rewards will then be automatically added to your delegation. ### Annual Inflation {: #annual-inflation} The distribution of the annual inflation goes as follows: === "Moonbeam" | Variable | Value | |:-----------------------------------------:|:-------------------------------------------------------------------------------------:| | Annual inflation | {{ networks.moonbeam.inflation.total_annual_inflation }}% | | Rewards pool for collators and delegators | {{ networks.moonbeam.inflation.delegator_reward_inflation }}% of the annual inflation | | Collator commission | {{ networks.moonbeam.inflation.collator_reward_inflation }}% of the annual inflation | | Parachain bond reserve | {{ networks.moonbeam.inflation.parachain_bond_inflation }}% of the annual inflation | === "Moonriver" | Variable | Value | |:-----------------------------------------:|:--------------------------------------------------------------------------------------:| | Annual inflation | {{ networks.moonriver.inflation.total_annual_inflation }}% | | Rewards pool for collators and delegators | {{ networks.moonriver.inflation.delegator_reward_inflation }}% of the annual inflation | | Collator commission | {{ networks.moonriver.inflation.collator_reward_inflation }}% of the annual inflation | | Parachain bond reserve | {{ networks.moonriver.inflation.parachain_bond_inflation }}% of the annual inflation | === "Moonbase Alpha" | Variable | Value | |:-----------------------------------------:|:-------------------------------------------------------------------------------------:| | Annual inflation | {{ networks.moonbase.inflation.total_annual_inflation }}% | | Rewards pool for collators and delegators | {{ networks.moonbase.inflation.delegator_reward_inflation }}% of the annual inflation | | Collator commission | {{ networks.moonbase.inflation.collator_reward_inflation }}% of the annual inflation | | Parachain bond reserve | {{ networks.moonbase.inflation.parachain_bond_inflation }}% of the annual inflation | From the rewards pool, collators get the rewards corresponding to their stake in the network. The rest are distributed among delegators by stake. ### Calculating Rewards {: #calculating-rewards } Mathematically speaking, for collators, the reward distribution per block proposed and finalized would look like this: ![Staking Collator Reward](/images/learn/features/staking/staking-overview-1.webp) Where `amount_due` is the corresponding inflation being distributed in a specific block, the `stake` corresponds to the number of tokens bonded by the collator in respect to the total stake of that collator (accounting delegations). For each delegator, the reward distribution (per block proposed and finalized by the delegated collator) would look like this: ![Staking Delegator Reward](/images/learn/features/staking/staking-overview-2.webp) Where `amount_due` is the corresponding inflation being distributed in a specific block, the `stake` corresponds to the amount of tokens bonded by each delegator in respect to the total stake of that collator. ## Risks {: #risks } *Holders of MOVR/GLMR tokens should perform careful due diligence on collators before delegating. Being listed as a collator is not an endorsement or recommendation from the Moonbeam Network, the Moonriver Network, or Moonbeam Foundation. Neither the Moonbeam Network, Moonriver Network, nor Moonbeam Foundation has vetted the list collators and assumes no responsibility with regard to the selection, performance, security, accuracy, or use of any third-party offerings. You alone are responsible for doing your own diligence to understand the applicable fees and all risks present, including actively monitoring the activity of your collators.* *You agree and understand that neither the Moonbeam Network, the Moonriver Network, nor Moonbeam Foundation guarantees that you will receive staking rewards and any applicable percentage provided (i) is an estimate only and not guaranteed, (ii) may change at any time and (iii) may be more or less than the actual staking rewards you receive. The Moonbeam Foundation makes no representations as to the monetary value of any rewards at any time.* *Staking MOVR/GLMR tokens is not free of risk.* *Staked MOVR/GLMR tokens are locked up, and retrieving them requires a {{ networks.moonriver.delegator_timings.del_bond_less.days }} day/{{ networks.moonbeam.delegator_timings.del_bond_less.days }} day waiting period .* *Additionally, if a collator fails to perform required functions or acts in bad faith, a portion of their total stake can be slashed (i.e. destroyed). This includes the stake of their delegators. If a collators behaves suspiciously or is too often offline, delegators can choose to unbond from them or switch to another collator. Delegators can also mitigate risk by electing to distribute their stake across multiple collators.* --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/features/treasury/ --- BEGIN CONTENT --- --- title: Treasury description: Moonbeam has an on-chain Treasury controlled by Treasury Council members, enabling stakeholders to submit proposals to further the network. categories: Basics --- # Treasury on Moonbeam ## Introduction {: #introduction } The Moonbeam Treasury is an on-chain collection of funds launched at the network's genesis. Initially pre-funded with 0.5% of the token supply, the Treasury continues to accumulate GLMR as {{ networks.moonbeam.inflation.parachain_bond_treasury }}% of the parachain bond reserve inflation goes to the Treasury. For more information about Moonbeam inflation figures, see [GLMR Tokenomics](https://moonbeam.foundation/glimmer-token-tokenomics/){target=\_blank}. The Moonbeam Treasury funds initiatives that support and grow the network. Stakeholders can propose spending requests for Treasury Council review, focusing on efforts like integrations, collaborations, community events, and outreach. Treasury spend proposers must submit their proposals to the [Moonbeam Forum](https://forum.moonbeam.network/c/governance/treasury-proposals/8){target=\_blank}. For submission details, see [How to Propose a Treasury Spend](/tokens/governance/treasury-spend/){target=\_blank}. The [Treasury Council](https://forum.moonbeam.network/g/TreasuryCouncil){target=\_blank} oversees the spending of the Moonbeam Treasury and votes on funding proposals. It comprises two members from the Moonbeam Foundation and three external community members. The three external members are elected to terms of {{ networks.moonbeam.treasury.months_elected }} months. The same Treasury Council oversees Treasury requests for both Moonbeam and Moonriver. The Council meets monthly to review proposals submitted on the [Moonbeam Forum](https://forum.moonbeam.network/c/governance/treasury-proposals/8){target=\_blank}. Once a proposal is agreed upon, the Council members must complete the on-chain approval process. ## General Definitions {: #general-definitions } Some important terminology to understand regarding treasuries: - **Treasury Council** — a group of Moonbeam Foundation representatives and external community members. The Council reviews funding proposals, ensures alignment with the community, and ultimately authorizes Treasury spending - **Proposal** — a plan or suggestion submitted by stakeholders to further the network to be approved by the Treasury Council ## Treasury Addresses {: #treasury-addresses } The Treasury address for each respective network can be found below: === "Moonbeam" [0x6d6F646c70632f74727372790000000000000000](https://moonbase.subscan.io/account/0x6d6F646c70632f74727372790000000000000000){target=_blank} === "Moonriver" [0x6d6f646C70792f74727372790000000000000000](https://moonriver.subscan.io/account/0x6d6f646C70792f74727372790000000000000000){target=_blank} === "Moonbase Alpha" [0x6d6F646c70632f74727372790000000000000000](https://moonbase.subscan.io/account/0x6d6F646c70632f74727372790000000000000000){target=_blank} ## Roadmap of a Treasury Proposal {: #roadmap-of-a-treasury-proposal } The happy path of a Treasury spend request is as follows: 1. **Proposal submission** - the user submits a proposal to the [Moonbeam Forum](https://forum.moonbeam.network/c/governance/treasury-proposals/8){target=\_blank} 2. **Forum discussion** - the proposal is discussed by the community on the Forum. The ultimate Aye/Nay decision is determined by the Treasury council 3. **Treasury approval and action** - if the Treasury Council agrees, it authorizes the Treasury spending and moves the process forward ## Treasury Council Voting Process {: #treasury-council-voting-process } A member of the Treasury Council will submit a `treasury.spend` call. This call requires specifying the amount, the asset type, and the beneficiary account to receive the funds. The Treasury supports spending various token types beyond GLMR, including native USDT/USDC. Once this extrinsic is submitted, a new Treasury Council collective proposal will be created and made available for council members to vote on. Once approved through the Treasury Council's internal voting process, the funds will be released automatically to the beneficiary account through the `treasury.payout` extrinsic. !!! note There is no on-chain action for the proposer or beneficiary of the Treasury spend request. All Treasury spend actions will be completed by members of the Treasury Council. Note that this process has changed significantly from prior Treasury processes, where tokenholders could submit Treasury proposals with bonds attached. Now, no on-chain action is necessary to submit a Treasury proposal. Rather, all that is needed is to raise a Treasury Council request on the [Moonbeam Forum](https://forum.moonbeam.network/c/governance/treasury-proposals/8){target=\_blank} and the Treasury Council will take care of the on-chain components. For more information, see [How to Propose a Treasury Spend](/tokens/governance/treasury-spend/#next-steps){target=\_blank} --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/features/xchain-plans/ --- BEGIN CONTENT --- --- title: Cross-Chain Communication description: This guide covers the ways you can build cross-chain dApps with Moonbeam, including via XCM, cross consensus messaging, and GMP, general message passing. categories: Basics, XCM --- # Cross-Chain Communication Methods Moonbeam makes it easy for developers to build smart contracts that connect across chains, both within the Polkadot ecosystem and outside the Polkadot ecosystem. This page will provide an overview of the underlying protocols that enable cross-chain communication and how you can leverage them to build connected contracts. For step-by-step guides of how to put these principles into practice, be sure to check out the [interoperability tutorials](/tutorials/interoperability/){target=\_blank}. Two key terms that will come up frequently in this guide are XCM and GMP. [XCM](/builders/interoperability/xcm/){target=\_blank} refers to cross-consensus messaging, and it's Polkadot's native interoperability language that facilitates communication between Polkadot blockchains. You can read more about the [standardized XCM message format](https://docs.polkadot.com/develop/interoperability/intro-to-xcm/){target=\_blank} and [How to Get Started Building with XCM](/builders/interoperability/xcm/){target=\_blank}. [GMP](https://moonbeam.network/news/seamless-blockchain-interoperability-the-power-of-general-message-passing-gmp){target=\_blank}, or general message passing, refers to the sending and receiving of messages within decentralized blockchain networks. While XCM is a type of general message passing, GMP colloquially refers to cross-chain communication between Moonbeam and blockchains outside of Polkadot. Similarly, in this guide, XCM refers to cross-chain messaging within Polkadot, and GMP refers to cross-chain messaging between Moonbeam and other ecosystems outside of Polkadot. ## Quick Reference {: #quick-reference } === "Comparison of XCM vs GMP" | Specification | XCM | GMP | |:---------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| | **Scope** | Polkadot and its connected parachains | Any blockchain supported by a GMP provider | | **Provider** | Polkadot | [Axelar](/builders/interoperability/protocols/axelar/){target=\_blank}, [Wormhole](/builders/interoperability/protocols/wormhole/){target=\_blank}, [LayerZero](/builders/interoperability/protocols/layerzero/){target=\_blank}, [Hyperlane](/builders/interoperability/protocols/hyperlane/){target=\_blank}, etc. | | **Implementation** | [XCM Virtual Machine](https://wiki.polkadot.network/learn/learn-xcvm/){target=\_blank} | Smart contracts | | **Security** | Polkadot's shared security | Proprietary consensus determined by GMP provider | | **Fees** | [Purchased with `BuyExecution` XCM instruction with supported asset](/builders/interoperability/xcm/core-concepts/weights-fees/){target=\_blank} | User sends value with transaction to pay for gas on the destination chain | | **Adding New Chains** | Requires creation of XCM channels by both connected chains | Requires GMP provider to add support | ## XCM Transport Methods {: #xcm-transport-methods } XCMP is the protocol that carries messages conforming to the XCM standard. The difference between the two is easy to remember with the added letter "P" for protocol. While XCM is the language that defines the format of the message to send, XCMP can be thought of as the pipes that enable the delivery of said messages. XCMP is comprised of channels that enable communication between connected blockchains. When a parachain launches on Polkadot, two XCM channels are established automatically to allow for communication between the Polkadot relay chain and the parachain itself. XCM channels are omnidirectional, so two channels must be established for bidirectional communication. Polkadot parachains can optionally choose to establish additional XCM channels with other parachains. Establishing XCM channels with other chains is a double opt-in process, so the receiving chain must also agree to have the channel established. Establishing XCM channels with another parachain allows for the exchange of XCM messages, enabling the flow of cross-chain assets and remote contract calls, to name a few examples. There are several different subcategories of XCM transport methods, including: ### VMP {: #vmp } VMP, or [Vertical Message Passing](https://wiki.polkadot.network/learn/learn-xcm-transport/#vmp-vertical-message-passing){target=\_blank}, refers to message passing between the relay chain and a parachain. Given that XCM channels are one-way, there are two types of message passing that comprise VMP, namely: - **UMP** - Upward Message Passing refers to message passing from a parachain to the relay chain - **DMP** - Downward Message Passing refers to message passing from the relay chain to a parachain ### HRMP {: #HRMP } [Horizontal Relay-routed Message Passing](https://wiki.polkadot.network/learn/learn-xcm-transport/#hrmp-xcmp-lite){target=\_blank} (HRMP) is a temporary protocol that is currently being used while XCMP (Cross-Chain Message Passing) is still under development. HRMP serves as a placeholder and provides the same functionality and interface as XCMP. However, HRMP is more resource-intensive because it stores all messages within the Relay Chain's storage. When opening XCM channels with other parachains today, those channels are using HRMP in place of the aforementioned XCMP. Once the implementation of XCMP is complete, the plan is to phase out HRMP and replace it with XCMP gradually. For more information about each one, be sure to check out [Polkadot's Guide to XCM Transport](https://wiki.polkadot.network/learn/learn-xcm-transport/){target=\_blank}. ## General Message Passing {: #general-message-passing } As you know, GMP colloquially refers to cross-chain communication between Moonbeam and other blockchains outside of Polkadot. General message passing is enabled by cross-chain protocols that specialize in cross-chain communication. Each GMP provider takes a slightly different approach, but conceptually, they are quite similar. There are different contracts and functions for each provider, but each GMP provider has the same end goal: to provide secure and reliable cross-chain communication. ### Happy Path of a Cross-Chain Message {: #happy-path-of-a-cross-chain-message } At a high level, the happy path of a message sent via GMP is as follows. A user or developer will call a contract specific to the GMP protocol, sometimes referred to as a mailbox contract or a gateway contract. This call typically includes parameters like the destination chain, the destination contract address, and includes sufficient value to pay for the transaction on the destination chain. A GMP provider listens for specific events on the origin blockchain pertaining to their gateway or mailbox contracts that indicate that a user wants to send a cross-chain message using their protocol. The GMP provider will validate certain parameters, including whether or not sufficient value was provided to pay for gas on the destination chain. In fact, the GMP provider may have a decentralized network of many nodes checking the authenticity of the message and verifying parameters. The GMP provider will not validate the integrity of the contract call to be delivered on the destination chain. E.g., the GMP provider will happily deliver a valid, paid-for message that contains a smart contract call that reverts on arrival. Finally, if everything checks out according to the consensus mechanism of the GMP provider, the message will be delivered to the destination chain, triggering the respective contract call at the destination. ![Happy Path of a cross chain GMP message](/images/learn/features/xchain-plans/xchain-plans-1.webp) ### GMP Providers Integrated with Moonbeam {: #gmp-providers-integrated-with-moonbeam } A large number of GMP providers have integrated with Moonbeam, which is beneficial for several reasons. For one, it enables you to work with whichever GMP provider you prefer. Second, it means that Moonbeam is connected to a rapidly growing number of chains. Whenever a GMP provider integrated with Moonbeam adds support for another chain, Moonbeam is automatically now connected with that chain. GMP providers are constantly adding support for new chains, and it's exciting to see those new integrations benefit the Moonbeam community. Additionally, having a variety of GMP providers allows for redundancy and backup. GMP providers have occasional maintenance windows or downtime; thus, it may make sense to add support for multiple GMP providers to ensure consistent uptime. A significant number of GMP providers have integrated with Moonbeam, offering multiple benefits. Firstly, this integration allows users the flexibility to choose their preferred GMP provider. Secondly, Moonbeam's connectivity is enhanced as it automatically links with any new chains that its GMP providers support. Given that GMP providers frequently expand their support to new chains, the continuous roll out of new chains is a promising ongoing benefit for the Moonbeam community. Additionally, the diversity of GMP providers ensures better reliability and backup options. Since GMP providers can occasionally experience downtime or scheduled maintenance, the ability to integrate with multiple GMP providers is an important benefit. The following GMP providers have integrated with Moonbeam: - [Axelar](/builders/interoperability/protocols/axelar/){target=\_blank} - [Hyperlane](/builders/interoperability/protocols/hyperlane/){target=\_blank} - [LayerZero](/builders/interoperability/protocols/layerzero/){target=\_blank} - [Wormhole](/builders/interoperability/protocols/wormhole/){target=\_blank} ## Implementing Both XCM and GMP {: #implementing-both-xcm-and-gmp } Building with XCM or GMP does not preclude building with the other. As they suit different use cases, a team may seek to utilize XCM to handle interoperability needs within Polkadot, and GMP to deliver cross-chain messages to and from blockchains outside of Polkadot. As an example, several DEXes on Moonbeam support the trading of tokens migrated to Moonbeam via XCM, such as xcDOT, and assets bridged from ecosystems outside of Polkadot, such as USDC via Wormhole. ### Moonbeam Routed Liquidity {: #moonbeam-routed-liquidity } [Moonbeam Routed Liquidity](/builders/interoperability/mrl/) (MRL) enables seamless liquidity between external blockchains connected to Moonbeam via Wormhole to Polkadot parachains connected to Moonbeam via XCM. This combination of GMP and XCM means that any ERC-20 token on a chain that Wormhole has integrated with can be routed through Moonbeam to a destination parachain (and back). A diagram of the happy path of a token transfer to a parachain via MRL is shown below, and you can find more information at the [MRL docs](/builders/interoperability/mrl/). ![Happy Path of an MRL token transfer](/images/learn/features/xchain-plans/xchain-plans-2.webp)
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/ --- BEGIN CONTENT --- --- title: Learn About Moonbeam description: Learn all about Moonbeam, including the basics about the Ethereum-compatible smart contract platform and its compelling features. template: main-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/platform/code/ --- BEGIN CONTENT --- --- title: Moonbeam Source Code description: Moonbeam is an open source project in the Polkadot ecosystem, with publicly available and auditable source code. categories: Basics --- # Moonbeam Source Code Moonbeam is an open source project. The main Moonbeam repo can be found here: [:fontawesome-brands-github: https://github.com/moonbeam-foundation/moonbeam](https://github.com/moonbeam-foundation/moonbeam){target=\_blank} Moonbeam is implemented using the Substrate framework. The source code for Substrate can be found here: [:fontawesome-brands-github: https://github.com/paritytech/substrate](https://github.com/paritytech/polkadot-sdk/tree/master/substrate){target=\_blank} We also work on Ethereum compatibility features along with engineers from Parity as part of the Frontier project. Source code for Frontier can be found here: [:fontawesome-brands-github: https://github.com/polkadot-evm/frontier](https://github.com/polkadot-evm/frontier){target=\_blank} If you are interested in contributing code to Moonbeam, please raise an issue or PR on the [Moonbeam GitHub repository](https://github.com/moonbeam-foundation/moonbeam){target=\_blank} --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/platform/glossary/ --- BEGIN CONTENT --- --- title: Glossary description: We've compiled a glossary of terms related to Polkadot that'll make it easier to learn more about the ecosystem. categories: Reference --- # Glossary There's a great deal of terminology that's specific to Polkadot, Substrate, and the emerging Parity/Web3 ecosystem. We've compiled a list of terms we think you'll want to know as you review the Moonbeam documentation, plans, and tutorials. ### Collators {: #collators } One of the key network participants needed to support parachains within the Polkadot Network. In Moonbeam, collators are the nodes that are responsible for block production and for submitting produced blocks up to the Polkadot relay chain for finalization. ### Delegators {: #delegators } Moonbeam token holders who stake tokens, vouching for specific collator candidates on the parachain. Any user that holds a minimum amount of tokens as [free balance](https://wiki.polkadot.network/learn/learn-accounts/#balance-types){target=\_blank} can become a delegator by staking their tokens. ### Nominators {: #nominators } Relay chain token holders who select to "back" a validator. They can receive part of the validator's reward, but are subject to slashing of their staked tokens in case the validator misbehaves. A nominator can back up to 16 validators, and their bond is fully distributed between the backed validators that were selected for the validator set. ### Nominated Proof of Stake {: #nominated-proof-of-stake } The mechanism used by Polkadot for selecting its block validator set to maximize chain security. At its core, it is a Proof-of-Stake system (PoS) in which nominators back validators. The latter with the highest backing are selected to be part of the validator set for a session. The stake of a validator is slashed in case of misbehavior. Thus, nominators are expected to do due diligence on the validators they nominate. ### Parachains {: #parachains } A blockchain which has a slot and is connected to Polkadot. Parachains receive shared security from Polkadot and the ability to interact with other parachains on the Polkadot network. They must lock DOT, the native relay chain token, to secure a slot for a specific period (up two years). ### Parathreads {: #parathreads } A blockchain which can connect to Polkadot. Parathreads are able to interact with other members of the Polkadot network, but they bid for block finalization (in DOT) on a block-to-block basis. They compete with other parathreads for block finalization, meaning that the block with the highest bid is selected to be finalize in that round. ### Polkadot {: #polkadot } A network of connected blockchains that provides shared security and the ability to interact between chains. Polkadot is built using the Substrate development framework. Chains that connect to Polkadot are called parachains. ### Relay Chain {: #relay-chain } The backbone blockchain supporting the Polkadot network. Parachains connect to the relay chain and use it for shared security and message passing. Validators on the relay chain help secure the parachains. ### Smart Contract {: #smart-contract } A smart contract is a computer program or a transaction protocol that is intended to automatically execute, control, or document legally relevant events and actions according to the terms of a contract or an agreement. Smart contracts intend to reduce the need for trusted intermediators, arbitrations, and enforcement costs, as well as reduce fraud losses and malicious and accidental exceptions. [Learn more](https://en.wikipedia.org/wiki/Smart_contract){target=\_blank}. ### Substrate {: #substrate } A Rust-based blockchain development framework created by Parity Technologies based on their experience implementing multiple blockchain clients. Substrate comes with many modules and functionalities that are needed when building a blockchain, including P2P networking, consensus mechanisms, staking, cryptocurrency, on-chain governance modules, and more. It dramatically reduces the time and engineering effort required to implement a blockchain. Substrate is now part of the [Polkadot SDK](https://polkadot.com/platform/sdk/){target=\_blank}. ### Substrate Frame Pallets {: #substrate-frame-pallets } Substrate Frame Pallets are a collection of Rust-based modules, providing the functionality required for building a blockchain. ### Validators {: #validators } A node that secures the Polkadot relay chain by staking DOT in the network, which is slashed if they misbehave. They finalize blocks from collators on parachains and also participate on consensus for the next relay chain block with other validators. ### WebAssembly/Wasm {: #webassemblywasm } WebAssembly is an open standard that defines a portable binary code format. It is supported by different programming languages, compilers, and browsers. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/platform/ --- BEGIN CONTENT --- --- title: Smart Contract Platform description: Learn about the Moonbeam smart contract platform, including the Moonbeam networks, the vision, roadmap, technology, tokens, and more. dropdown_description: Dive into underlying technology and design aspects template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/platform/links/ --- BEGIN CONTENT --- --- title: Important Moonbeam Related Links description: If you're new to Moonbeam or the Polkadot network, here are some important links to review, including compatible Ethereum tools. categories: Basics --- # Links - **[Polkadot Docs](https://docs.polkadot.com/){target=\_blank}** - starting point for learning about the [Polkadot SDK](https://docs.polkadot.com/develop/parachains/intro-polkadot-sdk/){target=\_blank}, a Rust-based framework for developing blockchains. Moonbeam is developed using Substrate and uses many of the modules that come with it - **[Polkadot.com](https://polkadot.com){target=\_blank}** - learn about Polkadot, including the vision behind the network and how the system works, i.e., staking, governance, etc. - **[Polkadot-JS Apps](https://polkadot.js.org/apps){target=\_blank}** - a web-based interface for interacting with Substrate based nodes, including Moonbeam - **[Solidity Docs](https://solidity.readthedocs.io){target=\_blank}** - Solidity is the main smart contract programming language supported by Ethereum and Moonbeam. The Solidity docs site is very comprehensive - **[Remix](https://remix.ethereum.org){target=\_blank}** - web-based IDE for Solidity smart contract development that is compatible with Moonbeam - **[Hardhat](https://hardhat.org){target=\_blank}** - development tools for Solidity, including debugging, testing, and automated deployment that is compatible with Moonbeam --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/platform/networks/ --- BEGIN CONTENT --- --- title: Networks description: Learn the basics about each of the Moonbeam networks, including Moonbeam, Moonriver, and the Moonbase Alpha TestNet. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/platform/networks/moonbase/ --- BEGIN CONTENT --- --- title: Moonbase Alpha TestNet Overview description: An overview of the current configuration of the Moonbeam TestNet, Moonbase Alpha, and information on how to start building on it using Solidity. categories: Basics --- # The Moonbase Alpha TestNet ## Goal {: #goal } The first Moonbeam TestNet, named Moonbase Alpha, aims to provide developers with a place to start experimenting and building on Moonbeam in a shared environment. Since Moonbeam is deployed as a parachain on Kusama and Polkadot, the goal of the TestNet is to reflect the production configurations. For this reason, it was decided that it needed to be a parachain-based configuration rather than a Substrate development setup. In order to collect as much feedback as possible and provide fast issue resolution, please join the [Moonbeam Discord](https://discord.com/invite/PfpUATX){target=\_blank}. ## Initial Configuration {: #initial-configuration } Moonbase Alpha has the following configuration: - Runs as a parachain connected to a relay chain - Has an active set of {{ networks.moonbase.staking.max_candidates }} collator nodes run by the community - The relay chain hosts validators to finalize relay chain blocks. One of them is selected to finalize each block collated by Moonbeam's collators. This setup provides room to expand to a two-parachain configuration in the future - Has infrastructure providers that provide [API endpoints](/builders/get-started/endpoints/){target=\_blank} to connect to the network. Projects can also [run their own node](/node-operators/networks/run-a-node/){target=\_blank} to have access to their own private endpoints ![TestNet Diagram](/images/learn/platform/networks/moonbase-diagram.webp) Some important variables/configurations to note include: === "General" | Variable | Value | |:---------------------:|:------------------------------------------:| | Minimum gas price | {{ networks.moonbase.min_gas_price }} Gwei | | Target block time | {{ networks.moonbase.block_time }} seconds | | Block gas limit | {{ networks.moonbase.gas_block }} | | Transaction gas limit | {{ networks.moonbase.gas_tx }} | === "Staking" | Variable | Value | |:---------------------------------:|:-------------------------------------------------------------------------------------------------------------------------------------------:| | Minimum delegation stake | {{ networks.moonbase.staking.min_del_stake }} DEV | | Maximum delegators per candidates | {{ networks.moonbase.staking.max_del_per_can }} | | Maximum delegations per account | {{ networks.moonbase.staking.max_del_per_del }} | | Round | {{ networks.moonbase.staking.round_blocks }} blocks ({{ networks.moonbase.staking.round_hours }} hour) | | Bond duration | Delegations take effect in the next round; funds are withdrawn immediately | | Unbond duration | {{ networks.moonbase.delegator_timings.del_bond_less.rounds }} rounds ({{ networks.moonbase.delegator_timings.del_bond_less.hours }} hours) | !!! note As of runtime 3000, [asynchronous backing](https://wiki.polkadot.network/learn/learn-async-backing/){target=\_blank} has been enabled on all Moonbeam networks. As a result, the target block time was reduced from 12 seconds to 6 seconds, which may break some timing-based assumptions. Additionally, as of runtime 2900, the block and transaction gas limits increased by 4x on Moonbase Alpha. ## Network Endpoints {: #network-endpoints } Moonbase Alpha has two types of endpoints available for users to connect to: one for HTTPS and one for WSS. If you're looking for your own endpoints suitable for production use, you can check out the [Endpoint Providers](/builders/get-started/endpoints/#endpoint-providers){target=\_blank} section of our documentation. Otherwise, to get started quickly you can use one of the following public HTTPS or WSS endpoints. === "HTTPS" | Provider | RPC URL | Limits | |:-------------------:|:------------------------------------------------------------------:|:-----------:| | Dwellir |
```https://moonbase-rpc.dwellir.com```
| 20 req/sec | | OnFinality |
```https://moonbeam-alpha.api.onfinality.io/public```
| 40 req/sec | | Moonbeam Foundation |
```https://rpc.api.moonbase.moonbeam.network```
| 25 req/sec | | UnitedBloc |
```https://moonbase.unitedbloc.com```
| 32 req/sec | | RadiumBlock |
```https://moonbase.public.curie.radiumblock.co/http```
| 200 req/sec | === "WSS" | Provider | RPC URL | Limits | |:-------------------:|:-----------------------------------------------------------------:|:-----------:| | Dwellir |
```wss://moonbase-rpc.dwellir.com```
| 20 req/sec | | OnFinality |
```wss://moonbeam-alpha.api.onfinality.io/public-ws```
| 40 req/sec | | Moonbeam Foundation |
```wss://wss.api.moonbase.moonbeam.network```
| 25 req/sec | | UnitedBloc |
```wss://moonbase.unitedbloc.com```
| 32 req/sec | | RadiumBlock |
```wss://moonbase.public.curie.radiumblock.co/ws```
| 200 req/sec | #### Relay Chain {: #relay-chain } To connect to the Moonbase Alpha relay chain, you can use the following WS Endpoint: | Provider | RPC URL | |:--------:|:----------------------------------------------------------:| | OpsLayer |
```wss://relay.api.moonbase.moonbeam.network```
| ## Quick Start {: #quick-start } For the [Web3.js library](/builders/ethereum/libraries/web3js/){target=\_blank}, you can create a local Web3 instance and set the provider to connect to Moonbase Alpha (both HTTP and WS are supported): ```js const { Web3 } = require('web3'); // Load Web3 library . . . // Create local Web3 instance - set Moonbase Alpha as provider const web3 = new Web3('https://rpc.api.moonbase.moonbeam.network'); ``` For the [Ethers.js library](/builders/ethereum/libraries/ethersjs/){target=\_blank}, define the provider by using `ethers.JsonRpcProvider(providerURL, {object})` and setting the provider URL to Moonbase Alpha: ```js const ethers = require('ethers'); // Load Ethers library const providerURL = 'https://rpc.api.moonbase.moonbeam.network'; // Define provider const provider = new ethers.JsonRpcProvider(providerURL, { chainId: 1287, name: 'moonbase-alphanet' }); ``` Any Ethereum wallet should be able to generate a valid address for Moonbeam (for example, [MetaMask](https://metamask.io){target=\_blank}). ## Chain ID {: #chain-id } Moonbase Alpha TestNet chain ID is: `1287`, which is `0x507` in hex. ## Alphanet Relay Chain {: #relay-chain } The Alphanet relay chain is connected to Moonbase Alpha and is [Westend](https://polkadot.com/blog/westend-introducing-a-new-testnet-for-polkadot-and-kusama){target=\_blank}-based but unique to the Moonbeam ecosystem. It resembles how you would interact with Kusama or Polkadot. The native tokens of the Alphanet relay chain are UNIT tokens, which are for testing purposes only and have no real value. ## Telemetry {: #telemetry } You can see current Moonbase Alpha telemetry information by visiting [Polkadot's Telemetry dashboard](https://telemetry.polkadot.io/#list/0x91bc6e169807aaa54802737e1c504b2577d4fafedd5a02c10293b1cd60e39527){target=\_blank}. ## Tokens {: #tokens } Tokens on Moonbase Alpha, named DEV, will be issued on demand. **DEV tokens hold no value and can be freely acquired**. You can enter your address to automatically request DEV tokens from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} website. The faucet dispenses {{ networks.moonbase.website_faucet_amount }} every 24 hours. For token requests of more than the limited amount allowed by the faucet, contact a moderator directly via the [Moonbeam Discord server](https://discord.com/invite/PfpUATX){target=\_blank}. We are happy to provide the tokens needed to test your applications. ## Proof of Stake {: #proof-of-stake } The Moonbase Alpha TestNet is a fully decentralized Delegated Proof of Stake network where users of the network can delegate collator candidates to produce blocks and "earn rewards" for testing purposes. Please note, that the Moonbase Alpha DEV tokens have no real value. The number of candidates in the active set will be subject to governance. The active set will consist of the top candidates by stake, including delegations. ## Limitations {: #limitations } This is the first TestNet for Moonbeam, so there are some limitations. Some [precompiles](https://www.evm.codes/precompiled){target=\_blank} are yet to be included. You can check out the list of supported precompiles on the [Canonical Contract page](/builders/ethereum/precompiles/){target=\_blank}. However, all built-in functions are available. Since the release of Moonbase Alpha v6, the maximum gas limit per block has been set to {{ networks.moonbase.gas_block }}, with a maximum gas limit per transaction of {{ networks.moonbase.gas_tx }}. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/platform/networks/moonbeam/ --- BEGIN CONTENT --- --- title: Moonbeam Network Overview description: An overview of the current configuration of the Moonbeam deployment on Polkadot, Moonbeam, and information on how to start building on it using Solidity. categories: Basics --- # Moonbeam ## Goal {: #goal } Moonbeam was onboarded as a parachain to Polkadot on December 17th 2021. Moonbeam is the most Ethereum compatible smart-contract parachain in the Polkadot ecosystem. It allows developers to port their projects with minimal to no code changes, enabling them to tap into the Polkadot ecosystem and all its assets. In order to collect as much feedback as possible and provide fast issue resolution, you can check out the dedicated [Moonbeam Network section on Discord](https://discord.com/invite/PfpUATX){target=\_blank}. ## Initial Configurations {: #initial-configurations } Currently, Moonbeam has the following configurations: - Runs as a parachain connected to the Polkadot relay chain - Has an active set of {{ networks.moonbeam.staking.max_candidates }} collators - Has infrastructure providers that provide [API endpoints](/builders/get-started/endpoints/){target=\_blank} to connect to the network. Projects can also [run their own node](/node-operators/networks/run-a-node/){target=\_blank} to have access to their own private endpoints ![Moonbeam Diagram](/images/learn/platform/networks/moonbeam-diagram.webp) Some important variables/configurations to note include (still subject to change): === "General" | Variable | Value | |:---------------------:|:-----------------------------------------------------------------------:| | Minimum gas price | {{ networks.moonbeam.min_gas_price }} Gwei* | | Target block time | {{ networks.moonbeam.block_time }} seconds | | Block gas limit | {{ networks.moonbeam.gas_block }} | | Transaction gas limit | {{ networks.moonbeam.gas_tx }} | === "Staking" | Variable | Value | |:---------------------------------:|:-------------------------------------------------------------------------------------------------------:| | Minimum delegation stake | {{ networks.moonbeam.staking.min_del_stake }} GLMR | | Maximum delegators per candidates | {{ networks.moonbeam.staking.max_del_per_can }} | | Maximum delegations per account | {{ networks.moonbeam.staking.max_del_per_del }} | | Round | {{ networks.moonbeam.staking.round_blocks }} blocks ({{ networks.moonbeam.staking.round_hours }} hours) | | Bond duration | delegation takes effect in the next round (funds are withdrawn immediately) | | Unbond duration | {{ networks.moonbeam.delegator_timings.del_bond_less.rounds }} rounds | _*Read more about [token denominations](#token-denominations)_ ## Network Endpoints {: #network-endpoints } Moonbeam has two types of endpoints available for users to connect to: one for HTTPS and one for WSS. If you're looking for your own endpoints suitable for production use, you can check out the [Endpoint Providers](/builders/get-started/endpoints/#endpoint-providers){target=\_blank} section of our documentation. Otherwise, to get started quickly you can use one of the following public HTTPS or WSS endpoints: === "HTTPS" | Provider | RPC URL | Limits | |:-----------:|:------------------------------------------------------------------:|:-----------:| | Blast |
```https://moonbeam.public.blastapi.io```
| 80 req/sec | | Dwellir |
```https://moonbeam-rpc.dwellir.com```
| 20 req/sec | | OnFinality |
```https://moonbeam.api.onfinality.io/public```
| 40 req/sec | | UnitedBloc |
```https://moonbeam.unitedbloc.com```
| 32 req/sec | | RadiumBlock |
```https://moonbeam.public.curie.radiumblock.co/http```
| 200 req/sec | | 1RPC |
```https://1rpc.io/glmr```
| 10k req/day | | Grove |
```https://moonbeam.rpc.grove.city/v1/01fdb492```
| 5k req/day | === "WSS" | Provider | RPC URL | Limits | |:-----------:|:--------------------------------------------------------------:|:-----------:| | Blast |
```wss://moonbeam.public.blastapi.io```
| 80 req/sec | | Dwellir |
```wss://moonbeam-rpc.dwellir.com```
| 20 req/sec | | OnFinality |
```wss://moonbeam.api.onfinality.io/public-ws```
| 40 req/sec | | UnitedBloc |
```wss://moonbeam.unitedbloc.com```
| 32 req/sec | | RadiumBlock |
```wss://moonbeam.public.curie.radiumblock.co/ws```
| 200 req/sec | | 1RPC |
```wss://1rpc.io/glmr```
| 10k req/day | ## Quick Start {: #quick-start } Before getting started, make sure you've retrieved your own endpoint and API key from one of the custom [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. Then for the [Web3.js library](/builders/ethereum/libraries/web3js/){target=\_blank}, you can create a local Web3 instance and set the provider to connect to Moonbeam (both HTTP and WS are supported): ```js const { Web3 } = require('web3'); // Load Web3 library . . . // Create local Web3 instance - set Moonbeam as provider const web3 = new Web3('INSERT_RPC_API_ENDPOINT'); // Insert your RPC URL here ``` For the [Ethers.js library](/builders/ethereum/libraries/ethersjs/){target=\_blank}, define the provider by using `ethers.JsonRpcProvider(providerURL, {object})` and setting the provider URL to Moonbeam: ```js const ethers = require('ethers'); // Load Ethers library const providerURL = 'INSERT_RPC_API_ENDPOINT'; // Insert your RPC URL here // Define provider const provider = new ethers.JsonRpcProvider(providerURL, { chainId: 1284, name: 'moonbeam' }); ``` Any Ethereum wallet should be able to generate a valid address for Moonbeam (for example, [MetaMask](https://metamask.io){target=\_blank}). ## Chain ID {: #chain-id } Moonbeam chain ID is: `1284`, or `0x504` in hex. ## Telemetry {: #telemetry } You can see current Moonbeam telemetry information by visiting [Polkadot's Telemetry dashboard](https://telemetry.polkadot.io/#list/0xfe58ea77779b7abda7da4ec526d14db9b1e9cd40a217c34892af80a9b332b76d){target=\_blank}. ## Tokens {: #tokens } The tokens on Moonbeam are called Glimmer (GLMR). Check out the Moonbeam Foundation site for more information on the [Glimmer](https://moonbeam.foundation/glimmer-token-tokenomics){target=\_blank} token. ### Token Denominations {: #token-denominations } The smallest unit of Glimmer (GMLR), similarly to Ethereum, is a Wei. It takes 10^18 Wei to make one Glimmer. The denominations are as follows: | Unit | Glimmer (GLMR) | Wei | |:---------:|:--------------------:|:-----------------------------:| | Wei | 0.000000000000000001 | 1 | | Kilowei | 0.000000000000001 | 1,000 | | Megawei | 0.000000000001 | 1,000,000 | | Gigawei | 0.000000001 | 1,000,000,000 | | Microglmr | 0.000001 | 1,000,000,000,000 | | Milliglmr | 0.001 | 1,000,000,000,000,000 | | GLMR | 1 | 1,000,000,000,000,000,000 | | Kiloglmr | 1,000 | 1,000,000,000,000,000,000,000 | ## Proof of Stake {: #proof-of-stake } The Moonriver network is a fully decentralized Delegated Proof of Stake network where users of the network can delegate collator candidates to produce blocks and earn rewards. It uses the [Nimbus framework](/learn/features/consensus/){target=\_blank} framework for parachain consensus. The number of candidates in the active set will be subject to governance. The active set will consist of the top candidates by stake, including delegations. ## Limitations {: #limitations } Some [precompiles](https://www.evm.codes/precompiled){target=\_blank} are yet to be included. You can check a list of supported precompiles on the [Solidity Precompiles page](/builders/ethereum/precompiles/overview/){target=\_blank}. However, all built-in functions are available. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/platform/networks/moonriver/ --- BEGIN CONTENT --- --- title: Moonriver Overview description: An overview of the current configuration of the Moonbeam deployment on Kusama, Moonriver, and information on how to start building on it using Solidity. categories: Basics --- # Moonriver ## Goal {: #goal } In June 2021, Moonriver was first launched as a parachain on the Kusama network. Moonriver is a sister network of Moonbeam, and provides an environment to test new code under real economic conditions. Developers now have access to start building on an incentivized canary network connected to Kusama. In order to collect as much feedback as possible and provide fast issue resolution, you can check out the dedicated [Moonriver section on Discord](https://discord.com/invite/5TaUvbRvgM){target=\_blank}. ## Initial Configurations {: #initial-configurations } Currently, Moonriver has the following configurations: - Runs as a parachain connected to the Kusama relay chain - Has an active set of {{ networks.moonriver.staking.max_candidates }} collators - Has infrastructure providers that provide [API endpoints](/builders/get-started/endpoints/){target=\_blank} to connect to the network. Projects can also [run their own node](/node-operators/networks/run-a-node/){target=\_blank} to have access to their own private endpoints ![Moonriver Diagram](/images/learn/platform/networks/moonriver-diagram.webp) Some important variables/configurations to note include: === "General" | Variable | Value | |:---------------------:|:--------------------------------------------:| | Minimum gas price | {{ networks.moonriver.min_gas_price }} Gwei* | | Target block time | {{ networks.moonriver.block_time }} seconds | | Block gas limit | {{ networks.moonriver.gas_block }} | | Transaction gas limit | {{ networks.moonriver.gas_tx }} | === "Staking" | Variable | Value | |:---------------------------------:|:---------------------------------------------------------------------------------------------------------:| | Minimum delegation stake | {{ networks.moonriver.staking.min_del_stake }} MOVR | | Maximum delegators per candidates | {{ networks.moonriver.staking.max_del_per_can }} | | Maximum delegations per account | {{ networks.moonriver.staking.max_del_per_del }} | | Round | {{ networks.moonriver.staking.round_blocks }} blocks ({{ networks.moonriver.staking.round_hours }} hours) | | Bond duration | delegation takes effect in the next round (funds are withdrawn immediately) | | Unbond duration | {{ networks.moonriver.delegator_timings.del_bond_less.rounds }} rounds | _*Read more about [token denominations](#token-denominations)_ !!! note As of runtime 3000, [asynchronous backing](https://wiki.polkadot.network/learn/learn-async-backing/){target=\_blank} has been enabled on all Moonbeam networks. As a result, the target block time was reduced from 12 seconds to 6 seconds, which may break some timing-based assumptions. Additionally, the block and transaction gas limits increased by 4x on Moonriver. ## Network Endpoints {: #network-endpoints } Moonriver has two types of endpoints available for users to connect to: one for HTTPS and one for WSS. If you're looking for your own endpoints suitable for production use, you can check out the [Endpoint Providers](/builders/get-started/endpoints/#endpoint-providers){target=\_blank} section of our documentation. Otherwise, to get started quickly you can use one of the following public HTTPS or WSS endpoints: === "HTTPS" | Provider | RPC URL | Limits | |:-----------:|:-------------------------------------------------------------------:|:-----------:| | Dwellir |
```https://moonriver-rpc.dwellir.com```
| 20 req/sec | | OnFinality |
```https://moonriver.api.onfinality.io/public```
| 40 req/sec | | UnitedBloc |
```https://moonriver.unitedbloc.com```
| 32 req/sec | | RadiumBlock |
```https://moonriver.public.curie.radiumblock.co/http```
| 200 req/sec | | Grove |
```https://moonriver.rpc.grove.city/v1/01fdb492```
| 5k req/day | === "WSS" | Provider | RPC URL | Limits | |:-----------:|:---------------------------------------------------------------:|:-----------:| | Dwellir |
```wss://moonriver-rpc.dwellir.com```
| 20 req/sec | | OnFinality |
```wss://moonriver.api.onfinality.io/public-ws```
| 40 req/sec | | UnitedBloc |
```wss://moonriver.unitedbloc.com```
| 32 req/sec | | RadiumBlock |
```wss://moonriver.public.curie.radiumblock.co/ws```
| 200 req/sec | ## Quick Start {: #quick-start } Before getting started, make sure you've retrieved your own endpoint and API key from one of the custom [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. Then for the [Web3.js library](/builders/ethereum/libraries/web3js/){target=\_blank}, you can create a local Web3 instance and set the provider to connect to Moonriver (both HTTP and WS are supported): ```js const { Web3 } = require('web3'); // Load Web3 library . . . // Create local Web3 instance - set Moonriver as provider const web3 = new Web3('INSERT_RPC_API_ENDPOINT'); // Insert your RPC URL here ``` For the [Ethers.js library](/builders/ethereum/libraries/ethersjs/){target=\_blank}, define the provider by using `ethers.JsonRpcProvider(providerURL, {object})` and setting the provider URL to Moonriver: ```js const ethers = require('ethers'); // Load Ethers library const providerURL = 'INSERT_RPC_API_ENDPOINT'; // Insert your RPC URL here // Define provider const provider = new ethers.JsonRpcProvider(providerURL, { chainId: 1285, name: 'moonriver' }); ``` Any Ethereum wallet should be able to generate a valid address for Moonbeam (for example, [MetaMask](https://metamask.io){target=\_blank}). ## Chain ID {: #chain-id } Moonriver chain ID is: `1285`, or `0x505` in hex. ## Telemetry {: #telemetry } You can see current Moonriver telemetry information by visiting [Polkadot's Telemetry dashboard](https://telemetry.polkadot.io/#list/0x401a1f9dca3da46f5c4091016c8a2f26dcea05865116b286f60f668207d1474b){target=\_blank}. ## Tokens {: #tokens } The tokens on Moonriver will also be called Moonriver (MOVR). Check out the Moonbeam Foundation site for more information on the [Moonriver token](https://moonbeam.foundation/moonriver-token-tokenomics){target=\_blank}. ### Token Denominations {: #token-denominations } The smallest unit of Moonriver, similarly to Ethereum, is a Wei. It takes 10^18 Wei to make one Moonriver. The denominations are as follows: | Unit | Moonriver (MOVR) | Wei | |:--------------:|:--------------------:|:-----------------------------:| | Wei | 0.000000000000000001 | 1 | | Kilowei | 0.000000000000001 | 1,000 | | Megawei | 0.000000000001 | 1,000,000 | | Gigawei | 0.000000001 | 1,000,000,000 | | Micromoonriver | 0.000001 | 1,000,000,000,000 | | Millimoonriver | 0.001 | 1,000,000,000,000,000 | | Moonriver | 1 | 1,000,000,000,000,000,000 | | Kilomoonriver | 1,000 | 1,000,000,000,000,000,000,000 | ## Proof of Stake {: #proof-of-stake } The Moonriver network is a fully decentralized Delegated Proof of Stake network where users of the network can delegate collator candidates to produce blocks and earn rewards. It uses the [Nimbus framework](/learn/features/consensus/){target=\_blank} framework for parachain consensus. The number of candidates in the active set will be subject to governance. The active set will consist of the top candidates by stake, including delegations. ## Limitations {: #limitations } Some [precompiles](https://www.evm.codes/precompiled){target=\_blank} are yet to be included. You can check a list of supported precompiles on the [Canonical Contract page](/builders/ethereum/precompiles/){target=\_blank}. However, all built-in functions are available. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/platform/networks/overview/ --- BEGIN CONTENT --- --- title: Overview of Networks description: An overview of all of the MainNet and TestNet deployments of Moonbeam, an Ethereum-compatible smart contract parachain on Polkadot and Kusama. categories: Basics --- # Networks There are multiple long-lived Moonbeam-based networks. Most significantly, there is the Moonbeam deployment on Polkadot and Kusama. An overview of our parachain deployments is as follows: - Moonbeam: deployment on Polkadot (_December 2021_) - Moonriver: deployment on Kusama (_June 2021_) - Moonbase Alpha: Parachain TestNet for Moonbeam and Moonriver (_September 2020_) This strategy allows us to de-risk software upgrades to Moonbeam on the Polkadot MainNet while still maintaining a reasonable update velocity. ## Moonbeam {: #moonbeam } The Moonbeam production MainNet is a parachain on Polkadot and has been since December 17th, 2021. Moonbeam features the highest levels of security and availability. Code running on the MainNet has generally been vetted through one or more of the other networks listed above. Moonbeam will offer parachain-related functionalities such as [XCMP](https://wiki.polkadot.network/learn/learn-xcm-transport/#xcmp-cross-chain-message-passing){target=\_blank} and [SPREE](https://wiki.polkadot.network/learn/learn-spree/){target=\_blank} as these features become available. [Learn more about Moonbeam](/learn/platform/networks/moonbeam/). ## Moonriver {: #moonriver } In advance of deploying to the Polkadot MainNet, [Moonbeam launched Moonriver](https://moonbeam.network/news/moonriver-won-a-parachain-slot-and-is-now-producing-blocks-on-the-kusama-network){target=\_blank} as a parachain on the Kusama network. The parachain functionality is live on Kusama. Moonriver will offer parachain-related functionalities such as [XCMP](https://wiki.polkadot.network/learn/learn-xcm-transport/#xcmp-cross-chain-message-passing){target=\_blank} and [SPREE](https://wiki.polkadot.network/learn/learn-spree/){target=\_blank} as these features become available. [Learn more about Moonriver](/learn/platform/networks/moonriver/). ## Moonbase Alpha {: #moonbase-alpha } This TestNet is a network hosted by OpsLayer. It features a parachain/relay chain scheme. The goal is to allow developers to test the Ethereum compatibility features of Moonbeam in a shared parachain environment without needing to run their own nodes or network. [Learn more about Moonbase Alpha](/learn/platform/networks/moonbase/). --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/platform/technology/ --- BEGIN CONTENT --- --- title: Technology & Architecture description: Moonbeam is built using Rust and Polkadot's Substrate framework, enabling rich tools for implementation while allowing for specialization and optimization. categories: Basics --- # Technology & Architecture ## The Moonbeam Development Stack {: #the-moonbeam-development-stack } Moonbeam is a smart contract blockchain platform built in the Rust programming language using the Substrate framework. Substrate, developed by [Parity Technologies](https://www.parity.io/){target=_blank} (the original founding contributors of Polkadot), is an open-source, modular SDK for creating blockchains. Substrate allows developers to customize their blockchains while still benefiting from features such as forkless upgrades, shared security (when connected as a parachain to Polkadot or Kusama), and an extensive library of pre-built runtime modules known as pallets. ### Rust Programming Language {: #rust-programming-language } Rust is a good language for implementing a blockchain. It is highly performant like C and C++ but has built-in memory safety features enforced at compile time, preventing many common bugs and security issues arising from C and C++ implementations. ### Substrate Framework {: #substrate-framework } Substrate provides a rich set of tools for creating blockchains, including a runtime execution environment that enables a generic state transition function and a pluggable set of modules (pallets) that implement various blockchain subsystems. By using Substrate, Moonbeam can leverage several key features offered to parachains launched on the Polkadot relay chain, including: - **Shared security** — Polkadot's validators secure all parachains - **Cross-Consensus Messaging (XCM)** — native interoperability with other parachains - **Flexible upgrades** — Substrate’s forkless upgrade mechanism Pallets are at the heart of Substrate-based chains, providing specific functionality in modular form. Examples include: - **Balances pallet** — manages account balances and transfers - **Assets pallet** — handles the creation and management of on-chain fungible assets - **Consensus pallets** — provide mechanisms like AURA or BABE for block production - **Governance pallets** — facilitate on-chain governance - **Frontier pallets** — the Ethereum compatibility layer pioneered by the Moonbeam team - **Parachain Staking pallet** — enables Delegated Proof of Stake (DPoS) In addition to these pallets provided by Polkadot's Substrate, developers can [create their own pallets](https://docs.polkadot.com/develop/parachains/customize-parachain/make-custom-pallet/){target=_blank} to add custom functionality. Moonbeam leverages multiple existing Substrate frame pallets as well as several custom pallets for features such as cross-chain token integration, the [Orbiter Program](/node-operators/networks/collators/orbiter/){target=_blank}, and more. You can find the Moonbeam runtime (built using Substrate) and related pallets in the [Moonbeam GitHub repository](https://github.com/moonbeam-foundation/moonbeam){target=_blank}. Moonbeam also uses the Cumulus library to facilitate integration with the Polkadot relay chain. ### Frontier: Substrate's Ethereum Compatibility Layer {: #frontier } [Frontier](https://polkadot-evm.github.io/frontier){target=\_blank} serves as Substrate's Ethereum compatibility layer, facilitating the seamless operation of standard Ethereum DApps on Substrate-based chains without requiring modifications. This compatibility is achieved by integrating specialized Substrate pallets into the Substrate runtime. These pallets include: - **EVM pallet** — responsible for executing EVM operations - **Ethereum pallet** — manages block data storage and offers RPC compatibility - **Base Fee pallet and Dynamic Fee pallet** — provide EIP-1559 functionality (not used in Moonbeam) Moonbeam uses the EVM and Ethereum pallets to achieve full Ethereum compatibility. Instead of the Base Fee or Dynamic Fee pallets, Moonbeam has its own [dynamic fee mechanism](https://forum.moonbeam.network/t/proposal-dynamic-fee-mechanism-for-moonbeam-and-moonriver/241){target=\_blank} for base fee calculations. Basing the EVM implementation on the Substrate EVM Pallet provides a Rust-based EVM engine and support from the Parity engineering team. ## Blockchain Runtime {: #blockchain-runtime } The core Moonbeam runtime specifies the state transition function and behavior of the Moonbeam blockchain. The runtime is built using [FRAME](/learn/platform/glossary/#substrate-frame-pallets){target=\_blank}, compiled to a [WebAssembly (Wasm)](/learn/platform/glossary/#webassemblywasm){target=\_blank} binary as well as a native binary. These compiled versions are executed in the Polkadot relay chain and Moonbeam node environments. !!! note Substrate FRAME pallets are a collection of Rust-based modules that provide the functionality required when building a blockchain. WebAssembly is an open standard that defines a portable binary code format. Different programming languages, compilers, and browsers support it. Find more definitions [in our glossary](/learn/platform/glossary/){target=\_blank}. Some of the key Substrate FRAME pallets used in the Moonbeam runtime include: - **Balances** — support for accounts, balances, and transfers - **EVM** — a full Rust-based EVM implementation based on SputnikVM (part of Frontier) - **Ethereum** — provides emulation of Ethereum block processing for the EVM (part of Frontier) - **Executive** — orchestration layer that dispatches calls to other runtime modules - **Identity** — support for setting on-chain identities for account addresses - **System** — provides low-level types, storage, and blockchain functions - **Treasury** — on-chain treasury that can be used to fund public goods such as a parachain slot In addition to these Substrate FRAME Pallets, Moonbeam implements custom pallets to achieve additional functionality, such as: - **Parachain Staking** — enables a Delegated Proof of Stake (DPoS) system - **Moonbeam Orbiters** — supports the [Orbiter Program](/node-operators/networks/collators/orbiter/){target=\_blank}, which diversifies the collator pool - **XCM Transactor** — simplifies remote cross-chain calls via [Cross-Consensus Messaging (XCM)](/builders/interoperability/xcm/overview/){target=\_blank} - **Asset Manager** — registers XCM assets ### Forkless Upgrades {: #forkless-upgrades } One of the best things about developing on Polkadot with Substrate is the ability to introduce [forkless upgrades](https://docs.polkadot.com/develop/parachains/maintenance/runtime-upgrades/){target=_blank} to blockchain runtimes. In traditional blockchain architectures, substantial changes to the blockchain's rules often require a hard fork, which can be disruptive and contentious. Substrate takes a different approach by separating the blockchain's state (data) from its logic (rules). Logic lives in the runtime, which is itself stored on-chain. Whenever a new runtime is uploaded (via FRAME's `set_code` call) and approved through on-chain governance, all nodes automatically switch to the new runtime at a specified block. This process is seamless and does not split the network. Moonbeam regularly uses forkless upgrades to add features or fixes without requiring node operators to upgrade their software manually. You can keep track of and discuss upcoming Moonbeam upgrades on the [Moonbeam forum](https://forum.moonbeam.network){target=_blank}. ## Ethereum Compatibility Architecture {: #ethereum-compatibility-architecture } Smart contracts on Moonbeam can be implemented using Solidity, Vyper, and any other language that compiles smart contracts to EVM-compatible bytecode. Moonbeam aims to provide a low-friction and secure environment for the development, testing, and execution of smart contracts while remaining compatible with the existing Ethereum developer toolchain. The execution behavior and semantics of Moonbeam-based smart contracts strive to be as close as possible to Ethereum Layer 1. Moonbeam is a single shard, so cross-contract calls have the same synchronous execution semantics as on Ethereum Layer 1. ![Diagram showing the interactions made possible through Moonbeam's Ethereum compatibility](/images/learn/platform/technology-diagram.webp) A high-level interaction flow is shown above. A Web3 RPC call from a DApp or existing Ethereum developer tool, such as Hardhat, is received by a Moonbeam node. The node has both Web3 RPCs and Substrate RPCs available, meaning you can use Ethereum or Substrate tools when interacting with a Moonbeam node. Associated Substrate runtime functions handle these RPC calls. The Substrate runtime checks signatures and handles any extrinsics. Smart contract calls are ultimately passed to the EVM to execute the state transitions. ### Ethereum Pallet {: #ethereum-pallet} The [Ethereum pallet](https://polkadot-evm.github.io/frontier/overview){target=\_blank} is responsible for handling blocks and transaction receipts and statuses. It enables sending and receiving Ethereum-formatted data to and from Moonbeam by storing an Ethereum-style block and its associated transaction hashes in the Substrate runtime. When a user submits a raw Ethereum transaction, it converts into a Substrate transaction through the Ethereum pallet's `transact` extrinsic—using the Ethereum pallet as the sole executor of the EVM pallet forces all of the data to be stored and transacted in an Ethereum-compatible way, which is how explorers like [Moonscan](/builders/get-started/explorers/#moonscan){target=\_blank} (built by Etherscan) can index block data. ### EVM Pallet {: #evm-pallet } The [EVM pallet](https://polkadot-evm.github.io/frontier/overview){target=\_blank} implements a sandboxed virtual stack machine and uses the [SputnikVM](https://github.com/rust-ethereum/evm){target=\_blank} as the underlying EVM engine. It executes Ethereum smart contract bytecode in a manner similar to Ethereum mainnet, including gas metering and state changes. Moonbeam uses unified accounts, meaning an H160 (Ethereum-style) address is also a valid Substrate address, so you only need a single account to interact with the Substrate runtime and the EVM. Once a balance exists in the EVM, smart contracts can be created and interacted with through standard Ethereum RPC calls. The EVM pallet should produce nearly identical execution results to Ethereum, such as gas cost and balance changes. However, there are some differences. Although the EVM pallet aims for near-identical behavior to Ethereum, some differences exist, for example, Moonbeam's [dynamic fee mechanism](https://forum.moonbeam.network/t/proposal-dynamic-fee-mechanism-for-moonbeam-and-moonriver/241){target=\_blank}. For more information, refer to the [Frontier EVM Pallet documentation](https://polkadot-evm.github.io/frontier/){target=\_blank}. Moonbeam includes additional EVM precompiles for functionalities like cryptographic operations (ECRecover, SHA256, BLAKE2, BN128) and dispatching Substrate calls directly from within the EVM. Moonbeam uses the following EVM precompiles: - **[pallet-evm-precompile-simple](https://polkadot-evm.github.io/frontier/rustdocs/pallet_evm_precompile_simple){target=\_blank}** - includes five basic precompiles: ECRecover, ECRecoverPublicKey, Identity, RIPEMD160, SHA256 - **[pallet-evm-precompile-blake2](https://polkadot-evm.github.io/frontier/rustdocs/pallet_evm_precompile_blake2/struct.Blake2F.html){target=\_blank}** - includes the BLAKE2 precompile - **[pallet-evm-precompile-bn128](https://polkadot-evm.github.io/frontier/rustdocs/pallet_evm_precompile_bn128/index.html){target=\_blank}** - includes three BN128 precompiles: BN128Add, BN128Mul, and BN128Pairing - **[pallet-evm-precompile-modexp](https://polkadot-evm.github.io/frontier/rustdocs/pallet_evm_precompile_modexp/struct.Modexp.html){target=\_blank}** - includes the modular exponentiation precompile - **[pallet-evm-precompile-sha3fips](https://polkadot-evm.github.io/frontier/rustdocs/pallet_evm_precompile_sha3fips/struct.Sha3FIPS256.html){target=\_blank}** -includes the standard SHA3 precompile - **[pallet-evm-precompile-dispatch](https://polkadot-evm.github.io/frontier/rustdocs/pallet_evm_precompile_dispatch/struct.Dispatch.html){target=\_blank}** - includes the dispatch precompile You can find an overview of most of these precompiles on the [Ethereum MainNet Precompiled Contracts](/builders/ethereum/precompiles/utility/eth-mainnet/){target=\_blank} page. ## Native Interoperability {: #native-interoperability } While Substrate allows developers to create blockchains, one of its most significant advantages is that it supports integration for native interoperability through relay chains like Polkadot and Kusama. A relay chain is a central chain that connects several blockchains, known as parachains. Each parachain is a distinct blockchain with its runtime and state, but all are connected to and secured by the relay chain. Once connected, parachains can communicate via [Cross-Consensus Messaging (XCM)](/builders/interoperability/xcm/overview/){target=_blank} to exchange information and conduct transactions in the same language, enabling a wide range of interoperable applications. Moonbeam and Moonriver have established XCM connections with a large number of parachains. You can see a visualization of all XCM integrations in this [XCM Channel Viewer](https://dotsama-channels.vercel.app/#/){target=_blank}. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/platform/tokens/ --- BEGIN CONTENT --- --- title: Utility Tokens description: Each of the Moonbeam networks require a utility token to function. Glimmer (GLMR) for Moonbeam on Polkadot and Moonriver (MOVR) for Moonriver on Kusama. categories: Basics --- # Introduction As a decentralized smart contract platform, Moonbeam requires a utility token to function. This token is central to the design of Moonbeam and cannot be removed without sacrificing essential functionality. The Moonbeam token uses include: - Supporting the gas metering of smart contract execution - Incentivizing collators and powering the mechanics around the creation of a decentralized node infrastructure on which the platform can run - Facilitating the on-chain governance mechanism, including proposing referenda, electing council members, voting, etc. - Paying for network transaction fees ## Glimmer Token {: #glimmer-token } In the Moonbeam deployment on Polkadot MainNet, this token is called Glimmer, as in, “that smart contract call will cost 0.3 Glimmer.” The token symbol is GLMR. You can find more information about Glimmer on the [Moonbeam Foundation](https://moonbeam.foundation/glimmer-token-tokenomics) website. ## Moonriver Token {: #moonriver-token } In the Moonbeam deployment on Kusama (called Moonriver), this token is called Moonriver, as in, “that smart contract call will cost 0.003 Moonriver.” The token symbol will be MOVR. You can find more information about Moonriver on the [Moonbeam Foundation](https://moonbeam.foundation/moonriver-token-tokenomics) website. ## DEV Token {: #dev-token } In the Moonbeam TestNet (called Moonbase Alpha), the token is called DEV. This token can be acquired freely, as its only purpose is to drive development and testing on Moonbase Alpha. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank}. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/platform/vision/ --- BEGIN CONTENT --- --- title: The Moonbeam Vision | Multi-chain description: Moonbeam is designed to enable a multi-chain future, where users and assets can move freely across many specialized and heterogeneous chains. categories: Basics --- # Our Vision for Moonbeam We believe in a multi-chain future with many chains, and many users and assets on those chains. In this context, we have created Moonbeam: a smart contract platform that provides an Ethereum-compatible environment for building decentralized applications. Moonbeam was designed to serve these new kinds of assets and users that exist across two or more chains. Existing smart contract platforms are designed to service the users and assets on a single, specific chain. By providing cross-chain smart contract functionality, Moonbeam allows developers to shift existing workloads and logic to Moonbeam and extend the reach of their applications to new users and assets on other chains. Moonbeam's cross-chain integration is accomplished by becoming a [parachain](/learn/platform/glossary/#parachains) on the Polkadot network. The [Polkadot network](/learn/platform/glossary/#polkadot) provides integration and connectivity between parachains that are connected to the network and to other non-Polkadot-based chains, such as Ethereum and Bitcoin, via bridges. ## Who Benefits From Moonbeam {: #who-benefits-from-moonbeam } There are three main audiences who can most benefit from Moonbeam's cross-chain functionality: ### Existing Ethereum-Based Projects {: #existing-ethereum-based-projects } Projects that are struggling with cost and scalability challenges on Ethereum can use Moonbeam to: - Move portions of their existing workloads and state off of Ethereum Layer 1 with minimal required changes. - Implement a hybrid approach, where applications live on both Ethereum and Moonbeam simultaneously. - Extend their reach to the Polkadot network and other chains that are connected to Polkadot. ### Polkadot Ecosystem Projects {: #polkadot-ecosystem-projects } Ecosystem projects that need smart contract functionality can use Moonbeam to: - Augment their existing parachains and parathreads. - Add new functionality that is needed but not included on the main [Polkadot relay chain](/learn/platform/glossary/#relay-chain). For example, they could create a place where teams can crowdfund their projects, implement lockdrops, and process other, more complex financial transactions than are provided by base [Substrate](/learn/platform/glossary/#substrate) functionality. - Leverage the mature and extensive Ethereum development toolchain. ### Developers of New DApps {: #developers-of-new-dapps } Individuals and teams that want to try building on Polkadot can use Moonbeam to: - Leverage the specialized functionality from Polkadot parachains while reaching users and assets on other chains. - Compose functionality from Polkadot parachains by using Moonbeam as a lightweight integration layer that aggregates network services before presenting them to end users. Implementing a composed service using pre-built integrations on a smart contract platform will be a lot faster and easier (in many cases) than building a full Substrate runtime and performing the integrations yourself in the runtime. ## Key Features and Functionality {: #key-features-and-functionality } Moonbeam achieves these goals with the following key features: - **Decentralized and Permissionless** , providing a base requirement for censorship resistance and support for many existing and future DApp use cases. - **Contains a Full EVM Implementation** , enabling Solidity-based smart contracts to be migrated with minimal change and with expected execution results. - **Implements the Web3 RPC API** so that existing DApp front-ends can be migrated with minimal change required, and so existing Ethereum-based tools, such as Hardhat, Remix, and MetaMask, can be used without modification against Moonbeam. - **Compatible with the Substrate Ecosystem Toolset** , including block explorers, front-end development libraries, and wallets, allowing developers and users to use the right tool for what they are trying to accomplish. - **Native Cross-Chain Integration** via the Polkadot network and via token bridges, which allows for token movement, state visibility, and message passing with Ethereum and other chains. - **On-Chain Governance** to allow stakeholders to quickly and forklessly evolve the base protocol according to developer and community needs. This unique combination of elements fills a strategic market gap, while allowing Moonbeam to address future developer needs as the Polkadot network grows over time. Building your own chain with Substrate is powerful, but also comes with a number of additional responsibilities, such as learning and implementing the chain’s runtime in Rust, creating a token economy, and incentivizing a community of node operators. For many developers and projects, an Ethereum-compatible smart contract approach will be much simpler and faster to implement. And by building these smart contracts on Moonbeam, developers can still integrate with other chains and get value from Polkadot-based network effects. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/learn/platform/why-polkadot/ --- BEGIN CONTENT --- --- title: Why Polkadot description: Moonbeam is built on the Substrate framework and connected to the Polkadot network, adding speed and security to the platform. categories: Basics --- # Why We're Building on Polkadot After extensive research, we decided to build Moonbeam using the [Substrate development framework](/learn/platform/glossary/#substrate) and to deploy Moonbeam as a [parachain](/learn/platform/glossary/#parachains) on the [Polkadot network](/learn/platform/glossary/#polkadot). ## Substrate Blockchain Framework {: #substrate-blockchain-framework } Substrate is a good technical fit for Moonbeam. By building on top of this framework, we can leverage the extensive functionality that Substrate includes out-of-the-box, rather than building it ourselves. This includes peer-to-peer networking, consensus mechanisms, governance functionality, an EVM implementation, and more. Overall, using Substrate will dramatically reduce the time and implementation effort needed to implement Moonbeam. Substrate allows a great degree of customization, which is necessary in order to achieve our Ethereum compatibility goals. And, by using Rust, we benefit from both safety guarantees and performance gains. ## Polkadot Network and Ecosystem {: #polkadot-network-and-ecosystem } The Polkadot network is also a good fit for Moonbeam. As a parachain on Polkadot, Moonbeam will be able to directly integrate with — and move tokens between — any other parachains and parathreads on the network. We can also leverage any of the bridges that are independently built to connect non-Polkadot chains to Polkadot, including bridges to Ethereum. Polkadot’s interoperability model uniquely supports Moonbeam’s cross-chain integration goals and is a key enabling technology to support the Moonbeam vision. But perhaps just as important as the technical criteria above, we are impressed with the people in the Polkadot ecosystem. This includes individuals at Parity, the Web3 Foundation, and other projects in the ecosystem. We have built many valuable relationships and find the people to be both extremely talented and the kind of people we want to be around. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/node-operators/ --- BEGIN CONTENT --- --- title: Node Operators & Collators description: Learn how to become a node operator on Moonbeam, including running a Moonbeam full node or collator node, indexer nodes, and oracle nodes. template: main-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/node-operators/indexer-nodes/ --- BEGIN CONTENT --- --- title: Run Indexer Nodes description: Learn how to run an indexer node, such as a Graph node, on Moonbeam to provide indexing and querying services of on-chain data. dropdown_description: Run infrastructure for indexing and querying services template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/node-operators/indexer-nodes/thegraph-node/ --- BEGIN CONTENT --- --- title: Run a Graph Node description: Use Docker to spin up and run your own Graph node to provide indexing and querying services of on-chain data on Moonbeam. categories: Indexer Nodes and Queries --- # Running a Graph Node on Moonbeam ## Introduction {: #introduction } A [Graph](https://thegraph.com){target=\_blank} Node sources events from a blockchain to deterministically update a data store that can be then queried via a GraphQL endpoint. There are two ways you can set up a Graph Node: you can use Docker to run an all-in-one image, or you can run their [Rust implementation](https://github.com/graphprotocol/graph-node){target=\_blank}. The steps described in this guide will only cover the Docker alternative, as it is more convenient, and you can set up a Graph Node very quickly. !!! note The steps described in this guide have been tested in both Ubuntu 18.04-based and MacOS environments, and they will need to be adapted accordingly for other systems.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Checking Prerequisites {: #checking-prerequisites } Before diving into setting up a Graph Node, you need to have the following installed on your system: - [Docker](https://docs.docker.com/get-started/get-docker/){target=\_blank} - [Docker Compose](https://docs.docker.com/compose/install){target=\_blank} - [JQ](https://stedolan.github.io/jq/download){target=\_blank} In this guide, you will learn how to run a Graph node against a Moonbase Alpha tracing node with the `tracing` flag enabled. To spin up a full node with the `tracing` flag enabled, check out the [Debug & Trace](/node-operators/networks/tracing-node/){target=\_blank} guide. This guide can also be adapted for Moonbeam and Moonriver. To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank}. ## Running a Graph Node {: #running-a-graph-node } The first step is to clone the [Graph Node repository](https://github.com/graphprotocol/graph-node){target=\_blank}: ```bash git clone https://github.com/graphprotocol/graph-node/ \ && cd graph-node/docker ``` Next, execute the `setup.sh` file. This will pull all the necessary Docker images and write the necessary information in the `docker-compose.yml` file. ```bash ./setup.sh ``` The tail end from the logs of the previous command should look something similar to:
Pull complete: d073cd070242 Pull complete: 03790957a916 Pull complete: b3776ac15dab Pull complete: 7144fd00aec4 Pull complete: 54f6491bd120 Pull complete: 247ab23c6036 Pull complete: 57800498c536 Pull complete: beb15a4d14f4 Pull complete: cfc751ecbc6e Pull complete: bbf042afd4a4 Pull complete: 453056a20de6 Pull complete: d5b1a75378ef Pull complete: 78412074775 Digest: sha256:61d5d8ef6c42035f05326b6455c201a809354084c842669048dd35602 Status: Downloaded newer image for postgres: latest Creating docker_postgres_1 ... done Creating docker_ipfs_1 ... done Recreating docker_graph-node_1 ... done Starting graph-node ... done Host IP: 172.18.0.1 Stopping docker_graph-node_1 ... done
Once everything is set up, you need to modify the "Ethereum environment" inside the `docker-compose.yml` file, so that it points to the endpoint of the node you are running this Graph Node against. Note that the `setup.sh` file detects the `Host IP` and writes its value, so you'll need to modify it accordingly. === "Moonbeam" ```yaml ethereum: 'moonbeam:{{ networks.development.rpc_url }}' ``` === "Moonriver" ```yaml ethereum: 'moonriver:{{ networks.development.rpc_url }}' ``` === "Moonbase Alpha" ```yaml ethereum: 'mbase:{{ networks.development.rpc_url }}' ``` === "Moonbeam Dev Node" ```yaml ethereum: 'mbase:{{ networks.development.rpc_url }}' ``` The entire `docker-compose.yml` file should look something similar to: ```yaml version: '3' services: graph-node: image: graphprotocol/graph-node ports: - '8000:8000' - '8001:8001' - '8020:8020' - '8030:8030' - '8040:8040' depends_on: - ipfs - postgres environment: postgres_host: postgres postgres_user: graph-node postgres_pass: let-me-in postgres_db: graph-node ipfs: 'ipfs:5001' ethereum: 'mbase:{{ networks.development.rpc_url }}' RUST_LOG: info ipfs: image: ipfs/go-ipfs:v0.4.23 ports: - '5001:5001' volumes: - ./data/ipfs:/data/ipfs postgres: image: postgres ports: - '5432:5432' command: ["postgres", "-cshared_preload_libraries=pg_stat_statements"] environment: POSTGRES_USER: graph-node POSTGRES_PASSWORD: let-me-in POSTGRES_DB: graph-node volumes: - ./data/postgres:/var/lib/postgresql/data ``` Lastly, to run the Graph Node, just run the following command: ```bash docker-compose up ```
docker-compose up Starting docker_postgres_1 ... done Starting docker_ipfs_1 ... done Recreating docker_graph-node_1 ... done Attaching to docker_ipfs_1, docker_postgres_1, docker_graph-node_1 ipfs_1 | Changing user to ipfs ipfs_1 | IPFS version 0.4.23 ipfs_1 | Initializing IPFS node at /data/ipfs postgres_1 | The files belonging to this database system will be owned by user "postgres" postgres_1 | This user must also own the server process. postgres_1 | The database cluster will be initialized with locale "en_US.utf8" postgres_1 | The default database encoding has accordingly been set to "UTF8" postgres_1 | The default text search configuration will be set to "english" postgres_1 | Data page checksums are disabled. postgres_1 | Fixing permissions on existing directory /var/lib/postgresql/data ... ok postgres_1 | Creating subdirectories ... ok postgres_1 | Selecting dynamic shared memory implementation ... posix postgres_1 | Selecting default max_connections ... 100
After a while, you should see logs related to the Graph Node syncing with the latest available block in the network:
graph-node_1 | Aug 1 11:04:56.017 INFO Starting JSON-RPC admin server at: http://localhost Aug 1 11:04:56.022 INFO Started all subgraphs, component: SubgraphRegistrar graph-node_1 | Aug 1 11:04:56.024 INFO Starting GraphQL HTTP server at: http://localhost:8000, component: GraphQLServer Aug 1 11:04:56.024 INFO Starting index node server at: http://localhost:8030, component: IndexNodeServer Aug 1 11:04:56.028 INFO Starting metrics server at: http://localhost:8040, component: MetricsServer graph-node_1 | Aug 1 11:04:56.029 INFO Starting GraphQL WebSocket server at: ws://localhost:8001, component: SubscriptionServer graph-node_1 | Aug 1 11:04:56.151 INFO Downloading latest blocks from Ethereum. This may take a few minutes..., provider: mbase-rpc-0, component: BlockIngestor graph-node_1 | Aug 1 11:05:03.083 INFO Syncing 1 blocks from Ethereum., code: BlockIngestionStatus, blocks_needed: 1, blocks_behind: 1, latest_block_head: 132365, current_block_head: 132364, provider: mbase-rpc-0, component: BlockIngestor graph-node_1 | Aug 1 11:05:11.715 INFO Syncing 1 blocks from Ethereum., code: BlockIngestionStatus, blocks_needed: 1, blocks_behind: 1, latest_block_head: 132366, current_block_head: 132365, provider: mbase-rpc-0, component: BlockIngestor
And that is it! You have a Graph Node running against the Moonbase Alpha TestNet. Feel free to adapt this example for Moonbeam and Moonriver as well.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/node-operators/networks/collators/account-management/ --- BEGIN CONTENT --- --- title: Collator Account Management description: Learn how to manage your collator account, including generating session keys, mapping Nimbus IDs, setting an identity, and creating proxy accounts. categories: Node Operators and Collators --- # Collator Account Management ## Introduction {: #introduction } When running a collator node on Moonbeam-based networks, there are some account management activities that you will need to be aware of. First and foremost you will need to create [session keys](https://wiki.polkadot.network/general/web3-and-polkadot/#session-keys){target=\_blank} for your primary and backup servers which will be used to determine block production and sign blocks. In addition, there are some optional account management activities that you can consider such as setting an on-chain identity or setting up proxy accounts. This guide will cover how to manage your collator account including generating and rotating your session keys, registering and updating your session keys, setting an identity, and creating proxy accounts. ## Process to Add and Update Session Keys {: #process } The process for adding your session keys for the first time is the same as it would be for rotating your session keys. The process to create/rotate session keys is as follows: 1. [Generate session keys](#session-keys) using the `author_rotateKeys` RPC method. The response to calling this method will be a 128 hexadecimal character string containing a Nimbus ID and the public key of a VRF session key 2. [Join the candidate pool](/node-operators/networks/collators/activities/#become-a-candidate){target=\_blank} if you haven't already 3. [Map the session keys](#mapping-extrinsic) to your candidate account using the [Author Mapping Pallet](#author-mapping-interface)'s `setKeys(keys)` extrinsic, which accepts the entire 128 hexadecimal character string as the input. When you call `setKeys` for the first time, you'll be required to submit a [mapping bond](#mapping-bonds). If you're rotating your keys and you've previously submitted a mapping bond, no new bond is required Each step of the process is outlined in the following sections. ## Generate Session Keys {: #session-keys } To match the Substrate standard, Moonbeam collator's session keys are [SR25519](https://wiki.polkadot.network/learn/learn-cryptography/#what-is-sr25519-and-where-did-it-come-from){target=\_blank}. This guide will show you how you can create/rotate your session keys associated with your collator node. First, make sure you're [running a collator node](/node-operators/networks/run-a-node/overview/){target=\_blank}. Once you have your collator node running, your terminal should print similar logs:
2025-02-25 20:00:52 [Relaychain] 💤 Idle (6 peers), best: #12706 (0x1d51.3042), finalized #12704 (0xf74b.aa44), 1 0.4kiB/s 1 0.6kiB/s 2025-02-25 20:00:52 💤 Idle (6 peers), best: #5751 (Oxc5alesb5), finalized #5750 (0x9dc..e bad), 1 9.6kiB/s 1 3.5kiB/s 2025-02-25 20:00:53 [Relaychain] ✨ Imported #12707 (0x77ea.4299) 2025-02-25 20:00:57 [Relaychain] 💤 Idle (6 peers), best: #12707 (0x77ea..4299), finalized #12704 (0xf74b..aa44), | 16.4kiB/s 1 12.2kiB/s 2025-02-25 20:00:57 💤 Idle (6 peers), best: #5751 (0xc5a1e8b5), finalized #5750 (0x9fdc...e bad), 1 1.6kiB/s 1 0.4kiB/s 2025-02-25 20:00:59 [Relaychain] ✨ Imported #12708 (0x009f...3bbf) 2025-02-25 20:01:00 ✨ Imported #5753 (0x8981.6c81) 2025-02-25 20:01:00 ✨ Imported #5753 (0x33a...b5e3) 2025-02-25 20:01:02 [Relaychain] 💤 Idle (6 peers), best: #12708 (0x009f...3bbf), finalized #12706 (0x1d51.3042), 1 1.5kiB/s 1 1.3kiB/s 2025-02-25 20:01:02 💤 Idle (6 peers), best: #5752 (0x7036.569e), finalized #5751 (0xc5a1..e8b5), 1 3.3kiB/s 1 5.8kiB/s 2025-02-25 20:01:05 [Relaychain] ✨ Imported #12709 (0x76b9...bf65) 2025-02-25 20:01:07 [Relaychain] 💤 Idle (6 peers), best: #12709 (0x76b9..bf65), finalized #12706 (0x1d51.3042), | 2.0kiB/s | 0.9kiB/s 2025-02-25 20:01:07 💤 Idle (6 peers), best: #5752 (0x7036.569e), finalized #5751 (0xc5a1..e8b5), 1 0 1 0
Next, session keys can be created/rotated by sending an RPC call to the HTTP endpoint with the `author_rotateKeys` method. When you call `author_rotateKeys`, the result is the size of two keys. The response will contain a concatenated Nimbus ID and VRF key. The Nimbus ID will be used to sign blocks and the [VRF](https://wiki.polkadot.network/general/web3-and-polkadot/#vrf){target=\_blank} key is required for block production. The concatenated keys will be used to create an association to your H160 account for block rewards to be paid out. For reference, if your collator's HTTP endpoint is at port `9944`, the JSON-RPC call might look like this: ```bash curl http://127.0.0.1:9944 -H \ "Content-Type:application/json;charset=utf-8" -d \ '{ "jsonrpc":"2.0", "id":1, "method":"author_rotateKeys", "params": [] }' ``` The collator node should respond with the concatenated public keys of your new session keys. The first 64 hexadecimal characters after the `0x` prefix represent your Nimbus ID and the last 64 hexadecimal characters are the public key of your VRF session key. You'll use the concatenated public keys when mapping your Nimbus ID and setting the session keys in the next section.
curl http://127.0.0.1:9933-H\ "Content-Type: application/json;charset=utf-8" -d \ '{ "jsonrpc": "2.0", "id" :1, "method": "author_rotatekeys", "params": [] }' {"jsonrpc": "2.0", "result":"0x72c7ca7ef0794103caeb520806576b52cb085f7577cc12cd36c2d64dbf73757a789407ec0f401a8792ac57c4fb7dabd4da6cc74d9ac9b8dd8c4faf770255403f", "id" :1}
Make sure you write down the concatenated public keys. Each of your servers, your primary and backup, should have their own unique keys. Since the keys never leave your servers, you can consider them a unique ID for that server. Next, you'll need to register your session keys and map them to an H160 Ethereum-styled address to which the block rewards are paid. ## Manage Session Keys {: #manage-session-keys } Once you've created or rotated your session keys, you'll be able to manage your session keys using the extrinsics in the Author Mapping Pallet. You can map your session keys, verify the on-chain mappings, and remove session keys. ### Author Mapping Pallet Interface {: #author-mapping-interface } The `authorMapping` module has the following extrinsics: - **setKeys**(keys) — accepts the result of calling `author_rotateKeys`, which is the concatenated public keys of your Nimbus and VRF keys, and sets the session keys at once. Useful after a key rotation or migration. Calling `setKeys` requires a [bond](#mapping-bonds). Replaces the deprecated `addAssociation` and `updateAssociation` extrinsics - **removeKeys**() - removes the session keys. This is only required if you intend to stop collating and leave the candidate pool. Replaces the deprecated `clearAssociation` extrinsic The module also adds the following RPC calls (chain state): - **mappingWithDeposit**(NimbusPrimitivesNimbusCryptoPublic | string | Uint8Array) — displays all mappings stored on-chain, or only that related to the Nimbus ID if provided - **nimbusLookup**(AccountId20) - displays a reverse mapping of account IDs to Nimbus IDs for all collators or for a given collator address ### Map Session Keys {: #mapping-extrinsic } With your newly generated session keys in hand, the next step is to map your session keys to your H160 account (an Ethereum-style address). Make sure you hold the private keys to this account, as this is where the block rewards are paid out to. To map your session keys to your account, you need to be inside the [candidate pool](/node-operators/networks/collators/activities/#become-a-candidate){target=\_blank}. Once you are a candidate, you need to send a mapping extrinsic, which requires a mapping bond. #### Mapping Bonds {: #mapping-bonds } The mapping bond is per session keys registered. The bond for mapping your session keys to your account is as follows: === "Moonbeam" ```text {{ networks.moonbeam.staking.collator_map_bond }} GLMR ``` === "Moonriver" ```text {{ networks.moonriver.staking.collator_map_bond }} MOVR ``` === "Moonbase Alpha" ```text {{ networks.moonbase.staking.collator_map_bond }} DEV ``` #### Use Polkadot.js Apps to Map Session Keys {: #use-polkadotjs-apps } In this section, you'll learn how to map session keys from Polkadot.js Apps. To learn how to create the mapping through the author mapping precompiled contract, you can refer to the page on [Interacting with the Author Mapping Precompile](/node-operators/networks/collators/author-mapping/){target=\_blank}. To create the mapping from [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/assets){target=\_blank} (make sure you're connected to the correct network), click on **Developer** at the top of the page, choose the **Extrinsics** option from the dropdown, and take the following steps: 1. Choose the account that you want to map your author ID to be associated with, from which you'll sign this transaction 2. Select the **authorMapping** extrinsic 3. Set the method to **setKeys()** 4. Enter the **keys**. It is the response obtained via the RPC call `author_rotateKeys` in the previous section, which is the concatenated public keys of your Nimbus ID and VRF key 5. Click on **Submit Transaction** ![Author ID Mapping to Account Extrinsic](/images/node-operators/networks/collators/account-management/account-1.webp) !!! note If you receive the following error, you may need to try rotating and mapping your keys again: `VRF PreDigest was not included in the digests (check rand key is in keystore)`. If the transaction is successful, you will see a confirmation notification on your screen. If not, make sure you've [joined the candidate pool](/node-operators/networks/collators/activities/#become-a-candidate){target=\_blank}. ### Check Mappings {: #checking-the-mappings } You can check the current on-chain mappings by verifying the chain state. You can do this one of two ways: via the `mappingWithDeposit` method or the `nimbusLookup` method. Both methods can be used to query the on-chain data for all of the collators or for a specific collator. You can check the current on-chain mappings for a specific collator or you can also check all of the mappings stored on-chain. #### Using the Mapping with Deposit Method {: #using-mapping-with-deposit } To use the `mappingWithDeposit` method to check the mapping for a specific collator, you'll need to get the Nimbus ID. To do so, you can take the first 64 hexadecimal characters of the concatenated public keys to get the Nimbus ID. To verify that the Nimbus ID is correct, you can run the following command with the first 64 characters passed into the `params` array: ```bash curl {{ networks.development.rpc_url }} -H "Content-Type:application/json;charset=utf-8" -d '{ "jsonrpc":"2.0", "id":1, "method":"author_hasKey", "params": ["72c7ca7ef07941a3caeb520806576b52cb085f7577cc12cd36c2d64dbf73757a", "nmbs"] }' ``` If it's correct the response should return `"result": true`.
curl http://127.0.0.1:9933 -H "Content-Type:application/json;char set=utf-8" -d '{ "jsonrpc":"2.0" "id" :1, "method": "author_hasKey", "params": ["72c7ca7ef07941a3caeb520806576b52cb085f7577c12c36c2d64dbf73757a", "nmbs"] }' {"jsonrpc":"2.0", "result" :true, "id" :1}
From [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/assets){target=\_blank}, click on **Developer** at the top of the page, then choose **Chain State** from the dropdown, and take the following steps: 1. Choose **authorMapping** as the state to query 2. Select the **mappingWithDeposit** method 3. Provide a Nimbus ID to query. Optionally, you can disable the slider to retrieve all mappings 4. Click on the **+** button to send the RPC call ![Nimbus ID Mapping Chain State](/images/node-operators/networks/collators/account-management/account-2.webp) You should be able to see the H160 account associated with the Nimbus ID provided and the deposit paid. If no Nimbus ID was included, this would return all the mappings stored on-chain. #### Using the Nimbus Lookup Method {: #using-nimbus-lookup } To use the `nimbusLookup` method to check the mapping for a specific collator, you'll need the collator's address. If you do not pass an argument to the method, you can retrieve all of the on-chain mappings. From [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/assets){target=\_blank}, click on **Developer** at the top of the page, then choose **Chain State** from the dropdown, and take the following steps: 1. Choose **authorMapping** as the state to query 2. Select the **nimbusLookup** method 3. Provide a collator's address to query. Optionally, you can disable the slider to retrieve all mappings 4. Click on the **+** button to send the RPC call ![Nimbus ID Mapping Chain State](/images/node-operators/networks/collators/account-management/account-3.webp) You should be able to see the nimbus ID associated with the H160 account provided. If no account was provided, this would return all the mappings stored on-chain. ### Remove Session Keys {: #removing-session-keys } Before removing your session keys, you'll want to make sure that you've stopped collating and left the candidate pool. To stop collating, you'll need to schedule a request to leave the candidate pool, wait a delay period, and then execute the request. For step-by-step instructions, please refer to the [Stop Collating](/node-operators/networks/collators/activities/#stop-collating){target=\_blank} section of the Moonbeam Collator Activities page. Once you have left the candidate pool, you can remove your session keys. After which, the mapping bond you deposited will be returned to your account. From [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/assets){target=\_blank}, click on **Developer** at the top of the page, then choose **Extrinsics** from the dropdown, and take the following steps: 1. Select your account 2. Choose the **authorMapping** pallet and the **removeKeys** extrinsic 3. Click **Submit Transaction** ![Remove session keys on Polkadot.js Apps](/images/node-operators/networks/collators/account-management/account-4.webp) Once the transaction goes through, the mapping bond will be returned to you. To make sure that the keys were removed, you can follow the steps in the [Check Mappings](#checking-the-mappings) section. ## Setting an Identity {: #setting-an-identity } Setting an on-chain identity enables your collator node to be easily identifiable. As opposed to showing your account address, your chosen display name will be displayed instead. There are a couple of ways you can set your identity, to learn how to set an identity for your collator node please check out the [Managing your Account Identity](/tokens/manage/identity/){target=\_blank} page of our documentation. ## Proxy Accounts {: #proxy-accounts } Proxy accounts are accounts that can be enabled to perform a limited number of actions on your behalf. Proxies allow users to keep a primary account securely in cold storage while using the proxy to actively participate in the network on behalf of the primary account. You can remove authorization of the proxy account at any time. As an additional layer of security, you can setup your proxy with a delay period. This delay period would provide you time to review the transaction, and cancel if needed, before it automatically gets executed. To learn how to setup a proxy account, please refer to the [Setting up a Proxy Account](/tokens/manage/proxy-accounts/){target=\_blank} page of our documentation. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/node-operators/networks/collators/activities/ --- BEGIN CONTENT --- --- title: Moonbeam Collator Activities description: Instructions on how to dive in and learn about the related activities for becoming and maintaining a collator node in the Moonbeam Network. categories: Node Operators and Collators --- # Collator Activities ## Introduction {: #introduction } Becoming a collator on Moonbeam-based networks requires you to meet [bonding requirements](/node-operators/networks/collators/requirements/#bonding-requirements){target=\_blank} and join the candidate pool. Once you're in the candidate pool, you can adjust your self-bond amount or decide to leave the pool at any time. If you wish to reduce your self-bond amount or leave the candidate pool, it requires you to first schedule a request to leave and then execute upon the request after a [delay period](#collator-timings) has passed. This guide will take you through important timings to be aware of when leaving or reducing your self-bond amount, how to join and leave the candidate pool, and how to adjust your self-bond. ## Collator Timings {: #collator-timings } Before getting started, it's important to note some of the timing of different actions related to collator activities: === "Moonbeam" | Variable | Value | |:-------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------:| | Round duration | {{ networks.moonbeam.staking.round_blocks }} blocks ({{ networks.moonbeam.staking.round_hours }} hours) | | Leave candidates | {{ networks.moonbeam.collator_timings.leave_candidates.rounds }} rounds ({{ networks.moonbeam.collator_timings.leave_candidates.hours }} hours) | | Revoke delegation | {{ networks.moonbeam.delegator_timings.revoke_delegations.rounds }} rounds ({{ networks.moonbeam.delegator_timings.revoke_delegations.hours }} hours) | | Reduce self-delegation | {{ networks.moonbeam.collator_timings.can_bond_less.rounds }} rounds ({{ networks.moonbeam.collator_timings.can_bond_less.hours }} hours) | | Rewards payouts (after current round) | {{ networks.moonbeam.delegator_timings.rewards_payouts.rounds }} rounds ({{ networks.moonbeam.delegator_timings.rewards_payouts.hours }} hours) | | Maximum offline rounds | {{ networks.moonbeam.collator_timings.max_offline.rounds }} rounds ({{ networks.moonbeam.collator_timings.max_offline.hours }} hours) | === "Moonriver" | Variable | Value | |:-------------------------------------:|:-------------------------------------------------------------------------------------------------------------------------------------------------------:| | Round duration | {{ networks.moonriver.staking.round_blocks }} blocks ({{ networks.moonriver.staking.round_hours }} hours) | | Leave candidates | {{ networks.moonriver.collator_timings.leave_candidates.rounds }} rounds ({{ networks.moonriver.collator_timings.leave_candidates.hours }} hours) | | Revoke delegation | {{ networks.moonriver.delegator_timings.revoke_delegations.rounds }} rounds ({{ networks.moonriver.delegator_timings.revoke_delegations.hours }} hours) | | Reduce self-delegation | {{ networks.moonriver.collator_timings.can_bond_less.rounds }} rounds ({{ networks.moonriver.collator_timings.can_bond_less.hours }} hours) | | Rewards payouts (after current round) | {{ networks.moonriver.delegator_timings.rewards_payouts.rounds }} rounds ({{ networks.moonriver.delegator_timings.rewards_payouts.hours }} hours) | | Maximum offline rounds | {{ networks.moonriver.collator_timings.max_offline.rounds }} rounds ({{ networks.moonriver.collator_timings.max_offline.hours }} hours) | === "Moonbase Alpha" | Variable | Value | |:-------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------:| | Round duration | {{ networks.moonbase.staking.round_blocks }} blocks ({{ networks.moonbase.staking.round_hours }} hours) | | Leave candidates | {{ networks.moonbase.collator_timings.leave_candidates.rounds }} rounds ({{ networks.moonbase.collator_timings.leave_candidates.hours }} hours) | | Revoke delegation | {{ networks.moonbase.delegator_timings.revoke_delegations.rounds }} rounds ({{ networks.moonbase.delegator_timings.revoke_delegations.hours }} hours) | | Reduce self-delegation | {{ networks.moonbase.collator_timings.can_bond_less.rounds }} rounds ({{ networks.moonbase.collator_timings.can_bond_less.hours }} hours) | | Rewards payouts (after current round) | {{ networks.moonbase.delegator_timings.rewards_payouts.rounds }} rounds ({{ networks.moonbase.delegator_timings.rewards_payouts.hours }} hours) | | Maximum offline rounds | {{ networks.moonbase.collator_timings.max_offline.rounds }} rounds ({{ networks.moonbase.collator_timings.max_offline.hours }} hours) | !!! note The values presented in the previous table are subject to change in future releases. !!! note As of runtime 3000, [asynchronous backing](https://wiki.polkadot.network/learn/learn-async-backing/){target=\_blank} has been enabled on all Moonbeam networks. As a result, the target block time was reduced from 12 seconds to 6 seconds, which may break some timing-based assumptions. ## Become a Candidate {: #become-a-candidate } ### Get the Size of the Candidate Pool {: #get-the-size-of-the-candidate-pool } First, you need to get the `candidatePool` size (this can change through governance), as you'll need to submit this parameter in a later transaction. To do so, you'll have to run the following JavaScript code snippet from within [Polkadot.js](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/js){target=\_blank}: ```js // Simple script to get candidate pool size const candidatePool = await api.query.parachainStaking.candidatePool(); console.log(`Candidate pool size is: ${candidatePool.length}`); ``` Head to the **Developer** tab, select **JavaScript** from the dropdown, and take the following steps: 1. Copy the code from the previous snippet and paste it inside the code editor box. (Optional) Click the save icon and set a name for the code snippet, for example, "Get candidatePool size". This will save the code snippet locally 2. To execute the code, click on the run button 3. Copy the result, as you'll need it when joining the candidate pool ![Get Number of Candidates](/images/node-operators/networks/collators/activities/activities-1.webp) ### Join the Candidate Pool {: #join-the-candidate-pool } Once your node is running and in sync with the network, you become a candidate and join the candidate pool. Depending on which network you are connected to, head to [Polkadot.js](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/accounts){target=\_blank}, click on the **Developer** tab, select **Extrinsics** from the dropdown, and take the following steps: 1. Select the account you want to become a collator. Confirm your account is funded with at least the [minimum stake required](/node-operators/networks/collators/requirements/#minimum-collator-bond){target=\_blank} plus some extra for transaction fees 2. Select **parachainStaking** pallet under the **submit the following extrinsic** menu 3. Open the drop-down menu, which lists all the possible extrinsics related to staking, and select the **joinCandidates** function 4. Set the bond to at least the [minimum amount](/node-operators/networks/collators/requirements/#minimum-collator-bond){target=\_blank} to be considered a candidate. You'll need to enter this amount in `Wei`. As an example, the minimum bond of {{ networks.moonbase.staking.min_can_stk }} DEV on Moonbase Alpha would be `{{ networks.moonbase.staking.min_can_stk_wei }}` in Wei ({{ networks.moonbase.staking.min_can_stk }} + 18 extra zeros). Only the candidate bond counts for this check. Additional delegations do not count 5. Set the candidate count as the candidate pool size. To learn how to retrieve this value, check the [Get the Size of the Candidate Pool](#get-the-size-of-the-candidate-pool) section 6. Submit the transaction. Follow the wizard and sign the transaction using the password you set for the account ![Join candidate pool via Polkadot.js](/images/node-operators/networks/collators/activities/activities-2.webp) !!! note Function names and the minimum bond requirement are subject to change in future releases. As mentioned before, only the top candidates by delegated stake will be in the active set of collators. The exact number of candidates in the top for each network and the minimum bond amount can be found in the [Minimum Collator Bond](/node-operators/networks/collators/requirements/#minimum-collator-bond){target=\_blank} section. ## Stop Collating {: #stop-collating } To stop collating and leave the candidate pool, you must first schedule a request to leave the pool. Scheduling a request automatically removes you from the active set, so you will no longer be eligible to produce blocks or earn rewards. You must wait for the duration of the [exit delay](#collator-timings) before you can execute the request to leave. After the request has been executed, you will be removed from the candidate pool. Similar to [Polkadot's `chill()`](https://docs.polkadot.com/infrastructure/running-a-validator/operational-tasks/pause-validating/){target=\_blank} functionality, you can [temporarily leave the candidate pool](#temporarily-leave-the-candidate-pool) without unbonding your tokens. ### Schedule Request to Leave Candidates {: #schedule-request-to-leave-candidates } To get started and schedule a request, navigate to the **Developer** tab, click on **Extrinsics**, and take the following steps: 1. Select your candidate account 2. Select **parachainStaking** pallet under the **submit the following extrinsic** menu 3. Select the **scheduleLeaveCandidates** extrinsic 4. Enter the `candidateCount` which you should have retrieved in the [Get the Size of the Candidate Pool](#get-the-size-of-the-candidate-pool) section 5. Submit the transaction. Follow the wizard and sign the transaction using the password you set for the account ![Schedule leave candidates request](/images/node-operators/networks/collators/activities/activities-3.webp) ### Execute Request to Leave Candidates {: #execute-request-to-leave-candidates } After the waiting period has passed, you'll be able to execute the request. To execute the request to leave the candidate pool, you'll first need to obtain the number of delegations the candidate has. To do so, you can query the candidate information, which will include the delegation count. To get started, click on the **Developer** tab, select **Chain state**, and take the following steps: 1. From the **selected state query** dropdown, choose **parachainStaking** 2. Select the **candidateInfo** extrinsic 3. Choose the candidate account to get the information for 4. Click the **+** button to submit the extrinsic 5. Copy the **`delegationCount`** to be used for executing the leave candidates request ![Get delegation count](/images/node-operators/networks/collators/activities/activities-4.webp) Now that you have the delegation count, you can execute the request. Switch back to the **Extrinsics** tab and follow these steps: 1. Select your candidate account 2. Select **parachainStaking** pallet under the **submit the following extrinsic** menu 3. Select the **executeLeaveCandidates** extrinsic 4. Select the target candidate account (anyone can execute the request after the exit delay has passed after submitting the `scheduleLeaveCandidates` extrinsic) 5. Enter the candidate's delegation count 6. Submit the transaction. Follow the wizard and sign the transaction using the password you set for the account ![Execute leave candidates request](/images/node-operators/networks/collators/activities/activities-5.webp) ### Cancel Request to Leave Candidates {: #cancel-request-to-leave-candidates } If you scheduled a request to leave the candidate pool but changed your mind, as long as the request has not been executed, you can cancel the request and remain in the candidate pool. To cancel the request, make sure you've clicked on **Extrinsics** from the **Developer** tab, and then follow these steps: 1. Select your candidate account 2. Select **parachainStaking** pallet under the **submit the following extrinsic** menu 3. Select the **cancelLeaveCandidates** extrinsic 4. Provide the `candidateCount` which you should have retrieved in the [Get the Size of the Candidate Pool](#get-the-size-of-the-candidate-pool) section 5. Submit the transaction. Follow the wizard and sign the transaction using the password you set for the account ![Cancel leave candidates request](/images/node-operators/networks/collators/activities/activities-6.webp) ### Temporarily Leave the Candidate Pool {: #temporarily-leave-the-candidate-pool } If you want to temporarily leave the candidate pool, you can easily do so using the `goOffline` method. This can be useful, for example, if you need to temporarily leave to perform maintenance operations. Once you're done, you can then rejoin the pool using the `goOnline` method. To temporarily leave, you can take the following steps: 1. Navigate to the **Developer** tab 2. Click on **Extrinsics** 3. Select your candidate account 4. Select **parachainStaking** pallet under the **submit the following extrinsic** menu 5. Select the **goOffline** extrinsic 6. Submit the transaction. Follow the wizard and sign the transaction using the password you set for the account ![Temporarily leave candidates pool](/images/node-operators/networks/collators/activities/activities-7.webp) Then, whenever you wish to rejoin, you can use the `goOnline` method by following the same steps outlined above, and then in step 5, choose the `goOnline` extrinsic. Please note that you can only call `goOnline` if you have previously called `goOffline`. ## Change Self-Bond Amount {: #change-self-bond-amount } As a candidate, changing your self-bond amount varies slightly depending on whether you're bonding more or less. If you're bonding more, it is a straightforward process where you can increase your stake via the `candidateBondMore()` extrinsic. You do not have to wait for any delays, and you do not need to schedule a request and then execute it; instead, your request will be executed instantly and automatically. If you wish to bond less, you have to schedule a request, wait for an [exit delay](#collator-timings), and then you will be able to execute the request and get a specified amount of tokens back into your free balance. In other words, scheduling the request doesn't decrease the bond instantly or automatically; it will only decrease once the request has been executed. ### Bond More {: #bond-more } As a candidate, there are two options for increasing one's stake. The first and recommended option is to send the funds to be staked to another owned address and [delegate to your collator](/tokens/staking/stake/#how-to-nominate-a-collator). Alternatively, collators that already have at least the [minimum self-bond amount](/node-operators/networks/collators/requirements/#minimum-collator-bond){target=\_blank} staked can increase their bond from [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonriver.moonbeam.network#/accounts){target=\_blank}. Navigate to the **Developer** tab, click on **Extrinsics**, and follow these steps: 1. Select your collator account (and verify it contains the additional funds to be bonded) 2. Select **parachainStaking** pallet under the **submit the following extrinsic** menu 3. Open the drop-down menu, which lists all the possible extrinsics related to staking, and select the **candidateBondMore** function 4. Specify the additional amount to be bonded in the **more: BalanceOf** field 5. Submit the transaction. Follow the wizard and sign the transaction using the password you set for the account ![Collator Bond More](/images/node-operators/networks/collators/activities/activities-8.webp) ### Bond Less {: #bond-less} As a collator or collator candidate, you may decrease your amount bonded as long as you have more than the [minimum self-bond amount](/node-operators/networks/collators/requirements/#minimum-collator-bond){target=\_blank} after the decrease. In order to bond less, you have to first schedule a request, wait for the duration of the [exit delay](#collator-timings), and then execute the request. You can [cancel a request](#cancel-bond-less-request) at any time, as long as the request hasn't been executed yet. #### Schedule Bond Less Request {: #schedule-bond-less } To schedule a request to bond less, make sure you've clicked on the **Developer** tab and clicked on **Extrinsics**, then you can follow these steps: 1. Select your candidate account 2. Select **parachainStaking** pallet under the **submit the following extrinsic** menu 3. Open the drop-down menu and select the **scheduleCandidateBondLess** function 4. Specify the amount to decrease the bond by in the **less: BalanceOf** field 5. Submit the transaction. Follow the wizard and sign the transaction using the password you set for the account ![Schedule Candidate Bond Less](/images/node-operators/networks/collators/activities/activities-9.webp) Once the transaction is confirmed, you must wait the duration of the exit delay and then you will be able to execute and decrease the bond amount. If you try to execute the request before the exit delay, your extrinsic will fail, and you'll see an error in Polkadot.js for `parachainStaking.PendingDelegationRequest`. #### Execute Bond Less Request {: #execute-bond-less-request } After the exit delay has passed from scheduling a request to decrease your bond, you can execute the request to actually decrease the bond amount. Head to the **Developer** tab, select **Extrinsics**, and follow these steps: 1. Select an account to execute the request with 2. Select **parachainStaking** pallet under the **submit the following extrinsic** menu 3. Select the **executeCandidateBondLess** extrinsic 4. Select the target candidate account (anyone can execute the request after the exit delay has passed since the `scheduleCandidateBondLess` was submitted) 5. Submit the transaction. Follow the wizard and sign the transaction using the password you set for the account ![Execute Candidate Bond Less](/images/node-operators/networks/collators/activities/activities-10.webp) Once the transaction has been confirmed, you can check your free and reserved balances from the **Accounts** tab and notice that, now that the execution has gone through, your balances have been updated. #### Cancel Bond Less Request {: #cancel-bond-less-request } If you scheduled a request to bond more or less but changed your mind, as long as the request has not been executed, you can cancel the request at any time and keep your bond amount as is. To cancel the request, head to the **Developer** tab, select **Extrinsics**, and follow these steps: 1. Select your candidate account (and verify it contains the additional funds to be bonded) 2. Select **parachainStaking** pallet under the **submit the following extrinsic** menu 3. Select the **cancelCandidateBondRequest** extrinsic 4. Submit the transaction. Follow the wizard and sign the transaction using the password you set for the account ![Cancel leave candidates request](/images/node-operators/networks/collators/activities/activities-11.webp) ## Mark a Collator as Inactive {: #mark-collator-as-inactive } If there is an inactive collator that has not produced blocks for a consecutive number of rounds, you can mark a collator as inactive. The maximum number of rounds a collator can be offline before they can be marked as inactive is as follows: === "Moonbeam" {{ networks.moonbeam.collator_timings.max_offline.rounds }} round ({{ networks.moonbeam.collator_timings.max_offline.hours }} hours) === "Moonriver" {{ networks.moonriver.collator_timings.max_offline.rounds }} rounds ({{ networks.moonriver.collator_timings.max_offline.hours }} hours) === "Moonbase Alpha" {{ networks.moonbase.collator_timings.max_offline.rounds }} rounds ({{ networks.moonbase.collator_timings.max_offline.hours }} hours) To mark a collator as inactive, you can use the `notifyInactiveCollator` extrinsic, which will notify the runtime when a collator is inactive and, by default, mark the collator as offline. To do so, you can head to [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/accounts){target=\_blank}, make sure that you are connected to the correct network, then click on the **Developer** tab, select **Extrinsics** from the dropdown, and take the following steps: 1. Select your account 2. Select **parachainStaking** pallet under the **submit the following extrinsic** menu 3. Select the **notifyInactiveCollator** extrinsic 4. Specify the collator to mark as inactive 5. Submit the transaction. Follow the wizard and sign the transaction using the password you set for the account ![Mark a collator as inactive](/images/node-operators/networks/collators/activities/activities-12.webp) The collator will temporarily be removed from the candidate pool, and they can rejoin at any time by calling the `goOnline` extrinsic. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/node-operators/networks/collators/author-mapping/ --- BEGIN CONTENT --- --- title: Author Mapping Precompile description: A guide for collators to learn how to use the Author Mapping Solidity interface to map session keys to a Moonbeam address where block rewards are paid out.  keywords: solidity, ethereum, author mapping, collator, moonbeam, precompiled, contracts, block producer categories: Node Operators and Collators --- # Interacting with the Author Mapping Precompile ## Introduction {: #introduction } The author mapping precompiled contract on Moonbeam allows collator candidates to map session keys to a Moonbeam address where block rewards are paid out, through a familiar and easy-to-use Solidity interface. This enables candidates to complete author mapping with a Ledger or any other Ethereum wallet compatible with Moonbeam. However, it is recommended to generate your keys on an air-gapped machine. You can find out more information by referring to the [account requirements section of the Collator Requirements page](/node-operators/networks/collators/requirements/#account-requirements){target=\_blank}. To become a collator candidate, you must be [running a collator node](/node-operators/networks/run-a-node/overview/){target=\_blank}. You'll also need to [join the candidate pool](/node-operators/networks/collators/activities/#become-a-candidate){target=\_blank} fully sync your node and submit the required [bonds](#bonds) before generating your session keys and mapping them to your account. There is an [additional bond](#bonds) that must be paid when mapping your session keys. The precompile is located at the following address: === "Moonbeam" ```text {{networks.moonbeam.precompiles.author_mapping }} ``` === "Moonriver" ```text {{networks.moonriver.precompiles.author_mapping }} ``` === "Moonbase Alpha" ```text {{networks.moonbase.precompiles.author_mapping }} ``` !!! note There can be some unintended consequences when using the precompiled contracts on Moonbeam. Please refer to the [Security Considerations](/learn/core-concepts/security/){target=\_blank} page for more information. ## The Author Mapping Solidity Interface {: #the-solidity-interface } [`AuthorMappingInterface.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/author-mapping/AuthorMappingInterface.sol){target=\_blank} is a Solidity interface that allows developers to interact with the precompile's methods. - **removeKeys**() - removes the author ID and session keys. Replaces the deprecated `clearAssociation` extrinsic - **setKeys**(*bytes memory* keys) — accepts the result of calling `author_rotateKeys`, which is the concatenated public keys of your Nimbus and VRF keys, and sets the author ID and the session keys at once. Useful after a key rotation or migration. Calling `setKeys` requires a [bond](#bonds). Replaces the deprecated `addAssociation` and `updateAssociation` extrinsics - **nimbusIdOf**(*address* who) - retrieves the Nimbus ID of the given address. If no Nimbus ID exists for the given address, it returns `0` - **addressOf**(*bytes32* nimbusId) - retrieves the address associated to a given Nimbus ID. If the Nimbus ID is unknown, it returns `0` - **keysOf**(*bytes32* nimbusId) - retrieves the keys associated to the given Nimbus ID. If the Nimbus ID is unknown, it returns empty bytes ## Required Bonds {: #bonds } To follow along with this tutorial, you'll need to join the candidate pool and map your session keys to your H160 Ethereum-style account. Two bonds are required to perform both of these actions. The minimum bond to join the candidate pool is set as follows: === "Moonbeam" ```text {{ networks.moonbeam.staking.min_can_stk }} GLMR ``` === "Moonriver" ```text {{ networks.moonriver.staking.min_can_stk }} MOVR ``` === "Moonbase Alpha" ```text {{ networks.moonbase.staking.min_can_stk }} DEV ``` There is a bond that is sent when mapping your session keys with your account. This bond is per session keys registered. The bond set is as follows: === "Moonbeam" ```text {{ networks.moonbeam.staking.collator_map_bond }} GLMR ``` === "Moonriver" ```text {{ networks.moonriver.staking.collator_map_bond }} MOVR ``` === "Moonbase Alpha" ```text {{ networks.moonbase.staking.collator_map_bond }} DEV ``` ## Interact with the Solidity Interface {: #interact-with-the-solidity-interface } ### Checking Prerequisites {: #checking-prerequisites } The below example is demonstrated on Moonbase Alpha, however, similar steps can be taken for Moonbeam and Moonriver. You should: - Have MetaMask installed and [connected to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank} - Have an account with DEV tokens. You should have enough to cover the [candidate and mapping bonds](#bonds) plus gas fees to send the transaction and map your session keys to your account. To get enough DEV tokens to follow along with this guide, you can contact a moderator directly via the [Moonbeam Discord server](https://discord.com/invite/PfpUATX){target=\_blank} - Make sure you're [running a collator node](/node-operators/networks/run-a-node/overview/){target=\_blank} and it's fully synced - Make sure you've [joined the candidate pool](/node-operators/networks/collators/activities/#become-a-candidate){target=\_blank} As previously mentioned, you can use a Ledger by connecting it to MetaMask, please refer to the [Ledger](/tokens/connect/ledger/){target=\_blank} guides on how to import your Ledger to MetaMask. Please note that it is not recommended to use Ledger for production purposes. You can find out more information by referring to the [account requirements section of the Collator Requirements page](/node-operators/networks/collators/requirements/#account-requirements){target=\_blank}. ### Generate Session Keys {: #generate-session-keys } To match the Substrate standard, Moonbeam collator's session keys are [SR25519](https://wiki.polkadot.network/learn/learn-cryptography/#what-is-sr25519-and-where-did-it-come-from){target=\_blank}. This guide will show you how you can create/rotate your session keys associated with your collator node. First, make sure you're [running a collator node](/node-operators/networks/run-a-node/overview/){target=\_blank}. Once you have your collator node running, your terminal should print similar logs:
2025-02-25 20:00:52 [Relaychain] 💤 Idle (6 peers), best: #12706 (0x1d51.3042), finalized #12704 (0xf74b.aa44), 1 0.4kiB/s 1 0.6kiB/s 2025-02-25 20:00:52 💤 Idle (6 peers), best: #5751 (Oxc5alesb5), finalized #5750 (0x9dc..e bad), 1 9.6kiB/s 1 3.5kiB/s 2025-02-25 20:00:53 [Relaychain] ✨ Imported #12707 (0x77ea.4299) 2025-02-25 20:00:57 [Relaychain] 💤 Idle (6 peers), best: #12707 (0x77ea..4299), finalized #12704 (0xf74b..aa44), | 16.4kiB/s 1 12.2kiB/s 2025-02-25 20:00:57 💤 Idle (6 peers), best: #5751 (0xc5a1e8b5), finalized #5750 (0x9fdc...e bad), 1 1.6kiB/s 1 0.4kiB/s 2025-02-25 20:00:59 [Relaychain] ✨ Imported #12708 (0x009f...3bbf) 2025-02-25 20:01:00 ✨ Imported #5753 (0x8981.6c81) 2025-02-25 20:01:00 ✨ Imported #5753 (0x33a...b5e3) 2025-02-25 20:01:02 [Relaychain] 💤 Idle (6 peers), best: #12708 (0x009f...3bbf), finalized #12706 (0x1d51.3042), 1 1.5kiB/s 1 1.3kiB/s 2025-02-25 20:01:02 💤 Idle (6 peers), best: #5752 (0x7036.569e), finalized #5751 (0xc5a1..e8b5), 1 3.3kiB/s 1 5.8kiB/s 2025-02-25 20:01:05 [Relaychain] ✨ Imported #12709 (0x76b9...bf65) 2025-02-25 20:01:07 [Relaychain] 💤 Idle (6 peers), best: #12709 (0x76b9..bf65), finalized #12706 (0x1d51.3042), | 2.0kiB/s | 0.9kiB/s 2025-02-25 20:01:07 💤 Idle (6 peers), best: #5752 (0x7036.569e), finalized #5751 (0xc5a1..e8b5), 1 0 1 0
Next, session keys can be created/rotated by sending an RPC call to the HTTP endpoint with the `author_rotateKeys` method. When you call `author_rotateKeys`, the result is the size of two keys. The response will contain a concatenated Nimbus ID and VRF key. The Nimbus ID will be used to sign blocks and the [VRF](https://wiki.polkadot.network/general/web3-and-polkadot/#vrf){target=\_blank} key is required for block production. The concatenated keys will be used to create an association to your H160 account for block rewards to be paid out. For reference, if your collator's HTTP endpoint is at port `9944`, the JSON-RPC call might look like this: ```bash curl http://127.0.0.1:9944 -H \ "Content-Type:application/json;charset=utf-8" -d \ '{ "jsonrpc":"2.0", "id":1, "method":"author_rotateKeys", "params": [] }' ``` The collator node should respond with the concatenated public keys of your new session keys. The first 64 hexadecimal characters after the `0x` prefix represent your Nimbus ID and the last 64 hexadecimal characters are the public key of your VRF session key. You'll use the concatenated public keys when mapping your Nimbus ID and setting the session keys in the next section.
curl http://127.0.0.1:9933-H\ "Content-Type: application/json;charset=utf-8" -d \ '{ "jsonrpc": "2.0", "id" :1, "method": "author_rotatekeys", "params": [] }' {"jsonrpc": "2.0", "result":"0x72c7ca7ef0794103caeb520806576b52cb085f7577cc12cd36c2d64dbf73757a789407ec0f401a8792ac57c4fb7dabd4da6cc74d9ac9b8dd8c4faf770255403f", "id" :1}
Make sure you write down the concatenated public keys. Each of your servers, your primary and backup, should have their own unique keys. Since the keys never leave your servers, you can consider them a unique ID for that server. Next, you'll need to register your session keys and map them to an H160 Ethereum-styled address to which the block rewards are paid. ### Remix Set Up {: #remix-set-up } To get started, get a copy of [`AuthorMappingInterface.sol`](https://github.com/moonbeam-foundation/moonbeam/blob/master/precompiles/author-mapping/AuthorMappingInterface.sol){target=\_blank} and take the following steps: 1. Click on the **File explorer** tab 2. Copy and paste the file contents into a [Remix file](https://remix.ethereum.org){target=\_blank} named `AuthorMappingInterface.sol` ![Copying and Pasting the Author Mapping Interface into Remix](/images/node-operators/networks/collators/author-mapping/author-mapping-1.webp) ### Compile the Contract {: #compile-the-contract } 1. Click on the **Compile** tab, second from top 2. Then to compile the interface, click on **Compile AuthorMappingInterface.sol** ![Compiling AuthorMappingInterface.sol](/images/node-operators/networks/collators/author-mapping/author-mapping-2.webp) ### Access the Contract {: #access-the-contract } 1. Click on the **Deploy and Run** tab, directly below the **Compile** tab in Remix. Note: you are not deploying a contract here, instead you are accessing a precompiled contract that is already deployed 2. Make sure **Injected Provider - Metamask** is selected in the **ENVIRONMENT** drop down 3. Ensure **AuthorMappingInterface.sol** is selected in the **CONTRACT** dropdown. Since this is a precompiled contract there is no need to deploy, instead you are going to provide the address of the precompile in the **At Address** field 4. Provide the address of the author mapping precompile for Moonbase Alpha: `{{networks.moonbase.precompiles.author_mapping}}` and click **At Address** ![Provide the address](/images/node-operators/networks/collators/author-mapping/author-mapping-3.webp) The author mapping precompile will appear in the list of **Deployed Contracts**. ### Map Session Keys {: #map-session-keys } The next step is to map your session keys to your H160 account (an Ethereum-style address). Make sure you hold the private keys to this account, as this is where the block rewards are paid out to. To map your session keys to your account, you need to be inside the [candidate pool](/node-operators/networks/collators/activities/#become-a-candidate){target=\_blank}. Once you are a candidate, you need to send a mapping extrinsic. Note that this will bond tokens per author ID registered. Before getting started, ensure you're connected to the account that you want to map your session keys to. This will be the account where you will receive block rewards. 1. Expand the **AUTHORMAPPING** contract 2. Expand the **setKeys** method 3. Enter your session keys 4. Click **transact** 5. Confirm the MetaMask transaction that appears by clicking **Confirm** ![Map your session keys](/images/node-operators/networks/collators/author-mapping/author-mapping-4.webp) To verify you have mapped your session keys successfully, you can use either the `mappingWithDeposit` method or the `nimbusLookup` method of the [author mapping pallet](/node-operators/networks/collators/account-management/#author-mapping-interface){target=\_blank}. To do so, please refer to the [Check Mappings section of the Collator Account Management guide](/node-operators/networks/collators/account-management/#check-the-mappings){target=\_blank}. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/node-operators/networks/collators/faq/ --- BEGIN CONTENT --- --- title: Collators FAQ description: Some FAQs around becoming a collator, collator activities, and things to be aware of when running and operating a collator node on Moonbeam. categories: Node Operators and Collators --- # Frequently Asked Questions ## Introduction {: #introduction } Collators are an integral part of the parachains they take part in. They receive transactions and create state transition proofs for the relay chain validators. Running a Moonbeam collator requires Linux systems administration skills, careful monitoring, and an attention to detail. Below are some tips and tricks that have been accumulated which should help you get up and running quickly. ## Q & A **Q: Where can I get help?** **A:** There is an active and friendly [Discord](https://discord.com/invite/RyVefR79FA){target=\_blank} community for collators. Join the server and introduce yourself even before you need help. Send **gilmouta** or **artkaseman** a DM and let them know who you are, and they can reach out to you if they see any issues with your node. *** **Q: How do I stay up to date?** **A:** All upgrades and important technical information are announced on [Discord](https://discord.com/invite/PhfEbKYqak){target=\_blank}, in the **#tech-upgrades-announcements** channel. Join and follow this channel. You can set up integrations to Slack or Telegram if those are your preferred communication channels. *** **Q: How do I register my node?** **A:** There is a [questionnaire](https://docs.google.com/forms/d/e/1FAIpQLSfjmcXdiOXWtquYlBhdgXBunCKWHadaQCgPuBtzih1fd0W3aA/viewform){target=\_blank}, in which you will be able to provide your contact information as well as some basic hardware specs. You must be running a collator node on Moonbase Alpha to fill out the questionnaire. *** **Q: What are the hardware requirements?** **A:** Running a collator requires top of the line hardware to be able to process transactions and maximize your rewards. This is a very important factor in block production and rewards. Run a systemd service on a top of the line bare-metal machine (i.e. run a physical server, not a cloud VM, or a docker container). You can run your own, or select a provider to manage the server for you. Run only one service at a time per bare-metal machine. Do not run multiple instances. *** **Q: What is the recommended hardware to run a collator?** **A:** Hardware recommendations: - Top of the line CPU: - Ryzen 9 5950x or 5900x - Intel Xeon E-2386 or E-2388 - Primary and backup bare metal servers in different data centers and countries (Hetzner is OK for one of them) - Dedicated server for Moonbeam that isn't shared with any other apps - 1 TB NVMe SSD - 32 GB RAM *** **Q: What about backup nodes?** **A:** Run two bare-metal machines of the same specifications, in different countries and service providers. If your primary fails you can quickly resume services on your backup and continue to produce blocks and earn rewards. Please refer to the Q&A on [failovers](#:~:text=What is the failover process if my Primary node is down) below. *** **Q: What are the different networks?** **A:** There are three networks, and each requires dedicated hardware. The Moonbase Alpha TestNet is free and should be used to familiarize yourself with the setup. - **Moonbeam** - production network on Polkadot - **Moonriver** - production network on Kusama - **Moonbase Alpha TestNet** - development network *** **Q: What ports do I allow on my firewall?** **A:** - Allow all incoming requests on TCP ports {{ networks.parachain.p2p }} and {{ networks.relay_chain.p2p }} - Allow requests from your management IPs on TCP port 22 - Drop all other ports *** **Q: Is there a CPU optimized binary?** **A:** On each [release page](https://github.com/moonbeam-foundation/moonbeam/releases){target=\_blank} are CPU optimized binaries. Select the binary for your CPU architecture. - **Moonbeam-znver3** - Ryzen 9 - **Moonbeam-skylake** - Intel - **Moonbeam** - generic can be used for all others *** **Q: What are the recommendations on monitoring my node?** **A:** Monitoring is very important for the health of the network and to maximize your rewards. We recommend using [Grafana Labs](https://grafana.com){target=\_blank}. They have a free tier which should handle 6+ moonbeam servers. *** **Q: What are the KPIs I should be monitoring?** **A:** The main key performance indicator is blocks produced. The prometheus metric for this is called `substrate_proposer_block_constructed_count`. *** **Q: How should I setup alerting?** **A:** Alerting is critical to keeping your moonbeam node producing blocks and earning rewards. We recommend [pagerduty.com](https://www.pagerduty.com){target=\_blank}, which is supported by [Grafana Labs](https://grafana.com){target=\_blank}. Use the [KPI query](#:~:text=substrate_proposer_block_constructed_count) above and set an alert when this drops below 1. The alert should page the person on-call 24/7. *** **Q: What are Nimbus keys?** **A:** Nimbus keys are just like [session keys in Polkadot](https://wiki.polkadot.network/general/web3-and-polkadot/#session-keys){target=\_blank}. You should have unique keys on your primary and backup servers. Save the key output somewhere safe where you can access it in the middle of the night if you receive an alert. To create your keys, please refer to the [Session Keys](/node-operators/networks/collators/account-management/#session-keys){target=\_blank} section of the documentation. *** **Q: What is the failover process if my primary node is down?** **A:** When the primary server is down, the best way to perform a failover to the backup server is to perform a key association update. Each server should have a unique set of [keys](#:~:text=What are Nimbus keys) already. Run the `setKeys` author mapping extrinsic. You can follow the [Mapping Extrinsic](/node-operators/networks/collators/account-management/#mapping-extrinsic){target=\_blank} instructions and modify the instructions to use the `setKeys` extrinsic. *** **Q: Should I set up centralized logging?** **A:** [Grafana Labs](https://grafana.com){target=\_blank} can also be configured for centralized logging and is recommended. You can see all your nodes in one place. [Kibana](https://www.elastic.co/kibana){target=\_blank} has a more robust centralized logging offering, but Grafana is simple and good enough to start. *** **Q: What should I look for in the logs?** **A:** Logs are very useful to determine if you are in sync and ready to join the collators pool. Look at the tail end of the logs to determine if: 1. Your Relay chain is in sync 2. Your parachain is in sync You should see **Idle** in your logs when your node is in sync. ![In sync Relay chain and parachain](/images/node-operators/networks/collators/account-management/account-1.webp) A common issue is joining the pool before your node is in sync. You will be unable to produce any blocks or receive any rewards. Wait until you are in sync and idle before joining the candidate pool.
moonbase[52847]: 2025-07-10 09:04:26 [Relaychain] 🌗 ⚙️ 10 Syncing 137.9 bps, target=#12325010 (8 peers), best: #21001 (0x25d9...57d8), finalized #20992 (0x1ebb..fd23), # 214.4kiB/s 11.7kiB/s moonbase[52847]: 2025-07-10 09:04:26 🌗 ⚙️ * Syncing 182.7 bps, target=#5219905 (8 peers), best: #22472 (0x875f..aed7), finalized #9625 (0x601b...e64f), # 371.0kiB/s 113.3kiB/s moonbase[52847]: 2025-07-10 09:04:26 [Relaychain] 🌗 ⚙️ I Syncing 186.6 bps, target=#12325011 (8 peers), best: #21935 (0x58f8...d312), finalized #21585 (0x1d73...13c8), #271.9kiB/s T1.3kiB/s moonbase[52847]: 2025-07-10 09:04:26 🌗 ⚙️ @ Syncing 193.4 bps, target=#5219905 (8 peers), best: #23440 (0xdce6...8ea6), finalized #9922 (0x07c9...1fdf), # 383.3kiB/s 17.5kiB/s moonbase[52847]: 2025-07-10 09:04:26 [Relaychain] 🌗 ⚙️ Ö Syncing 189.5 bps, target=#12325012 (8 peers), best: #22883 (0x6531.2281), finalized #22528 (0x0f21.0855), # 290.8kiB/s 10.6kiB/s moonbase[52847]: 2025-07-10 09:04:26 🌗 ⚙️ @ Syncing 206.4 bps, target=#5219905 (8 peers), best: #24474 (0x09dd...6700), finalized #10393 (0x3efc...8a40), #428.7kiB/s 12.4kiB/s moonbase[52847]: 2025-07-10 09:04:26 [Relaychain] 🌗 ⚙️ . Syncing 171.6 bps, target=#12325013 (8 peers), best: #23744 (0x4ced...cdae), finalized #23552 (0x1773..09d9), # 252.4kiB/s 10.6kiB/s moonbase[52847]: 2025-07-10 09:04:26 🌗 ⚙️ Syncing 212.3 bps, target=#5219905 (8 peers), best: #25536 (0x7bc0...e9b7), finalized #10905 (0x5c70...3063), 1427.1kiB/s 11.4kiB/s
The relay chain takes much longer to sync than the parachain. You will not see any finalized blocks until the relay chain has synced. *** **Q: How much is the bond to become a collator?** **A:** There are two bonds you need to be aware of. Make sure your node is configured and in sync before proceeding with these steps. The first is the [bond to join the collators](/node-operators/networks/collators/activities/#become-a-candidate){target=\_blank} pool: - **Moonbeam** - minimum of {{ networks.moonbeam.staking.min_can_stk }} GLMR - **Moonriver** - minimum of {{ networks.moonriver.staking.min_can_stk }} MOVR - **Moonbase Alpha** - minimum of {{ networks.moonbase.staking.min_can_stk }} DEV The second is the [bond for key association](/node-operators/networks/collators/account-management/#mapping-bonds){target=\_blank}: - **Moonbeam** - minimum of {{ networks.moonbeam.staking.collator_map_bond }} GLMR - **Moonriver** - minimum of {{ networks.moonriver.staking.collator_map_bond }} MOVR - **Moonbase Alpha** - minimum of {{ networks.moonbase.staking.collator_map_bond }} DEV *** **Q: How do I set an identity on my collator account?** **A:** Setting an identity on chain will help to identify your node and attract delegations. You can set an identity by following the instructions on the [Managing an Identity](/tokens/manage/identity/){target=\_blank} page of our documentation. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/node-operators/networks/collators/ --- BEGIN CONTENT --- --- title: Collators (Block Producers) description: Learn how to become a collator and produce blocks on Moonbeam, including requirements, account management, how to join the collator pool, FAQs, and more. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/node-operators/networks/collators/orbiter/ --- BEGIN CONTENT --- --- title: Orbiter Program for Collators description: Learn about the Moonbeam Orbiter Program for collators, including the eligibility criteria, bond requirements, rewards, performance metrics, and more. categories: Node Operators and Collators --- # Moonbeam Orbiter Program ## Introduction {: #introduction } The Moonbeam Foundation is announcing a limited trial of the orbiter program. Similar to [Decentralized Nodes](https://nodes.web3.foundation/){target=\_blank}, this program allows collators to participate in the diversity and security of the network even if they do not have enough funds or backing to otherwise be in the active set. This program was developed with the input from the community. The Moonbeam Foundation will maintain orbiter pools in the active set, and will assign authority to produce blocks to each of the members in the program, who are called orbiters. The active orbiter will rotate on a regular fixed basis to maintain a fair distribution of active rounds. The orbiters’ performance will be monitored and payouts for each round will be redirected to each orbiter based on their blocks produced that round. Rewards overall will be shared with all other orbiters assigned to each specific collator account. As long as an orbiter’s performance is within a range of their peers, they will maintain their position in the rotation. If they fall below this threshold, they will be removed from the pool and demoted to the back of the waiting list for Moonbase Alpha. A new orbiter from the waiting list will take their slot. ## Duration {: #duration } As the program progresses, the Moonbeam Foundation will assess the results and make adjustments. There is no specific end date, but the program may come to an end or materially change. Participants are both encouraged to give feedback throughout the program as well as be aware that it may change from the concept explained here. ## Eligibility {: #eligibility } To participate in the orbiter program, you must meet the following eligibility criteria: - Due to the nature of the program, each orbiter must pass an identity verification check, and cannot be a resident of certain jurisdictions - Each orbiter must post a bond. This bond is posted to protect against bad behavior and will be subject to slashing - Each entity (person or group) may only run one orbiter per network (i.e., one on Moonriver and one on Moonbeam) - Orbiters cannot run another active collator on the same network as their orbiter. They can, however, run an active collator on Moonbeam and an orbiter on Moonriver, or vice versa, as long as they do not also have both on the same network ## Communication {: #communication } A private discord group will be created for this program, and most communication will happen over this channel or through DM. Once you've filled out your application, you'll be added to the group. ## Orbiters and Orbiter Pool Configurations {: #configuration } Orbiter pools are maintained by the Moonbeam Foundation, and will assign block production authority to each orbiter. The maximum number of orbiters per orbiter pool for each network is as follows: === "Moonbeam" ```text {{ networks.moonbeam.orbiter.max_orbiters_per_collator }} orbiters per pool ``` === "Moonriver" ```text {{ networks.moonriver.orbiter.max_orbiters_per_collator }} orbiters per pool ``` === "Moonbase Alpha" ```text {{ networks.moonbase.orbiter.max_orbiters_per_collator }} orbiters per pool ``` For Moonbeam and Moonriver there is also a maximum number of orbiter pools that will be allowed in the active set. For Moonbase Alpha, there will be as many orbiter pools as needed. The maximum is as follows: === "Moonbeam" ```text {{ networks.moonbeam.orbiter.max_collators }} orbiter pools ``` === "Moonriver" ```text {{ networks.moonriver.orbiter.max_collators }} orbiter pools ``` === "Moonbase Alpha" ```text {{ networks.moonbase.orbiter.max_collators }} orbiter pools ``` Each orbiter will be active for a certain number of rounds before the next orbiter will take over. The number of active rounds for each network is as follows: === "Moonbeam" ```text {{ networks.moonbeam.orbiter.active.rounds }} round (~{{ networks.moonbeam.orbiter.active.hours }} hours) ``` === "Moonriver" ```text {{ networks.moonriver.orbiter.active.rounds }} rounds (~{{ networks.moonriver.orbiter.active.hours }} hours) ``` === "Moonbase Alpha" ```text {{ networks.moonbase.orbiter.active.rounds }} rounds (~{{ networks.moonbase.orbiter.active.hours }} hours) ``` ## Application and Onboarding Process {: #application-and-onboarding-process } To join the orbiter program, you'll need to start by filling out an application where you'll need to submit contact information, social media handles, and collator and node details. At the end of the form, you'll also need to follow the instructions to complete identity verification. Once you've passed identity verification and have been accepted into the program, you'll be notified and then the onboarding process will begin. New orbiters must run a Moonbase Alpha node for two weeks to be eligible to run a Moonriver node. Orbiters then must run a Moonriver node for four weeks to be eligible to run a Moonbeam node. Once you are eligible, you are not required to run orbiters on any network. You can leave other networks at any time by [unregistering](#leaving-the-program) and you will receive your bond back. To join again on that network you will need to re-register and will be at the end of the queue. An outline of the onboarding process is as follows: - [Prepare your node by syncing it](/node-operators/networks/run-a-node/overview/){target=\_blank} - Once fully synced, you can [generate your session keys](/node-operators/networks/collators/account-management/#session-keys){target=\_blank} - [Register your session keys](/node-operators/networks/collators/account-management/#map-author-id-set-session-keys){target=\_blank} and post the associated [mapping bond](#mapping-bond) - Once you are ready, register as an orbiter via the `moonbeamOrbiters.orbiterRegister()` extrinsic and post the associated [orbiter bond](#bond) - Orbiters will be placed in a waiting list for each network until a slot is available - Once a slot opens up, you'll begin producing blocks and receiving rewards on the respective network ## Bonds {: #bond } ### Mapping Bond {: #mapping-bond} There is a bond that is sent when mapping your author ID with your account. This bond is per author ID registered. The bond set is as follows: === "Moonbeam" ```text {{ networks.moonbeam.staking.collator_map_bond }} GLMR ``` === "Moonriver" ```text {{ networks.moonriver.staking.collator_map_bond }} MOVR ``` === "Moonbase Alpha" ```text {{ networks.moonbase.staking.collator_map_bond }} DEV ``` ### Orbiter Bond {: #orbiter-bond } As previously mentioned, each orbiter must submit a bond to join the program. This bond differs from the one for the active set as it does not earn any delegation rewards while bonded. The current bonds are as follows: === "Moonbeam" ```text {{ networks.moonbeam.orbiter.bond }} GLMR ``` === "Moonriver" ```text {{ networks.moonriver.orbiter.bond }} MOVR ``` === "Moonbase Alpha" ```text {{ networks.moonbase.orbiter.bond }} DEV ``` ## Rewards {: #rewards } Rewards for orbiters will be split between the other orbiters assigned to the same orbiter pool. The maximum orbiters per orbiter pool is described in the [configuration section](#configuration). In the case of Moonriver it’s {{ networks.moonriver.orbiter.max_orbiters_per_collator }}, so the rewards will be approximately 1/{{ networks.moonriver.orbiter.max_orbiters_per_collator }} of a collator’s rewards. The blocks produced by each orbiter while active are tracked, and rewards are proportionally distributed. ## Performance Metrics {: #performance-metrics } Each orbiter’s performance will be assessed over a period of time to determine they are active and producing blocks, and if their performance is within a range of all other orbiter pool collators. Orbiters are expected to run top tier hardware to stay within range. For more information on hardware requirements, please check out the [Collator Requirements page](/node-operators/networks/collators/requirements/){target=\_blank}. Metrics will be assessed over seven day periods. The performance metrics are as follows: - Orbiter has produced a block within the last three rounds they were active - Orbiter’s block production is within two standard deviation of the seven day program mean - Orbiter’s transactions per block is within two standard deviation of the seven day program mean - Orbiter’s block weight is within two standard deviation of the seven day program mean !!! note These factors are subject to change as the program progresses. ## Leaving the Program {: #leaving-the-program } An orbiter may leave the program and receive their bond back without any delay. The only limitation on this is if the orbiter is currently active they cannot leave; once they are no longer active they can leave at any time by issuing the `moonbeamOrbiters.orbiterUnregister()` extrinsic. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/node-operators/networks/collators/overview/ --- BEGIN CONTENT --- --- title: Run a Collator Node description: Instructions on how to dive in and become a collator in the Moonbeam Network once you are running a node. categories: Basics, Node Operators and Collators --- # Run a Collator on Moonbeam ## Introduction {: #introduction } Collators are members of the network that maintain the parachains they take part in. They run a full node (for both their particular parachain and the relay chain), and they produce the state transition proof for relay chain validators. There are some [requirements](/node-operators/networks/collators/requirements/){target=\_blank} that need to be considered prior to becoming a collator candidate including machine, bonding, account, and community requirements. Candidates will need a minimum amount of tokens bonded (self-bonded) to be considered eligible. Only a certain number of the top collator candidates by total stake, including self-bonded and delegated stake, will be in the active set of collators. Otherwise, the collator will remain in the candidate pool. Once a candidate is selected to be in the active set of collators, they are eligible to produce blocks. Moonbeam uses the [Nimbus Parachain Consensus Framework](/learn/features/consensus/){target=\_blank}. This provides a two-step filter to allocate candidates to the active set of collators, then assign collators to a block production slot: - The parachain staking filter selects the top candidates in terms of tokens staked in each network. For the exact number of top candidates per each network and the minimum bond amount, you can check out the [Minimum Collator Bond](/node-operators/networks/collators/requirements/#minimum-collator-bond){target=\_blank} section of our documentation. This filtered pool is called selected candidates (also known as the active set), which are rotated every round - The fixed size subset filter picks a pseudo-random subset of the previously selected candidates for each block production slot Users can spin up full nodes on Moonbeam, Moonriver, and Moonbase Alpha and activate the `collate` feature to participate in the ecosystem as collator candidates. To do this, you can checkout the [Run a Node](/node-operators/networks/run-a-node/){target=\_blank} section of the documentation and spin up a node using either [Docker](/node-operators/networks/run-a-node/docker/){target=\_blank} or [Systemd](/node-operators/networks/run-a-node/systemd/){target=\_blank}. ## Join the Discord {: #join-discord } As a collator, it is important to keep track of updates and changes to configuration. It is also important to be able to easily contact us and vice versa in case there is any issue with your node, as that will not only negatively affect collator and delegator rewards, it will also negatively affect the network. For this purpose, we use [Discord](https://discord.com/invite/moonbeam){target=\_blank}. The most relevant Discord channels for collators are the following: - **tech-upgrades-announcements** — here we will publish any updates or changes in configuration changes collators will be required to follow. We will also announce any technical issues to monitor, such as network stalls - **collators** — this is the general collator discussion channel. We are proud of having an active and friendly collator community so if you have any questions, this is the place to ask. We will also ping collators here for any issues that require their attention. - **meet-the-collators** — in this channel you can introduce yourself to potential delegators After you join our Discord, feel free to DM *gilmouta* or *artkaseman* and introduce yourself. This will let us know who to contact if we see an issue with your node, and will also let us assign the relevant Discord collator role, enabling you to post in *meet-the-collators*. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/node-operators/networks/collators/requirements/ --- BEGIN CONTENT --- --- title: Moonbeam Collator Requirements description: Learn about the requirements for becoming and maintaining a collator node on Moonbeam networks, including requirements for hardware, bonds, and more. categories: Node Operators and Collators --- # Collator Requirements ## Introduction {: #introduction } There are some requirements to keep in mind before diving into running a collator node. Primarily, you need to follow the community guidelines and meet the technical requirements. You should have top of the line hardware, securely created and stored accounts, meet bonding requirements, and fill out a collator questionnaire. It is recommended to go through all of the necessary requirements on the Moonbase Alpha TestNet before collating on a production network like Moonbeam or Moonriver. This guide will help you to get started fulfilling the collator requirements so you can get your node up and running in no time. ## Community Guidelines {: #community-guidelines } Collators have a responsibility to the network to act honorably. If any of the following forbidden offenses occur, action may be taken via on-chain governance: - An entity is running more than four collators in either network - A collator is running multiple nodes using the same Nimbus key causing equivocation. Equivocation is the action of submitting multiple blocks at the same block height, which forks the network. It is strictly forbidden due to the network degradation that it implies. This can be done by a malicious actor (trying to get more blocks included/produced) or by mistake (having a backup node running with the same key). Each node needs to have its own unique keys and any backup solutions need to ensure there can be no possibility of equivocation - A collator acts in a nefarious manner that is uncharitable to the community or other collators There is a level of commitment to the community and the network that is necessary to gain trust from the community of delegators and attract more delegations. The following contains some suggestions for contributing to the community: - Be active in the community - [Join the Discord](/node-operators/networks/collators/overview/#join-discord){target=\_blank} and introduce yourself, provide updates as needed, and help support community members or other collators - Create tutorials and educational content - [Become a Moonbeam Ambassador](https://moonbeam.network/community/ambassador){target=\_blank} - Contribute to open-source software relating to the ecosystem - Actively participate in governance and vote on proposals ## Hardware Requirements {: #hardware-requirements } Collators must have a full node running with the collation options. To do so, follow the [Run a Node](/node-operators/networks/run-a-node/overview/) tutorial and installation steps for [Using Systemd](/node-operators/networks/run-a-node/systemd/). Make sure you use the specific code snippets for collators. !!! note Running a **collator** node has higher CPU requirements than the ones provided in the above tutorial. In order for your collator node to be able to keep up with a high transaction throughput a CPU with high clock speed and single-core performance is important, as the block production/import process is almost entirely single-threaded. Running your collator node in Docker is also not recommended, as it will have a significant impact in performance. From a hardware perspective, it is important to have top of the line hardware to maximize block production and rewards. The following are some hardware recommendations that have performed well and provided the best results: - **Recommended CPUs** - Intel Xeon E-2386/2388 or Ryzen 9 5950x/5900x - **Recommended NVMe** - 1 TB NVMe - **Recommended RAM** - 32 GB RAM In addition, you should take into account the following considerations: - As most cloud providers focus on multi-thread rather than single-thread performance, using a bare-metal provider is recommended - You should have primary and backup bare metal servers in different data centers and countries. Hetzner is OK for one of these servers, but shouldn't be used for both - Your Moonbeam server should be dedicated for Moonbeam only, please do not use the same server for other apps ## Account Requirements {: #account-requirements } Similar to Polkadot validators, you need to create an account. For Moonbeam, this is an H160 account or an Ethereum-style account from which you hold the private keys. As a collator, you are responsible for correctly managing your own keys. Incorrectly doing so can result in a loss of funds. There are many Ethereum wallets that can be used, but for production purposes it is recommended to generate keys as securely as possible. It is also recommended to generate backup keys. You can actually generate keys using the Moonbeam binary through a tool called Moonkey. It can be used to generate both Ethereum-style accounts and Substrate-style accounts. To generate keys securely it is recommended to do so on an air-gapped machine. Once you generate your keys, make sure you store them safely. To securely store your keys, here are some recommendations, from least to most secure: - Write down and laminate your keys - Engrave your keys into a metal plate - Shard your keys using a tool like [Horcrux](https://gitlab.com/unit410/horcrux){target=\_blank} As always, it is recommended to do your own research and use tools that you vet as trustworthy. ### Getting Started with Moonkey {: #getting-started-with-moonkey } The first step is to fetch the moonkey binary file hosted on GitHub. To do so, you can download a binary file (tested on Linux/Ubuntu): `https://github.com/moonbeam-foundation/moonbeam/releases/download/v0.8.0/moonkey` Once you’ve downloaded the tool, ensure you have the correct access permissions to execute the binary file. Next, check that you have the right version by checking the downloaded file hash. For Linux-based systems such as Ubuntu, open the terminal and head to the folder where the moonkey binary file is located. Once there, you can use the sha256sum tool to calculate the SHA256 hash: ```text 019c3de832ded3fccffae950835bb455482fca92714448cc0086a7c5f3d48d3e ``` After you’ve verified the hash, it is recommended to move the binary file to an air-gapped machine (no network interfaces). You can also check the hash of the file in the air-gapped device directly. ### Generating an Account with Moonkey {: #generating-an-account-with-moonkey } Using the moonkey binary file is very straightforward. Every time you execute the binary, the information related to a newly created account is displayed. This information includes: - **Mnemonic seed** - a 24-word mnemonic that represents your account in readable words. This gives direct access to your funds, so you need to store these words securely - **Private key** - the private key associated with your account, used for signing. This is derived from the mnemonic seed. This gives direct access to your funds, so you need to store it securely - **Public address** - your account’s address - **Derivation path** - tells the Hierarchical Deterministic (HD) wallet how to derive the specific key !!! note Please safely store the private key/mnemonic and do not share it with anyone. Private keys/mnemonics provide direct access to your funds. It is recommended that you use the binary file in an air-gapped machine. ### Other Moonkey Features {: #other-moonkey-features } Moonkey provides some additional functionalities. The following flags can be provided: - `-help` – prints help information - `-version` – prints version of moonkey you are running - `-w12` – generates a 12 words mnemonic seed (default is 24) The following options are available: - `-account-index` – provide as input the account index to use in the derivation path - `-mnemonic` – provide as input the mnemonic ## Bonding Requirements {: #bonding-requirements } There are two bonds for you to be aware of: a bond to join the collator pool and a bond for key association. ### Minimum Collator Bond {: #minimum-collator-bond } First, you will need a minimum amount of tokens staked (self-bonded) to be considered eligible and become a candidate. Only a certain number of the top collator candidates by total stake, including self-bonded and delegated stake (total bonded), will be in the active set of collators. === "Moonbeam" | Variable | Value | |:-------------------------:|:--------------------------------------------------------:| | Minimum self-bond amount | {{ networks.moonbeam.staking.min_can_stk }} GLMR | | Active set size | {{ networks.moonbeam.staking.max_candidates }} collators | === "Moonriver" | Variable | Value | |:-------------------------:|:---------------------------------------------------------:| | Minimum self-bond amount | {{ networks.moonriver.staking.min_can_stk }} MOVR | | Active set size | {{ networks.moonriver.staking.max_candidates }} collators | === "Moonbase Alpha" | Variable | Value | |:-------------------------:|:--------------------------------------------------------:| | Minimum self-bond amount | {{ networks.moonbase.staking.min_can_stk }} DEV | | Active set size | {{ networks.moonbase.staking.max_candidates }} collators | ### Key Association Bond {: #key-association-bond } Secondly, you will need a bond for key association. This bond is required when [mapping your author ID](/node-operators/networks/collators/account-management/){target=\_blank} (session keys) with your account for block rewards, and is per author ID registered. === "Moonbeam" | Variable | Value | |:------------:|:------------------------------------------------------:| | Minimum bond | {{ networks.moonbeam.staking.collator_map_bond }} GLMR | === "Moonriver" | Variable | Value | |:------------:|:-------------------------------------------------------:| | Minimum bond | {{ networks.moonriver.staking.collator_map_bond }} MOVR | === "Moonbase Alpha" | Variable | Value | |:------------:|:-----------------------------------------------------:| | Minimum bond | {{ networks.moonbase.staking.collator_map_bond }} DEV | ## Collator Questionnaire {: #collator-questionnaire } There is a [Collator Questionnaire](https://docs.google.com/forms/d/e/1FAIpQLSfjmcXdiOXWtquYlBhdgXBunCKWHadaQCgPuBtzih1fd0W3aA/viewform){target=\_blank}, that aims to assess the state of all collators on Moonbase Alpha. You should be running a collator node on Moonbase Alpha before filling out this form. You will be able to provide your contact information as well as some basic hardware specs. It provides a way to open the lines of communication between you and the Moonbeam team in case any problems with your node arise. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/node-operators/networks/ --- BEGIN CONTENT --- --- title: Run a Full, Tracing, or Collator Node description: Learn how to spin up a full, tracing, or collator node on Moonbeam, as well as the requirements for being a collator (block producer). dropdown_description: Run full, tracing, or collator nodes template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/node-operators/networks/run-a-node/compile-binary/ --- BEGIN CONTENT --- --- title: Compile the Binary to Run a Node description: Learn how to manually compile the binary to run a full Moonbeam node. Compiling the binary can take around 30 minutes and requires at least 32GB of memory. categories: Node Operators and Collators --- # Manually Compile the Moonbeam Binary ## Introduction Running a full node on a Moonbeam-based network allows you to connect to the network, sync with a boot node, obtain local access to RPC endpoints, author blocks on the parachain, and more. This guide is meant for people with experience compiling [Substrate](https://docs.polkadot.com/){target=\_blank}-based blockchain nodes. A parachain node is similar to a typical Substrate node, but there are some differences. A Substrate parachain node will be a bigger build because it contains code to run the parachain itself as well as code to sync the relay chain and facilitate communication between the two. This build is quite large, may take over 30 minutes, and requires at least 32 GB of memory. To get started quickly without the hassle of compiling the binary yourself, you can use [The Release Binary](/node-operators/networks/run-a-node/systemd/){target=\_blank}. ## Compile the Binary {: #compile-the-binary } Manually compiling the binary can take around 30 minutes and requires 32GB of memory. The following commands will build the latest release of the Moonbeam parachain. 1. Clone the Moonbeam repo ```bash git clone https://github.com/moonbeam-foundation/moonbeam cd moonbeam ``` 2. Check out the latest release ```bash git checkout tags/$(git describe --tags) ``` 3. If you already have Rust installed, you can skip the next two steps. Otherwise, install Rust and its prerequisites [via Rust's recommended method](https://www.rust-lang.org/tools/install){target=\_blank} ```bash curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` 4. Update your `PATH` environment variable ```bash source $HOME/.cargo/env ``` 5. Build the parachain binary !!! note If you are using Ubuntu 20.04 or 22.04, then you will need to install these additional dependencies before building the binary: ```bash apt install clang protobuf-compiler libprotobuf-dev pkg-config libssl-dev -y ``` ```bash cargo build --release ``` ![Compiling Binary](/images/node-operators/networks/run-a-node/compile-binary/full-node-binary-1.webp) If a _cargo not found error_ shows up in the terminal, manually add Rust to your system path or restart your system: ```bash source $HOME/.cargo/env ``` Now you can use the Moonbeam binary to run a Systemd service. To set up the service and run it, please refer to the [Run a Node on Moonbeam Using Systemd](/node-operators/networks/run-a-node/systemd/){target=\_blank} guide. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/node-operators/networks/run-a-node/docker/ --- BEGIN CONTENT --- --- title: Use Docker to Run a Node description: How to run a full parachain node so you can have your own RPC endpoint or produce blocks for the Moonbeam Network using Docker. categories: Node Operators and Collators --- # Run a Node on Moonbeam Using Docker ## Introduction {: #introduction } Running a full node on a Moonbeam-based network allows you to connect to the network, sync with a bootnode, obtain local access to RPC endpoints, author blocks on the parachain, and more. In this guide, you'll learn how to quickly spin up a Moonbeam node using [Docker](https://www.docker.com){target=\_blank} and how to maintain and purge your node. ## Checking Prerequisites {: #checking-prerequisites } To get started, you'll need to: - [Install Docker](https://docs.docker.com/get-started/get-docker/){target=\_blank}. At the time of writing, the Docker version used was 24.0.6 - Make sure that your system meets the [requirements](/node-operators/networks/run-a-node/overview/#requirements){target=\_blank}. When connecting to Moonriver on Kusama or Moonbeam on Polkadot, it will take a few days to completely sync the embedded relay chain ## Set up Storage for Chain Data {: #storage-chain-data } To set up the directory for storing chain data, you'll need to: 1. Create a local directory === "Moonbeam" ```bash mkdir {{ networks.moonbeam.node_directory }} ``` === "Moonriver" ```bash mkdir {{ networks.moonriver.node_directory }} ``` === "Moonbase Alpha" ```bash mkdir {{ networks.moonbase.node_directory }} ``` 2. Set the ownership and permissions for the local directory that stores the chain data. You can set the permissions either for a specific or current user (replace `INSERT_DOCKER_USER` for the actual user that will run the `docker` command) === "Moonbeam" ```bash # chown to a specific user chown INSERT_DOCKER_USER {{ networks.moonbeam.node_directory }} # chown to current user sudo chown -R $(id -u):$(id -g) {{ networks.moonbeam.node_directory }} ``` === "Moonriver" ```bash # chown to a specific user chown INSERT_DOCKER_USER {{ networks.moonriver.node_directory }} # chown to current user sudo chown -R $(id -u):$(id -g) {{ networks.moonriver.node_directory }} ``` === "Moonbase Alpha" ```bash # chown to a specific user chown INSERT_DOCKER_USER {{ networks.moonbase.node_directory }} # chown to current user sudo chown -R $(id -u):$(id -g) {{ networks.moonbase.node_directory }} ``` ## Start-up Commands {: #start-up-commands } To spin up your node, you'll need to execute the `docker run` command. If you're setting up a collator node, make sure to follow the code snippets for [collators](#collator-node). Note that in the following start-up command, you have to: - Replace `INSERT_YOUR_NODE_NAME` with your node name of choice. You'll have to do this in two places: one for the parachain and one for the relay chain - Replace `INSERT_RAM_IN_MB` for 50% of the actual RAM your server has. For example, for 32GB of RAM, the value must be set to `16000`. The minimum value is `2000`, but it is below the recommended specs For an overview of the flags used in the following start-up commands, plus additional commonly used flags, please refer to the [Flags](/node-operators/networks/run-a-node/flags/){target=\_blank} page of our documentation. ### Full Node {: #full-node } ???+ code "Linux snippets" === "Moonbeam" ```bash docker run --network="host" -v "{{ networks.moonbeam.node_directory }}:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonbeam.parachain_release_tag }} \ --base-path /data \ --chain {{ networks.moonbeam.chain_spec }} \ --name "INSERT_YOUR_NODE_NAME" \ --state-pruning archive \ --trie-cache-size 1073741824 \ --db-cache INSERT_RAM_IN_MB \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast ``` === "Moonriver" ```bash docker run --network="host" -v "{{ networks.moonriver.node_directory }}:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonriver.parachain_release_tag }} \ --base-path /data \ --chain {{ networks.moonriver.chain_spec }} \ --name "INSERT_YOUR_NODE_NAME" \ --state-pruning archive \ --trie-cache-size 1073741824 \ --db-cache INSERT_RAM_IN_MB \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast ``` === "Moonbase Alpha" ```bash docker run --network="host" -v "{{ networks.moonbase.node_directory }}:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonbase.parachain_release_tag }} \ --base-path /data \ --chain {{ networks.moonbase.chain_spec }} \ --name "INSERT_YOUR_NODE_NAME" \ --state-pruning archive \ --trie-cache-size 1073741824 \ --db-cache INSERT_RAM_IN_MB \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast ``` ??? code "MacOS snippets" === "Moonbeam" ```bash docker run -p 9944:9944 -v "/var/lib/moonbeam-data:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonbeam.parachain_release_tag }} \ --base-path /data \ --chain moonbeam \ --name "INSERT_YOUR_NODE_NAME" \ --state-pruning archive \ --trie-cache-size 1073741824 \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast ``` === "Moonriver" ```bash docker run -p 9944:9944 -v "/var/lib/moonriver-data:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonriver.parachain_release_tag }} \ --base-path /data \ --chain moonriver \ --name "INSERT_YOUR_NODE_NAME" \ --state-pruning archive \ --trie-cache-size 1073741824 \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast ``` === "Moonbase Alpha" ```bash docker run -p 9944:9944 -v "/var/lib/alphanet-data:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonbase.parachain_release_tag }} \ --base-path /data \ --chain alphanet \ --name "INSERT_YOUR_NODE_NAME" \ --state-pruning archive \ --trie-cache-size 1073741824 \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast ``` #### Allow External Access to Your Node {: #allow-external-access } If you want to run an RPC endpoint, connect to Polkadot.js Apps, or run your own application, you can use the `--unsafe-rpc-external` flag to run the full node with external access to the RPC ports. ??? code "Example start-up command for Moonbeam" === "Linux" ```bash hl_lines="10" docker run --network="host" -v "{{ networks.moonbeam.node_directory }}:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonbeam.parachain_release_tag }} \ --base-path /data \ --chain {{ networks.moonbeam.chain_spec }} \ --name "INSERT_YOUR_NODE_NAME" \ --state-pruning archive \ --trie-cache-size 1073741824 \ --db-cache INSERT_RAM_IN_MB \ --unsafe-rpc-external \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast ``` === "MacOS" ```bash hl_lines="9" docker run -p 9944:9944 -v "/var/lib/moonbeam-data:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonbeam.parachain_release_tag }} \ --base-path /data \ --chain moonbeam \ --name "INSERT_YOUR_NODE_NAME" \ --state-pruning archive \ --trie-cache-size 1073741824 \ --unsafe-rpc-external \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast ``` #### Use a SQL Backend for Frontier {: #use-sql } The default [Frontier](/learn/platform/technology/#frontier){target=\_blank} database, which comes standard with Moonbeam nodes and contains all of the Ethereum-related elements, such as transactions, blocks, and logs, can be modified to use a SQL backend. Since `eth_getLogs` is a very resource-intensive method, the SQL backend aims to provide a more performant alternative for indexing and querying Ethereum logs in comparison to the default RocksDB database. To spin up a node with a Frontier SQL backend, you'll need to add the `--frontier-backend-type sql` flag to your start-up command. There are additional flags you can use to configure the pool size, query timeouts, and more for your SQL backend; please refer to the [Flags](/node-operators/networks/run-a-node/flags/#flags-for-sql-backend){target=\_blank} page for more information. ??? code "Example start-up command for Moonbeam" === "Linux" ```bash hl_lines="11" docker run --network="host" -v "{{ networks.moonbeam.node_directory }}:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonbeam.parachain_release_tag }} \ --base-path /data \ --chain {{ networks.moonbeam.chain_spec }} \ --name "INSERT_YOUR_NODE_NAME" \ --state-pruning archive \ --trie-cache-size 1073741824 \ # This is a comment --db-cache INSERT_RAM_IN_MB \ --frontier-backend-type sql \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast ``` === "MacOS" ```bash hl_lines="9" docker run -p 9944:9944 -v "/var/lib/moonbeam-data:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonbeam.parachain_release_tag }} \ --base-path /data \ --chain moonbeam \ --name "INSERT_YOUR_NODE_NAME" \ --state-pruning archive \ --trie-cache-size 1073741824 \ --frontier-backend-type sql \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast ``` ### Collator Node Beginning with v0.39.0, new Moonbeam collator nodes will no longer generate session keys automatically on start-up. Nodes in existence prior to v0.39.0 do not need to make changes to how they handle session keys. When setting up a new node, run the following command to generate and store on disk the session keys that will be referenced in the start-up command: === "Moonbeam" ```bash docker run --network="host" -v "/var/lib/moonbeam-data:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonbeam.parachain_release_tag }} key generate-node-key --base-path /var/lib/moonbeam-data --chain moonbeam ``` === "Moonriver" ```bash docker run --network="host" -v "/var/lib/moonriver-data:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonriver.parachain_release_tag }} key generate-node-key --base-path /var/lib/moonriver-data --chain moonriver ``` === "Moonbase Alpha" ```bash docker run --network="host" -v "/var/lib/alphanet-data:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonbase.parachain_release_tag }} key generate-node-key --base-path /var/lib/alphanet-data --chain alphanet && sudo chown -R moonbase_service /var/lib/alphanet-data ``` !!! note You need to [change ownership of the newly created folder](#storage-chain-data) to the specific user or current user for Docker. Node key generation steps can be bypassed using the `--unsafe-force-node-key-generation` parameter in the start-up command, although this is not the recommended practice. Now you can run your Docker start up commands: ???+ code "Linux snippets" === "Moonbeam" ```bash docker run --network="host" -v "{{ networks.moonbeam.node_directory }}:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonbeam.parachain_release_tag }} \ --base-path /data \ --chain {{ networks.moonbeam.chain_spec }} \ --name "INSERT_YOUR_NODE_NAME" \ --collator \ --trie-cache-size 1073741824 \ --db-cache INSERT_RAM_IN_MB \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast ``` === "Moonriver" ```bash docker run --network="host" -v "{{ networks.moonriver.node_directory }}:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonriver.parachain_release_tag }} \ --base-path /data \ --chain {{ networks.moonriver.chain_spec }} \ --name "INSERT_YOUR_NODE_NAME" \ --collator \ --trie-cache-size 1073741824 \ --db-cache INSERT_RAM_IN_MB \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast ``` === "Moonbase Alpha" ```bash docker run --network="host" -v "{{ networks.moonbase.node_directory }}:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonbase.parachain_release_tag }} \ --base-path /data \ --chain {{ networks.moonbase.chain_spec }} \ --name "INSERT_YOUR_NODE_NAME" \ --collator \ --trie-cache-size 1073741824 \ --db-cache INSERT_RAM_IN_MB \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast ``` ??? code "MacOS snippets" === "Moonbeam" ```bash docker run -p 9944:9944 -v "/var/lib/moonbeam-data:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonbeam.parachain_release_tag }} \ --base-path /data \ --chain moonbeam \ --name "INSERT_YOUR_NODE_NAME" \ --collator \ --trie-cache-size 1073741824 \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast ``` === "Moonriver" ```bash docker run -p 9944:9944 -v "/var/lib/moonriver-data:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonriver.parachain_release_tag }} \ --base-path /data \ --chain moonriver \ --name "INSERT_YOUR_NODE_NAME" \ --collator \ --trie-cache-size 1073741824 \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast ``` === "Moonbase Alpha" ```bash docker run -p 9944:9944 -v "/var/lib/alphanet-data:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonbase.parachain_release_tag }} \ --base-path /data \ --chain alphanet \ --name "INSERT_YOUR_NODE_NAME" \ --collator \ --trie-cache-size 1073741824 \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast ``` ## Syncing Your Node {: #syncing-your-node } Once Docker pulls the necessary images, your full node will start, displaying lots of information, such as the chain specification, node name, role, genesis state, and more.
docker run --network="host" -v "/var/lib/alphanet-data:/d ata" -u $(id-u ${USER}):$(id -g #{USER}) moonbeam-foundation/moonbeam:v0.45.0 --base-path=/d ata --chain alphanet --name="TestNode" --state-pruning archive --trie-cache-size 1073741824 --db-cache 8000 ----name="TestNode (Embedded Relay)" 2025-07-10 09:04:26 Moonbeam Parachain Collator 2025-07-10 09:04:26 ✌️ version 0.46.0-d7df89e7161 2025-07-10 09:04:26 ❤️ by PureStake, 2019-2025 2025-07-10 09:04:26 📋 Chain specification: Moonbase Development Testnet 2025-07-10 09:04:26 🏷 Node name: TestNode 2025-07-10 09:04:26 👤 Role: FULL 2025-07-10 09:04:26 💾 Database: RocksDb at /data/chains/moonbase_alpha/db/full 2025-07-10 09:04:26 Database: RocksDb at 2025-07-10 09:04:26 & Native runtime: moonbase-3501 (moonbase-0.tx2.au4) 2025-07-10 09:04:26 Parachain id: Id(1000) 2025-07-10 09:04:26 Parachain Account: 5Ec4AhPZk8STuex8Wsi9TwDtJQxKqzPJRCH7348Xtcs9vZLJ 2025-07-10 09:04:26 Parachain genesis state: 0x0000000000000000000000000000000000000000000000000000000000000000006505bc9a20d69f14620b2417b6d777c398ceb3e32119b9a53507111d1880927c03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c11131400 2025-07-10 09:04:26 Is collating: no 2025-07-10 09:04:26 [ 1 ^ Initializing Genesis block/state (state: 0xb505..927c, header-hash: 0x91bc...9527) 2025-07-10 09:04:26 [Relaychain] ^ Initializing Genesis block/state (state: 0x96a6..9426, header-hash: 0xelea..9443)
During the syncing process, you will see logs from both the embedded relay chain ([Relaychain]) and the parachain ([🌗]). These logs display a target block (live network state) and a best block (local node synced state).
moonbase[52847]: 2025-07-10 09:04:26 [Relaychain] 🌗 ⚙️ 10 Syncing 137.9 bps, target=#12325010 (8 peers), best: #21001 (0x25d9...57d8), finalized #20992 (0x1ebb..fd23), # 214.4kiB/s 11.7kiB/s moonbase[52847]: 2025-07-10 09:04:26 🌗 ⚙️ * Syncing 182.7 bps, target=#5219905 (8 peers), best: #22472 (0x875f..aed7), finalized #9625 (0x601b...e64f), # 371.0kiB/s 113.3kiB/s moonbase[52847]: 2025-07-10 09:04:26 [Relaychain] 🌗 ⚙️ I Syncing 186.6 bps, target=#12325011 (8 peers), best: #21935 (0x58f8...d312), finalized #21585 (0x1d73...13c8), #271.9kiB/s T1.3kiB/s moonbase[52847]: 2025-07-10 09:04:26 🌗 ⚙️ @ Syncing 193.4 bps, target=#5219905 (8 peers), best: #23440 (0xdce6...8ea6), finalized #9922 (0x07c9...1fdf), # 383.3kiB/s 17.5kiB/s moonbase[52847]: 2025-07-10 09:04:26 [Relaychain] 🌗 ⚙️ Ö Syncing 189.5 bps, target=#12325012 (8 peers), best: #22883 (0x6531.2281), finalized #22528 (0x0f21.0855), # 290.8kiB/s 10.6kiB/s moonbase[52847]: 2025-07-10 09:04:26 🌗 ⚙️ @ Syncing 206.4 bps, target=#5219905 (8 peers), best: #24474 (0x09dd...6700), finalized #10393 (0x3efc...8a40), #428.7kiB/s 12.4kiB/s moonbase[52847]: 2025-07-10 09:04:26 [Relaychain] 🌗 ⚙️ . Syncing 171.6 bps, target=#12325013 (8 peers), best: #23744 (0x4ced...cdae), finalized #23552 (0x1773..09d9), # 252.4kiB/s 10.6kiB/s moonbase[52847]: 2025-07-10 09:04:26 🌗 ⚙️ Syncing 212.3 bps, target=#5219905 (8 peers), best: #25536 (0x7bc0...e9b7), finalized #10905 (0x5c70...3063), 1427.1kiB/s 11.4kiB/s
If you followed the installation instructions for Moonbase Alpha, once synced, you will have a node of the Moonbase Alpha TestNet running locally! For Moonbeam or Moonriver, once synced, you will be connected to peers and see blocks being produced on the network! !!! note It may take a few days to completely sync the embedded relay chain. Make sure that your system meets the [requirements](/node-operators/networks/run-a-node/overview/#requirements){target=\_blank}. ## Maintain Your Node {: #maintain-your-node } As Moonbeam development continues, it will sometimes be necessary to upgrade your node software. Node operators will be notified on our [Discord channel](https://discord.com/invite/PfpUATX){target=\_blank} when upgrades are available and whether they are necessary (some client upgrades are optional). The upgrade process is straightforward and is the same for a full node or collator. 1. Stop the Docker container: ```bash sudo docker stop INSERT_CONTAINER_ID ``` 2. Get the latest version of Moonbeam from the [Moonbeam GitHub Release](https://github.com/moonbeam-foundation/moonbeam/releases){target=\_blank} page 3. Use the latest version to spin up your node. To do so, replace the version in the start-up command with the latest and run it Once your node is running again, you should see logs in your terminal. ## Purge Your Node {: #purge-your-node } If you need a fresh instance of your Moonbeam node, you can purge your node by removing the associated data directory. You'll first need to stop the Docker container: ```bash sudo docker stop INSERT_CONTAINER_ID ``` If you did not use the `-v` flag to specify a local directory for storing your chain data when you spun up your node, then the data folder is related to the Docker container itself. Therefore, removing the Docker container will remove the chain data. If you did spin up your node with the `-v` flag, you will need to purge the specified directory. For example, for the suggested data directly, you can run the following command to purge your parachain and relay chain data: === "Moonbeam" ```bash sudo rm -rf {{ networks.moonbeam.node_directory }}/* ``` === "Moonriver" ```bash sudo rm -rf {{ networks.moonriver.node_directory }}/* ``` === "Moonbase Alpha" ```bash sudo rm -rf {{ networks.moonbase.node_directory }}/* ``` To only remove the parachain data for a specific chain, you can run: === "Moonbeam" ```bash sudo rm -rf {{ networks.moonbeam.node_directory }}/chains/* ``` === "Moonriver" ```bash sudo rm -rf {{ networks.moonriver.node_directory }}/chains/* ``` === "Moonbase Alpha" ```bash sudo rm -rf {{ networks.moonbase.node_directory }}/chains/* ``` Similarly, to only remove the relay chain data, you can run: === "Moonbeam" ```bash sudo rm -rf {{ networks.moonbeam.node_directory }}/polkadot/* ``` === "Moonriver" ```bash sudo rm -rf {{ networks.moonriver.node_directory }}/polkadot/* ``` === "Moonbase Alpha" ```bash sudo rm -rf {{ networks.moonbase.node_directory }}/polkadot/* ``` Now that your chain data has been purged, you can start a new node with a fresh data directory. You can install the newest version by repeating the instructions in this guide. Make sure you are using the latest tag available, which you can find on the [Moonbeam GitHub Release](https://github.com/moonbeam-foundation/moonbeam/releases) page. !!! note On an as-needed basis, Moonbase Alpha might be purged and reset. In these instances, you will need to purge both the parachain data and the relay chain data. If a purge is required, node operators will be notified in advance (via our [Discord channel](https://discord.com/invite/PfpUATX){target=\_blank}). --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/node-operators/networks/run-a-node/flags/ --- BEGIN CONTENT --- --- title: Run a Node Flags & Options description: A list of helpful flags for spinning up a full parachain node on Moonbeam. Also learn how to access all of the flags available for node operators. categories: Node Operators and Collators --- # Helpful Flags for Running a Node on Moonbeam ## Introduction {: #introduction } When spinning up your own Moonbeam node, there are some required and optional flags that can be used. This guide will cover some of the most common flags and show you how to access all of the available flags. ## Common Flags {: #common-flags } - **`--collator`** - enables collator mode for collator candidates and, if eligible, allows the node to actively participate in block production - **`--port`** - specifies the peer-to-peer protocol TCP port. The default port for parachains is `{{ networks.parachain.p2p }}` and `{{ networks.relay_chain.p2p }}` for the embedded relay chain - **`--rpc-port`** - sets the unified port for both HTTP and WS connections. The default port for parachains is `{{ networks.parachain.rpc }}` and `{{ networks.relay_chain.ws }}` for the embedded relay chain - **`--ws-port`** - - *deprecated as of [client v0.33.0](https://github.com/moonbeam-foundation/moonbeam/releases/tag/v0.33.0){target=\_blank}, use `--rpc-port` for HTTP and WS connections instead* - sets the unified port for both HTTP and WS connections. The default port for parachains is `{{ networks.parachain.ws }}` and `{{ networks.relay_chain.ws }}` for the embedded relay chain - **`--rpc-max-connections`** - specifies the maximum number of HTTP and WS server connections. The default is 100 - **`--ws-max-connections`** - *deprecated as of [client v0.33.0](https://github.com/moonbeam-foundation/moonbeam/releases/tag/v0.33.0){target=\_blank}, use `--rpc-max-connections` to adjust the combined HTTP and WS connection limit instead* - specifies the maximum number of HTTP and WS server connections. The default is 100 - **`--wasm-execution`** - specifies the method for executing Wasm runtime code. The available options are: - **`compiled`** - this is the default and uses the [Wasmtime](https://github.com/paritytech/wasmtime){target=\_blank} compiled runtime - **`interpreted-i-know-what-i-do`** - uses the [wasmi interpreter](https://github.com/wasmi-labs/wasmi){target=\_blank} - **`--state-pruning`** - specifies the state pruning mode. For client versions prior to v0.27.0, the `--state-pruning` flag was named `--pruning`. If running a node with the `--collator` flag, the default is to keep the full state of all blocks. Otherwise, the state is only kept for the last 256 blocks. The available options are: - **`archive`** - keeps the full state of all blocks - **``** - specifies a custom number of blocks to keep the state for - **`--trie-cache-size`** - specifies the size of the internal state cache. The default is `67108864`. You can try setting this value to `1073741824` (1GB) to improve collator performance. However, this value may be too low and need to be adjusted. For client versions prior to v0.27.0, the `--trie-cache-size` flag was named `--state-cache-size` - **`--db-cache`** - specifies the memory the database cache is limited to use. It is recommended to set it to 50% of the actual RAM your server has. For example, for 32 GB RAM, the value should be set to `16000`. The minimum value is `2000`, but it is below the recommended specs - **`--base-path`** - specifies the base path where your chain data is stored - **`--chain`** - specifies the chain specification to use. It can be a predefined chainspec such as `{{ networks.moonbeam.chain_spec }}`, `{{ networks.moonriver.chain_spec }}`, or `{{ networks.moonbase.chain_spec }}`. Or it can be a path to a file with the chainspec (such as the one exported by the `build-spec` command) - **`--name`** - specifies a human-readable name for the node, which can be seen on [telemetry](https://telemetry.polkadot.io){target=\_blank}, if enabled - **`--telemetry-url`** - specifies the URL of the telemetry server to connect to. This flag can be passed multiple times as a means to specify multiple telemetry endpoints. This flag takes two parameters: the URL and the verbosity level. Verbosity levels range from 0-9, with 0 denoting the least verbosity. Expected format is '', e.g. `--telemetry-url 'wss://foo/bar 0'`. - **`--in-peers`** - specifies the maximum amount of accepted incoming connections. The default is `25` - **`--out-peers`** - specifies the maximum amount of outgoing connections to maintain. The default is `25` - **`--runtime-cache-size 64`** - configures the number of different runtime versions preserved in the in-memory cache to 64 - **`--eth-log-block-cache`** - size in bytes the LRU cache for block data is limited to use. This flag mostly pertains to RPC providers. The default is `300000000` - **`--eth-statuses-cache`** - size in bytes the LRU cache for transaction statuses data is limited to use. This flag mostly pertains to RPC providers. The default is `300000000` - **`--sync`** - sets the blockchain syncing mode, which can allow for the blockchain to be synced faster. The available options are: - **`full`** - downloads and validates the full blockchain history - **`fast`** - downloads blocks without executing them and downloads the latest state with proofs - **`fast-unsafe`** - same as `fast`, but skips downloading the state proofs - **`warp`** - downloads the latest state and proof - **`--prometheus-port`** - specifies a custom Prometheus port - **`--lazy-loading-remote-rpc`** - allows [lazy loading](/node-operators/networks/run-a-node/overview/#lazy-loading){target=\_blank} by relying on a specified RPC endpoint for network state until the node is fully synchronized e.g. `--lazy-loading-remote-rpc 'https://moonbeam.unitedbloc.com'`, as long as the specified RPC endpoint has sufficient rate limits to handle the expected load. Private (API key) endpoints are strongly recommended over public endpoints - **`--lazy-loading-block`** - optional parameter to specify the block hash for lazy loading. This parameter allows you to specify a block hash from which to start loading data. If not provided, the latest block will be used - **`--lazy-loading-state-overrides`** - optional parameter to specify state overrides during lazy loading. This parameter allows you to provide a path to a file containing state overrides. The file can contain any custom state modifications that should be applied - **`--lazy-loading-runtime-override`** - optional parameter to specify a runtime override when starting the lazy loading. If not provided, it will fetch the runtime from the block being forked - **`--lazy-loading-delay-between-requests`** - the delay (in milliseconds) between RPC requests when using lazy loading. This parameter controls the amount of time to wait between consecutive RPC requests. This can help manage request rate and avoid overwhelming the server. Default value is `100` milliseconds - **`--lazy-loading-max-retries-per-request`** - the maximum number of retries for an RPC request when using lazy loading. Default value is `10` retries ## Flags for Configuring a SQL Backend {: #flags-for-sql-backend } - **`--frontier-backend-type`** - sets the Frontier backend type to one of the following options: - **`key-value`** - uses either RocksDB or ParityDB as per inherited from the global backend settings. This is the default option and RocksDB is the default backend - **`sql`** - uses a SQL database with custom log indexing - **`frontier-sql-backend-pool-size`** - sets the Frontier SQL backend's maximum number of database connections that a connection pool can simultaneously handle. The default is `100` - **`frontier-sql-backend-num-ops-timeout`** - sets the Frontier SQL backend's query timeout in number of VM operations. The default is `10000000` - **`frontier-sql-backend-thread-count`** - sets the Frontier SQL backend's auxiliary thread limit. The default is `4` - **`frontier-sql-backend-cache-size`** - sets the Frontier SQL backend's cache size in bytes. The default value is 200MB, which is `209715200` bytes ## How to Access All of the Available Flags {: #how-to-access-all-of-the-available-flags } For a complete list of the available flags, you can spin up your Moonbeam node with `--help` added to the end of the command. The command will vary depending on how you choose to spin up your node, and if you're using Docker or Systemd. ### Docker {: #docker } === "Moonbeam" ```bash docker run --network="host" -v "{{ networks.moonbeam.node_directory }}:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonbeam.parachain_release_tag }} \ --help ``` === "Moonriver" ```bash docker run --network="host" -v "{{ networks.moonriver.node_directory }}:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonriver.parachain_release_tag }} \ --help ``` === "Moonbase Alpha" ```bash docker run --network="host" -v "{{ networks.moonbase.node_directory }}:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam:{{ networks.moonbase.parachain_release_tag }} \ --help ``` ### Systemd {: #systemd } === "Moonbeam" ```bash # If you used the release binary ./{{ networks.moonbeam.binary_name }} --help # Or if you compiled the binary ./target/release/{{ networks.moonbeam.binary_name }} --help ``` === "Moonriver" ```bash # If you used the release binary ./{{ networks.moonriver.binary_name }} --help # Or if you compiled the binary ./target/release/{{ networks.moonriver.binary_name }} --help ``` === "Moonbase Alpha" ```bash # If you used the release binary ./{{ networks.moonbase.binary_name }} --help # Or if you compiled the binary ./target/release/{{ networks.moonbase.binary_name }} --help ``` --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/node-operators/networks/run-a-node/ --- BEGIN CONTENT --- --- title: Run a Full Parachain Node description: Learn how to run a full parachain node on any of the Moonbeam networks using Docker or Systemd, so you can have your own RPC endpoint or produce blocks. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/node-operators/networks/run-a-node/overview/ --- BEGIN CONTENT --- --- title: Run a Node description: Learn about all of the necessary details to run a full parachain node for the Moonbeam Network to have your RPC endpoint or produce blocks. categories: Basics, Node Operators and Collators --- # Run a Node on Moonbeam ## Introduction {: #introduction } Running a full node on a Moonbeam-based network allows you to connect to the network, sync with a bootnode, obtain local access to RPC endpoints, author blocks on the parachain, and more. There are multiple deployments of Moonbeam, including the Moonbase Alpha TestNet, Moonriver on Kusama, and Moonbeam on Polkadot. Here's how these environments are named and their corresponding [chain specification file](https://docs.polkadot.com/develop/parachains/deployment/generate-chain-specs/) names: | Network | Hosted By | Chain Name | |:--------------:|:-------------------:|:-----------------------------------:| | Moonbase Alpha | Moonbeam Foundation | {{ networks.moonbase.chain_spec }} | | Moonriver | Kusama | {{ networks.moonriver.chain_spec }} | | Moonbeam | Polkadot | {{ networks.moonbeam.chain_spec }} | !!! note Moonbase Alpha is still considered an Alphanet, and as such _will not_ have 100% uptime. The parachain might be purged as needed. During the development of your application, make sure you implement a method to redeploy your contracts and accounts to a fresh parachain quickly. If a chain purge is required, it will be announced via our [Discord channel](https://discord.com/invite/PfpUATX) at least 24 hours in advance. ## Requirements {: #requirements } Running a parachain node is similar to a typical Substrate node, but there are some differences. A Substrate parachain node is a bigger build because it contains code to run the parachain itself, as well as code to sync the relay chain and facilitate communication between the two. As such, this build is quite large and may take over 30 min and require 32GB of memory. The minimum specs recommended to run a node are shown in the following table. For our Kusama and Polkadot MainNet deployments, disk requirements will be higher as the network grows. === "Moonbeam" | Component | Requirement | |:------------:|:--------------------------------------------------------------------------------------------------------------------------:| | **CPU** | {{ networks.moonbeam.node.cores }} Cores (Fastest per core speed) | | **RAM** | {{ networks.moonbeam.node.ram }} GB | | **SSD** | {{ networks.moonbeam.node.hd }} TB (recommended) | | **Firewall** | P2P port must be open to incoming traffic:
    - Source: Any
    - Destination: 30333, 30334 TCP | === "Moonriver" | Component | Requirement | |:------------:|:--------------------------------------------------------------------------------------------------------------------------:| | **CPU** | {{ networks.moonriver.node.cores }} Cores (Fastest per core speed) | | **RAM** | {{ networks.moonriver.node.ram }} GB | | **SSD** | {{ networks.moonriver.node.hd }} TB (recommended) | | **Firewall** | P2P port must be open to incoming traffic:
    - Source: Any
    - Destination: 30333, 30334 TCP | === "Moonbase Alpha" | Component | Requirement | |:------------:|:--------------------------------------------------------------------------------------------------------------------------:| | **CPU** | {{ networks.moonbase.node.cores }} Cores (Fastest per core speed) | | **RAM** | {{ networks.moonbase.node.ram }} GB | | **SSD** | {{ networks.moonbase.node.hd }} TB (recommended) | | **Firewall** | P2P port must be open to incoming traffic:
    - Source: Any
    - Destination: 30333, 30334 TCP | !!! note If you don't see an `Imported` message (without the `[Relaychain]` tag) when running a node, you might need to double-check your port configuration. ## Running Ports {: #running-ports } As stated before, the relay/parachain nodes will listen on multiple ports. The default Substrate ports are used in the parachain, while the relay chain will listen on the next higher port. The only ports that need to be open for incoming traffic are those designated for P2P. **Collators must not have RPC or WS ports opened**. !!! note As of client v0.33.0, the `--ws-port` and `--ws-max-connections` flags have been deprecated and removed in favor of the `--rpc-port` and `--rpc-max-connections` flags for both RPC and WSS connections. The default port is `9944`, and the default maximum number of connections is set to 100. ### Default Ports for a Parachain Full-Node {: #default-ports-for-a-parachain-full-node } | Description | Port | |:--------------:|:-----------------------------------:| | **P2P** | {{ networks.parachain.p2p }} (TCP) | | **RPC & WS** | {{ networks.parachain.ws }} | | **Prometheus** | {{ networks.parachain.prometheus }} | ### Default Ports of Embedded Relay Chain {: #default-ports-of-embedded-relay-chain } | Description | Port | |:--------------:|:-------------------------------------:| | **P2P** | {{ networks.relay_chain.p2p }} (TCP) | | **RPC & WS** | {{ networks.relay_chain.ws }} | | **Prometheus** | {{ networks.relay_chain.prometheus }} | ## Installation {: #installation } There are a couple different guides to help you get started running a Moonbeam-based node: - [Using Docker](/node-operators/networks/run-a-node/docker/) - this method provides a quick and easy way to get started with a Docker container - [Using Systemd](/node-operators/networks/run-a-node/systemd/) - this method is recommended for those with experience compiling a Substrate node ## Debug, Trace and TxPool APIs {: #debug-trace-txpool-apis } You can also gain access to some non-standard RPC methods by running a tracing node, which allow developers to inspect and debug transactions during runtime. Tracing nodes use a different Docker image than a standard Moonbase Alpha, Moonriver, or Moonbeam node. Check out the [Run a Tracing Node](/node-operators/networks/tracing-node/) guide and be sure to switch to the right network tab throughout the instructions. Then to interact with your tracing node, check out the [Debug & Trace](/builders/ethereum/json-rpc/debug-trace/) guide. ## Lazy Loading {: #lazy-loading } Lazy loading lets a Moonbeam node operate while downloading network state in the background, eliminating the need to wait for full synchronization before use. You can activate lazy loading with the following flag: - **`--lazy-loading-remote-rpc`** - allows lazy loading by relying on a specified RPC for network state until the node is fully synchronized e.g. `--lazy-loading-remote-rpc 'INSERT-RPC-URL'` Upon spooling up a node with this feature, you'll see output like the following:
[Lazy loading 🌗]
You are now running the Moonbeam client in lazy loading mode, where data is retrieved
from a live RPC node on demand.
Using remote state from: https://moonbeam.unitedbloc.com
Forking from block: 8482853
To ensure the client works properly, please note the following:
1. *Avoid Throttling*: Ensure that the backing RPC node is not limiting the number of
requests, as this can prevent the lazy loading client from functioning correctly;
2. *Be Patient*: As the client may take approximately 20 times longer than normal to
retrieve and process the necessary data for the requested operation.
The service will start in 10 seconds...
!!! note Lazy loading a Moonbeam requires a large number of RPC requests. To avoid being rate-limited by a public endpoint, it's highly recommended to use a [dedicated endpoint](/builders/get-started/endpoints#endpoint-providers). You can further customize your use of the lazy loading functionality with the following optional parameters: - **`--lazy-loading-block`** - specifies a block hash from which to start loading data. If not provided, the latest block will be used - **`--lazy-loading-delay-between-requests`** - the delay (in milliseconds) between RPC requests when using lazy loading. This parameter controls the amount of time to wait between consecutive RPC requests. This can help manage request rate and avoid overwhelming the server. Default value is `100` milliseconds - **`--lazy-loading-max-retries-per-request`** - the maximum number of retries for an RPC request when using lazy loading. Default value is `10` retries - **`--lazy-loading-runtime-override`** - path to a WASM file to override the runtime when forking. If not provided, it will fetch the runtime from the block being forked - **`--lazy-loading-state-overrides`** - path to a JSON file containing state overrides to be applied when forking The state overrides file should define the respective pallet, storage item, and value that you seek to override as follows: ```json [ { "pallet": "System", "storage": "SelectedCandidates", "value": "0x04f24ff3a9cf04c71dbc94d0b566f7a27b94566cac" } ] ``` ## Logs and Troubleshooting {: #logs-and-troubleshooting } You will see logs from both the relay chain and the parachain. The relay chain will be prefixed by `[Relaychain]`, while the parachain has no prefix. ### P2P Ports Not Open {: #p2p-ports-not-open } If you don't see an `Imported` message (without the `[Relaychain]` tag), you need to check the P2P port configuration. P2P port must be open to incoming traffic. ### In Sync {: #in-sync } Both chains must be in sync at all times, and you should see either `Imported` or `Idle` messages and have connected peers. ### Genesis Mismatching {: #genesis-mismatching } The Moonbase Alpha TestNet may need to be purged and upgraded once in a while. Consequently, you may see the following message: ```text DATE [Relaychain] Bootnode with peer id `ID` is on a different chain (our genesis: GENESIS_ID theirs: OTHER_GENESIS_ID) ``` This typically means that you are running an older version and will need to upgrade. We announce the upgrades (and corresponding chain purge) via our [Discord channel](https://discord.com/invite/PfpUATX) at least 24 hours in advance. Instructions for purging chain data will vary slightly depending on how you spun up your node: - For Docker, you can check out the [Purge Your Node](/node-operators/networks/run-a-node/docker/#purge-your-node) section of the [Using Docker](/node-operators/networks/run-a-node/docker/) page - For Systemd, you can take a look at the [Purge Your Node](/node-operators/networks/run-a-node/systemd/#purge-your-node) section of the [Using Systemd](/node-operators/networks/run-a-node/systemd/) page --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/node-operators/networks/run-a-node/systemd/ --- BEGIN CONTENT --- --- title: Run a Node on Moonbeam Using Systemd description: How to run a full parachain node so you can have your own RPC endpoint or produce blocks for the Moonbeam Network using Systemd. categories: Node Operators and Collators --- # Run a Node on Moonbeam Using Systemd ## Introduction {: #introduction } Running a full node on a Moonbeam-based network allows you to connect to the network, sync with a bootnode, obtain local access to RPC endpoints, author blocks on the parachain, and more. In this guide, you'll learn how to spin up a Moonbeam node using [Systemd](https://systemd.io){target=\_blank} and how to maintain and purge your node. If you're interested in compiling the binary yourself, which may take over 30 min and require 32GB of memory, you can check out the [Manually Compile the Moonbeam Binary](/node-operators/networks/run-a-node/compile-binary/){target=\_blank} guide. ## Checking Prerequisites {: #checking-prerequisites } The following sections go through the process of using the binary and running a Moonbeam full node as a systemd service. To get started, you'll need to: - Make sure you're running Ubuntu 18.04, 20.04, or 22.04. Moonbeam may work with other Linux flavors, but Ubuntu is currently the only tested version - Make sure that your system meets the [requirements](/node-operators/networks/run-a-node/overview/#requirements){target=\_blank}. When connecting to Moonriver on Kusama or Moonbeam on Polkadot, it will take a few days to completely sync the embedded relay chain ## Download the Latest Release Binary {: #the-release-binary } To download the latest [release binary](https://github.com/moonbeam-foundation/moonbeam/releases){target=\_blank}, take the following steps: 1. Create a directory to store the binary and chain data (you might need `sudo`) === "Moonbeam" ```bash mkdir {{ networks.moonbeam.node_directory }} ``` === "Moonriver" ```bash mkdir {{ networks.moonriver.node_directory }} ``` === "Moonbase Alpha" ```bash mkdir {{ networks.moonbase.node_directory }} ``` 2. Use `wget` to grab the latest [release binary](https://github.com/moonbeam-foundation/moonbeam/releases){target=\_blank} and output it to the directory created in the previous step === "Moonbeam" ```bash wget https://github.com/moonbeam-foundation/moonbeam/releases/download/{{ networks.moonbeam.parachain_release_tag }}/moonbeam \ -O {{ networks.moonbeam.node_directory }}/moonbeam ``` === "Moonriver" ```bash wget https://github.com/moonbeam-foundation/moonbeam/releases/download/{{ networks.moonriver.parachain_release_tag }}/moonbeam \ -O {{ networks.moonriver.node_directory }}/moonbeam ``` === "Moonbase Alpha" ```bash wget https://github.com/moonbeam-foundation/moonbeam/releases/download/{{ networks.moonbase.parachain_release_tag }}/moonbeam \ -O {{ networks.moonbase.node_directory }}/moonbeam ``` 3. To verify that you have downloaded the correct version, you can run the following command in your terminal === "Moonbeam" ```bash sha256sum {{ networks.moonbeam.node_directory }}/moonbeam ``` === "Moonriver" ```bash sha256sum {{ networks.moonriver.node_directory }}/moonbeam ``` === "Moonbase Alpha" ```bash sha256sum {{ networks.moonbase.node_directory }}/moonbeam ``` You should receive the following output: === "Moonbeam" ```text {{ networks.moonbeam.parachain_sha256sum }} ``` === "Moonriver" ```text {{ networks.moonriver.parachain_sha256sum }} ``` === "Moonbase Alpha" ```text {{ networks.moonbase.parachain_sha256sum }} ``` ## Set Up the Service {: #set-up-the-service } The following commands will set up everything regarding running the service: 1. Create a service account to run the service === "Moonbeam" ```bash adduser moonbeam_service --system --no-create-home ``` === "Moonriver" ```bash adduser moonriver_service --system --no-create-home ``` === "Moonbase Alpha" ```bash adduser moonbase_service --system --no-create-home ``` 2. Ensure that you properly configure the ownership and permissions for the local directory housing the chain data, and also remember to grant execute permission to the binary file === "Moonbeam" ```bash sudo chown -R moonbeam_service {{ networks.moonbeam.node_directory }} sudo chmod +x {{ networks.moonbeam.node_directory }}/moonbeam ``` === "Moonriver" ```bash sudo chown -R moonriver_service {{ networks.moonriver.node_directory }} sudo chmod +x {{ networks.moonriver.node_directory }}/moonbeam ``` === "Moonbase Alpha" ```bash sudo chown -R moonbase_service {{ networks.moonbase.node_directory }} sudo chmod +x {{ networks.moonbase.node_directory }}/moonbeam ``` ## Create the Configuration File {: #create-the-configuration-file } Next, create the systemd service file. If you're configuring a collator node, use the [collator-specific](#collator) configuration snippets below. First, you'll need to create a file named `/etc/systemd/system/moonbeam.service` to store the configurations. Note that in the following start-up configurations, you have to: - Replace `INSERT_YOUR_NODE_NAME` with your node name of choice. You'll have to do this in two places: one for the parachain and one for the relay chain - Replace `INSERT_RAM_IN_MB` for 50% of the actual RAM your server has. For example, for 32GB of RAM, the value must be set to `16000`. The minimum value is `2000`, but it is below the recommended specs - Double-check that the binary is in the proper path as described below (_ExecStart_) - Double-check the base path if you've used a different directory For an overview of the flags used in the following start-up commands, plus additional commonly used flags, please refer to the [Flags](/node-operators/networks/run-a-node/flags/){target=\_blank} page of our documentation. ### Full Node {: #full-node } === "Moonbeam" ```bash [Unit] Description="Moonbeam systemd service" After=network.target StartLimitIntervalSec=0 [Service] Type=simple Restart=on-failure RestartSec=10 User=moonbeam_service SyslogIdentifier=moonbeam SyslogFacility=local7 KillSignal=SIGHUP ExecStart={{ networks.moonbeam.node_directory }}/{{ networks.moonbeam.binary_name }} \ --state-pruning archive \ --trie-cache-size 1073741824 \ --db-cache INSERT_RAM_IN_MB \ --base-path {{ networks.moonbeam.node_directory }} \ --chain {{ networks.moonbeam.chain_spec }} \ --name "INSERT_YOUR_NODE_NAME" \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast [Install] WantedBy=multi-user.target ``` === "Moonriver" ```bash [Unit] Description="Moonriver systemd service" After=network.target StartLimitIntervalSec=0 [Service] Type=simple Restart=on-failure RestartSec=10 User=moonriver_service SyslogIdentifier=moonriver SyslogFacility=local7 KillSignal=SIGHUP ExecStart={{ networks.moonriver.node_directory }}/{{ networks.moonriver.binary_name }} \ --state-pruning archive \ --trie-cache-size 1073741824 \ --db-cache INSERT_RAM_IN_MB \ --base-path {{ networks.moonriver.node_directory }} \ --chain {{ networks.moonriver.chain_spec }} \ --name "INSERT_YOUR_NODE_NAME" \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast [Install] WantedBy=multi-user.target ``` === "Moonbase Alpha" ```bash [Unit] Description="Moonbase Alpha systemd service" After=network.target StartLimitIntervalSec=0 [Service] Type=simple Restart=on-failure RestartSec=10 User=moonbase_service SyslogIdentifier=moonbase SyslogFacility=local7 KillSignal=SIGHUP ExecStart={{ networks.moonbase.node_directory }}/{{ networks.moonbase.binary_name }} \ --state-pruning archive \ --trie-cache-size 1073741824 \ --db-cache INSERT_RAM_IN_MB \ --base-path {{ networks.moonbase.node_directory }} \ --chain {{ networks.moonbase.chain_spec }} \ --name "INSERT_YOUR_NODE_NAME" \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast [Install] WantedBy=multi-user.target ``` #### Allow External Access to Your Node {: #allow-external-access } If you want to run an RPC endpoint, connect to Polkadot.js Apps, or run your own application, you can use the `--unsafe-rpc-external` flag to run the full node with external access to the RPC ports. ??? code "Example start-up command for Moonbeam" ```bash [Unit] Description="Moonbeam systemd service" After=network.target StartLimitIntervalSec=0 [Service] Type=simple Restart=on-failure RestartSec=10 User=moonbeam_service SyslogIdentifier=moonbeam SyslogFacility=local7 KillSignal=SIGHUP ExecStart={{ networks.moonbeam.node_directory }}/{{ networks.moonbeam.binary_name }} \ --state-pruning archive \ --trie-cache-size 1073741824 \ --db-cache INSERT_RAM_IN_MB \ --base-path {{ networks.moonbeam.node_directory }} \ --chain {{ networks.moonbeam.chain_spec }} \ --name "INSERT_YOUR_NODE_NAME" \ --unsafe-rpc-external \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast [Install] WantedBy=multi-user.target ``` #### Use a SQL Backend for Frontier {: #use-sql } The default [Frontier](/learn/platform/technology/#frontier){target=\_blank} database, which comes standard with Moonbeam nodes and contains all of the Ethereum-related elements, such as transactions, blocks, and logs, can be modified to use a SQL backend. Since `eth_getLogs` is a very resource-intensive method, the SQL backend aims to provide a more performant alternative for indexing and querying Ethereum logs in comparison to the default RocksDB database. To spin up a node with a Frontier SQL backend, you'll need to add the `--frontier-backend-type sql` flag to your start-up command. There are additional flags you can use to configure the pool size, query timeouts, and more for your SQL backend; please refer to the [Flags](/node-operators/networks/run-a-node/flags/#flags-for-sql-backend){target=\_blank} page for more information. ??? code "Example start-up command for Moonbeam" ```bash [Unit] Description="Moonbeam systemd service" After=network.target StartLimitIntervalSec=0 [Service] Type=simple Restart=on-failure RestartSec=10 User=moonbeam_service SyslogIdentifier=moonbeam SyslogFacility=local7 KillSignal=SIGHUP ExecStart={{ networks.moonbeam.node_directory }}/{{ networks.moonbeam.binary_name }} \ --state-pruning archive \ --trie-cache-size 1073741824 \ --db-cache INSERT_RAM_IN_MB \ --base-path {{ networks.moonbeam.node_directory }} \ --chain {{ networks.moonbeam.chain_spec }} \ --name "INSERT_YOUR_NODE_NAME" \ --frontier-backend-type sql \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast [Install] WantedBy=multi-user.target ``` ### Collator {: #collator } Beginning with v0.39.0, new Moonbeam collator nodes will no longer generate session keys automatically on start-up. Nodes in existence prior to v0.39.0 do not need to make changes to how they handle session keys. When setting up a new node, run the following command to generate and store on disk the session keys that will be referenced in the start-up command: === "Moonbeam" ```bash /var/lib/moonbeam-data/moonbeam key generate-node-key --base-path /var/lib/moonbeam-data --chain moonbeam && sudo chown -R moonbeam_service /var/lib/moonbeam-data ``` === "Moonriver" ```bash /var/lib/moonriver-data/moonbeam key generate-node-key --base-path /var/lib/moonriver-data --chain moonriver && sudo chown -R moonriver_service /var/lib/moonriver-data ``` === "Moonbase Alpha" ```bash /var/lib/alphanet-data/moonbeam key generate-node-key --base-path /var/lib/alphanet-data --chain alphanet && sudo chown -R moonbase_service /var/lib/alphanet-data ``` !!! note This step can be bypassed using the `--unsafe-force-node-key-generation` parameter in the start-up command, although this is not the recommended practice. Now you can create the systemd configuration file: === "Moonbeam" ```bash [Unit] Description="Moonbeam systemd service" After=network.target StartLimitIntervalSec=0 [Service] Type=simple Restart=on-failure RestartSec=10 User=moonbeam_service SyslogIdentifier=moonbeam SyslogFacility=local7 KillSignal=SIGHUP ExecStart={{ networks.moonbeam.node_directory }}/{{ networks.moonbeam.binary_name }} \ --collator \ --trie-cache-size 1073741824 \ --db-cache INSERT_RAM_IN_MB \ --base-path {{ networks.moonbeam.node_directory }} \ --chain {{ networks.moonbeam.chain_spec }} \ --name "INSERT_YOUR_NODE_NAME" \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast [Install] WantedBy=multi-user.target ``` === "Moonriver" ```bash [Unit] Description="Moonriver systemd service" After=network.target StartLimitIntervalSec=0 [Service] Type=simple Restart=on-failure RestartSec=10 User=moonriver_service SyslogIdentifier=moonriver SyslogFacility=local7 KillSignal=SIGHUP ExecStart={{ networks.moonriver.node_directory }}/{{ networks.moonriver.binary_name }} \ --collator \ --trie-cache-size 1073741824 \ --db-cache INSERT_RAM_IN_MB \ --base-path {{ networks.moonriver.node_directory }} \ --chain {{ networks.moonriver.chain_spec }} \ --name "INSERT_YOUR_NODE_NAME" \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast [Install] WantedBy=multi-user.target ``` === "Moonbase Alpha" ```bash [Unit] Description="Moonbase Alpha systemd service" After=network.target StartLimitIntervalSec=0 [Service] Type=simple Restart=on-failure RestartSec=10 User=moonbase_service SyslogIdentifier=moonbase SyslogFacility=local7 KillSignal=SIGHUP ExecStart={{ networks.moonbase.node_directory }}/{{ networks.moonbase.binary_name }} \ --collator \ --trie-cache-size 1073741824 \ --db-cache INSERT_RAM_IN_MB \ --base-path {{ networks.moonbase.node_directory }} \ --chain {{ networks.moonbase.chain_spec }} \ --name "INSERT_YOUR_NODE_NAME" \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" \ --sync fast [Install] WantedBy=multi-user.target ``` ## Run the Service {: #run-the-service } Register and start the service by running: ```bash systemctl enable moonbeam.service systemctl start moonbeam.service ``` And lastly, verify that the service is running: ```bash systemctl status moonbeam.service ```
systemctl status moonbeam.service • moonbeam.service - "Moonbase Alpha systemd service" Loaded: loaded (/etc/systemd/system/moonbeam.service; enabled; vendor preset:> Active: active (running) since Tue 2025-07-10 09:04:26 UTC; 45 ago Main PID: 52847 (moonbeam) Tasks: 13 (limit: 4662) Memory: 113.7M CPU: 6.9995 CGroup: /system.slice/moonbeam.service └─52847 /var/lib/alphanet-data/moonbeam --state-pruning=archive --tri> lines 1-9/9 (END)
You can also check the logs by executing: ```bash journalctl -f -u moonbeam.service ```
moonbase[52847]: 2025-07-10 09:04:26 [Relaychain] 🌗 ⚙️ @ Syncing 158.7 bps, target=#12361301 (9 peers), best: #35487 (0x527e...c72b), finalized #35328 (0xfcd2...828), # 239.9kiB/s 15.6kiB/s moonbase[52847]: 2025-07-10 09:04:26 Syncing 150.7 bps, target=#5236155 (9 peers), best: #40870 (0x3659...c530), finalized #16793 (0x815...578), # 299.7kiB/s 10.6kiB/s moonbase[52847]: 2025-07-10 09:04:26 [Relaychain] 🌗 ⚙️ Syncing 162.5 bps, target=#12361302 (9 peers), best: #36300 (0x9edb..b2c2), finalized #35985 (0x7345..e874), +256.6kiB/s 19.6kiB/s moonbase[52847]: 2025-07-10 09:04:26 Syncing 168.8 bps, target=#5236155 (9 peers), best: #41714 (0x2feb...3f10), finalized #17122 (0x4954...8161), +353.2kiB/s 11.4kB/s moonbase[52847]: 2025-07-10 09:04:26 [Relaychain] 🌗 ⚙️ @ Syncing 181.3 bps, target=#12361303 (9 peers), best: #37208 (0xbad2...6c2d), finalized #36864 (0x3015..bd42), # 288.4kiB/s 14.8kiB/s moonbase[52847]: 2025-07-10 09:04:26 Syncing 161.9 bps, target=#5236155 (9 peers), best: #42525 (0x9711...0de7), finalized #17561 (0x56f4...ad20), # 310.0kiB/s 11.0kiB/s moonbase[52847]: 2025-07-10 09:04:26 [Relaychain] 🌗 ⚙️ @ Syncing 166.0 bps, target=#12361303 (9 peers), best: #38039 (0xb19f445c), finalized #37888 (0x68bb...6900), +176.9kiB/s 13.1kiB/s moonbase[52847]: 2025-07-10 09:04:26 Syncing 183.7 bps, target=#5236155 (9 peers), best: #43444 (0xccd0...a18f), finalized #18073 (0xe474...2032), #357.3kiB/s 10.3kiB/s
During the syncing process, you will see logs from both the embedded relay chain ([Relaychain]) and the parachain ([🌗]). These logs display a target block (live network state) and a best block (local node synced state). !!! note It may take a few days to completely sync the embedded relay chain. Make sure that your system meets the [requirements](/node-operators/networks/run-a-node/overview/#requirements){target=\_blank}. If you need to stop the service for any reason, you can run: ```bash systemctl stop moonbeam.service ``` ## Maintain Your Node {: #maintain-your-node } As Moonbeam development continues, it will sometimes be necessary to upgrade your node software. Node operators will be notified on our [Discord channel](https://discord.com/invite/PfpUATX){target=\_blank} when upgrades are available and whether they are necessary (some client upgrades are optional). The upgrade process is straightforward and is the same for a full node or collator. If you want to update your client, you can keep your existing chain data in tact, and only update the binary by following these steps: 1. Stop the systemd service ```bash sudo systemctl stop moonbeam.service ``` 2. Remove the old binary file === "Moonbeam" ```bash rm {{ networks.moonbeam.node_directory }}/moonbeam ``` === "Moonriver" ```bash rm {{ networks.moonriver.node_directory }}/moonbeam ``` === "Moonbase Alpha" ```bash rm {{ networks.moonbase.node_directory }}/moonbeam ``` 3. Get the latest version of the [Moonbeam release binary on GitHub](https://github.com/moonbeam-foundation/moonbeam/releases){target=\_blank} and run the following command to update to that version === "Moonbeam" ```bash wget https://github.com/moonbeam-foundation/moonbeam/releases/download/INSERT_NEW_VERSION_TAG/moonbeam \ -O {{ networks.moonbeam.node_directory }}/moonbeam ``` === "Moonriver" ```bash wget https://github.com/moonbeam-foundation/moonbeam/releases/download/INSERT_NEW_VERSION_TAG/moonbeam \ -O {{ networks.moonriver.node_directory }}/moonbeam ``` === "Moonbase Alpha" ```bash wget https://github.com/moonbeam-foundation/moonbeam/releases/download/INSERT_NEW_VERSION_TAG/moonbeam \ -O {{ networks.moonbase.node_directory }}/moonbeam ``` !!! note If you [compiled the binary manually](/node-operators/networks/run-a-node/compile-binary/){target=\_blank}, you'll need to move the binary from `./target/release/{{ networks.moonbeam.binary_name }}` to the data directory. 4. Update permissions === "Moonbeam" ```bash chmod +x {{ networks.moonbeam.node_directory }}/moonbeam chown moonbeam_service {{ networks.moonbeam.node_directory }}/moonbeam ``` === "Moonriver" ```bash chmod +x {{ networks.moonriver.node_directory }}/moonbeam chown moonriver_service {{ networks.moonriver.node_directory }}/moonbeam ``` === "Moonbase Alpha" ```bash chmod +x {{ networks.moonbase.node_directory }}/moonbeam chown moonbase_service {{ networks.moonbase.node_directory }}/moonbeam ``` 5. Start your service ```bash systemctl start moonbeam.service ``` To check the status of the service and/or logs, you can refer to the [commands from before](#run-the-service). ## Purge Your Node {: #purge-your-node } If you need a fresh instance of your Moonbeam node, you can purge your node by removing the associated data directory. You'll first need to stop the systemd service: ```bash sudo systemctl stop moonbeam ``` To purge your parachain and relay chain data, you can run the following command: === "Moonbeam" ```bash sudo rm -rf {{ networks.moonbeam.node_directory }}/* ``` === "Moonriver" ```bash sudo rm -rf {{ networks.moonriver.node_directory }}/* ``` === "Moonbase Alpha" ```bash sudo rm -rf {{ networks.moonbase.node_directory }}/* ``` To only remove the parachain data for a specific chain, you can run: === "Moonbeam" ```bash sudo rm -rf {{ networks.moonbeam.node_directory }}/chains/* ``` === "Moonriver" ```bash sudo rm -rf {{ networks.moonriver.node_directory }}/chains/* ``` === "Moonbase Alpha" ```bash sudo rm -rf {{ networks.moonbase.node_directory }}/chains/* ``` Similarly, to only remove the relay chain data, you can run: === "Moonbeam" ```bash sudo rm -rf {{ networks.moonbeam.node_directory }}/polkadot/* ``` === "Moonriver" ```bash sudo rm -rf {{ networks.moonriver.node_directory }}/polkadot/* ``` === "Moonbase Alpha" ```bash sudo rm -rf {{ networks.moonbase.node_directory }}/polkadot/* ``` Now that your chain data has been purged, you can start a new node with a fresh data directory. You can install the newest version by repeating the instructions in this guide. Make sure you are using the latest tag available, which you can find on the [Moonbeam GitHub Release](https://github.com/moonbeam-foundation/moonbeam/releases) page. !!! note On an as-needed basis, Moonbase Alpha might be purged and reset. In these instances, you will need to purge both the parachain data and the relay chain data. If a purge is required, node operators will be notified in advance (via our [Discord channel](https://discord.com/invite/PfpUATX){target=\_blank}). --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/node-operators/networks/tracing-node/ --- BEGIN CONTENT --- --- title: Run a Tracing Node description: Learn how to leverage Geth's Debug and Txpool APIs, and OpenEthereum's Trace module to run a tracing node on Moonbeam. categories: Node Operators and Collators --- # Run a Tracing Node ## Introduction {: #introduction } Geth's `debug` and `txpool` APIs and OpenEthereum's `trace` module provide non-standard RPC methods for getting a deeper insight into transaction processing. As part of Moonbeam's goal of providing a seamless Ethereum experience for developers, there is support for some of these non-standard RPC methods. Supporting these RPC methods is an important milestone because many projects, such as [The Graph](https://thegraph.com){target=\_blank}, rely on them to index blockchain data. To use the supported RPC methods, you need to run a tracing node, which is slightly different than running a full node. There is a different Docker image, called `moonbeamfoundation/moonbeam-tracing` that needs to be used for tracing. Additional flags will also need to be used to tell the node which of the non-standard features to support. This guide will show you how to get started running a tracing node on Moonbeam with the `debug`, `txpool`, and `tracing` flags enabled. ## Checking Prerequisites {: #checking-prerequisites } Similarly to running a regular node, you can spin up a tracing node using Docker or Systemd. If you choose to use Docker, you must [install Docker](https://docs.docker.com/get-started/get-docker/){target=\_blank} if you haven't already. At the time of writing, the Docker version used was 19.03.6. ## Tracing Node Flags {: #tracing-node-flags } Spinning up a `debug`, `txpool`, or `tracing` node is similar to [running a full node](/node-operators/networks/run-a-node/overview/){target=\_blank}. However, there are some additional flags that you may want to enable specific tracing features: - **`--ethapi debug`** - optional flag that enables `debug_traceTransaction`, `debug_traceBlockByNumber`, `debug_traceBlockByHash`, and `debug_traceCall` - **`--ethapi trace`** - optional flag that enables `trace_filter` - **`--ethapi txpool`** - optional flag that enables `txpool_content`, `txpool_inspect`, and `txpool_status` - **`--wasm-runtime-overrides `** - **required** flag for tracing that specifies the path where the local Wasm runtimes are stored. If you're using Docker, the path is as follows: `/moonbeam/-substitutes-tracing`. Accepts the network as a parameter: `moonbeam`, `moonriver`, or `moonbase` (for development nodes and Moonbase Alpha) - **`--runtime-cache-size 64`** - **required** flag that configures the number of different runtime versions preserved in the in-memory cache to 64 - **`--ethapi-trace-max-count `** — sets the maximum number of trace entries to be returned by the node. The default maximum number of trace entries a single request of `trace_filter` returns is `500` - **`-ethapi-trace-cache-duration `** — sets the duration (in seconds) after which the cache of `trace_filter,` for a given block, is discarded. The default amount of time blocks are stored in the cache is `300` seconds !!! note If you want to run an RPC endpoint, to connect to Polkadot.js Apps, or to run your own application, use the `--unsafe-rpc-external` flag to run the full node with external access to the RPC ports. More details are available by running `moonbeam --help`. ## Run a Tracing Node with Docker {: #run-a-tracing-node-with-docker } If you haven't previously run a standard full Moonbeam node, you will need to setup a directory to store chain data: === "Moonbeam" ```bash mkdir {{ networks.moonbeam.node_directory }} ``` === "Moonriver" ```bash mkdir {{ networks.moonriver.node_directory }} ``` === "Moonbase Alpha" ```bash mkdir {{ networks.moonbase.node_directory }} ``` Before getting started, you'll need to set the necessary permissions either for a specific or current user (replace `INSERT_DOCKER_USER` for the actual user that will run the `docker` command): === "Moonbeam" ```bash # chown to a specific user chown INSERT_DOCKER_USER {{ networks.moonbeam.node_directory }} # chown to current user sudo chown -R $(id -u):$(id -g) {{ networks.moonbeam.node_directory }} ``` === "Moonriver" ```bash # chown to a specific user chown INSERT_DOCKER_USER {{ networks.moonriver.node_directory }} # chown to current user sudo chown -R $(id -u):$(id -g) {{ networks.moonriver.node_directory }} ``` === "Moonbase Alpha" ```bash # chown to a specific user chown INSERT_DOCKER_USER {{ networks.moonbase.node_directory }} # chown to current user sudo chown -R $(id -u):$(id -g) {{ networks.moonbase.node_directory }} ``` Instead of the standard `moonbeamfoundation/moonbeam` docker image, you will need to use `moonbeamfoundation/moonbeam-tracing` image. The latest supported version can be found on the [Docker Hub for the `moonbeam-tracing` image](https://hub.docker.com/r/moonbeamfoundation/moonbeam-tracing/tags){target=\_blank}. Now, execute the docker run command. Note that you have to: - Replace `INSERT_YOUR_NODE_NAME` in two different places - Replace `INSERT_RAM_IN_MB` for 50% of the actual RAM your server has. For example, for 32 GB RAM, the value must be set to `16000`. The minimum value is `2000`, but it is below the recommended specs !!! note As of client v0.33.0, the `--ws-port` and `--ws-max-connections` flags have been deprecated and removed in favor of the `--rpc-port` and `--rpc-max-connections` flags for both RPC and WSS connections. The default port is `9944`, and the default maximum number of connections is set to 100. The complete command for running a tracing node is as follows: === "Moonbeam" ```bash docker run --network="host" -v "{{ networks.moonbeam.node_directory }}:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ {{ networks.moonbeam.tracing_tag }} \ --base-path /data \ --chain {{ networks.moonbeam.chain_spec }} \ --name "INSERT_YOUR_NODE_NAME" \ --state-pruning archive \ --trie-cache-size 1073741824 \ --db-cache INSERT_RAM_IN_MB \ --ethapi debug,trace,txpool \ --wasm-runtime-overrides /moonbeam/moonbeam-substitutes-tracing \ --runtime-cache-size 64 \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" ``` === "Moonriver" ```bash docker run --network="host" -v "{{ networks.moonriver.node_directory }}:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ {{ networks.moonriver.tracing_tag }} \ --base-path /data \ --chain {{ networks.moonriver.chain_spec }} \ --name INSERT_YOUR_NODE_NAME" \ --state-pruning archive \ --trie-cache-size 1073741824 \ --db-cache INSERT_RAM_IN_MB \ --ethapi debug,trace,txpool \ --wasm-runtime-overrides /moonbeam/moonriver-substitutes-tracing \ --runtime-cache-size 64 \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" ``` === "Moonbase Alpha" ```bash docker run --network="host" -v "{{ networks.moonbase.node_directory }}:/data" \ -u $(id -u ${USER}):$(id -g ${USER}) \ {{ networks.moonbase.tracing_tag }} \ --base-path /data \ --chain {{ networks.moonbase.chain_spec }} \ --name "INSERT_YOUR_NODE_NAME" \ --state-pruning archive \ --trie-cache-size 1073741824 \ --db-cache INSERT_RAM_IN_MB \ --ethapi debug,trace,txpool \ --wasm-runtime-overrides /moonbeam/moonbase-substitutes-tracing \ --runtime-cache-size 64 \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" ``` === "Moonbeam Dev Node" ```bash docker run --network="host" \ -u $(id -u ${USER}):$(id -g ${USER}) \ {{ networks.development.tracing_tag }} \ --name "INSERT_YOUR_NODE_NAME" \ --ethapi debug,trace,txpool \ --wasm-runtime-overrides /moonbeam/moonbase-substitutes-tracing \ --runtime-cache-size 64 \ --dev ``` You should see a terminal log similar to the following if you spun up a Moonbase Alpha tracing node:
docker run --network host \
-u $(id -u ${USER}):$(id -g ${USER}) \ moonbeamfoundation/moonbeam-tracing:v0.45.0-3701-a160 \
--name="Moonbean-Tracing-Tutorial" \
--unsafe-rpc-external \
--ethapi=debug,trace,txpool \
--wasm-runtime-overrides=/moonbeam/moonbase-substitutes-tracing \
--runtime-cache-size 64 \
--dev

2025-07-10 09:04:26 Moonbeam Parachain Collator
2025-07-10 09:04:26 ✌️ version 0.46.0-d7df89e7161
2025-07-10 09:04:26 ❤️ by PureStake, 2019-2025
2025-07-10 09:04:26 📋 Chain specification: Moonbase Development Testnet
2025-07-10 09:04:26 🏷 Node name: Moonbean-Tracing-Tutorial
2025-07-10 09:04:26 👤 Role: AUTHORITY
2025-07-10 09:04:26 💾 Database: RocksDb at /tmp/substrateO3YeRz/chains/moonbase_dev/db/full
2025-07-10 09:04:26 Found wasm override. version=moonbase-300 (moonbase-0.tx2.au3) file=/moonbeam/moonbase-substitutes-tracing/moonbase-runtime-300-substitute-tracing.wasm
...
2025-07-10 09:04:26 💤 Idle (0 peers), best: #0 (0x18e6…2eb1), finalized #0 (0x18e6…2eb1), ⬇ 0 ⬆ 0
## Run a Tracing Node with Systemd {: #run-a-tracing-node-with-systemd } When you run a node using Systemd, you'll need to start off by setting up the Moonbeam binary. To do so you'll need to follow the instructions on the [Run a Node on Moonbeam Using Systemd](/node-operators/networks/run-a-node/systemd/){target=\_blank} page. In general, you'll need to: 1. Setup the Moonbeam binary by following the [Release Binary](/node-operators/networks/run-a-node/systemd/#the-release-binary){target=\_blank} instructions. Or if you want to compile the binary yourself, you can follow the [Compile the Binary](/node-operators/networks/run-a-node/systemd/#compile-the-binary){target=\_blank} instructions 2. Follow the instructions in the [Setup the Service](/node-operators/networks/run-a-node/systemd/#setup-the-service){target=\_blank} instructions Once you've finished going through the instructions in those specific sections, you can continue on to the below instructions. ### Setup the Wasm Overrides {: #setup-the-wasm-overrides } You'll need to create a directory for the Wasm runtime overrides and obtain them from the [Moonbeam Runtime Overrides repository](https://github.com/moonbeam-foundation/moonbeam-runtime-overrides){target=\_blank} on GitHub. You can clone the repository to any location on your local machine. For simplicity, you can use the directory where you're storing on-chain data. To set up the Wasm override files, you can take the following steps: 1. Clone the [Moonbeam Runtime Overrides repository](https://github.com/moonbeam-foundation/moonbeam-runtime-overrides){target=\_blank} ```bash git clone https://github.com/moonbeam-foundation/moonbeam-runtime-overrides.git ``` 2. Move the Wasm overrides into your on-chain data directory: === "Moonbeam" ```bash mv moonbeam-runtime-overrides/wasm {{ networks.moonbeam.node_directory }} ``` === "Moonriver" ```bash mv moonbeam-runtime-overrides/wasm {{ networks.moonriver.node_directory }} ``` === "Moonbase Alpha" ```bash mv moonbeam-runtime-overrides/wasm {{ networks.moonbase.node_directory }} ``` 3. Delete the override files for the networks that you aren't running === "Moonbeam" ```bash rm {{ networks.moonbeam.node_directory }}/wasm/moonriver-runtime-* && rm {{ networks.moonbeam.node_directory }}/wasm/moonbase-runtime-* ``` === "Moonriver" ```bash rm {{ networks.moonriver.node_directory }}/wasm/moonbeam-runtime-* && rm {{ networks.moonriver.node_directory }}/wasm/moonbase-runtime-* ``` === "Moonbase Alpha" ```bash rm {{ networks.moonbase.node_directory }}/wasm/moonbeam-runtime-* && rm {{ networks.moonbase.node_directory }}/wasm/moonriver-runtime-* ``` 4. Set user permissions for the overrides: === "Moonbeam" ```bash chmod +x {{ networks.moonbeam.node_directory }}/wasm/* chown moonbeam_service {{ networks.moonbeam.node_directory }}/wasm/* ``` === "Moonriver" ```bash chmod +x {{ networks.moonriver.node_directory }}/wasm/* chown moonriver_service {{ networks.moonriver.node_directory }}/wasm/* ``` === "Moonbase Alpha" ```bash chmod +x {{ networks.moonbase.node_directory }}/wasm/* chown moonbase_service {{ networks.moonbase.node_directory }}/wasm/* ``` ### Create the Configuration File {: #create-the-configuration-file } The next step is to create the systemd configuration file, you'll need to: - Replace `INSERT_YOUR_NODE_NAME` in two different places - Replace `INSERT_RAM_IN_MB` for 50% of the actual RAM your server has. For example, for 32 GB RAM, the value must be set to `16000`. The minimum value is `2000`, but it is below the recommended specs - Double-check that the binary is in the proper path as described below (_ExecStart_) - Double-check the base path if you've used a different directory - Name the file `/etc/systemd/system/moonbeam.service` !!! note As of client v0.33.0, the `--ws-port` and `--ws-max-connections` flags have been deprecated and removed in favor of the `--rpc-port` and `--rpc-max-connections` flags for both RPC and WSS connections. The default port is `9944`, and the default maximum number of connections is set to 100. === "Moonbeam" ```bash [Unit] Description="Moonbeam systemd service" After=network.target StartLimitIntervalSec=0 [Service] Type=simple Restart=on-failure RestartSec=10 User=moonbeam_service SyslogIdentifier=moonbeam SyslogFacility=local7 KillSignal=SIGHUP ExecStart={{ networks.moonbeam.node_directory }}/{{ networks.moonbeam.binary_name }} \ --state-pruning archive \ --trie-cache-size 1073741824 \ --db-cache INSERT_RAM_IN_MB \ --base-path {{ networks.moonbeam.node_directory }} \ --ethapi debug,trace,txpool \ --wasm-runtime-overrides {{ networks.moonbeam.node_directory }}/wasm \ --runtime-cache-size 64 \ --chain {{ networks.moonbeam.chain_spec }} \ --name "INSERT_YOUR_NODE_NAME" \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" [Install] WantedBy=multi-user.target ``` === "Moonriver" ```bash [Unit] Description="Moonriver systemd service" After=network.target StartLimitIntervalSec=0 [Service] Type=simple Restart=on-failure RestartSec=10 User=moonriver_service SyslogIdentifier=moonriver SyslogFacility=local7 KillSignal=SIGHUP ExecStart={{ networks.moonriver.node_directory }}/{{ networks.moonriver.binary_name }} \ --state-pruning archive \ --trie-cache-size 1073741824 \ --db-cache INSERT_RAM_IN_MB \ --base-path {{ networks.moonriver.node_directory }} \ --ethapi debug,trace,txpool \ --wasm-runtime-overrides {{ networks.moonriver.node_directory }}/wasm \ --runtime-cache-size 64 \ --chain {{ networks.moonriver.chain_spec }} \ --name "INSERT_YOUR_NODE_NAME" \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" [Install] WantedBy=multi-user.target ``` === "Moonbase Alpha" ```bash [Unit] Description="Moonbase Alpha systemd service" After=network.target StartLimitIntervalSec=0 [Service] Type=simple Restart=on-failure RestartSec=10 User=moonbase_service SyslogIdentifier=moonbase SyslogFacility=local7 KillSignal=SIGHUP ExecStart={{ networks.moonbase.node_directory }}/{{ networks.moonbase.binary_name }} \ --state-pruning archive \ --trie-cache-size 1073741824 \ --db-cache INSERT_RAM_IN_MB \ --base-path {{ networks.moonbase.node_directory }} \ --ethapi debug,trace,txpool \ --wasm-runtime-overrides {{ networks.moonbase.node_directory }}/wasm \ --runtime-cache-size 64 \ --chain {{ networks.moonbase.chain_spec }} \ --name "INSERT_YOUR_NODE_NAME" \ -- \ --name "INSERT_YOUR_NODE_NAME (Embedded Relay)" [Install] WantedBy=multi-user.target ``` !!! note If you want to run an RPC endpoint, to connect polkadot.js.org, or to run your own application, use the `--unsafe-rpc-external` flag to run the full node with external access to the RPC ports. More details are available by running `moonbeam --help`. ### Run the Service {: #run-the-service } Register and start the service by running: ```bash systemctl enable moonbeam.service systemctl start moonbeam.service ``` And lastly, verify that the service is running: ```bash systemctl status moonbeam.service ```
systemctl status moonbeam.service ● moonbeam.service - "Moonbase Alpha systemd service"
Loaded: loaded (/etc/systemd/system/moonbeam.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2022-06-03 12:45:08 EDT; 10min ago
Main PID: 2115 (moonbeam)
Tasks: 43 (limit: 19141)
Memory: 9.5G
CGroup:/system.slice/moonbeam.service
--2115 /var/lib/alphanet-data/moonbeam --port 30334 --rpc-port 9944

Jun 03 12:55:07 vmi719182.contaboserver.net moonbase [2115]: 2022-06-03 12:55:07 [🌗] >
Jun 03 12:55:08 vmi719182.contaboserver.net moonbase [2115]: 2022-06-03 12:55:08 [Rela>
Jun 03 12:55:12 vmi719182.contaboserver.net moonbase [2115]: 2022-06-03 12:55:12 [🌗] >
Jun 03 12:55:13 vmi719182.contaboserver.net moonbase [2115]: 2022-06-03 12:55:13 [Rela>
Jun 03 12:55:17 vmi719182.contaboserver.net moonbase [2115]: 2022-06-03 12:55:17 [🌗] >
Jun 03 12:55:18 vmi719182.contaboserver.net moonbase [2115]: 2022-06-03 12:55:18 [Rela>
Jun 03 12:55:19 vmi719182.contaboserver.net moonbase [2115]: 2022-06-03 12:55:19 [Rela>
Jun 03 12:55:19 vmi719182.contaboserver.net moonbase [2115]: 2022-06-03 12:55:19 [Rela>
Jun 03 12:55:19 vmi719182.contaboserver.net moonbase [2115]: 2022-06-03 12:55:19 [Rela>
Jun 03 12:55:19 vmi719182.contaboserver.net moonbase [2115]: 2022-06-03 12:55:19 [Rela>
You can also run the following command to see logs of the tracing node spinning up: ```bash journalctl -f -u moonbeam.service ``` Your terminal should display logs similar to the following:
asm override. version=moonbase-400 (moonbase-0.tx2.au3) file=/var/lib/alphanet-data/wasm/moo nbase-runtime-400-substitute-tracing.wasm
Jun 03 12:45:55 vmi719182.contaboserver.net moonbase [2115]: 2022-06-03 12:45:55 [🌗] Found w asm override. version-moonbase-155 (moonbase-0.tx2.au3) file=/var/lib/alphanet-data/wasm/moo nbase-runtime-155-substitute-tracing. wasm
Jun 03 12:45:56 vmi719182. contaboserver.net moonbase [2115]: 2022-06-03 12:45:56 [🌗] Found w asm override. version-moonbase-501 (moonbase-0.tx2.au3) file=/var/lib/alphanet-data/wasm/moo nbase-runtime-501-substitute-tracing.wasm
Jun 03 12:45:57 vmi719182.contaboserver.net moonbase [2115]: 2022-06-03 12:45:57 [🌗] Found w asm override. version-moonbase-1200 (moonbase-0.tx2.au3) file=/var/lib/alphanet-data/wasm/mo onbase-runtime-1200-substitute-tracing.wasm
Jun 03 12:45:58 vmi719182.contaboserver.net moonbase [2115]: 2022-06-03 12:45:58 [🌗] Found w asm override. version-moonbase-47 (moonbase-1.tx2.au3) file=/var/lib/alphanet-data/wasm/moon base-runtime-47-substitute-tracing.wasm
Jun 03 12:46:00 vmi719182.contaboserver.net moonbase [2115]: 2022-06-03 12:46:00 [🌗] Found w asm override. version=moonbase-1501 (moonbase-0.tx2.au3) file=/var/lib/alphanet-data/wasm/mo onbase-runtime-1501-substitute-tracing.wasm
Jun 03 12:46:01 vmi719182.contaboserver.net moonbase [2115]: 2022-06-03 12:46:01 [🌗] Found w asm override. version-moonbase-900 (moonbase-0.tx2.au3) file=/var/lib/alphanet-data/wasm/moo nbase-runtime-900-substitute-tracing.wasm
Jun 03 12:46:04 vmi719182.contaboserver.net moonbase [2115]: 2022-06-03 12:46:04 [🌗] Found w asm override. version-moonbase-1504 (moonbase-0.tx2.au3) file=/var/lib/alphanet-data/wasm/mo onbase-runtime-1504-substitute-tracing.wasm
Jun 03 12:46:05 vmi719182.contaboserver.net moonbase [2115]: 2022-06-03 12:46:05 [🌗] Found w asm override. version-moonbase-1101 (moonbase-0.tx2.au3) file=/var/lib/alphanet-data/wasm/mo onbase-runtime-1101-substitute-tracing.wasm
Jun 03 12:46:07 vmi719182.contaboserver.net moonbase [2115]: 2022-06-03 12:46:07 [🌗] Found w asm override. version-moonbase-800 (moonbase-0.tx2.au3) file=/var/lib/alphanet-data/wasm/moo nbase-runtime-800-substitute-tracing.wasm
## Using a Tracing Node {: #using-a-tracing-node } To explore the different non-standard RPC methods available on Moonbeam, and how to use these methods with a tracing node, check out the [Debug & Trace](/builders/ethereum/json-rpc/debug-trace/) guide. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/node-operators/oracle-nodes/ --- BEGIN CONTENT --- --- title: Run Oracle Nodes description: Run an oracle node, such as a ChainLink node, on Moonbeam and provide off-chain data to smart contracts running on Moonbeam. dropdown_description: Run infrastructure for oracles services template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/node-operators/oracle-nodes/node-chainlink/ --- BEGIN CONTENT --- --- title: Run a Chainlink Node description: How to set up a Chainlink Oracle node for the Moonbeam Network to feed data on-chain to be used by smart contracts. categories: Oracle Nodes --- # Run a Chainlink Oracle Node on Moonbeam ## Introduction {: #introduction } As an open, permissionless network, anyone may choose to operate an oracle providing data to smart contracts running on Moonbeam. This article provides an overview in regards to setting up a Chainlink oracle on Moonbase Alpha. !!! note The examples provided are for demonstration purposes only. Passwords **MUST** be managed securely and never stored in plaintext. These examples assume an Ubuntu 18.04-based environment, but call-outs for MacOS are included. This guide is for a development setup only, do not use this for a production environment.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Basic Request Model {: #basic-request-model } Before going into fetching the data itself, it is important to understand the basics of the "basic request model." The generic flow for requesting and receiving data from a Chainlink oracle is as follows: 1. A client contract creates and makes a request for data to a Chainlink oracle 2. The request is sent through the `transferAndCall` function of the LINK token contract, which is an [ERC-677](https://github.com/ethereum/EIPs/issues/677){target=\_blank} compliant token, that allows tokens to be transferred and relays the request to the oracle contract 3. Once the token is transferred the LINK contract calls the oracle contract's `onTokenTransfer` function 4. The oracle contract is owned by the oracle node operators and is responsible for handling on-chain requests made through the LINK token. Once the request is received by the oracle contract an event is emitted to the node which acts upon it 5. After the request has been fulfilled by the oracle node, the node uses the `fulfillOracleRequest` function of the oracle contract to return the result to the client via the callback function defined in the original request ![Basic Request Diagram](/images/builders/integrations/oracles/chainlink/chainlink-basic-request.webp) When a request for data is created through the client contract, the following parameters need to be passed in to ensure the transaction will go through and the correct information will be returned: - **Oracle address** - address of the contract deployed by the oracle node - **Job ID** - the task to be executed. An oracle node has a set of job IDs, where each job corresponds to a task that can be requested by a user, for example, fetching a price feed - **Payment** - payment in LINK tokens that the oracle will receive for fulfiling the request ## Advanced Users {: #advanced-users } If you are familiar with running Chainlink oracle nodes, this information will get you started on the Moonbase Alpha TestNet quickly: - Chainlink documentation on [Running a Chainlink Node](https://docs.chain.link/chainlink-nodes/v1/running-a-chainlink-node){target=\_blank} - Moonbase Alpha WSS EndPoint: `wss://wss.api.moonbase.moonbeam.network` - Moonbase Alpha ChainId: `{{ networks.moonbase.chain_id }}` (hex: `{{ networks.moonbase.hex_chain_id}}`) - LINK Token on Moonbase Alpha: `0xa36085F69e2889c224210F603D836748e7dC0088` - You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} ## Checking Prerequisites {: #checking-prerequisites } To follow along with this guide, you will need to have: - [Docker installed](https://docs.docker.com/get-started/get-docker/){target=\_blank} for running Postgres DB and ChainLink node containers - An account with funds. You can create one with [MetaMask](/tokens/connect/metamask/){target=\_blank}. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} - Access to the [Remix IDE](https://remix.ethereum.org){target=\_blank} in case you want to use it to deploy the oracle contract. For more information you can check out the [Using Remix to Deploy to Moonbeam](/builders/ethereum/dev-env/remix/){target=\_blank} tutorial ## Getting Started {: #getting-started } This guide will walk through the process of setting up the oracle node, summarized as: - Setup a Chainlink node connected to Moonbase Alpha - Fund the node - Deploy an oracle contract - Create a job on the node - Bond the node and oracle - Test using a client contract ## Node Setup {: #node-setup } To get the node setup, you can take the following steps: 1. Create a new directory to place all the necessary files ```bash mkdir -p ~/.chainlink-moonbeam && cd ~/.chainlink-moonbeam ``` 2. Create a Postgres DB with Docker (MacOS users may replace `--network host \` with `-p 5432:5432`) ```bash docker run -d --name chainlink_postgres_db \ --volume chainlink_postgres_data:/var/lib/postgresql/data \ -e 'POSTGRES_PASSWORD={INSERT_PASSWORD}' \ -e 'POSTGRES_USER=chainlink' \ --network host \ -t postgres:11 ``` Make sure to replace `{INSERT_PASSWORD}` with an actual password. Docker will proceed to download the necessary images if they haven't already been downloaded 3. Create an environment file for Chainlink in the `chainlink-moonbeam` directory. This file is read on the creation of the Chainlink container. MacOS users may replace `localhost` with `host.docker.internal` ```bash echo "ROOT=/chainlink LOG_LEVEL=debug ETH_CHAIN_ID=1287 MIN_OUTGOING_CONFIRMATIONS=2 LINK_CONTRACT_ADDRESS={INSERT_LINK_TOKEN_CONTRACT_ADDRESS} CHAINLINK_TLS_PORT=0 SECURE_COOKIES=false GAS_UPDATER_ENABLED=false ALLOW_ORIGINS=* ETH_URL=wss://wss.api.moonbase.moonbeam.network DATABASE_URL=postgresql://chainlink:{INSERT_PASSWORD}@localhost:5432/chainlink?sslmode=disable MINIMUM_CONTRACT_PAYMENT=0" > ~/.chainlink-moonbeam/.env ``` Here, besides the password (`{INSERT_PASSWORD}`), you also need to provide the LINK token contract (`{INSERT_LINK_TOKEN_CONTRACT_ADDRESS}`) 4. Create an `.api` file that stores the user and password used to access the node's API, the node's operator UI, and the Chainlink command line ```bash touch .api ``` 5. Set both an email address and another password ```bash echo "{INSERT_EMAIL_ADDRESS}" > ~/.chainlink-moonbeam/.api echo "{INSERT_ANOTHER_PASSWORD}" >> ~/.chainlink-moonbeam/.api ``` 6. Lastly, you need another file that stores the wallet password for the node's address ```bash touch .password ``` 7. Set the third password ```bash echo "{INSERT_THIRD_PASSWORD}" > ~/.chainlink-moonbeam/.password ``` 8. Launch the containers (MacOS users may replace `--network host \` with `-p 6688:6688`) ```bash docker run -d --name chainlink_oracle_node \ --volume $(pwd):/chainlink \ --env-file=.env \ --network host \ -t smartcontract/chainlink:0.9.2 \ local n \ -p /chainlink/.password \ -a /chainlink/.api ``` !!! note Reminder, do not store any production passwords in a plaintext file. The examples provided are for demonstration purposes only. To verify everything is running and that the logs are progressing use: ```bash docker ps #Containers Running docker logs --tail 50 {INSERT_CONTAINER_ID} #Logs progressing ``` ![Docker logs](/images/node-operators/oracle-nodes/chainlink/chainlink-node-1.webp) ## Contract Setup {: #contract-setup } With the oracle node running, you can start to configure the smart contract side of things. First, you'll need to fund the oracle node by taking the following steps: 1. Retrieve the address that the oracle node will use to send transactions and write data on-chain by logging into the Chainlink node's UI (located at `http://localhost:6688/`). You'll need to use the credentials from the `.api` file ![Chainlink login](/images/node-operators/oracle-nodes/chainlink/chainlink-node-2.webp) 2. Go to the **Configuration Page** and copy the node address 3. Fund the node. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} ![Chainlink address](/images/node-operators/oracle-nodes/chainlink/chainlink-node-3.webp) Next, you'll need to deploy the oracle contract, which is the middleware between the chain and the node. The contract emits an event with all the necessary information, which is read by the oracle node. Then, the node fulfills the request and writes the requested data in the caller's contract. The source code of the oracle contract can be found in [Chainlink's official GitHub repository](https://github.com/smartcontractkit/chainlink/blob/v1.13.3/contracts/src/v0.6/Oracle.sol){target=\_blank}. For this example, you can use Remix to interact with Moonbase Alpha and deploy the contract. In [Remix](https://remix.ethereum.org){target=\_blank}, you can create a new file and copy the following code: ```bash pragma solidity ^0.6.6; import "@chainlink/contracts/src/v0.6/Oracle.sol"; ``` After compiling the contract, you can take the following steps to deploy and interact with the contract: 1. Head to the **Deploy and Run Transactions** tab 2. Make sure you've selected **Injected Web3** and have MetaMask connected to Moonbase Alpha 3. Verify your address is selected 4. Enter the LINK token address and click **Deploy** to deploy the contract. MetaMask will pop-up and you can confirm the transaction 5. Once deployed, under the **Deployed Contracts** section, copy the address of the contract ![Deploy Oracle using Remix](/images/node-operators/oracle-nodes/chainlink/chainlink-node-4.webp) Lastly, you have to bond the oracle node and the oracle smart contract. A node can listen to the requests sent to a certain oracle contract, but only authorized (aka. bonded) nodes can fulfill the request with a result. To bond the oracle node and smart contract, you can take the following steps: 1. To set the authorization using the `setFulfillmentPermission()` function from the oracle contract, enter the address of the node that you want to bond to the contract 2. In the `_allowed` field you can set a boolean that indicates the status of the bond, for this example enter in `true` 3. Click **transact** to send the request. MetaMask will pop-up and you can confirm the transaction 4. Check the oracle node is authorized with the `getAuthorizationStatus()` view function, passing in the oracle node address ![Authorize Chainlink Oracle Node](/images/node-operators/oracle-nodes/chainlink/chainlink-node-5.webp) ## Creating a Job {: #creating-a-job } The last step to have a fully configured Chainlink oracle is to create a job. Referring to [Chainlink’s official documentation](https://docs.chain.link/chainlink-nodes/oracle-jobs/v1/job-specifications){target=\_blank}: > A Job specifications, or specs, contain the sequential tasks that the node must perform to produce a final result. A spec contains at least one initiator and one task, which are discussed in detail below. Specs are defined using standard JSON so that they are human-readable and can be easily parsed by the Chainlink node. Seeing an oracle as an API service, a job here would be one of the functions that you can call and that will return a result. To get started creating your first job, take the following steps: 1. Go to the **Jobs** sections of your node at `http://localhost:6688/jobs` 2. Click on **New Job** ![Chainlink oracle New Job](/images/node-operators/oracle-nodes/chainlink/chainlink-node-6.webp) Next, you can create the new job: 1. Paste the following JSON. This will create a job that will request the current ETH price in USD ```json { "initiators": [ { "type": "runlog", "params": { "address": "INSERT_YOUR_ORACLE_CONTRACT_ADDRESS" } } ], "tasks": [ { "type": "httpget", "params": { "get": "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD" } }, { "type": "jsonparse", "params": { "path": ["USD"] } }, { "type": "multiply", "params": { "times": 100 } }, { "type": "ethuint256" }, { "type": "ethtx" } ] } ``` 2. Make sure you enter your oracle contract address (`INSERT_YOUR_ORACLE_CONTRACT_ADDRESS`) 3. Create the job by clicking on **Create Job** ![Chainlink New Job JSON Blob](/images/node-operators/oracle-nodes/chainlink/chainlink-node-7.webp) And that is it! You have fully set up a Chainlink oracle node that is running on Moonbase Alpha. ### Using Any API {: #using-any-api } You can also create and use a job spec to work with any API. You can search for preexisting jobs from an independent listing service such as [market.link](https://market.link){target=\_blank}. Please note that although the jobs might be implemented for other networks, you'll be able to use the job spec to create the job for your oracle node on Moonbase Alpha. Once you find a job that fits your needs, you'll need to copy the job spec JSON and use it to create a new job. For example, the previous job spec can be altered to be more generic so it can be used for any API: ```json { "initiators": [ { "type": "runlog", "params": { "address": "INSERT_YOUR_ORACLE_CONTRACT_ADDRESS" } } ], "tasks": [ { "type": "httpget" }, { "type": "jsonparse" }, { "type": "multiply" }, { "type": "ethuint256" }, { "type": "ethtx" } ] } ``` If you need a more custom solution, you can check out Chainlink's documentation to learn how to build your own [External Adapter](https://docs.chain.link/chainlink-nodes/external-adapters/developers){target=\_blank}. ## Test the Oracle {: #test-the-oracle } To verify the oracle is up and answering requests, follow the [using a Chainlink Oracle](/builders/integrations/oracles/chainlink/) tutorial. The main idea is to deploy a client contract that makes requests to the oracle, and the oracle writes the requested data into the contract's storage.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/connect/coinbase-wallet/ --- BEGIN CONTENT --- --- title: Connect Coinbase Wallet to Moonbeam description: This guide walks you through how to configure the Coinbase Wallet extension and mobile app for Moonbeam and how to create a wallet and send funds on Moonbeam. categories: Tokens and Accounts --- # Interacting with Moonbeam Using Coinbase Wallet ## Introduction {: #introduction } [Coinbase Wallet](https://wallet.coinbase.com/?_branch_match_id=977295450874474909&_branch_referrer=H4sIAAAAAAAAA8soKSkottLXT8%2FXS07SLddLzs%2FVD8%2FJynFKSy02zE4CAFZ0JzQfAAAA){target=\_blank} is a self-custody (non-custodial) wallet, like [MetaMask](/tokens/connect/metamask/){target=\_blank}, available as a mobile application for iOS and Android and a browser extension. You can use Coinbase Wallet to interact with Moonbeam, Moonriver, and the Moonbase Alpha TestNet after adding them as custom networks. Please note that Coinbase Wallet is an entirely different product from Coinbase Exchange, a custodial platform for buying and selling cryptocurrency. Holding a token in your Coinbase Wallet does not imply it is supported on Coinbase Exchange. If you send a token from your Coinbase Wallet to Coinbase Exchange that is not supported by the exchange, you will lose those funds forever. In this guide, you'll go through the process of setting up the Coinbase Wallet mobile application and browser extension and configuring it for the Moonbeam network.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Install Coinbase Wallet {: #install-coinbase-wallet } You can [download Coinbase Wallet](https://wallet.coinbase.com/?_branch_match_id=977295450874474909&_branch_referrer=H4sIAAAAAAAAA8soKSkottLXT8%2FXS07SLddLzs%2FVD8%2FJynFKSy02zE4CAFZ0JzQfAAAA){target=\_blank} as a mobile app from the iOS App Store or Google Play Store, or as a desktop browser extension from the Chrome Store. The interfaces for the mobile app and browser extension are quite similar, so you can adapt the following instructions for the browser extension. The one major difference between the two is that when you add Moonbase Alpha as a custom network, you can interact with the network on the browser extension but not from the mobile app. This difference only applies to Moonbase Alpha. If you're connecting to Moonbeam or Moonriver, you'll be able to interact with either network from both the browser extension and mobile app. ## Create a Wallet {: #create-a-wallet } After installing and opening the app, you'll be greeted with the option to create a new wallet or import an existing one. For this exercise, set up a new wallet by tapping **Create a new wallet**. You'll be prompted to create a passcode, and once you've entered in your passcode, you'll need to verify it by entering it again a second time. ![Create an account on the Coinbase Wallet mobile app.](/images/tokens/connect/coinbase-wallet/coinbase-1.webp) Once you've created your passcode, your wallet will be created. The last step to take is to secure your account by backing up your wallet's recovery phrase. To back up your wallet, you can take the following steps: 1. Navigate to the **Settings** screen 2. Choose **Security** from the menu 3. Tap on your wallet that you want to back up; it should say **Not backed up** next to it 4. Enter your passcode 5. Select how you want to back up your recovery phrase: make an encrypted backup of the seed phrase to iCloud (iOS) or Google Drive (Android), save the phrase manually, or do both. If you are backing up your phrase to the iCloud or Google Drive, you'll have to create a password that will secure your phrase in the cloud. **This password cannot be reset, so you'll need to keep it safe**. If you are manually saving your phrase, make sure you store it exactly as displayed and save it in a secure location 6. When you're done, click **Complete backup** ![Back up your wallet's recovery phrase through the settings menu.](/images/tokens/connect/coinbase-wallet/coinbase-2.webp) !!! note If you're using the browser extension, you'll follow a slightly different flow, as you'll be prompted to back up your wallet right away, and you'll only have the option to manually do this. Congratulations! You've completed the setup steps, and your wallet is now fully initialized. In the next step, you'll see how you can connect Coinbase Wallet to the Moonbeam network. ### Connect Coinbase Wallet to Moonbeam {: #connect-coinbase-to-moonbeam } Although Coinbase Wallet has a built-in browser, it doesn't currently support automatically adding custom networks, so you'll have to add the network details manually. To do so, perform the following steps: 1. Navigate to the **Settings** tab 2. Tap on **Networks** 3. Tap on the **+** icon in the upper right corner 4. Here, you can fill in the network details for Moonbeam, Moonriver, or the Moonbase Alpha TestNet === "Moonbeam" | Variable | Value | |:-------------------------:|:--------------------------------------------------------------------------------:| | Network Name | `Moonbeam` | | RPC URL | `{{ networks.moonbeam.public_rpc_url }}` | | ChainID | `{{ networks.moonbeam.chain_id }}` (hex: `{{ networks.moonbeam.hex_chain_id }}`) | | Symbol (Optional) | `GLMR` | | Block Explorer (Optional) | `{{ networks.moonbeam.block_explorer }}` | === "Moonriver" | Variable | Value | |:-------------------------:|:----------------------------------------------------------------------------------:| | Network Name | `Moonriver` | | RPC URL | `{{ networks.moonriver.public_rpc_url }}` | | ChainID | `{{ networks.moonriver.chain_id }}` (hex: `{{ networks.moonriver.hex_chain_id }}`) | | Symbol (Optional) | `MOVR` | | Block Explorer (Optional) | `{{ networks.moonriver.block_explorer }}` | === "Moonbase Alpha" | Variable | Value | |:-------------------------:|:--------------------------------------------------------------------------------:| | Network Name | `Moonbase Alpha` | | RPC URL | `{{ networks.moonbase.rpc_url }}` | | ChainID | `{{ networks.moonbase.chain_id }}` (hex: `{{ networks.moonbase.hex_chain_id }}`) | | Symbol (Optional) | `DEV` | | Block Explorer (Optional) | `{{ networks.moonbase.block_explorer }}` | 5. Press **Add Network** once finished ![Add Moonbeam as a custom network through the network settings.](/images/tokens/connect/coinbase-wallet/coinbase-3.webp) After returning to the **Networks** screen, you can view the newly added network from the **Custom** tab. To interact with Moonbeam, you'll need to mark the network as **Active** by taking the following steps: 1. Tap on **Moonbeam** 2. Scroll down to the bottom of the screen and toggle the **Active network** switch to on 3. Tap **Save** ![Set Moonbeam as the active network.](/images/tokens/connect/coinbase-wallet/coinbase-4.webp) ### Receiving Funds {: #receiving-funds } To view and manage your assets, you can click on **Assets** from the bottom navigation menu. Since you created a new wallet in this demo, the app displays a balance of `$0.00` and doesn't list any assets in the **Crypto** tab. You can change this by sending some GLMR to this account. To send funds to your Coinbase Wallet account, take the following steps: 1. Tap on **Receive** 2. Tap on the QR code icon or the copy icon next to **Ethereum address**. Since Moonbeam is Ethereum-compatible, you can use the Ethereum account it provides you with on Moonbeam ![Copy your Ethereum address so you can receive funds.](/images/tokens/connect/coinbase-wallet/coinbase-5.webp) Now that you have your receiving address, you can send assets to it. To view your assets once they arrive, you'll need to make sure that you've activated the correct network from the network's configuration screen in the **Networks** settings, as outlined in the [previous section](#connect-coinbase-to-moonbeam). ### Sending Funds {: #sending-funds } To send funds from your Coinbase Wallet, navigate to the **Assets** tab, then take the following steps: 1. Tap **Send** 2. On the next screen, enter the amount of the asset you'd like to send 3. Tap **Next** 4. Enter the address you'd like to send it to 5. Tap **Confirm** to continue 6. Review the transaction details to ensure accuracy, then press **Send** 7. Upon successfully sending the transaction, you can tap **Done** ![Send funds.](/images/tokens/connect/coinbase-wallet/coinbase-6.webp) From the **Transactions** tab, you'll be able to see your outgoing transactions, including the address you sent the transaction to, the status of the transaction, and the amount you sent. You can tap on each transaction to find out more information. ![View your transaction history from the transactions screen.](/images/tokens/connect/coinbase-wallet/coinbase-7.webp) And that's it! You've successfully set up your Coinbase Wallet app, connected it to the Moonbeam network, and learned how to send and receive funds. ## Subscribe to Updates from Moonbeam {: #subscribe-to-updates-from-moonbeam } Coinbase Wallet has a messaging and subscription feature that uses [XMTP](https://docs.xmtp.org/){target=\_blank}, an on-chain messaging network designed to deliver fully encrypted messages between wallet addresses. In addition to messaging other Coinbase Wallet users who have enabled this feature, you can subscribe to updates from the Moonbeam Foundation. These updates are designed to provide timely and essential information from the Moonbeam Foundation, such as governance and protocol upgrade notifications. ### Setting up Coinbase Wallet on Mobile {: #setting-up-coinbase-wallet-on-mobile } To enable XMTP in your Coinbase Wallet App and subscribe to Moonbeam, you must have both the browser extension and the wallet dApp. The [Coinbase Wallet download page](https://www.coinbase.com/wallet/downloads){target=\_blank} has links to both. After installation, ensure you have the same seed in both (e.g., don't create separate seed phrases for each). To get started with XMTP, from the first tab of the Coinbase Wallet App (the Assets tab), take the following steps: 1. Click the messaging icon in the upper right corner 2. Press **Start Messaging** ![Sign up for XMTP.](/images/tokens/connect/coinbase-wallet/coinbase-8.webp) Next, you'll be prompted to configure your notification settings to allow push notifications. Take the following steps: 1. Press **Enable Push Notifications** 2. Press **Allow** in the resulting prompt ![Configure notifications.](/images/tokens/connect/coinbase-wallet/coinbase-9.webp) ### Subscribing in the Moonbeam dApp {: #subscribing-in-the-moonbeam-dapp } As a quick reminder, you'll need to have the Coinbase Wallet extension installed on your computer's browser loaded with the same seed as the one used on your phone. To minimize the risk of errors, ensure that the Coinbase Wallet extension is the only cryptocurrency wallet extension active in your browser. You can temporarily disable other wallet apps as follows: 1. Click the Extensions Icon in the upper right corner 2. Click **Manage Extensions** 3. Disable any other active wallet extensions !!! note Disabling MetaMask keeps your keys intact, but removing MetaMask could result in losing your private keys. Be careful not to accidentally remove a wallet entirely. ![Disable other active crypto extensions.](/images/tokens/connect/coinbase-wallet/coinbase-10.webp) Then, head to the [Moonbeam dApp](https://apps.moonbeam.network/moonbeam){target=\_blank}, and take the following steps to connect the Coinbase Wallet extension: 1. Press **Connect wallet** 2. Select **Coinbase Wallet** from the list of options 3. Press **Connect** when Coinbase Wallet pops up ![Connect the Moonbeam dApp to Coinbase Wallet](/images/tokens/connect/coinbase-wallet/coinbase-11.webp) To subscribe, take the following steps: 1. Press the Mailbox icon in the upper right 2. Press **Subscribe** in the pop-up ![Subscribe in the Moonbeam dApp](/images/tokens/connect/coinbase-wallet/coinbase-12.webp) 1. Press **Connect your wallet** in the resulting Coinbase pop up 2. Next, you'll have two signature requests in your Coinbase Wallet. The first one asks you to enable XTMP Identity. Press **Sign** 3. The next signature request is to enable the subscription to messages from the Moonbeam Foundation. Press **Sign** !!! note You may receive three signature requests in the prior step if you didn't enable XMTP on your phone. The third signature request will take care of that, however, you may still need to enable notifications for the Coinbase Wallet app on your phone to ensure you receive them. ![Confirm subscription](/images/tokens/connect/coinbase-wallet/coinbase-13.webp) And that's it! Once done, you'll see the below confirmation screen. For questions about Coinbase Wallet, please refer to the [Coinbase Wallet Help](https://help.coinbase.com/en/wallet/messaging/info#connecting-to-the-xmtp-network){target=\_blank}. ![Finalized](/images/tokens/connect/coinbase-wallet/coinbase-14.webp) ## Limitations {: #limitations } - At this time, Coinbase Wallet displays only outgoing transactions in your transaction history in the app. You can see your full transaction history, including incoming transactions, by looking up your address on a blockchain explorer such as [Moonscan](https://moonscan.io){target=\_blank} - On the Coinbase Wallet mobile app, you can add Moonbase Alpha as a custom network; however, you won't be able to see your balances or send transactions from the app. You'll need to use the browser extension instead ## Additional Resources {: #additional-resources } - [Coinbase Wallet FAQ](https://help.coinbase.com/en/wallet){target=\_blank} - [Coinbase Wallet Getting Started Guide](https://www.coinbase.com/wallet/articles/getting-started-mobile){target=\_blank}
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/connect/ --- BEGIN CONTENT --- --- title: Connect your Wallet to Moonbeam description: Learn about some of the supported wallets available for Moonbeam, and how to connect your wallet and use it to interact with Moonbeam networks. dropdown_description: Connect your wallet to Moonbeam template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/connect/ledger/ethereum/ --- BEGIN CONTENT --- --- title: Ethereum App description: This guide walks you through how to use your Ledger hardware wallet to sign transactions in Moonbeam-based networks using the Ethereum app on Ledger Live. categories: Tokens and Accounts, Ethereum Toolkit --- # Interacting with Moonbeam Using Ledger and the Ethereum App ## Introduction {: #introduction } Hardware wallets provide a safer way to store crypto funds because the private key (used for signing transactions) is stored offline. Ledger offers two hardware wallet solutions at the time of writing: Ledger Nano S and Ledger Nano X. For Moonbeam, Moonriver, and the Moonbase Alpha TestNet, you can use the Ethereum app on Ledger Live by setting the chain ID. For Moonbeam, the chain ID is 1284, for Moonriver it's 1285, and for Moonbase Alpha it's 1287. For Moonbeam and Moonriver you also have the option of using the dedicated [Moonbeam app](/tokens/connect/ledger/moonbeam/){target=\_blank} or [Moonriver app](/tokens/connect/ledger/moonriver/){target=\_blank} on Ledger Live, this way you do not have to worry about setting the chain ID and you know you are connected to the right network. Please note that you can only use the Moonbeam app to connect to the Moonbeam network, and the Moonriver app can only be used to connect to the Moonriver network. These dedicated apps will not work for other Moonbeam-based networks. In this tutorial, you will learn how to get started with your Ledger hardware wallet on Moonbeam using the Ethereum app. This guide only illustrates the steps for a Ledger Nano X device, but you can follow along with a Ledger Nano S as well.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Checking Prerequisites {: #checking-prerequisites } Before you get started, update [Ledger Live](https://www.ledger.com/ledger-live){target=\_blank} to the latest version available. Also, make sure you've your Ledger hardware wallet device running the latest firmware. The Ledger support website offers tutorials on [how to update](https://support.ledger.com/article/360013349800-zde){target=\_blank} the firmware. At the time of writing, the following versions were used: - [Ledger Live 2.35.1](https://support.ledger.com/article/What-s-new-in-Ledger-Live){target=\_blank} - [Ledger Nano S firmware v2.0.0](https://support.ledger.com/article/360010446000-zd){target=\_blank} - [Ledger Nano X firmware v2.0.1](https://support.ledger.com/article/360014980580-zd){target=\_blank} As of November 29, 2022, the Moonbeam and Ledger Live integration was released, allowing you to send and receive GLMR tokens with your Ledger device directly in Ledger Live. With this integration, you'll no longer need to connect your Ledger to MetaMask. If you prefer this method, please skip ahead to the [Use Ledger Live to Send & Receive GLMR](#use-ledger-live) section of this guide. If you prefer to use MetaMask as an intermediary between your Ledger device and Moonbeam, make sure that your MetaMask is [connected to Moonbeam](/tokens/connect/metamask/){target=\_blank}. As of [MetaMask version 10.5.0](https://consensys.io/blog/metamask-and-ledger-integration-fixed){target=\_blank}, connecting your Ledger device with MetaMask on Chrome is easy again. You just need to have the latest version of MetaMask installed. ## Install the Ledger Live App {: install-the-ledger-live-app } If you want to connect to Moonbeam, Moonriver, or the Moonbase Alpha TestNet you can do so by installing the Ethereum app, and later on you'll need to specify a chain ID. To get started, open up Ledger Live and: 1. Select **Manager** from the menu 2. Connect and unlock your device (this must be done before installation) 3. In the **App catalog** search for Ethereum (ETH) and click **Install**. Your Ledger device will show **Processing** and once the installation is complete, the app will appear on your Ledger device In the Ledger Live app, depending on which app(s) you installed you should see them listed under the **Apps installed** tab on the **Manager** page. After the app(s) have been successfully installed, you can close out of Ledger Live. Moonriver Ledger App Installed ## Import your Ledger Account to MetaMask {: #import-your-ledger-account-to-metamask } Now that you've installed the app(s) on Ledger Live, you can connect your Ledger to the computer and unlock it, and open the Ethereum app. Then import your Ledger account to MetaMask using the following steps: 1. Click on the top-right logo to expand the menu 2. Select **Connect Hardware Wallet** ![MetaMask Connect Hardware Wallet](/images/tokens/connect/ledger/ethereum/ledger-2.webp) In the next screen, you are prompted to select which hardware wallet you'll like to use in MetaMask. At the moment of writing, only Ledger and Trezor hardware wallets are supported. Here, take the following steps: 1. Select the Ledger logo 2. Click on **Continue** ![MetaMask Select Ledger Hardware Wallet](/images/tokens/connect/ledger/ethereum/ledger-3.webp) If you're using Chrome or a Chrome-based browser like Brave, you'll be prompted to select your Ledger device to connect via WebHID: 1. Select your Ledger device from the pop-up 2. Click **Connect** ![Ledger on Chrome](/images/tokens/connect/ledger/ethereum/ledger-4.webp) If a pop-up doesn't appear, you may need to change your MetaMask settings to enable a WebHID connection. You can check and update your MetaMask settings by following these steps: 1. Expand the top-right menu and go to **Settings** 2. Navigate to **Advanced** 3. Scroll down to **Preferred Ledger Connection Type** and select **WebHID** from the dropdown !!! note The **Preferred Ledger Connection Type** setting is only available on Chrome and Chrome-based browsers. This setting doesn't exist on other browsers such as Firefox. If MetaMask was able to connect successfully to your Ledger device, you should see a list of five Moonbeam/Ethereum-styled accounts. If not, double-check that Ledger Live is closed, you've connected your Ledger device to the computer, and unlocked it, and make sure the Ethereum app is open. ### Import Accounts and View Balances {: #import-accounts-and-view-balances } From the list of accounts, take the following steps: 1. Select the accounts you would like to import from your Ledger device 2. Click on **Unlock** ![MetaMask Select Ethereum Accounts to Import](/images/tokens/connect/ledger/ethereum/ledger-5.webp) If you've imported your Ledger account successfully, you should see your account and balance displayed in the main MetaMask screen like shown in the following image: ![MetaMask Successfully Imported Ledger Account](/images/tokens/connect/ledger/ethereum/ledger-6.webp) You can switch accounts in MetaMask at any time to view the balance of your other imported Ledger accounts. You've now successfully imported a Moonbeam compatible account from your Ledger device and are now ready to start interacting with your Ledger device. ## Receive Tokens {: #receive-tokens } To get started interacting with your Ledger device, you will need to send some funds to it. Copy your address from MetaMask by clicking on your account name and address in MetaMask. ![MetaMask Copy Account](/images/tokens/connect/ledger/ethereum/ledger-7.webp) Next, you will need to obtain some GLMR, MOVR, or DEV tokens and using the address you just copied, send the tokens to your account. After the transaction has successfully gone through, you will see your balance update. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank}. ## Send Tokens {: #send-tokens } Next up is sending and signing transactions on Moonbeam using your Ledger device. To get started sending a transaction, click on the **Send** button: ![MetaMask Ledger Account Funded](/images/tokens/connect/ledger/ethereum/ledger-8.webp) As you would in a standard transaction, set the recipient address, enter the number of tokens to send, review transaction details and confirm it. This will initiate the transaction signature wizard in your Ledger device. Here, take the following steps: 1. Click the button to proceed to the next screen. Your Ledger device is only warning you to review the transaction 2. Check the number of tokens being sent then proceed to the next screen 3. Check the recipient's address and proceed to the next screen 4. Check the chain ID of the network. This information confirms which network MetaMask is connected to. For Moonbeam the chain ID is 1284 (hex: 0x504), Moonriver is 1285 (hex: 0x505), and Moonbase Alpha is 1287 (hex: 0x507). When ready, proceed to the next screen 5. Check the max fees applicable to this transaction. This is the gas price multiplied by the gas limit you've set on MetaMask. When ready, proceed to the next screen 6. If you agree with all the transaction details, approve it. This will sign the transaction and will trigger MetaMask to send it. If you don't agree with all the transaction details, reject it. This will cancel the transaction, and MetaMask will mark it as failed ![MetaMask Ledger Transaction Wizard](/images/tokens/connect/ledger/ethereum/ledger-9.webp) Right after you've approved the transaction, MetaMask sends it to the network. Once the transaction is confirmed, it will be displayed as **Send** on the **Activity** tab in MetaMask. ![MetaMask Ledger Transaction Wizard](/images/tokens/connect/ledger/ethereum/ledger-10.webp) And that is it! You've signed a transaction and sent some tokens on Moonbeam using your Ledger hardware wallet! ## Interact with Contracts Using your Ledger {: #interact-with-contracts-using-your-ledger } By default, Ledger devices don't admit a `data` field in the transaction object. Consequently, users can't deploy or interact with smart contracts. However, if you want to use your Ledger hardware wallet for transactions related to smart contracts, you need to change a configuration parameter inside the app on your device. To do so, take the following steps: 1. On your Ledger, open the Moonriver or Ethereum app 2. Navigate to **Settings** 3. Find the **Blind signing** page. It should state **NOT Enabled** at the bottom 4. Select/validate the option to change its value to **Enabled** !!! note This option is necessary to use your Ledger device to interact with ERC-20 token contracts that might live inside the Moonbeam ecosystem. ![MetaMask Ledger Allow Contracts Tx](/images/tokens/connect/ledger/ethereum/ledger-11.webp) ## Use Ledger Live to Send & Receive GLMR {: #use-ledger-live } You can also use your Ledger device to send and receive GLMR tokens securely from within Ledger Live. This enables you to manage your GLMR tokens without connecting your device to MetaMask. When you open up the Ledger Live app, make sure that you've installed the latest updates. If there are any pending updates that need to be installed, there will be a banner at the top of the screen that prompts you to install the updates. To get started, you'll need to login to your Ledger device to unlock it. From Ledger Live, click on **My Ledger**. On your device, you'll be prompted to allow Ledger manager; you can click both buttons on your device to allow it. Once on the Ledger manager, you'll need to make sure that your firmware is up to date, and if the Moonbeam and/or Ethereum apps need to be updated, go ahead and install the latest versions. Next, you'll need to add an account to your Ledger Live app. To do so, you can take the following steps: 1. Click on **Accounts** from the left-side menu 2. Select **Add account** 3. A dropdown will appear. Search for GLMR and **Moonbeam (GLMR)** should appear for you to select 4. Click **Continue** ![Add account to Ledger Live](/images/tokens/connect/ledger/moonbeam/ledger-12.webp) Next, you'll be able to enter an account name and click **Add account**. If your account was successfully added, you can click **Done** and your account will appear in your list of accounts. ### Receive Tokens To receive GLMR to your Ledger device, you can take the following steps from Ledger Live: 1. Click on **Receive** from the left-side menu 2. A pop-up will appear. You can select your Moonbeam account where you want to receive tokens from the **Account to credit** dropdown 3. Click **Continue** ![Verify receiving address in Ledger Live](/images/tokens/connect/ledger/moonbeam/ledger-13.webp) Next, your address should appear on Ledger Live, and you'll be prompted to verify your address on your Ledger device. On your device, you can take the following steps: 1. You should see **Verify Address** on your device's screen. Click the right button to start verifying your address 2. On the next screen, you should see your address. Compare the address on your device to the one displayed on Ledger Live and verify it matches. At this time, you'll want to copy the address from Ledger Live so you can send a transaction to it. Click the right button to continue 3. Now, you should see the **Approve** screen. If the addresses match, you can click both buttons on your device to approve the verification. Otherwise, click the right button again to get to the **Reject** screen where you can click both buttons to reject the verification ![Verify receiving address on Ledger device](/images/tokens/connect/ledger/moonbeam/ledger-14.webp) Over on Ledger Live, you'll see that your address has been shared securely, and you can click **Done**. Now, you can send some GLMR to your Ledger account. ### Send Tokens To send GLMR from your Ledger device, you can take the following steps from Ledger Live: 1. Click on **Send** from the left-side menu 2. A pop-up will appear. From the **Account to debit** dropdown, you can select your Moonbeam account that you want to send tokens from 3. Enter an address in the **Receipient address** field 4. Click **Continue** ![Send transaction in Ledger Live](/images/tokens/connect/ledger/moonbeam/ledger-15.webp) On the next screen, you can enter the amount of GLMR that you would like to send and click **Continue**. ![Enter amount to send in Ledger Live](/images/tokens/connect/ledger/moonbeam/ledger-16.webp) The last step on Ledger Live is to verify that the transaction details are correct. If everything looks good, you can click **Continue**. Then you'll be prompted to confirm the transaction on your Ledger device: 1. The first screen will be the **Review transaction** screen. Click the right button to proceed to the next screen 2. Verify the amount of GLMR you're sending and click the right button to proceed 3. Verify the address you're sending the GLMR to and click the right button to proceed 4. The **Network** screen should show **Moonbeam**. Click the right button to proceed 5. Review the **Max Fees** and click the right button to proceed 6. If everything looks good, you can click both buttons to **Accept and send** the transaction. Otherwise, you can click the right button to get to the **Reject** screen where you can click both buttons to reject the transaction ![Send transaction from Ledger device](/images/tokens/connect/ledger/moonbeam/ledger-17.webp) On Ledger Live, you should see that your transaction was sent, and you can view the details of the transaction. Once the transaction has been confirmed, your GLMR balance will update. And that is it! You've successfully used the Moonbeam Ledger Live integration to receive and send tokens with your Ledger device directly from Ledger Live!
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/connect/ledger/ --- BEGIN CONTENT --- --- title: Connect & Use Ledger description: Learn how to use your Ledger hardware wallet to sign transactions on Moonbeam networks using the native Moonbeam and Moonriver apps and the Ethereum app. template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/connect/ledger/moonbeam/ --- BEGIN CONTENT --- --- title: Moonbeam App description: This guide walks you through how to use your Ledger hardware wallet to sign transactions in Moonbeam using the native Moonbeam Ledger Live app. categories: Tokens and Accounts, Ethereum Toolkit --- # Interacting with Moonbeam Using Ledger and the Moonbeam App
## Introduction {: #introduction } Hardware wallets provide a safer way to store crypto funds because the private key (used for signing transactions) is stored offline. Ledger offers two hardware wallet solutions at the time of writing: Ledger Nano S and Ledger Nano X. You can interact with Moonbeam using your Ledger hardware wallet through the Moonbeam Ledger Live app. With the dedicated Moonbeam app, you do not have to worry about setting the chain ID and you know you are connected to the right network. Please note that you can only use the Moonbeam app to connect to the Moonbeam network, it cannot be used to connect to other Moonbeam-based networks. You also have the option of using the Ethereum app to connect to Moonbeam. The main difference between using the Moonbeam and the Ethereum app is that you have to specify the chain ID when you use the Ethereum app, which is 1284 for Moonbeam. If you're interested in using the Ethereum app instead, you can check out the [Interacting with Moonbeam Using Ledger and the Ethereum App](/tokens/connect/ledger/ethereum/){target=\_blank} guide. In this tutorial, you will learn how to get started with your Ledger hardware wallet on Moonbeam using the Moonbeam app. This guide only illustrates the steps for a Ledger Nano X device, but you can follow along with a Ledger Nano S as well.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Checking Prerequisites {: #checking-prerequisites } Before you get started, update [Ledger Live](https://www.ledger.com/ledger-live){target=\_blank} to the latest version available. Also, make sure you've your Ledger hardware wallet device running the latest firmware. The Ledger support website offers tutorials on [how to update](https://support.ledger.com/article/360013349800-zde){target=\_blank} the firmware. At the time of writing, the following versions were used: - [Ledger Live 2.35.1](https://support.ledger.com/article/What-s-new-in-Ledger-Live){target=\_blank} - [Ledger Nano S firmware v2.0.0](https://support.ledger.com/article/360010446000-zd){target=\_blank} - [Ledger Nano X firmware v2.0.1](https://support.ledger.com/article/360014980580-zd){target=\_blank} As of November 29, 2022, the Moonbeam and Ledger Live integration was released, allowing you to send and receive GLMR tokens with your Ledger device directly in Ledger Live. With this integration, you'll no longer need to connect your Ledger to MetaMask. If you prefer this method, please skip ahead to the [Use Ledger Live to Send & Receive GLMR](#use-ledger-live) section of this guide. If you prefer to use MetaMask as an intermediary between your Ledger device and Moonbeam, make sure that your MetaMask is [connected to Moonbeam](/tokens/connect/metamask/){target=\_blank}. As of [MetaMask version 10.5.0](https://consensys.io/blog/metamask-and-ledger-integration-fixed){target=\_blank}, connecting your Ledger device with MetaMask on Chrome is easy again. You just need to have the latest version of MetaMask installed. ## Install the Moonbeam Ledger Live App {: install-the-moonbeam-ledger-live-app } The Moonbeam app is dependent on the Ethereum app, so first you will need to install the Ethereum app. Once the Ethereum app is installed you will be able to install the Moonbeam app without a problem. Please note that the Moonbeam app is only for the Moonbeam network, it will not work for Moonriver or Moonbase Alpha. To get started, open up Ledger Live and: 1. Select **Manager** from the menu 2. Connect and unlock your device (this must be done before installation) 3. In the **App catalog** search for Ethereum (ETH) and click **Install**. Your Ledger device will show **Processing** and once the installation is complete, the app will appear on your Ledger device 4. Search for Moonbeam (GLMR) in the **App catalog** and click **Install**. Again, your Ledger device will show **Processing** and once complete, the Moonbeam app will appear on your Ledger device In the Ledger Live app, you should see the Ethereum and Moonbeam app listed under the **Apps installed** tab on the **Manager** page. After the apps have been successfully installed, you can close out of Ledger Live. Moonriver Ledger App Installed ## Import your Ledger Account to MetaMask {: #import-your-ledger-account-to-metamask } Now that you've installed the Ledger Live apps, you can connect your Ledger to the computer, unlock it, and open the Moonbeam app. Then import your Ledger account to MetaMask using the following steps: 1. Click on the top-right logo to expand the menu 2. Select **Connect Hardware Wallet** ![MetaMask Connect Hardware Wallet](/images/tokens/connect/ledger/moonbeam/ledger-2.webp) In the next screen, you are prompted to select which hardware wallet you'll like to use in MetaMask. At the moment of writing, only Ledger and Trezor hardware wallets are supported. Here, take the following steps: 1. Select the Ledger logo 2. Click on **Continue** ![MetaMask Select Ledger Hardware Wallet](/images/tokens/connect/ledger/moonbeam/ledger-3.webp) If you're using Chrome or a Chrome-based browser like Brave, you'll be prompted to select your Ledger device to connect via WebHID: 1. Select your Ledger device from the pop-up 2. Click **Connect** ![Ledger on Chrome](/images/tokens/connect/ledger/moonbeam/ledger-4.webp) If a pop-up doesn't appear, you may need to change your MetaMask settings to enable a WebHID connection. You can check and update your MetaMask settings by following these steps: 1. Expand the top-right menu and go to **Settings** 2. Navigate to **Advanced** 3. Scroll down to **Preferred Ledger Connection Type** and select **WebHID** from the dropdown !!! note The **Preferred Ledger Connection Type** setting is only available on Chrome and Chrome-based browsers. This setting doesn't exist on other browsers such as Firefox. If MetaMask was able to connect successfully to your Ledger device, you should see a list of five Moonbeam/Ethereum-styled accounts. If not, double-check that Ledger Live is closed, you've connected your Ledger device to the computer, unlocked it, and have the Moonbeam app open. ### Import Accounts and View Balances {: #import-accounts-and-view-balances } From the list of accounts, take the following steps: 1. Select the accounts you would like to import from your Ledger device 2. Click on **Unlock** ![MetaMask Select Ethereum Accounts to Import](/images/tokens/connect/ledger/moonbeam/ledger-5.webp) If you've imported your Ledger account successfully, you should see your account and balance displayed in the main MetaMask screen like shown in the following image: ![MetaMask Successfully Imported Ledger Account](/images/tokens/connect/ledger/moonbeam/ledger-6.webp) You can switch accounts in MetaMask at any time to view the balance of your other imported Ledger accounts. You've now successfully imported a Moonbeam compatible account from your Ledger device and are now ready to start interacting with your Ledger device. ## Receive Tokens {: #receive-tokens } To get started interacting with your Ledger device, you will need to send some funds to it. Copy your address from MetaMask by clicking on your account name and address in MetaMask. ![MetaMask Copy Account](/images/tokens/connect/ledger/moonbeam/ledger-7.webp) Next, you will need to obtain some GLMR tokens and using the address you just copied, send the tokens to your account. After the transaction has successfully gone through, you will see your balance update. ## Send Tokens {: #send-tokens } Next up is sending and signing transactions on Moonbeam using your Ledger device. To get started sending a transaction, click on the **Send** button: ![MetaMask Ledger Account Funded](/images/tokens/connect/ledger/moonbeam/ledger-8.webp) As you would in a standard transaction, set the recipient address, enter the number of tokens to send, review transaction details and confirm it. This will initiate the transaction signature wizard in your Ledger device. Here, take the following steps: 1. Click the button to proceed to the next screen. Your Ledger device is only warning you to review the transaction 2. Check the number of tokens being sent then proceed to the next screen 3. Check the recipient's address and proceed to the next screen 4. Check the max fees applicable to this transaction. This is the gas price multiplied by the gas limit you've set on MetaMask. When ready, proceed to the next screen 5. If you agree with all the transaction details, approve it. This will sign the transaction and will trigger MetaMask to send it. If you don't agree with all the transaction details, reject it. This will cancel the transaction, and MetaMask will mark it as failed ![MetaMask Ledger Transaction Wizard](/images/tokens/connect/ledger/moonbeam/ledger-9.webp) Right after you've approved the transaction, MetaMask sends it to the network. Once the transaction is confirmed, it will be displayed as **Send** on the **Activity** tab in MetaMask. ![MetaMask Ledger Transaction Wizard](/images/tokens/connect/ledger/moonbeam/ledger-10.webp) And that is it! You've signed a transaction and sent some GLMR tokens using your Ledger hardware wallet! ## Interact with Contracts Using your Ledger {: #interact-with-contracts-using-your-ledger } By default, Ledger devices don't admit a `data` field in the transaction object. Consequently, users can't deploy or interact with smart contracts. However, if you want to use your Ledger hardware wallet for transactions related to smart contracts, you need to change a configuration parameter inside the app on your device. To do so, take the following steps: 1. On your Ledger, open the Moonriver or Ethereum app 2. Navigate to **Settings** 3. Find the **Blind signing** page. It should state **NOT Enabled** at the bottom 4. Select/validate the option to change its value to **Enabled** !!! note This option is necessary to use your Ledger device to interact with ERC-20 token contracts that might live inside the Moonbeam ecosystem. ![MetaMask Ledger Allow Contracts Tx](/images/tokens/connect/ledger/moonbeam/ledger-11.webp) ## Use Ledger Live to Send & Receive GLMR {: #use-ledger-live } You can also use your Ledger device to send and receive GLMR tokens securely from within Ledger Live. This enables you to manage your GLMR tokens without connecting your device to MetaMask. When you open up the Ledger Live app, make sure that you've installed the latest updates. If there are any pending updates that need to be installed, there will be a banner at the top of the screen that prompts you to install the updates. To get started, you'll need to login to your Ledger device to unlock it. From Ledger Live, click on **My Ledger**. On your device, you'll be prompted to allow Ledger manager; you can click both buttons on your device to allow it. Once on the Ledger manager, you'll need to make sure that your firmware is up to date, and if the Moonbeam and/or Ethereum apps need to be updated, go ahead and install the latest versions. Next, you'll need to add an account to your Ledger Live app. To do so, you can take the following steps: 1. Click on **Accounts** from the left-side menu 2. Select **Add account** 3. A dropdown will appear. Search for GLMR and **Moonbeam (GLMR)** should appear for you to select 4. Click **Continue** ![Add account to Ledger Live](/images/tokens/connect/ledger/moonbeam/ledger-12.webp) Next, you'll be able to enter an account name and click **Add account**. If your account was successfully added, you can click **Done** and your account will appear in your list of accounts. ### Receive Tokens To receive GLMR to your Ledger device, you can take the following steps from Ledger Live: 1. Click on **Receive** from the left-side menu 2. A pop-up will appear. You can select your Moonbeam account where you want to receive tokens from the **Account to credit** dropdown 3. Click **Continue** ![Verify receiving address in Ledger Live](/images/tokens/connect/ledger/moonbeam/ledger-13.webp) Next, your address should appear on Ledger Live, and you'll be prompted to verify your address on your Ledger device. On your device, you can take the following steps: 1. You should see **Verify Address** on your device's screen. Click the right button to start verifying your address 2. On the next screen, you should see your address. Compare the address on your device to the one displayed on Ledger Live and verify it matches. At this time, you'll want to copy the address from Ledger Live so you can send a transaction to it. Click the right button to continue 3. Now, you should see the **Approve** screen. If the addresses match, you can click both buttons on your device to approve the verification. Otherwise, click the right button again to get to the **Reject** screen where you can click both buttons to reject the verification ![Verify receiving address on Ledger device](/images/tokens/connect/ledger/moonbeam/ledger-14.webp) Over on Ledger Live, you'll see that your address has been shared securely, and you can click **Done**. Now, you can send some GLMR to your Ledger account. ### Send Tokens To send GLMR from your Ledger device, you can take the following steps from Ledger Live: 1. Click on **Send** from the left-side menu 2. A pop-up will appear. From the **Account to debit** dropdown, you can select your Moonbeam account that you want to send tokens from 3. Enter an address in the **Receipient address** field 4. Click **Continue** ![Send transaction in Ledger Live](/images/tokens/connect/ledger/moonbeam/ledger-15.webp) On the next screen, you can enter the amount of GLMR that you would like to send and click **Continue**. ![Enter amount to send in Ledger Live](/images/tokens/connect/ledger/moonbeam/ledger-16.webp) The last step on Ledger Live is to verify that the transaction details are correct. If everything looks good, you can click **Continue**. Then you'll be prompted to confirm the transaction on your Ledger device: 1. The first screen will be the **Review transaction** screen. Click the right button to proceed to the next screen 2. Verify the amount of GLMR you're sending and click the right button to proceed 3. Verify the address you're sending the GLMR to and click the right button to proceed 4. The **Network** screen should show **Moonbeam**. Click the right button to proceed 5. Review the **Max Fees** and click the right button to proceed 6. If everything looks good, you can click both buttons to **Accept and send** the transaction. Otherwise, you can click the right button to get to the **Reject** screen where you can click both buttons to reject the transaction ![Send transaction from Ledger device](/images/tokens/connect/ledger/moonbeam/ledger-17.webp) On Ledger Live, you should see that your transaction was sent, and you can view the details of the transaction. Once the transaction has been confirmed, your GLMR balance will update. And that is it! You've successfully used the Moonbeam Ledger Live integration to receive and send tokens with your Ledger device directly from Ledger Live!
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/connect/ledger/moonriver/ --- BEGIN CONTENT --- --- title: Using the Moonriver Ledger App description: This guide walks you through how to use your Ledger hardware wallet to sign transactions on Moonriver using the native Moonriver Ledger Live app. categories: Tokens and Accounts, Ethereum Toolkit --- # Interacting with Moonriver Using Ledger and the Moonriver App
## Introduction {: #introduction } Hardware wallets provide a safer way to store crypto funds because the private key (used for signing transactions) is stored offline. Ledger offers two hardware wallet solutions at the time of writing: Ledger Nano S and Ledger Nano X. You can interact with Moonriver using your Ledger hardware wallet through the Moonriver Ledger Live app. With the dedicated Moonriver app, you do not have to worry about setting the chain ID and you know you are connected to the right network. Please note that you can only use the Moonriver app to connect to the Moonriver network, it cannot be used to connect to other Moonbeam-based networks. You also have the option of using the Ethereum app to connect to Moonriver. The main difference between using the Moonriver and the Ethereum app is that you have to specify the chain ID when you use the Ethereum app, which is 1285 for Moonriver. If you're interested in using the Ethereum app on Moonriver instead, you can check out the [Interacting with Moonbeam Using Ledger and the Ethereum App](/tokens/connect/ledger/ethereum/){target=\_blank} guide. In this tutorial, you will learn how to get started with your Ledger hardware wallet on Moonriver using the Moonriver app. This guide only illustrates the steps for a Ledger Nano X device, but you can follow along with a Ledger Nano S as well.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Checking Prerequisites {: #checking-prerequisites } Before you get started, update [Ledger Live](https://www.ledger.com/ledger-live){target=\_blank} to the latest version available. Also, make sure you've your Ledger hardware wallet device running the latest firmware. The Ledger support website offers tutorials on [how to update](https://support.ledger.com/article/360013349800-zde){target=\_blank} the firmware. At the time of writing, the following versions were used: - [Ledger Live 2.35.1](https://support.ledger.com/article/What-s-new-in-Ledger-Live){target=\_blank} - [Ledger Nano S firmware v2.0.0](https://support.ledger.com/article/360010446000-zd){target=\_blank} - [Ledger Nano X firmware v2.0.1](https://support.ledger.com/article/360014980580-zd){target=\_blank} In addition, you'll need MetaMask as an intermediary between your Ledger device and Moonbeam. Make sure that your MetaMask is [connected to Moonbeam](/tokens/connect/metamask/){target=\_blank}. As of [MetaMask version 10.5.0](https://consensys.io/blog/metamask-and-ledger-integration-fixed){target=\_blank}, connecting your Ledger device with MetaMask on Chrome is easy again. You just need to have the latest version of MetaMask installed. ## Install the Moonriver Ledger Live App {: install-the-moonriver-ledger-live-app } The Moonriver app is dependent on the Ethereum app, so first you will need to install the Ethereum app. Once the Ethereum app is installed you will be able to install the Moonriver app without a problem. Please note that the Moonriver app is only for the Moonriver network, it will not work for Moonbeam or Moonbase Alpha. To get started, open up Ledger Live and: 1. Select **Manager** from the menu 2. Connect and unlock your device (this must be done before installation) 3. In the **App catalog** search for Ethereum (ETH) and click **Install**. Your Ledger device will show **Processing** and once the installation is complete, the app will appear on your Ledger device 4. Search for Moonriver (MOVR) in the **App catalog** and click **Install**. Again, your Ledger device will show **Processing** and once complete, the Moonriver app will appear on your Ledger device In the Ledger Live app, you should see the Ethereum and Moonriver app listed under the **Apps installed** tab on the **Manager** page. After the apps have been successfully installed, you can close out of Ledger Live. Moonriver Ledger App Installed ## Import your Ledger Account to MetaMask {: #import-your-ledger-account-to-metamask } Now that you've installed the Ledger Live apps, you can connect your Ledger to the computer, unlock it, and open the Moonriver app. Then import your Ledger account to MetaMask using the following steps: 1. Click on the top-right logo to expand the menu 2. Select **Connect Hardware Wallet** ![MetaMask Connect Hardware Wallet](/images/tokens/connect/ledger/moonriver/ledger-2.webp) In the next screen, you are prompted to select which hardware wallet you'll like to use in MetaMask. At the moment of writing, only Ledger and Trezor hardware wallets are supported. Here, take the following steps: 1. Select the Ledger logo 2. Click on **Continue** ![MetaMask Select Ledger Hardware Wallet](/images/tokens/connect/ledger/moonriver/ledger-3.webp) If you're using Chrome or a Chrome-based browser like Brave, you'll be prompted to select your Ledger device to connect via WebHID: 1. Select your Ledger device from the pop-up 2. Click **Connect** ![Ledger on Chrome](/images/tokens/connect/ledger/moonriver/ledger-4.webp) If a pop-up doesn't appear, you may need to change your MetaMask settings to enable a WebHID connection. You can check and update your MetaMask settings by following these steps: 1. Expand the top-right menu and go to **Settings** 2. Navigate to **Advanced** 3. Scroll down to **Preferred Ledger Connection Type** and select **WebHID** from the dropdown !!! note The **Preferred Ledger Connection Type** setting is only available on Chrome and Chrome-based browsers. This setting doesn't exist on other browsers such as Firefox. If MetaMask was able to connect successfully to your Ledger device, you should see a list of five Moonriver/Ethereum-styled accounts. If not, double-check that Ledger Live is closed, you've connected your Ledger device to the computer, unlocked it, and have the Moonriver app open. ### Import Accounts and View Balances {: #import-accounts-and-view-balances } From the list of accounts, take the following steps: 1. Select the accounts you would like to import from your Ledger device 2. Click on **Unlock** ![MetaMask Select Ethereum Accounts to Import](/images/tokens/connect/ledger/moonriver/ledger-5.webp) If you've imported your Ledger account successfully, you should see your account and balance displayed in the main MetaMask screen like shown in the following image: ![MetaMask Successfully Imported Ledger Account](/images/tokens/connect/ledger/moonriver/ledger-6.webp) You can switch accounts in MetaMask at any time to view the balance of your other imported Ledger accounts. You've now successfully imported a Moonriver compatible account from your Ledger device and are now ready to start interacting with your Ledger device. ## Receive Tokens {: #receive-tokens } To get started interacting with your Ledger device, you will need to send some funds to it. Copy your address from MetaMask by clicking on your account name and address in MetaMask. ![MetaMask Copy Account](/images/tokens/connect/ledger/moonriver/ledger-7.webp) Next, you will need to obtain some MOVR tokens and using the address you just copied, send the tokens to your account. After the transaction has successfully gone through, you will see your balance update. ## Send Tokens {: #send-tokens } Next up is sending and signing transactions on Moonriver using your Ledger device. To get started sending a transaction, click on the **Send** button: ![MetaMask Ledger Account Funded](/images/tokens/connect/ledger/moonriver/ledger-8.webp) As you would in a standard transaction, set the recipient address, enter the number of tokens to send, review transaction details and confirm it. This will initiate the transaction signature wizard in your Ledger device. Here, take the following steps: 1. Click the button to proceed to the next screen. Your Ledger device is only warning you to review the transaction 2. Check the number of tokens being sent then proceed to the next screen 3. Check the recipient's address and proceed to the next screen 4. Check the max fees applicable to this transaction. This is the gas price multiplied by the gas limit you've set on MetaMask. When ready, proceed to the next screen 5. If you agree with all the transaction details, approve it. This will sign the transaction and will trigger MetaMask to send it. If you don't agree with all the transaction details, reject it. This will cancel the transaction, and MetaMask will mark it as failed ![MetaMask Ledger Transaction Wizard](/images/tokens/connect/ledger/moonriver/ledger-9.webp) Right after you've approved the transaction, MetaMask sends it to the network. Once the transaction is confirmed, it will be displayed as **Send** on the **Activity** tab in MetaMask. ![MetaMask Ledger Transaction Wizard](/images/tokens/connect/ledger/moonriver/ledger-10.webp) And that is it! You've signed a transaction and sent some MOVR tokens using your Ledger hardware wallet! ## Interact with Contracts Using your Ledger {: #interact-with-contracts-using-your-ledger } By default, Ledger devices don't admit a `data` field in the transaction object. Consequently, users can't deploy or interact with smart contracts. However, if you want to use your Ledger hardware wallet for transactions related to smart contracts, you need to change a configuration parameter inside the app on your device. To do so, take the following steps: 1. On your Ledger, open the Moonriver or Ethereum app 2. Navigate to **Settings** 3. Find the **Blind signing** page. It should state **NOT Enabled** at the bottom 4. Select/validate the option to change its value to **Enabled** !!! note This option is necessary to use your Ledger device to interact with ERC-20 token contracts that might live inside the Moonbeam ecosystem. ![MetaMask Ledger Allow Contracts Tx](/images/tokens/connect/ledger/moonriver/ledger-11.webp)
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/connect/mathwallet/ --- BEGIN CONTENT --- --- title: Connect MathWallet description: This guide walks you through how to connect Mathwallet, a browser-based wallet that works with Ethereum, to Moonbeam. categories: Tokens and Accounts, Ethereum Toolkit --- # Interacting with Moonbeam Using MathWallet ## Introduction {: #introduction } MathWallet [announced](https://mathwallet.org/moonbeam-wallet/en) that it is now natively supporting each of the [Moonbeam-based networks](/learn/platform/networks/){target=\_blank}. This means that you are now able to interact with any of the networks using another wallet besides MetaMask. In this tutorial, we'll go through how to setup MathWallet to connect to each of the networks: [Moonbeam](#connect-to-moonbeam), [Moonriver](#connect-to-moonriver), and [Moonbase Alpha](#connect-to-moonbase-alpha). We'll also present a brief example of using MathWallet as a Web3 provider for other tools such as [Remix](/builders/ethereum/dev-env/remix/){target=\_blank}.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Checking Prerequisites {: #checking-prerequisites } First, you need to install the MathWallet browser extension, which you can get from their [website](https://mathwallet.org/en-us){target=\_blank}. With the browser extension installed, please open it and set a password. ![Set wallet password](/images/tokens/connect/mathwallet/mathwallet-1.webp) ## Connect to Moonbeam {: #connect-to-moonbeam } To get started with Moonbeam, all you have to do is click **Switch Network** and select **Moonbeam**. ![Switch to Moonbeam](/images/tokens/connect/mathwallet/mathwallet-2.webp) And that is it, you now have MathWallet connected to Moonbeam! Your wallet should look like this: Wallet Connected to Moonbeam Now that you've successfully connected to Moonbeam, you can skip ahead to the [Adding a Wallet](#adding-a-wallet) section to get started creating or importing a wallet. ## Connect to Moonriver {: #connect-to-moonriver } Getting started with Moonriver is a straightforward process. All you have to do is click **Switch Network** and select **Moonriver**. ![Connect to Moonriver](/images/tokens/connect/mathwallet/mathwallet-4.webp) And that is it, you now have MathWallet connected to Moonriver! Your wallet should look like this: Wallet Connected to Moonrive Now that you've successfully connected to Moonriver, you can skip ahead to the [Adding a Wallet](#adding-a-wallet) section to get started creating or importing a wallet. ## Connect to Moonbase Alpha {: #connect-to-moonbase-alpha } In this part, we'll go through the process of connecting MathWallet to Moonbase Alpha. First you'll need to enable Moonbase Alpha. To do so, go to the settings by clicking on the gear icon. Then click on **Networks** and scroll down through the **Ethereum** section until you find **Moonbase Alpha** and toggle the switch. ![Enable Moonbase Alpha](/images/tokens/connect/mathwallet/mathwallet-6.webp) Lastly you'll need to switch to Moonbase Alpha. From the main screen, click **Switch Network** and select **Moonbase Alpha**. ![Connect to Moonbase Alpha](/images/tokens/connect/mathwallet/mathwallet-7.webp) And that is it, you now have MathWallet connected to the Moonbase Alpha TestNet! Your wallet should look like this: ![Wallet Connected to Moonbase Alpha](/images/tokens/connect/mathwallet/mathwallet-8.webp) Now that you've successfully connected to Moonbase Alpha, you can move on to the [Adding a Wallet](#adding-a-wallet) section to get started creating or importing a wallet. ## Adding a Wallet {: #adding-a-wallet } The following steps will show you how to interact with the Moonbase Alpha TestNet, but can also be used to interact with Moonbeam and Moonriver. After you are connected to Moonbase Alpha, you can now create a wallet to get an account and start interacting with the TestNet. Currently, there are three ways to add a wallet: - Create a wallet - Import an existing wallet using a mnemonic or private key - Connect hardware wallet (_not supported for now_) ### Create a Wallet {: #create-a-wallet } The following steps for creating a wallet can be modified for Moonbeam and Moonriver. To create a new wallet, click the :heavy_plus_sign: sign next to **Moonbase Alpha** and select **Create Wallet**. ![MathWallet create a wallet](/images/tokens/connect/mathwallet/mathwallet-9.webp) Set and confirm a wallet name. Next, make sure you safely store the mnemonic, as it provides direct access to your funds. Once you have completed the process, you should see your newly created wallet with its associated public address. ![MathWallet wallet created](/images/tokens/connect/mathwallet/mathwallet-10.webp) ### Import a Wallet {: #import-a-wallet } To create a new wallet, click the :heavy_plus_sign: sign next to **Moonbase Alpha** and select **Import Wallet**. ![MathWallet import a wallet](/images/tokens/connect/mathwallet/mathwallet-11.webp) Next, select between importing using a mnemonic or a private key. For the first option, enter the mnemonic word by word, separated by spaces. For the second option, enter the private key (either with the `0x` prefix or not, it works both ways). ![MathWallet private key or mnemonic import](/images/tokens/connect/mathwallet/mathwallet-12.webp) After clicking next, set a wallet name, and that is it! You should see your imported wallet with its associated public address. ![MathWallet imported wallet](/images/tokens/connect/mathwallet/mathwallet-13.webp) ## Using MathWallet {: #using-mathwallet } MathWallet serves as a Web3 provider in tools such as [Remix](/builders/ethereum/dev-env/remix/). By having MathWallet connected to Moonbase Alpha or Moonriver, you can deploy contracts as you would like using MetaMask, signing the transactions with MathWallet instead. For example, in Remix, when deploying a smart contract to Moonbase Alpha, make sure you select the **Injected Web3** option in the **ENVIRONMENT** menu. If you have MathWallet connected, you will see the TestNet chain ID just below the box (_{{ networks.moonbase.chain_id }}_) and your MathWallet account injected into Remix as well. When sending a transaction, you should see a similar pop-up from MathWallet: ![MathWallet sign transaction](/images/tokens/connect/mathwallet/mathwallet-14.webp) By clicking on **Accept** you are signing this transaction, and the contract will be deployed to the Moonbase Alpha TestNet.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/connect/metamask/ --- BEGIN CONTENT --- --- title: How to Connect MetaMask description: This guide walks you through how to connect MetaMask, a browser-based Ethereum wallet, to Moonbeam-based networks and how to transfer funds. categories: Tokens and Accounts, Ethereum Toolkit --- # Interacting with Moonbeam Using MetaMask ## Introduction {: #introduction } Developers can leverage Moonbeam's Ethereum compatibility features to integrate tools, such as [MetaMask](https://metamask.io){target=\_blank}, into their dApps. By doing so, they can use the injected library MetaMask provides to interact with the blockchain. Currently, MetaMask can be configured to connect to a few networks: Moonbeam, Moonriver, the Moonbase Alpha TestNet, and a Moonbeam development node. If you already have MetaMask installed, you can easily connect MetaMask to the network of your choice: !!! note MetaMask will pop up asking for permission to add a custom network. Once you approve permissions, MetaMask will switch your current network. Learn [how to integrate a Connect MetaMask button](/builders/integrations/wallets/metamask/){target=\_blank} into your dApp, so that users can connect to Moonbase Alpha with a simple click of a button. The guide can also be adapted for the other Moonbeam-based networks.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Install the MetaMask Extension {: #install-the-metamask-extension } First, you'll start with a fresh and default [MetaMask](https://metamask.io){target=\_blank} installation from the Chrome store. After downloading, installing, and initializing the extension, follow the **Get Started** guide. In there, you need to create a wallet, set a password, and store your secret backup phrase (this gives direct access to your funds, so make sure to store these in a secure place). ## Setup a Wallet {: #setup-a-wallet } After installing [MetaMask](https://metamask.io){target=\_blank}, the setup will automatically open a new task with a welcome screen. Here, you are offered two options: - **Create a new wallet** - you'll go through some steps to get a new seed phrase. Ensure you store this phrase securely and you don't share it publicly - **Import an existing wallet** - you already have a seed phrase stored, and you want to restore an account from that recovery phrase ![Metamask Setup Interface](/images/tokens/connect/metamask/metamask-1.webp) Once you've selected the option that fits your needs, follow the steps, and you should be all set. !!! note Multiple accounts can be derived from a seed phrase by changing what is known as the address index. By default, when creating or importing an account from the seed phrase, you get the account with the address index 0. You can get the other indexes by just adding new accounts in the main Metamask screen. ## Import Accounts {: #import-accounts } Once you've created a wallet or imported an existing one, you can also import any account into MetaMask if you hold the private keys. For this example, you'll use private keys from the development account. Click the account switcher button to import an account using its private keys. That is where it says **Account 1**. ![Importing account from private key metamask menu](/images/tokens/connect/metamask/metamask-2.webp) Next, click on **Import Account**. ![Importing account from private key account switcher menu](/images/tokens/connect/metamask/metamask-3.webp) Finally, enter the private keys of the account you are trying to import. For example, you can use one of the accounts prefunded in the Moonbeam development node. This guide uses Gerald's key. Once you've entered the private key, click on **Import**. ??? note "Development account addresses and private keys" - Alith: - Public Address: `0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac` - Private Key: `0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133` - Baltathar: - Public Address: `0x3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0` - Private Key: `0x8075991ce870b93a8870eca0c0f91913d12f47948ca0fd25b49c6fa7cdbeee8b` - Charleth: - Public Address: `0x798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc` - Private Key: `0x0b6e18cafb6ed99687ec547bd28139cafdd2bffe70e6b688025de6b445aa5c5b` - Dorothy: - Public Address: `0x773539d4Ac0e786233D90A233654ccEE26a613D9` - Private Key: `0x39539ab1876910bbf3a223d84a29e28f1cb4e2e456503e7e91ed39b2e7223d68` - Ethan: - Public Address: `0xFf64d3F6efE2317EE2807d223a0Bdc4c0c49dfDB` - Private Key: `0x7dce9bc8babb68fec1409be38c8e1a52650206a7ed90ff956ae8a6d15eeaaef4` - Faith: - Public Address: `0xC0F0f4ab324C46e55D02D0033343B4Be8A55532d` - Private Key: `0xb9d2ea9a615f3165812e8d44de0d24da9bbd164b65c4f0573e1ce2c8dbd9c8df` - Goliath: - Public Address: `0x7BF369283338E12C90514468aa3868A551AB2929` - Private Key: `0x96b8a38e12e1a31dee1eab2fffdf9d9990045f5b37e44d8cc27766ef294acf18` - Heath: - Public Address: `0x931f3600a299fd9B24cEfB3BfF79388D19804BeA` - Private Key: `0x0d6dcaaef49272a5411896be8ad16c01c35d6f8c18873387b71fbc734759b0ab` - Ida: - Public Address: `0xC41C5F1123ECCd5ce233578B2e7ebd5693869d73` - Private Key: `0x4c42532034540267bf568198ccec4cb822a025da542861fcb146a5fab6433ff8` - Judith: - Public Address: `0x2898FE7a42Be376C8BC7AF536A940F7Fd5aDd423` - Private Key: `0x94c49300a58d576011096bcb006aa06f5a91b34b4383891e8029c21dc39fbb8b` - Gerald: - Public Address: `0x6Be02d1d3665660d22FF9624b7BE0551ee1Ac91b` - Private Key: `0x99b3c12287537e38c90a9219d4cb074a89a16e9cdb20bf85728ebd97c343e342` ![Paste your account key into MetaMask](/images/tokens/connect/metamask/metamask-4.webp) You should end up with an imported **Account 2** that looks like this: ![MetaMask displaying your new Account 2](/images/tokens/connect/metamask/metamask-5.webp) ## Connect MetaMask to Moonbeam {: #connect-metamask-to-moonbeam } Once you have [MetaMask](https://metamask.io){target=\_blank} installed and have created or imported an account, you can connect it to any Moonbeam-based network. To do so, take the following steps: 1. Click in the upper left network selector menu 2. Select **Add Network** ![Add new network in Metamask menu](/images/tokens/connect/metamask/metamask-6.webp) Next, go to the bottom of the page and click on **Add a network manually**: ![Add network manually in Metamask](/images/tokens/connect/metamask/metamask-7.webp) Here, you can configure MetaMask for the following networks: === "Moonbeam" | Variable | Value | |:-------------------------:|:--------------------------------------------------------------------------------:| | Network Name | `Moonbeam` | | RPC URL | `{{ networks.moonbeam.public_rpc_url }}` | | Chain ID | `{{ networks.moonbeam.chain_id }}` (hex: `{{ networks.moonbeam.hex_chain_id }}`) | | Symbol (Optional) | `GLMR` | | Block Explorer (Optional) | `{{ networks.moonbeam.block_explorer }}` | === "Moonriver" | Variable | Value | |:-------------------------:|:----------------------------------------------------------------------------------:| | Network Name | `Moonriver` | | RPC URL | `{{ networks.moonriver.public_rpc_url }}` | | Chain ID | `{{ networks.moonriver.chain_id }}` (hex: `{{ networks.moonriver.hex_chain_id }}`) | | Symbol (Optional) | `MOVR` | | Block Explorer (Optional) | `{{ networks.moonriver.block_explorer }}` | === "Moonbase Alpha" | Variable | Value | |:-------------------------:|:--------------------------------------------------------------------------------:| | Network Name | `Moonbase Alpha` | | RPC URL | `{{ networks.moonbase.rpc_url }}` | | Chain ID | `{{ networks.moonbase.chain_id }}` (hex: `{{ networks.moonbase.hex_chain_id }}`) | | Symbol (Optional) | `DEV` | | Block Explorer (Optional) | `{{ networks.moonbase.block_explorer }}` | === "Moonbeam Dev Node" | Variable | Value | |:-------------------------:|:--------------------------------------------------------------------------------------:| | Network Name | `Moonbeam Dev` | | RPC URL | `{{ networks.development.rpc_url }}` | | Chain ID | `{{ networks.development.chain_id }}` (hex: `{{ networks.development.hex_chain_id }}`) | | Symbol (Optional) | `DEV` | | Block Explorer (Optional) | `{{ networks.development.block_explorer }}` | To do so, fill in the following information: 1. **Network name** - name that represents the network you are connecting to 2. **RPC URL** - [RPC endpoint](/builders/get-started/endpoints/){target=\_blank} of the network 3. **Chain ID** - chain ID of the Ethereum compatible network 4. **Symbol** - (optional) symbol of the native token of the network. For example, for Moonbeam, the value would be **GLMR** 5. **Block Explorer** - (optional) URL of the [block explorer](/builders/get-started/explorers/){target=\_blank} 6. Once you've verified all the information, click on **Save** ![Add network in Metamask](/images/tokens/connect/metamask/metamask-8.webp) Once you've added the network, you'll be redirected to a screen stating that you've successfully added a network. Furthermore, you'll be prompted to **Switch to Moonbase Alpha**, the network added in this example. ![Successfully added a network in Metamask](/images/tokens/connect/metamask/metamask-9.webp) ## Interact with the Network {: #interact-with-the-network } Once you've [connected Metamask](#connect-metamask-to-moonbeam) to any Moonbeam-based network, you can start using your wallet by: - Sending a token transfer to another address - Adding ERC-20s to Metamask and interacting with them - Adding ERC-721s to Metamask and interacting with them ### Initiate a Transfer { #initiate-a-transfer } This section showcases how to do a simple token transfer to another address as an example of using Metamask with Moonbeam. To do so, take the following steps: 1. Ensure you are connected to the correct network 2. Ensure you have selected the account you want to use for the transfer 3. On the main screen of your Metamask wallet, click on **Send** ![Initiate balance transfer in Metamask](/images/tokens/connect/metamask/metamask-10.webp) Next, you can enter the address to which you want to send the tokens. For this example, a wallet that has already been imported to Metamask is selected, known as **Bob**. ![Select account to send tokens to in Metamask](/images/tokens/connect/metamask/metamask-11.webp) On the next screen, take the following steps: 1. Enter the number of tokens you want to send 2. Verify that all the information is correct, and click on **Next** ![Set the amount of tokens to send in Metamask](/images/tokens/connect/metamask/metamask-12.webp) Lastly, confirm that all the gas-related parameters and fees are correct. After you've verified that everything is OK, click **Confirm**. At this point, your transaction has been sent to the network! ![Confirming a transaction in Metamask](/images/tokens/connect/metamask/metamask-13.webp) Once you've confirmed your transaction, you are taken back to the main screen of your wallet, where you'll see the transaction as **Pending**. After less than a minute, the transaction should be **Confirmed**. If you click on your transaction, you can check more details and view it in a block explorer. ![Transaction confirmed in Metamask](/images/tokens/connect/metamask/metamask-14.webp) ### Add an ERC-20 Token {: #add-an-erc20-token } To add an ERC-20 to your MetaMask wallet, you'll need to import the token using its address: 1. Make sure you've switched to the **Tokens** tab in MetaMask 2. Click **Import tokens** 3. Enter the contract address of the token you want to import. The **Token symbol** and **Token decimal** fields will automatically be populated, but you can edit the **Token symbol** if needed 4. Click **Next** ![The tokens tab and the import tokens process in MetaMask, where the token address, symbol, and decimal are defined.](/images/tokens/connect/metamask/metamask-15.webp) Next, you'll be able to review the token import details. To finalize the import, you can click **Import**. ![Review the token details and finalize the import in MetaMask.](/images/tokens/connect/metamask/metamask-16.webp) Under the **Tokens** tab, you'll be able to see the token and the account balance for the token. ![View the imported token in the list of assets on the tokens tab in MetaMask.](/images/tokens/connect/metamask/metamask-17.webp) ### Add an ERC-721 Token {: #add-an-erc721-token } To add an ERC-721 to your MetaMask wallet, you'll need the token's address: 1. Make sure you've switched to the **NFTs** tab in MetaMask 2. Click **Import NFT** 3. Enter the **Address** of the NFT you want to import and the **Token ID** 4. Click **Import** ![The NFTs tab and the import NFT process in MetaMask, where the address and the token ID of the NFT are defined.](/images/tokens/connect/metamask/metamask-18.webp) Once you've imported your NFT, you'll be able to see a preview of your NFT in the **NFTs** tab. You can click on the NFT to see more details. ![View the imported NFT in the list of NFTs on the NFTs tab in MetaMask.](/images/tokens/connect/metamask/metamask-19.webp)
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/connect/on-ramps/ --- BEGIN CONTENT --- --- title: Fiat On-Ramps Available for Moonbeam description: This guide introduces on-ramps for Moonbeam, including Transak and Onramp, and provides an overview of the process to acquire GLMR from each. categories: Tokens and Accounts, Ethereum Toolkit --- # Fiat On-Ramp Services to Acquire GLMR for Moonbeam ## Introduction Interacting with dApps or deploying smart contracts on Moonbeam requires users to hold GLMR tokens, which are used to pay for network transaction fees (gas), except when using [gasless transactions](/tutorials/eth-api/call-permit-gasless-txs/){target=\_blank}. To help users acquire GLMR, there are several reliable on-ramp services available to convert local currency (fiat) into GLMR. This guide covers two popular options - [Transak](https://transak.com/buy/glmr){target=\_blank} and [Onramp](https://onramp.money/coins/moonbeam){target=\_blank} - each offering different payment methods and features to suit individual needs. Supporting bank transfers, credit cards, and mobile payment solutions, these platforms provide secure and regulated ways to acquire GLMR tokens. You can find a current list of supported on-ramps on the [Moonbeam dApp](https://apps.moonbeam.network/moonbeam){target=\_blank}. Please be aware that the availability of these services may vary by jurisdiction. For more information, please visit the website of the respective on-ramp. ## Transak Using Transak is a straightforward way to purchase GLMR tokens for the Moonbeam network. The process begins at [Transak](https://transak.com/buy/glmr){target=\_blank} with selecting GLMR as the desired cryptocurrency. Users select their local currency and purchase amount, then review the associated fees and processing time details. The next step requires entering the destination Moonbeam wallet address. For bank transfers and other fiat payment methods, a one-time KYC verification process must be completed by providing valid identification documents. After payment completion through the selected method (bank transfer, credit card, or other supported options), Transak processes the transaction and sends the GLMR tokens directly to the specified wallet address. Delivery time varies depending on the payment method selected, ranging from near-instant for card payments to up to 2 business days for bank transfers. ## Onramp [Onramp](https://onramp.money/coins/moonbeam){target=\_blank} offers a seamless fiat-to-crypto gateway for purchasing GLMR tokens, supporting over 400 different cryptocurrencies through their platform. The process begins with a straightforward phone-based OTP login system for verification. After login, the platform displays transaction details, including the GLMR amount and current market rates, for confirmation. Based on geographical location, Onramp displays relevant bank account details and available payment methods. Once payment is completed through the selected method, Onramp handles all aspects of the conversion - from payment processing to regulatory compliance and wallet management. Upon confirmation of the deposit, the platform automatically purchases GLMR at the current market price and then initiates an automatic withdrawal to the specified Moonbeam wallet address. Additional KYC verification may be required for larger transactions, but the platform manages all compliance requirements internally to ensure a smooth experience.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/connect/polkadotjs/ --- BEGIN CONTENT --- --- title: How to use Polkadot.js Apps description: Follow this quick tutorial to learn how to use Moonbeam’s Ethereum-style H160 addresses and send transactions with Polkadot.js Apps. categories: Tokens and Accounts, Ethereum Toolkit --- # How to use Polkadot.js Apps to Interact with Moonbeam ## Introduction {: #introduction } As a Polkadot parachain, Moonbeam uses a [unified account structure](/learn/core-concepts/unified-accounts/){target=\_blank} that allows you to interact with Substrate (Polkadot) functionality and Moonbeam's EVM, all from a single Ethereum-style address. This unified account structure means that you don't need to maintain both a Substrate and an Ethereum account to interact with Moonbeam - instead, you can do it all with a single Ethereum private key. The Polkadot.js Apps interface natively supports H160 addresses and ECDSA keys. So, in this tutorial, you can check out this integration of Ethereum-based accounts on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network%2Fpublic-ws#/accounts){target=\_blank}.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
!!! note Polkadot.js Apps is phasing out support for accounts stored locally in the browser's cache. Instead, it is recommended that you use a browser extension like [Talisman to inject your accounts into Polkadot.js Apps](/tokens/connect/talisman/){target=\_blank}. ## Connect Polkadot.js Apps to Moonbeam {: #connect-polkadotjs-apps } When launching [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network%2Fpublic-ws#/accounts){target=\_blank} for the first time, you may or may not be connected to the desired network. You can change the selected network by clicking the logo in the top left corner, where you'll find a list of networks organized by MainNets, TestNets, and local networks. Each network can be found under the following sections: | Network | Section | |:-------------------------:|:---------------------:| | Moonbeam | Polkadot & Parachains | | Moonriver | Kusama & Parachains | | Moonbase Alpha | Test Networks | | Moonbeam Development Node | Development | Once you've selected the correct network, you can scroll back to the top and click **Switch**. ![Connect to Moonbase Alpha](/images/tokens/connect/polkadotjs/polkadotjs-1.webp) After switching, the Polkadot.js site will not only connect to the chosen network, but the logo and styling will change for each network. ![Connect to Moonbase Alpha](/images/tokens/connect/polkadotjs/polkadotjs-2.webp) ## Create or Import an H160 Account into Polkadot.js Apps {: #creating-or-importing-an-h160-account } !!! note For security purposes, it is recommended that you do not store accounts locally in the browser. A more secure method is using a browser extension like [Talisman to inject your accounts into Polkadot.js Apps](/tokens/connect/talisman/){target=\_blank}. In this section, you'll learn how you can create a new account or import a preexisting MetaMask account to Polkadot.js Apps. First, there is one prerequisite step. As part of the process of phasing out support for accounts stored locally in the browser's cache, you'll need to enable support for local storage of accounts in the **Settings** tab. To do so, take the following steps: 1. Navigate to the **Settings** tab 2. Select **Allow local in-browser account storage** under the **in-browser account creation** heading 3. Press **Save** ![Allow local in-browser account storage](/images/tokens/connect/polkadotjs/polkadotjs-3.webp) You can now head back to the [Accounts page of Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network%2Fpublic-ws#/accounts){target=\_blank} and proceed with the next steps: 1. Navigate to the **Accounts** section 2. Click on the **Add account** button ![Connect to Moonbase Alpha](/images/tokens/connect/polkadotjs/polkadotjs-4.webp) This will open a wizard pop-up that will guide you through the process of adding an account to the Polkadot.js Apps interface: 1. Click on the drop-down menu 2. Change the selection from **Mnemonic** to **Private Key**, this allows you to add an account through a private key !!! note Currently, you can only create or import accounts in Polkadot.js via a private key. Doing so with the mnemonic will result in a different public address if you later try to import this account to an Ethereum wallet such as MetaMask. This is because Polkadot.js uses BIP39, whereas Ethereum uses BIP32 or BIP44. ![Connect to Moonbase Alpha](/images/tokens/connect/polkadotjs/polkadotjs-5.webp) Next, if you want to create a new account, make sure you store the private key displayed by the wizard. If you want to import an existing account, enter your private key that you can export from MetaMask. !!! note Never reveal your private keys as they give direct access to your funds. The steps in this guide are for demonstration purposes only. Make sure to include the prefix in the private key, i.e., `0x`. If you entered the information correctly, the corresponding public address should appear in the upper left corner of the window, and then click **Next**. ![Connect to Moonbase Alpha](/images/tokens/connect/polkadotjs/polkadotjs-6.webp) To finish the wizard, you can set an account name and password. After a confirmation message, you should see in the main **Accounts** tab the address with the corresponding balance: in this case, Bob's address. Moreover, you can overlay the MetaMask extension to see that both balances are the same. ![Connect to Moonbase Alpha](/images/tokens/connect/polkadotjs/polkadotjs-7.webp) ## Send a Transaction Through Substrate's API {: #sending-a-transaction-through-substrates-api } Now, to demonstrate the potential of Moonbeam's [unified accounts](/learn/core-concepts/unified-accounts/){target=\_blank} scheme, you can make a transfer through the Substrate API using Polkadot.js Apps. Remember that you are interacting with Substrate using an Ethereum-style H160 address. To do so, you can import another account. Next, click on Bob's **send** button, which opens another wizard that guides you through the process of sending a transaction. 1. Set the **send to address** 2. Enter the **amount** to send, which for this example is 1 DEV token 3. When ready, click on the **Make Transfer** button ![Connect to Moonbase Alpha](/images/tokens/connect/polkadotjs/polkadotjs-8.webp) Then you'll be prompted to enter your password and sign and submit the transaction. Once the transaction is confirmed, you should see the balances updated for each account. ![Connect to Moonbase Alpha](/images/tokens/connect/polkadotjs/polkadotjs-9.webp) And that is it! We are excited about being able to support H160 accounts in Polkadot.js Apps, as we believe this will greatly enhance the user experience on the Moonbeam Network and its Ethereum compatibility features.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/connect/subwallet/ --- BEGIN CONTENT --- --- title: How to Connect SubWallet to Moonbeam description: This guide walks you through how to connect SubWallet, a comprehensive Polkadot, Substrate, and Ethereum wallet, to Moonbeam. categories: Tokens and Accounts, Ethereum Toolkit --- # Interacting with Moonbeam Using SubWallet ## Introduction {: #introduction } Developers and users of Moonbeam have a variety of options when it comes to wallets. Thanks to Moonbeam's seamless Ethereum compatibility, Moonbeam supports a great variety of popular wallets, including [SubWallet](https://www.subwallet.app){target=\_blank}. SubWallet is a comprehensive Web3 wallet that natively supports Substrate and Ethereum accounts. Although Moonbeam is a Substrate-based blockchain, it has a [unified account system](/learn/core-concepts/unified-accounts/){target=\_blank} that replaces the default Substrate-style accounts and keys with Ethereum-style accounts and keys. Since SubWallet supports Ethereum-style accounts, you can interact with your Moonbeam account using SubWallet. This guide takes you through all the necessary steps, from installing SubWallet to setting up a wallet, connecting it to Moonbeam, and sending funds.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Install SubWallet {: #install-subwallet } There are several ways you can interact with SubWallet: they have **a browser extension, a mobile app, and a web-accessible dashboard**. You can get started by heading to [SubWallet's download page](https://www.subwallet.app/download.html){target=\_blank} and downloading SubWallet for the platform of your choice. If you choose to use the web-accessible dashboard, you won't need to download anything. You can access the dashboard at [web.subwallet.app](https://web.subwallet.app/welcome){target=\_blank}. The interfaces for the mobile app, browser extension, and web dashboard are quite similar, so you can adapt the following instructions, which focus on the browser extension, for the mobile app and web dashboard. ## Setup a Wallet {: #setup-a-wallet } Once you've downloaded the SubWallet Browser Extension, you'll be prompted to set up your wallet. You'll be able to choose from the following options: - **Create a new account** - allows you to create an entirely new account by creating a password and generating a seed phrase - **Import an account** - allows you to import an existing account using the seed phrase, JSON file, private key, or by QR code - **Attach an account** - allows you to connect to an account without the private key. You can use this method to connect to a cold storage wallet, like Keystone, or a watch-only account. With a watch-only account, you will not be able to transfer funds or interact with your account; you'll only be able to view account balances !!! note Ledger is supported on the browser extension but is not yet available on the mobile app. Support for Ledger on the mobile app is coming soon! - **Connect wallet** - *only available on the web dashboard* - allows you to connect to a browser extension wallet. You can use this method to easily connect to an account you've created using the SubWallet browser extension or another wallet, such as MetaMask The following sections will provide step-by-step instructions for [creating a new account](#create-a-new-account) and [importing an existing account](#import-an-account) with SubWallet. If you're attaching an account, you can find step-by-step instructions on [SubWallet's Account management documentation](https://docs.subwallet.app/main/extension-user-guide/account-management){target=\_blank}. Similarly, if you're connecting a wallet on the web dashboard, you can find instructions on [SubWallet's Connect extension documentation](https://docs.subwallet.app/main/web-dashboard-user-guide/account-management/connect-extension){target=\_blank}. ### Create a New Account {: #create-a-new-account } Creating a new account will generate a seed phrase that can derive multiple Ethereum and Substrate accounts. By default, SubWallet will generate a single Ethereum and a single Substrate account, but you can easily derive more from the same seed phrase. To interact with Moonbeam, you will need to use an Ethereum account. Click **Create a new account** to get started. ![The main screen of the SubWallet browser extension.](/images/tokens/connect/subwallet/subwallet-1.webp) On the following screen, you'll be prompted to create a password to secure your new wallet: 1. Enter a password that has at least 8 characters 2. Confirm the password by entering it again 3. Click **Continue** ![The create a password screen on the SubWallet browser extension.](/images/tokens/connect/subwallet/subwallet-2.webp) You'll then be prompted to back up your seed phrase. This is an important step, especially because you have the option to later derive additional accounts from this seed phrase. 1. View your seed phrase and save it in a safe place !!! remember You should never share your seed phrase (mnemonic) or private key with anyone. This gives them direct access to your funds. This guide is for educational purposes only. 2. Once you've safely stored your seed phrase, click **I have kept it somewhere safe** ![Back up your seed phrase on the SubWallet browser extension.](/images/tokens/connect/subwallet/subwallet-3.webp) !!! note If you're creating a new account on the mobile app, you'll have to re-enter your seed phrase to verify that you have stored it. The words have to be entered in the correct order. After you've created a password and saved your seed phrase, you'll be connected to your account. You can [add additional accounts](#add-additional-accounts) at any time. ### Import an Account {: #import-an-account } To import an existing account into SubWallet, you can select **Import an account**. ![The main screen of the SubWallet browser extension.](/images/tokens/connect/subwallet/subwallet-4.webp) On the following screen, select the method by which you would like to import the existing account. You can choose from **Import from seed phrase**, **Import from Polkadot.{js}**, **Import by MetaMask private key**, and **Import by QR code**. If you select **Import from seed phrase**, there are some incompatibility issues that can arise when importing an account from seed phrase. For example, Trust Wallet and SafePal are among the wallets not compatible with SubWallet. If you run into incompatibility issues, SubWallet recommends creating a new wallet. If you select **Import from Polkadot.{js}**, you'll need to make sure that the account was created in Polkadot.js via private key. If it was created with a seed phrase and you attempt to import it to SubWallet, a different public address will be used. This is because Polkadot.js uses [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki){target=\_blank}, whereas Ethereum uses [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki){target=\_blank} or [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki){target=\_blank}. ![Select the import option from the Import account screen of the SubWallet browser extension.](/images/tokens/connect/subwallet/subwallet-5.webp) If you import your account via seed phrase, you can select your account type as either Substrate (Polkadot) or EVM (Ethereum), or both. Moonbeam uses Ethereum-style accounts, so you'll need to select **Ethereum** to import an account for Moonbeam-based networks. ![Select the account type to import on the SubWallet browser extension.](/images/tokens/connect/subwallet/subwallet-6.webp) Once you've completed the import process, you'll be prompted to enter a password to secure your new wallet: 1. Enter a password that has at least 8 characters 2. Confirm the password by entering it again 3. Click **Continue** ![The create a password screen on the SubWallet browser extension.](/images/tokens/connect/subwallet/subwallet-7.webp) Next, you'll be able to provide the relevant seed phrase, private key, JSON file, or QR code, and you can begin using your new account right away. You can add [additional accounts](#add-additional-accounts) at any time. ### Add Additional Accounts {: #add-additional-accounts } After you have created a new account or imported an existing account to SubWallet, you can add additional accounts by taking the following steps: 1. Click on the account dropdown 2. Select one of the options from the bottom of the screen. You can click **Create a new account**, the import button to import an existing account, or the attach button to attach to an existing cold storage wallet or watch-only account ![View account details and create a new account, import one, or attach one.](/images/tokens/connect/subwallet/subwallet-8.webp) If you're creating a new account, you can then choose **Create with new seed phrase** or **Derive from an existing account**. If you're creating a new account with a new seed phrase, you'll need to select the account type and back up the account, similar to the instructions in the [Create a New Account](#create-a-new-account) section. If you choose to derive a new account, you'll be prompted to select the existing account that you want to derive the account from. If you're importing a new account, you'll need to choose whether to import using a seed phrase, JSON file, MetaMask private key or QR code, then repeat the process outlined in the [Import an Account](#import-an-account) section. If you're attaching an account, you can find out step-by-step instructions on [SubWallet's Account management documentation](https://docs.subwallet.app/main/extension-user-guide/account-management){target=\_blank}. ## Connect SubWallet to Moonbeam {: #connect-subwallet-to-moonbeam } To configure SubWallet for Moonbeam, select the **Customize your asset display** icon next to the **Search a token** icon. ![The tokens screen on the SubWallet browser extension.](/images/tokens/connect/subwallet/subwallet-9.webp) To add Moonbeam, you can: 1. Search for "Moon" to view all Moonbeam-based networks, or search for a specific network 2. Toggle the switch to connect to the network ![The customize asset display screen on the SubWallet browser extension.](/images/tokens/connect/subwallet/subwallet-10.webp) If you're trying to connect to a [local Moonbeam development node](/builders/get-started/networks/moonbeam-dev/){target=\_blank}, you can select the hamburger menu from the top left corner, which will take you to the settings page. ![The tokens screen on the SubWallet browser extension.](/images/tokens/connect/subwallet/subwallet-11.webp) From the settings menu, click **Manage networks**. ![The settings screen on the SubWallet browser extension.](/images/tokens/connect/subwallet/subwallet-12.webp) Click the **+** icon in the top right corner and enter in the [network configurations](/builders/get-started/quick-start/#network-configurations){target=\_blank}. You can also manage and connect to other networks from this menu. ![The tokens screen on the SubWallet browser extension.](/images/tokens/connect/subwallet/subwallet-13.webp) By default, all balances are hidden in SubWallet, but if you press the **Show balance** icon, you can toggle balance visibility. ![The tokens screen on the SubWallet browser extension.](/images/tokens/connect/subwallet/subwallet-14.webp) ## Interact with the Network {: #interact-with-the-network } Once you've [connected SubWallet](#connect-subwallet-to-moonbeam) to any Moonbeam-based network, you can start using your wallet by: - Receiving a token from another address - Sending a token to another address - Adding tokens to SubWallet and interacting with them ### Receive a Token {: #receive-a-token } To receive a token from another account, you would need to show your wallet address to your counterparty, and they can send their assets to such address. To copy your address, click on the **Get address** icon. ![The tokens screen on the SubWallet browser extension.](/images/tokens/connect/subwallet/subwallet-15.webp) If you have multiple accounts and have selected **All accounts** from the account dropdown menu, you'll need to select the receiving account you want to send the assets to. Otherwise, make sure that the account you're connected to (which is displayed at the top of the screen) is the account you want to send the assets to. **This should be your Moonbeam account, which is an Ethereum-style address.** ![Select an account to receive tokens on the SubWallet browser extension.](/images/tokens/connect/subwallet/subwallet-16.webp) Next, you can search for and choose the token that you would like to receive. For this example, DEV is chosen. ![Search and choose desired token on the SubWallet browser extension.](/images/tokens/connect/subwallet/subwallet-17.webp) !!! note SubWallet supports receiving cross-chain tokens, so please be sure to check that the chain logo under the token name matches your desired chain. You will be shown the QR code and the address linked to your account. **Double-check that the address shown is an Ethereum-style account**. ![QR code and address to receive tokens on the SubWallet browser extension.](/images/tokens/connect/subwallet/subwallet-18.webp) Now you just need to show the QR code or address to the sender. ### Send a Transaction {: #send-a-transaction } To get started with a simple token transfer to another address on Moonbeam, you can click the **Send** icon. ![The tokens screen on the SubWallet browser extension.](/images/tokens/connect/subwallet/subwallet-19.webp) Next, you can take the following steps: 1. Specify the asset to send and the destination chain !!! note Some tokens are allowed to be transferred cross-chain, so when choosing the destination network, you can choose the dropdown menu to see the available options. 2. Enter the destination address, which can also be done using the address book or by scanning the recipient's QR code !!! note If you're using the mobile app, click **Next** to proceed. 3. Enter the amount of tokens to send 4. Look over the transaction details, then press **Transfer** ![The transfer screen on the SubWallet browser extension, where you can enter in the transaction details.](/images/tokens/connect/subwallet/subwallet-20.webp) On the next screen, you'll be able to review the transaction details and submit the transaction. If the transaction details look good, you can click **Approve** to send the transaction. ![The transfer confirmation screen on the SubWallet browser extension.](/images/tokens/connect/subwallet/subwallet-21.webp) After you send the transaction, you'll be able to review the transaction details. And that's it! For more information on how to use SubWallet, please refer to [SubWallet's documentation](https://docs.subwallet.app/main){target=\_blank}.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/connect/talisman/ --- BEGIN CONTENT --- --- title: Using Talisman with Polkadot JS Apps description: Follow this quick tutorial to learn how to use Moonbeam’s Ethereum-style H160 addresses and send transactions with Polkadot.js Apps and Talisman. categories: Tokens and Accounts, Ethereum Toolkit --- # Interacting with Moonbeam Using Talisman ## Introduction {: #introduction } As a Polkadot parachain, Moonbeam uses a [unified account structure](/learn/core-concepts/unified-accounts/){target=\_blank} that allows you to interact with Substrate (Polkadot) functionality and Moonbeam's EVM, all from a single Ethereum-style address. This unified account structure means that you don't need to maintain both a Substrate and an Ethereum account to interact with Moonbeam - instead, you can do it all with a single Ethereum private key. [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network%2Fpublic-ws#/accounts){target=\_blank} supports H160 accounts injected into the browser via an extension like [Talisman](https://talisman.xyz){target=\_blank}. Note, Polkadot.js Apps is phasing out support for [accounts stored locally in the browser's cache](/tokens/connect/polkadotjs/). While you can continue to use any accounts that you've imported and stored in your browser locally via Polkadot.js Apps, you won't be able to add any new ones. This means that you'll need to use an extension like Talisman. Furthermore, injecting your account from an extension like Talisman is generally regarded to be safer than storing the account directly in the browser. This guide will include all of the steps for setting up an account in Talisman and using it to interact with Moonbeam through Polkadot.js Apps.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Setting up Talisman {: #setting-up-talisman } Talisman is a crypto-wallet that natively supports Substrate (Polkadot) and Ethereum accounts. The Talisman wallet browser extension is available on [Google Chrome](https://chromewebstore.google.com/detail/talisman-wallet/fijngjgcjhjmmpcmkeiomlglpeiijkld){target=\_blank} and [Brave](https://chromewebstore.google.com/detail/talisman-wallet/fijngjgcjhjmmpcmkeiomlglpeiijkld){target=\_blank}, and a corresponding asset dashboard is accessible at [app.talisman.xyz](https://app.talisman.xyz){target=\_blank} First, download and install the [Talisman extension](https://talisman.xyz){target=\_blank}. Once the extension opens up, you'll be prompted to either create a new wallet or import an existing one. For the purposes of this demo, you'll create a new wallet. On the following screen you'll be prompted to create a password to secure the new wallet. ![Create a new wallet or import an existing one into Talisman.](/images/tokens/connect/talisman/talisman-1.webp) !!! Remember Talisman does not require you to back up your seed phrase but will nudge you with a reminder at the bottom of the screen. If you don't back up your seed phrase, you could lose all of your assets. To back up your newly created wallet, take the following steps: 1. Press **Backup Now** 2. Enter the password to your Talisman wallet 3. Press **View Recovery Phrase** and store it in a secure place ![Back up your Talisman recovery phrase.](/images/tokens/connect/talisman/talisman-2.webp) ## Setting up Talisman to Connect to Testnets {: #setting-up-talisman-to-connect-to-testnets } Talisman works with all Moonbeam networks [after you enable Ethereum accounts](#connecting-talisman-to-moonbase-alpha-polkadot.js-apps). You can also see your balances across all networks in the **Portfolio** tab by clicking on the extension's Talisman logo in the upper left-hand corner. By default, Talisman hides your testnet account balances. However, you can change this by taking the following steps: 1. Open the Talisman extension and click on the Talisman logo 2. Select **Settings** 3. Select **Ethereum Networks** 4. Click **Enable Testnets** ![See your Moonbase Alpha testnet account balances in Talisman.](/images/tokens/connect/talisman/talisman-3.webp) ## Connecting Talisman to Moonbeam and Polkadot.js Apps {: #connecting-talisman-to-moonbase-alpha-polkadot.js-apps } Connecting Talisman to a Moonbeam-based network in Polkadot.js Apps is straightforward. Remember that you need to [enable testnets](#setting-up-talisman-to-connect-to-testnets) if you want to connect to Moonbase Alpha. To connect to a Moonbeam-based network, the Moonbase Alpha testnet in this example, head to [Moonbase Alpha Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network%2Fpublic-ws#/accounts){target=\_blank}. The Talisman extension will prompt you to select the accounts you'd like to use with Polkadot.js Apps. If it doesn't automatically pop up, you can open the Talisman extension and press the **Connected / Not Connected** button at the top. To configure Talisman to correctly interface with Moonbeam networks on Polkadot.js Apps, you should take the following steps: 1. Check the box next to **Show Ethereum Accounts** 2. Select the accounts you want to connect to Polkadot.js Apps. In this example, it is only **My Ethereum Account**. This is the default name assigned by Talisman which you can rename if you'd like 3. Press **Connect 1**. The value will change depending on the number of accounts you are connecting ![Enable Ethereum/Moonbeam accounts in Talisman.](/images/tokens/connect/talisman/talisman-4.webp) Your Talisman wallet is now connected to Polkadot.js Apps. After refreshing Polkadot.js Apps, you should see your Talisman account in the [Accounts page of Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network%2Fpublic-ws#/accounts){target=\_blank}. When launching [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network%2Fpublic-ws#/accounts){target=\_blank} for the first time, you may or may not be connected to the desired network. You can change your selected network to the Moonbase Alpha TestNet by clicking the logo in the top left corner, then scroll down to the **Test Networks** section, select Moonbase Alpha, and scroll back to the top and click **Switch**. ![Connect to Polkadot.js Apps.](/images/tokens/connect/talisman/talisman-5.webp) After switching, the Polkadot.js site will not only connect to Moonbase Alpha, but also change its styling to make a perfect match. ![Switch to Moonbase Alpha in Polkadot.js Apps.](/images/tokens/connect/talisman/talisman-6.webp) ## Adding a New Account to Talisman {: #adding-a-new-account-to-talisman } In this section, you'll learn how you can create a new account, or import an already existing MetaMask account to Polkadot.js Apps. 1. Open the Talisman extension and click on the Talisman logo in the upper left hand corner 2. Select **Add Account** 3. Select **New Account** 4. Select **Ethereum** as the account type 5. Give your new account a name 6. Press **Create** ![Create a new Moonbeam account in Talisman.](/images/tokens/connect/talisman/talisman-7.webp) Although our new account has been successfully created, Polkadot.js Apps isn't aware of it yet. To connect the new account to Polkadot.js Apps, take the following steps from [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network%2Fpublic-ws#/accounts){target=\_blank}: 1. Open the Talisman extension and Press the **Connected / Not-connected** button 2. Ensure **Show Eth accounts** is checked 3. Click on the account you'd like to connect. The green dot next to the account will light up if it is selected ![Connect Talisman account to Polkadot.js Apps.](/images/tokens/connect/talisman/talisman-8.webp) ## Sending a Transaction Through Substrate's API {: #sending-a-transaction-through-substrates-api } Now, to demonstrate the potential of Moonbeam's [unified accounts](/learn/core-concepts/unified-accounts/){target=\_blank} scheme you can make a transfer through the Substrate API using Polkadot.js Apps. Remember that you are interacting with Substrate using an Ethereum-style H160 address. To do so, you can [add another account](#adding-a-new-account-to-talisman). The accounts in Talisman have been renamed to the familiar Alice and Bob accounts. To send some DEV funds from Alice to Bob, take the following steps: Click on Alice's **send** button, which opens another wizard that guides you through the process of sending a transaction. 1. Set the **send to address** 2. Enter the **amount** to send, which is 4 DEV tokens in this example 3. When ready, click on the **Make Transfer** button 4. Approve the transaction in the Talisman pop up ![Send a Moonbeam transaction through the Substrate API with Talisman.](/images/tokens/connect/talisman/talisman-9.webp) After the transaction is confirmed, you should see the balances updated for each account. ![You can see your balances updated in Polkadot.js Apps after a successful transaction.](/images/tokens/connect/talisman/talisman-10.webp) And that is it! These steps have demonstrated the ease coupled with the robust security of interacting with injected H160 accounts in Polkadot.js Apps with Talisman. All of this is possible because of Moonbeam's unified account structure, a great example of Moonbeam's commitment to providing the best user experience.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/connect/trezor/ --- BEGIN CONTENT --- --- title: How to Connect & Use Trezor description: Learn how to import your Trezor hardware wallet to MetaMask and how to use your Trezor to sign transactions on Moonbeam. categories: Tokens and Accounts --- # Interacting with Moonbeam Using Trezor Hardware Wallet ## Introduction {: #introduction } Hardware wallets provide a safer way to store crypto funds because the private key (used for signing transactions) is stored offline. Trezor offers two hardware wallet solutions at the time of writing: Trezor One and Trezor Model T. Because Moonbeam is fully Ethereum compatible, you can use your Trezor device to sign transactions on Moonbeam! This tutorial shows you how to get started with your Trezor hardware wallet on Moonbase Alpha. The guide only illustrates the steps for a Trezor Model T device, but you can follow along with a Trezor One as well. Please note that your Trezor device will sign transactions in whichever MetaMask network is connected to.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Checking Prerequisites {: #checking-prerequisites } Before you get started, update [Trezor Suite](https://suite.trezor.io){target=\_blank} to the latest version available. Also, make sure your Trezor hardware wallet is running the latest firmware. The Trezor wiki offers tutorials on how to update the firmware of both [Trezor One](https://trezor.io/learn/a/update-trezor-device-firmware){target=\_blank} and [Trezor Model T](https://trezor.io/learn/a/update-trezor-device-firmware){target=\_blank} devices. At the time of writing, the following versions were used: - Trezor Suite 21.5.1 - Trezor One firmware v1.10.0 - Trezor Model T firmware v2.4.0 In addition, you'll need MetaMask as an intermediary between your Trezor device and Moonbase Alpha. Make sure that your MetaMask is [connected to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank}. Please note that your Trezor device will sign transactions in whichever MetaMask network is connected to. ## Importing your Trezor Account to MetaMask {: #importing-your-trezor-account-to-metamask } To get started, you need to have set up a wallet (either standard or a hidden wallet). Once you've connected your Trezor device, unlocked it, and set up a wallet in Trezor Suite. Next, to import your Trezor Ethereum account to MetaMask, take the following steps: 1. Click on the top-right logo to expand the menu 2. Select **Connect Hardware Wallet** ![MetaMask Connect Hardware Wallet](/images/tokens/connect/ledger/ethereum/ledger-2.webp) Right after, you are prompted to select which hardware wallet you'll like to use in MetaMask. At the moment of writing, only Ledger and Trezor hardware wallets are supported. If you have your Trezor device ready to go, take the following steps: 1. Select the Trezor logo 2. Click on **Continue** ![MetaMask Select Trezor Hardware Wallet](/images/tokens/connect/trezor/trezor-2.webp) After clicking the button, a new tab named **TrezorConnect** should show up, where you'll need to pair your device. This is not required if you've Trezor Suite opened and your device is connected. Here, click on **Pair devices**. ![Trezor Hardware Wallet Connect Pair Device](/images/tokens/connect/trezor/trezor-3.webp) On the next screen, take the following steps: 1. Click on **Check for devices.** This will open a menu showing which Trezor device (if available) you want to connect to 2. Select the Trezor device you want to use 3. Click on **Connect** ![Trezor Hardware Wallet Connect Wizard Select and Connect Device](/images/tokens/connect/trezor/trezor-4.webp) Once your device is connected, you need to allow MetaMask to read its public keys. Therefore, click on **Allow once for this session**. Optionally, you can also check the **Don't ask me again** box. ![Trezor Hardware Wallet Connect Wizard Allow Read Public Keys](/images/tokens/connect/trezor/trezor-5.webp) Next, you are asked if you want to export the public key of your Ethereum account (tab was cropped and labeled as 1 in the following image). Right after, you are prompted with an option to use [Trezor's passphrase option (tab cropped and labeled as 2 in the image). If you want to use the default wallet, just click on **Enter**. If not, please follow [Trezor's wiki article for passphrase wallets](https://trezor.io/learn/a/passphrases-and-hidden-wallets){target=\_blank}. ![Trezor Hardware Wallet Connect Wizard Allow Export and Passphrase](/images/tokens/connect/trezor/trezor-6.webp) If MetaMask was able to connect successfully to your Trezor device, you should see a list of five Ethereum-styled accounts. If not, please double-check that you've properly connected your Trezor device to the computer and it is unlocked. You can also repeat the process with the Trezor Suite app opened. From this list of five Ethereum accounts, take the following steps: 1. Select the accounts you would like to import from your Trezor device 2. Click on **Unlock** ![Trezor Select Ethereum Accounts to Import](/images/tokens/connect/trezor/trezor-7.webp) If you've imported your Trezor Ethereum-styled account successfully, you should see it displayed in the main MetaMask screen like shown in the following image: ![MetaMask Successfully Imported Trezor Account](/images/tokens/connect/trezor/trezor-8.webp) You've now successfully imported a Moonbeam compatible account from your Trezor device and are now ready to start [signing transactions using your hardware wallet](#signing-a-transaction-using-your-trezor). ## Signing a Transaction Using your Trezor {: #signing-a-transaction-using-your-trezor } If you've successfully [imported your Trezor account to MetaMask](#importing-your-trezor-account-to-metamask), you are ready to sign transactions on Moonbeam using your Trezor device. This tutorial will show you how to send a simple transaction on the Moonbase Alpha TestNet, but it applies to other Moonbeam ecosystem networks. First, make sure your Trezor account is [funded with DEV tokens](/builders/get-started/networks/moonbase/#get-tokens){target=\_blank}. Next, click on the **Send** button. ![MetaMask Trezor Account Funded](/images/tokens/connect/trezor/trezor-9.webp) A `TrezorConnect` tab should pop up, asking permission to read public keys from your device and prepare your Trezor for transaction and data signing. Once you are ready, click on **Allow once for this session**. Optionally, you can also check the **Don't ask me again** box. ![Trezor Hardware Wallet Allow Read Public Keys and Signing](/images/tokens/connect/trezor/trezor-10.webp) As you would in a standard transaction, set the recipient address, enter the number of tokens to send, review transaction details and confirm it. This will initiate the transaction signature wizard in your Trezor device. Here, take the following steps: 1. Review all transaction details. Please note that the token corresponds to the network MetaMask is connected to. **In this case, it is DEV tokens and not UNKN!** 2. Once all details have been checked, hold the button to confirm !!! note At the time of writing, the token name for all Moonbeam-related networks is always shown as `UNKN`. Please note that the token being handled is the one corresponding to the network MetaMask is connected to. ![Trezor Hardware Wallet Sign Transaction](/images/tokens/connect/trezor/trezor-11.webp) Right after you've approved the transaction, MetaMask sends it to the network. Once the transaction is confirmed, it will be displayed as **Send** on MetaMask's main screen. ![MetaMask Trezor Transaction Wizard](/images/tokens/connect/trezor/trezor-12.webp) And that is it! You've signed a transaction on Moonbase Alpha using your Trezor hardware wallet. The process of interacting with smart contracts using your Trezor device is similar. Make sure to double-check the data being signed on your Trezor device before confirming the transaction.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/governance/ --- BEGIN CONTENT --- --- title: Participate in Governance description: Learn how to participate in Moonbeam's on-chain governance, including how to propose an action to be voted on and how to vote on proposals. dropdown_description: Submit and vote on on-chain proposals template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/governance/proposals/ --- BEGIN CONTENT --- --- title: How to Propose an Action in OpenGov description: Follow these step-by-step instructions to learn how to submit a Democracy proposal for other token holders to vote on in Governance v2 (OpenGov) on Moonbeam. categories: Governance --- # How to Propose an Action in OpenGov (Governance v2) ## Introduction {: #introduction } A proposal is a submission to the chain in which a token holder suggests for an action to be enacted by the system. Proposals are one of the core elements of the governance system because they are the main tool for community members to propose actions/changes, which other token holders then vote on. In Moonbeam, users are able to create and vote on proposals using their H160 address and private key, that is, their regular Ethereum account! This guide will outline the process, with step-by-step instructions, of how to submit a proposal for other token holders to vote on in OpenGov (Governance v2). This guide will show you how to submit the proposal on Moonbase Alpha, but it can be easily adapted for Moonbeam and Moonriver. There is a separate guide on [How to Vote on a Proposal in OpenGov](/tokens/governance/voting/){target=\_blank}. For more information on Moonbeam's governance system, please refer to the [Governance on Moonbeam](/learn/features/governance/){target=\_blank} overview page. ## Definitions {: #definitions } Some of the key parameters for this guide are the following: - **Proposal** — an action or item, defined by the preimage hash, being proposed by a token holder and open for consideration and discussion by token holders - **Referendum** — a proposal that is up for token-holder voting. Each referendum is tied to a specific proposal for a change to the Moonbeam system including values for key parameters, code upgrades, or changes to the governance system itself - **Preimage hash** — hash of the proposal to be enacted. The first step to make a proposal is to submit a preimage. The hash is just its identifier. The proposer of the preimage can be different than the user that proposes that preimage as a formal proposal - **Preimage deposit** — amount of tokens that the proposer needs to bond when submitting a preimage. It is calculated as the sum of a base deposit per network plus a fee per byte of the preimage being proposed - **Submission Deposit** - the minimum deposit amount for submitting a public referendum proposal - **Lead-in Period** — the initial proposal voting and discussion period. At this stage, proposals are in an undecided state until they pass some criteria for the given Track. The criteria include: - **Prepare Period** — the minimum time the referendum needs to wait before it can progress to the next phase after submission - **Capacity** — limit for the number of referenda on a given Track that can be decided at once - **Decision Deposit** — the minimum deposit amount required for a referendum to progress to the decision phase after the end of the Lead-in Period. Since each Track has a defined Capacity, this deposit is larger than the submission deposit, and its goal is to mitigate spam Make sure you check the [Governance Parameters](/learn/features/governance/#governance-parameters-v2){target=\_blank} for each network and track. ## Roadmap of a Proposal {: #roadmap-of-a-proposal } This guide will cover the first few steps outlined in the proposal roadmap, as highlighted in the diagram below. You'll learn how to submit your proposal idea to the [Moonbeam Community Forum](https://forum.moonbeam.network){target=\_blank}, submit a preimage, and submit your proposal on-chain using the preimage hash. You can find a full explanation in the [Roadmap of a Proposal](/learn/features/governance/#roadmap-of-a-proposal-v2){target=\_blank} section on the Governance overview page. ![Proposal Roadmap](/images/tokens/governance/proposals/proposals-roadmap.webp) ## Submit your Idea to the Community Forum {: #submitting-your-idea-to-the-forum } Before diving into the steps for submitting a proposal, you'll want to get familiar with [Moonbeam's Community Forum](https://forum.moonbeam.network){target=\_blank}. It's highly recommended that you preface any proposal with a post on the forum to solicit feedback. You should allow a period of five days for the community to discuss and provide feedback on the Moonbeam Forum post before proceeding to submit the preimage and proposal. To access the Moonbeam Community Forum, you must be a member of the [Moonbeam Discord](https://discord.com/invite/PfpUATX){target=\_blank} community. You can then sign up to get access to the forum using your Discord credentials. Once you’re logged in, you can explore the latest discussions, join conversations, and create your own discussion for a proposal idea you may have. Before posting or commenting for the first time, be sure to familiarize yourself with the [FAQ](https://forum.moonbeam.network/faq){target=\_blank} to learn about the community guidelines. ![Moonbeam Forum Home](/images/tokens/governance/treasury-proposals/treasury-proposal-1.webp) When you're ready to create a post with the details of your proposal, you can head to the **Governance** page and click on **Democracy Proposals**. ![Governance page on Moonbeam Forum](/images/tokens/governance/proposals/proposals-1.webp) From there, you can click on **Open Draft** and begin to draft your proposal using the template provided. Make sure to update the title of the post and add any of the optional tags, such as **Moonbeam** if the proposal is for the Moonbeam network. The title should follow the format as the pre-populated title: [Proposal: XX][Status: Idea] proposal title. For example, [Proposal: XX][Status: Idea] Register XC-20 xcMYTOK. The XX will need to be updated with the proposal ID once the proposal has been formally submitted on-chain. ![Add a proposal to the Moonbeam Forum](/images/tokens/governance/proposals/proposals-2.webp) After you've filled out your proposal details, you can click **Create Topic** to save it to the forum and open the discussion on your idea. Based on the feedback you receive, you can update the proposal before proceeding to submit it. ## Proposing an Action {: #proposing-an-action } This section goes over the process of creating a proposal with OpenGov (Governance v2) on Moonbase Alpha. These steps can be adapted for Moonbeam and Moonriver. To make a proposal in the network, you can use the Polkadot.js Apps interface. To do so, you need to import an Ethereum-style account first (H160 address), which you can do following the [Creating or Importing an H160 Account](/tokens/connect/polkadotjs/#creating-or-importing-an-h160-account){target=\_blank} guide. For this example, three accounts were imported and named with super original names: Alice, Bob, and Charlie. ![Accounts in Polkadot.js](/images/tokens/governance/proposals/proposals-3.webp) For the proposal, you can choose anything you would like to propose, just make sure that you assign it to the right Origin and Track, so that it has the right privileges to execute the action. For the purposes of this guide, the action will be to set an on-chain remark using the General Admin Origin and Track. ### Submitting a Preimage of the Proposal {: #submitting-a-preimage-of-the-proposal } The first step is to submit a preimage of the proposal. This is because the storage cost of large preimages can be pretty hefty, as the preimage contains all the information regarding the proposal itself. With this configuration, one account with more funds can submit a preimage and another account can submit the proposal. First, navigate to [Moonbase Alpha's Polkadot.js Apps interface](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network){target=\_blank}. Everything related to governance lives under the **Governance** tab, including preimages. So, from the **Governance** dropdown, you can select **Preimages**. Once there, click on the **Add preimage** button. ![Add preimage in Polkadot.js](/images/tokens/governance/proposals/proposals-4.webp) Here, you need to provide the following information: 1. Select the account from which you want to submit the preimage 2. Choose the pallet you want to interact with and the dispatchable function (or action) to propose. The action you choose will determine the fields that need to fill in the following steps. In this case, it is the **system** pallet and the **remark** extrinsic 3. Enter any additional fields required for the extrinsic to be dispatched. For this example, you can enter the remark in hex or ascii format 4. Copy the preimage hash. This represents the proposal. You will use this hash when submitting the actual proposal 5. Click the **Submit preimage** button and sign the transaction ![Fill in the Preimage Information](/images/tokens/governance/proposals/proposals-5.webp) !!! note Make sure you copy the preimage hash, as it is necessary to submit the proposal. Note that the storage cost of the preimage can be calculated as the base fee (per network) plus the fee per byte of the preimage being proposed. After the transaction is submitted, you will see some confirmations on the top right corner of the Polkadot.js Apps interface and the preimage will be added to the list of **preimages**. ### Submitting a Proposal {: #submitting-a-proposal-v2 } Once you have committed the preimage (check the previous section), the roadmap's next major milestone is to submit the proposal related to it. To do so, select **Referenda** from the **Governance** dropdown, and click on **Submit proposal**. In order to submit a proposal, you'll need to choose which Origin class you want your proposal to be executed with. **Choosing the wrong Track/Origin might result in your proposal failing at execution**. For more information on each Origin class, please refer to the [General Definitions](/learn/features/governance/#general-definitions-gov2){target=\_blank} section on the Governance on Moonbeam overview page. ![Submit proposal](/images/tokens/governance/proposals/proposals-6.webp) Here, you need to provide the following information: 1. Select the account from which you want to submit the proposal (in this case, Alice) 2. Choose the Track to submit the proposal to. The Origin associated with the Track will need to have enough authority to execute the proposed action. For this example, to add an on-chain remark, you can select **2 / General Admin** from the **submission track** dropdown 3. In the **origin** dropdown, choose **Origins** 4. In the **Origins** dropdown, select the Origin, which in this case is **GeneralAdmin** 5. Enter the preimage hash related to the proposal. In this example, it is the hash of the `system.remark` preimage from the previous section 6. Choose the moment of enactment, either after a specific number of blocks, or at a specific block. It must meet the minimum Enactment Period, which you can find in OpenGov's [Governance Parameters](/learn/features/governance/#governance-parameters-v2) 7. Enter the number of blocks or the specific block to enact the proposal at 8. Click **Submit proposal** and sign the transaction ![Fill in the Proposal Information](/images/tokens/governance/proposals/proposals-7.webp) !!! note Tokens might be locked for an indeterminate amount of time because it is unknown when a proposal may become a referendum (if ever). After the transaction is submitted, you will see some confirmations on the top right corner of the Polkadot.js Apps interface. You should also see the proposal listed in the associated Origin section, displaying the proposed action, proposer, and more. If you login to [Polkassembly](https://moonbeam.polkassembly.io/opengov){target=\_blank} with the same account that you used to create the proposal, you'll be able to edit the description of the proposal to include a link to the proposal discussion on the [Moonbeam Community Forum](https://forum.moonbeam.network){target=\_blank}. This is a helpful step because while Polkassembly auto-generates a post for each proposal, it doesn't provide context information on the contents of the proposal. The proposal is now in the Lead-in Period and is ready to be voted on! In order for your proposal to progress out of the Lead-in Period to the next phase, at a minimum the Prepare Period will need to pass so there is enough time for the proposal to be discussed, there will need to be enough Capacity in the chosen Track, and the Decision Deposit will need to be submitted. The deposit can be paid by any token holder. If there isn't enough Capacity or the Decision Deposit hasn't been submitted, but the Prepare Period has passed, the proposal will remain in the Lead-in Period until all of the criteria is met. To learn how to vote on a proposal, please refer to the [How to Vote on a Proposal in OpenGov](/tokens/governance/voting/){target=\_blank} guide. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/governance/treasury-spend/ --- BEGIN CONTENT --- --- title: How to Propose a Treasury Spend description: Learn about the full life cycle of a Treasury proposal from the initial proposal on Moonbeam's Community Forum to Council approval of the on-chain spend. categories: Governance --- # How to Propose a Treasury Spend ## Introduction {: #introduction } Treasury spending proposals enable community members to request funding for projects that benefit the Moonbeam network, such as infrastructure improvements, resources, events, and ecosystem tools. The Treasury Council reviews proposals and weighs community feedback received in the Moonbeam Forum. However, the ultimate Aye/Nay decision rests with the Council. For more information about the structure of the Treasury Council, see the [Treasury page](/learn/features/treasury/){target=\_blank}. In this guide, you'll learn how to prepare and submit a Treasury spending proposal and understand the full lifecycle of a Treasury proposal. ## Definitions {: #definitions } Some of the key parameters for this guide are the following: - **Treasury address** — the address where Treasury funds accrue and are disbursed from - **Beneficiary** — the address, such as a [Moonbeam Safe multisig](/tokens/manage/multisig-safe/){target=\_blank}, that will receive the funds of the Treasury proposal if enacted - **Value** — the amount that is being asked for and will be allocated to the beneficiary address if the Treasury proposal is passed ## Treasury Addresses {: #treasury-addresses } The Treasury address for each respective network can be found below: === "Moonbeam" [0x6d6F646c70632f74727372790000000000000000](https://moonbase.subscan.io/account/0x6d6F646c70632f74727372790000000000000000){target=_blank} === "Moonriver" [0x6d6f646C70792f74727372790000000000000000](https://moonriver.subscan.io/account/0x6d6f646C70792f74727372790000000000000000){target=_blank} === "Moonbase Alpha" [0x6d6F646c70632f74727372790000000000000000](https://moonbase.subscan.io/account/0x6d6F646c70632f74727372790000000000000000){target=_blank} ## Roadmap of a Treasury Proposal {: #roadmap-of-a-treasury-proposal } The happy path of a Treasury spend request is as follows: 1. **Proposal submission** - the user submits a proposal to the [Moonbeam Forum](https://forum.moonbeam.network/c/governance/treasury-proposals/8){target=\_blank} 2. **Forum discussion** - the proposal is discussed by the community on the Forum. The ultimate Aye/Nay decision is determined by the Treasury council 3. **Treasury approval and action** - if the Treasury Council agrees, it authorizes the Treasury spending and moves the process forward ![Moonbeam Forum Home](/images/tokens/governance/treasury-proposals/treasury-proposal-1.webp) ## Submit Your Idea to the Forum {: #submitting-your-idea-to-the-forum } As mentioned in the happy path above, the first step of a Treasury proposal is to submit the proposal to the [Moonbeam Forum](https://forum.moonbeam.network/c/governance/treasury-proposals/8){target=\_blank}. You'll need to have an account on the [Moonbeam Forum](https://forum.moonbeam.network/){target=\_blank} and be logged in before submitting a Treasury spend proposal. To submit a Treasury spend proposal, follow these steps: 1. From the [**Governance** section](https://forum.moonbeam.network/c/governance/treasury-proposals/8){target=\_blank}, click **New Topic**. By starting the topic in the **Governance** section, the proposal will come pre-filled with a template to ensure you cover all the necessary points 2. Provide a **title** for the proposal 3. Enter the contents of the proposal, covering: the **Title** and **Proposal Status**, a brief **Abstract**, the **Motivation**, a **Project Overview** and **Team Experience**, the **Rationale**, any **Key Terms**, the **Overall Cost**, the **Use of Treasury Funds**, the **Technical Specifications**, and the **Steps to Implement** 4. Choose either **Moonbeam** or **Moonriver** as a tag to indicate which network your Treasury proposal applies to 5. Press **Create Topic** ![Submit a Treasury spend proposal](/images/tokens/governance/treasury-proposals/treasury-proposal-2.webp) ## Next Steps {: #next-steps } No further steps are required after proposing the spend. Members of the Treasury Council will complete all on-chain actions. If approved by the Treasury Council, the delivery of the Treasury payment to the designated beneficiary will happen automatically. For more information about the Treasury Council voting process, see the [Treasury page](/learn/features/treasury/#Treasury-council-voting-process){target=\_blank}. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/governance/voting/ --- BEGIN CONTENT --- --- title: How to Vote on a Proposal in OpenGov description: Follow this guide to learn how to vote and lock your tokens to support or reject a proposal put forth for a referendum in Governance v2 (OpenGov) on Moonbeam. categories: Governance --- # How to Vote on a Proposal in Governance v2: OpenGov ## Introduction {: #introduction } Referenda are simple, inclusive, and stake-based voting schemes. Each referendum has a proposal associated with it that suggests an action to take place. In OpenGov, each referendum will have a specified Origin class that the proposal will be executed with, and each Origin has its own Track that proposals will process through. Although referenda are completed by a common process, the requirements for approval are Track-specific. Token holders can vote on referenda using their own tokens, including those that are locked in staking. The weight of a vote is defined by two factors: the number of tokens locked and the lock duration (called Conviction). This is to ensure that there is an economic buy-in to prevent vote-selling. Consequently, the longer you are willing to lock your tokens, the stronger your vote will be weighted. You also have the option of not locking tokens at all, but the vote weight is drastically reduced. In Moonbeam, users are able to create and vote on proposals using their H160 address and private key, that is, their regular Ethereum account! This guide will outline the process, with step-by-step instructions, of how to vote on referenda in Governance v2: OpenGov. This guide will show you how to vote on Moonbase Alpha, but it can be easily adapted for Moonbeam and Moonriver. !!! note This page goes through the mechanics of how to vote at a more technical level. Token holders can leverage platforms such as [Polkassembly](https://moonbeam.network/news/participate-in-opengov-with-polkassembly-on-moonbeam){target=\_blank} to vote using a more friendly user interface. ## Definitions {: #definitions } Some of the key parameters for this guide are the following: - **Voting** — a mechanism for token holders to support (Aye), oppose (Nay), or remain neutral (Abstain) on a proposal. For Aye and Nay, the voting weight is determined by both the number of tokens locked and the lock duration (Conviction). Abstain votes do not receive additional weighting - **Conviction** — the time that token holders voluntarily lock their tokens when voting; the longer they are locked, the more weight their vote has - **Lock balance** — the number of tokens that a user commits to a vote (note, this is not the same as a user's total account balance) Moonbeam uses the concept of voluntary locking, which allows token holders to increase their voting power by locking tokens for a longer period of time. Specifying no Lock Period means a user's vote is valued at 10% of their lock balance. Specifying a greater Conviction increases voting power. For each increase in Conviction (vote multiplier), the Lock Periods double - **Maximum number of votes** — the maximum number of concurrent votes per account === "Moonbeam" ```text {{ networks.moonbeam.governance.max_votes }} votes ``` === "Moonriver" ```text {{ networks.moonriver.governance.max_votes }} votes ``` === "Moonbase Alpha" ```text {{ networks.moonbase.governance.max_votes }} votes ``` - **Approval** — minimum "Aye" votes as a percentage of overall Conviction-weighted votes needed for approval - **Support** — the minimum portion of Aye and Abstain votes (ignoring conviction) needed as a percentage of the total active supply for a proposal to pass. Nay votes do not count toward Support - **Lead-in Period** — the initial proposal voting and discussion period. At this stage, proposals are in an undecided state until they pass some criteria for the given Track. The criteria include: - **Prepare Period** — the minimum time the referendum needs to wait before it can progress to the next phase after submission - **Capacity** — limit for the number of referenda on a given Track that can be decided at once - **Decision Deposit** — the minimum deposit amount required for a referendum to progress to the decision phase after the end of the Lead-in Period. Since each Track has a defined Capacity, this deposit is larger than the submission deposit, and its goal is to mitigate spam - **Decide Period** - token holders continue to vote on the referendum. If a referendum does not pass by the end of the period, it will be rejected, and the Decision Deposit will be refunded - **Confirm Period** - a period of time within the Decide Period where the referendum needs to have maintained enough Approval and Support to be approved and move to the Enactment Period - **Enactment Period** - a specified time, which is defined at the time the proposal was created, that meets at least the minimum amount of time that an approved referendum waits before it can be dispatched - **Vote Delegation** — a voter can give their voting power, including Conviction voting, to another token holder (delegate), who may be more knowledgeable and able to make specific decisions - **Multirole Delegation** — the ability to delegate voting power on a Track-by-Track basis, where a token holder can specify different delegates for each Track For an overview of the Track-specific parameters such as the length of the Decide, Confirm, and Enactment Period, the Approval and Support requirements, and more, please refer to the [Governance Parameters for OpenGov (Governance v2) section of the governance overview page](/learn/features/governance/#governance-parameters-v2){target=\_blank}. ## Roadmap of a Proposal {: #roadmap-of-a-proposal } This guide will cover how to vote on public referenda, as seen in the steps highlighted in the proposal roadmap diagram below. In addition to learning how to vote on referenda, you'll also learn how the proposal progresses through the Lead-in Period, the Decide and Confirm Period, and the Enactment Period. You can find a full explanation of the [happy path for an OpenGov proposal on the Governance overview page](/learn/features/governance/#roadmap-of-a-proposal-v2){target=\_blank}. ![Proposal Roadmap](/images/tokens/governance/voting/proposal-roadmap.webp) ## Forum Discussion {: #forum-discussion} A vote on a democracy referendum is a binary outcome. However, a token holder's opinion is often more nuanced than yes or no, which is why it's strongly recommended that you preface any proposal with a post on [Moonbeam's Community Forum](https://forum.moonbeam.network){target=\_blank}. The forum serves the critical role of providing a platform for discussion and allowing proposers to receive feedback from the community prior to an on-chain action. Creating a post on the forum is quick and easy, as shown in the [Using the Moonbeam Community Forum](https://moonbeam.network/news/using-the-moonbeam-community-forum-to-submit-a-treasury-proposal){target=\_blank} guide. There are categories corresponding to each type of proposal, including democracy, treasury, and grant proposals. While this step is optional, explaining the details of the proposal and following up with any questions raised may increase the chances of the initiative being accepted and subsequently passed by the community. ![Moonbeam's Community Forum home](/images/tokens/governance/voting/vote-1.webp) ## Voting on a Referendum {: #voting-on-a-referendum } This section goes over the process of voting on a public referendum in OpenGov (Governance v2) on Moonbase Alpha. These steps can be adapted for Moonbeam and Moonriver. The guide assumes that there is one already taking place. If there is an open referendum that you want to vote on, you can adapt these instructions to learn how to vote on it. To vote on a proposal on the network, you need to use the Polkadot.js Apps interface. To do so, you need to import an Ethereum-style account first (H160 address), which you can do by following the [Creating or Importing an H160 Account](/tokens/connect/polkadotjs/#creating-or-importing-an-h160-account){target=\_blank} guide. For this example, three accounts were imported and named with super original names: Alice, Bob, and Charlie. ![Accounts in Polkadot.js](/images/tokens/governance/proposals/proposals-3.webp) To get started, you'll need to navigate to [Moonbase Alpha's Polkadot.js Apps interface](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network){target=\_blank}. Everything related to governance lives under the **Governance** tab. To view all of the referenda, you can choose **Referenda** from the **Governance** dropdown. On the **Referenda** page, you'll see a list of referenda organized by Track. To view the details of a specific referendum, you can click on the arrow next to the description. The number next to the action and description is called the referendum index. ### How to Support a Proposal by Contributing to the Decision Deposit {: #submit-decision-deposit } In order for a referendum to move out of the Lead-in Period into the Decide Period, the Decision Deposit must be submitted. This deposit can be submitted by the author of the proposal or any other token holder. The deposit varies depending on the Track of the proposal. For example, a referendum that is in the General Admin Track has a Decision Deposit of {{ networks.moonbase.governance.tracks.general_admin.decision_deposit }} on Moonbase Alpha. From the [list of referenda on Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/referenda){target=\_blank}, you may notice that some proposals are in the **Preparing** state. If a referendum requires the Decision Deposit to be submitted, you'll see a **Decision deposit** button. To submit the deposit, you can go ahead and click on this button. ![To start to submit a Decision Deposit for a referendum, click on the "Decision deposit" button on Polkadot.js Apps.](/images/tokens/governance/voting/vote-2.webp) Then take the following steps to submit the deposit from a specific account: 1. Select the **deposit from account**. This account does not need to be the author of the proposal; it can be from any token holder. However, if the proposal is deemed malicious, the Decision Deposit will be burned. So, before placing the deposit, it is advised to do your due diligence to ensure the proposal is not malicious 2. The **referendum id** and **decision deposit** fields will automatically be populated for you based on the referendum and Track it belongs to 3. Click **Place deposit** and sign the transaction ![To submit the Decision Deposit, choose the account to place the deposit and click on the "Place deposit" button on Polkadot.js Apps.](/images/tokens/governance/voting/vote-3.webp) Once the deposit has been placed, Polkadot.js Apps will update and display the account that paid the Decision Deposit along with the amount of the deposit. Now this referendum is one step closer to meeting the criteria of the Lead-in Period. If the Prepare Period has passed and there is enough space for a referendum in the General Admin Track, this proposal will move on to the Decide Period. ### How to Vote {: #how-to-vote } As you may have noticed, voting is not required in the Lead-in Period. However, it is essential in the Decide Period. The steps in this section will apply to referenda in both the Lead-in Period and the Decide Period. To vote and lock tokens either in favor of or against a referendum, you can get started by clicking on the **Vote** button next to the referendum you want to vote on. ![To vote on a referendum, click on the "Vote" button on Polkadot.js Apps.](/images/tokens/governance/voting/vote-4.webp) Then you can take the following steps to fill in the details of the vote: 1. Select the **vote with account** 2. Choose how you would like to vote on the referendum. You can choose **Aye** in favor of the referendum, **Nay** in opposition to it, or **Split** if you want to specify an "Aye" vote value and a "Nay" vote value 3. Enter the vote value 4. Set the vote conviction, which determines the weight of your vote (`vote_weight = tokens * conviction_multiplier`). Please refer to the [Conviction multiplier](/learn/features/governance/#conviction-multiplier){target=\_blank} docs for more information 5. Click **Vote** and sign the transaction ![To submit a vote on a referendum, fill out the details of the vote and click on the "Vote" button on Polkadot.js Apps.](/images/tokens/governance/voting/vote-5.webp) !!! note The lockup periods shown in the previous image are not to be taken as references as they are subject to change. To see how your vote and all of the other votes for a referendum impacted the Approval and Support curves, you can click on the arrow next to the **Vote** button. You'll notice there are two charts, one for each curve. If you hover over the charts, you can see the minimum Approval or Support required for a specific block along with the current Approval or Support. ![View the Approval and Support curves for a referendum on Polkadot.js Apps.](/images/tokens/governance/voting/vote-6.webp) A proposal in the General Admin Track on Moonbase Alpha would have the following characteristics: - The Approval curve starts at {{ networks.moonbase.governance.tracks.general_admin.min_approval.percent0 }}% on {{ networks.moonbase.governance.tracks.general_admin.min_approval.time0 }} and goes to {{ networks.moonbase.governance.tracks.general_admin.min_approval.percent1 }}% on {{ networks.moonbase.governance.tracks.general_admin.min_approval.time1 }} - The Support curve starts at {{ networks.moonbase.governance.tracks.general_admin.min_support.percent0 }}% on {{ networks.moonbase.governance.tracks.general_admin.min_support.time0 }} and goes to {{ networks.moonbase.governance.tracks.general_admin.min_support.percent1 }}% on {{ networks.moonbase.governance.tracks.general_admin.min_support.time1 }} - A referendum starts the Decide Period with 0% "Aye" votes (nobody voted in the Lead-in Period) - Token holders begin to vote, and the Approval increases to a value above {{ networks.moonbase.governance.tracks.general_admin.min_approval.percent1 }}% by {{ networks.moonbase.governance.tracks.general_admin.min_approval.time1 }} - If the Approval and Support thresholds are met for the duration of the Confirm Period ({{ networks.moonbase.governance.tracks.general_admin.confirm_period.blocks }} blocks, approximately {{ networks.moonbase.governance.tracks.general_admin.confirm_period.time }}), the referendum is approved - If the Approval and Support thresholds are not met during the Decision Period, the proposal is rejected. Note that the thresholds need to be met for the duration of the Confirm Period. Consequently, if they are met but the Decision Period expires before the completion of the Confirm Period, the proposal is rejected In the following image, you'll notice enough Approval and Support have been received, so the Confirm Period is underway. If the referendum maintains the Approval and Support levels, at block 124,962, the Confirm Period will end, and then the Enactment Period will begin. You can hover over the charts to find out more information on each of these periods. Assuming this referendum maintains the levels of Approval and Support it has received, the Enactment Period will end at block 132,262, and the proposal action will be dispatched. ![View the Approval and Support curves for a referendum on Polkadot.js Apps.](/images/tokens/governance/voting/vote-7.webp) If the referendum doesn't continuously receive enough Approval and Support during the Confirm Period, it still has a chance to pass as long as the Approval and Support requirements are met again and continuously for the duration of the Confirm Period. If a referendum enters the Confirm Period but the Decide Period is set to end before the Confirm Period is over, the Decide Period will actually be extended until the end of the Confirm Period. If the Decide Period ends and the referendum still hasn't received enough Approval and Support, the referendum will be rejected, and the Decision Deposit can be refunded. The Enactment Period is defined by the author of the proposal at the time it was initially submitted, but it needs to be at least the minimum Enactment Period. ### Delegate Voting {: #delegate-voting } Token holders have the option to delegate their vote to another account whose opinion they trust. The account being delegated does not need to take any particular action. When they vote, the vote weight (that is, tokens times the Conviction multiplier chosen by the delegator) is added to their vote. With the introduction of OpenGov (Governance v2), token holders can even delegate their vote on a Track-by-Track basis and specify different delegates for each Track, which is referred to as Multirole Delegation. From the [referenda page on Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/referenda){target=\_blank}, you can click **Delegate** to get started. ![To submit a delegate vote on a referendum, click on the "Delegate" button on Polkadot.js Apps.](/images/tokens/governance/voting/vote-8.webp) Then you can take the following steps to fill in the details of the delegation: 1. Enter the **delegate from account**, which should be the account that you wish to delegate your vote from 2. Select the **submission track** or switch the **apply delegation to all tracks** slider to on if you want the other account to vote on your behalf on any of the Tracks 3. Enter the **delegated vote value** 4. Set the vote conviction, which determines the weight of your vote (`vote_weight = tokens * conviction_multiplier`). Please refer to the [Conviction Multiplier](/learn/features/governance/#conviction-multiplier){target=\_blank} docs for more information 5. Click **Next** 6. On the next screen, select the **delegate to address**, which should be the account that you wish to delegate your vote to 7. Click **Delegate** and sign the transaction ![Submit a delegate vote on a referendum by filling in all of the delegation details and clicking on the "Delegate" button on Polkadot.js Apps.](/images/tokens/governance/voting/vote-9.webp) Now the account you selected to delegate your vote to will be able to vote on your behalf. Once this account votes, the total vote weight delegated will be allocated to the option that the account selected. For this example, Baltahar can vote in favor of a referendum with a total weight of 20000 (10000 tokens with an x2 Conviction factor) using the vote weight that Charleth delegated to him. You can continue the above process for each Track and delegate a different account with varying vote weights. To undelegate a delegation, you'll need to head to the **Developer** tab and click on **Extrinsics**. From there, you can take the following steps: 1. Select the account you have delegated from 2. Choose the **convictionVoting** pallet and the **undelegate** extrinsic 3. Enter the **class** of the Origin. For the General Admin Track, it is `2`. For a complete list of Track IDs, refer to the [OpenGov section of the governance overview page](/learn/features/governance/#general-parameters-by-track){target=\_blank} 4. Click **Submit transaction** and sign the transaction ![Undelegate a vote on Polkadot.js Apps.](/images/tokens/governance/voting/vote-10.webp) ### Refunding the Decision Deposit {: #refund-the-decision-deposit } If a referendum has been approved or rejected, the Decision Deposit will be eligible to be refunded, as long as it was not rejected due to it being a malicious proposal. Malicious proposals will result in the Decision Deposit being slashed. Any token holder can trigger the refund of the deposit back to the original account that placed the deposit. To refund the deposit, you can take the following steps on the [referenda page on Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/referenda){target=\_blank}. If the referendum is eligible and the deposit hasn't already been refunded, you'll see a **Refund deposit** button. So, you can go ahead and click that button to get started. ![Get started refunding a Decision Deposit from a passed referendum on Polkadot.js Apps.](/images/tokens/governance/voting/vote-11.webp) Then, to submit the refund transaction, you can: 1. Choose the account for which you want to trigger the refund. This does not need to be the account that initially placed the deposit 2. Click **Refund deposit** and sign the transaction ![Refund the Decision Deposit on Polkadot.js Apps.](/images/tokens/governance/voting/vote-12.webp) ### Unlocking Locked Tokens {: #unlocking-locked-tokens } When token holders vote, the tokens used are locked and cannot be transferred. You can verify if you have any locked tokens in the **Accounts** tab by expanding the address's account details. There, you will see different types of balances. If you have any tokens locked in referenda, you'll see **referenda** listed in your balance details, and you can hover over it to find out details about which referendum your tokens are locked for. Different lock statuses include: - Locked because of an ongoing referendum, meaning that you've used your tokens and have to wait until the referendum finishes, even if you've voted with a no-lock Conviction factor - Locked because of the Conviction multiplier selected, displaying the number of blocks and time left - Lock expired, meaning that you can now get your tokens back ![View locked balances on the account page of Polkadot.js Apps.](/images/tokens/governance/voting/vote-13.webp) Once the lock has expired, you can request your tokens back. To do so, navigate to the **Extrinsics** menu under the **Developers** tab. Here, two different extrinsics need to be sent. First, you need to provide the following information: 1. Select the account from which you want to recover your tokens 2. Choose the pallet you want to interact with. In this case, it is the `convictionVoting` pallet and the extrinsic to use for the transaction. This will determine the fields that you need to fill in the following steps. In this case, it is `removeVote` extrinsic. This step is necessary to unlock the tokens. This extrinsic can also be used to remove your vote from a referendum 4. Optionally, you can specify the Track ID to remove votes for. To do so, simply toggle the **include option** slider and enter the Track ID in the **class u16** field 5. Enter the referendum index. This is the number that appeared on the left-hand side of the **Referenda** tab 6. Click the **Submit Transaction** button and sign the transaction ![Submit an extrinsic to remove your vote on a referendum in Polkadot.js Apps.](/images/tokens/governance/voting/vote-14.webp) For the next extrinsic, you need to provide the following information: 1. Select the account from which you want to recover your tokens 2. Choose the pallet you want to interact with. In this case, it is the `convictionVoting` pallet 3. Choose the extrinsic method to use for the transaction. This will determine the fields that need to be filled out in the following steps. In this case, it is the `unlock` extrinsic 4. Enter the Track ID to remove the voting lock for 5. Enter the target account that will receive the unlocked tokens. In this case, the tokens will be returned to Alice 6. Click the **Submit Transaction** button and sign the transaction ![Submit an extrinsic to unlock your tokens that were locked in referenda in Polkadot.js Apps.](/images/tokens/governance/voting/vote-15.webp) Once the transaction goes through, the locked tokens should be unlocked. To double-check, you can go back to the **Accounts** tab and see that your full balance is now **transferable**. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/ --- BEGIN CONTENT --- --- title: How to use your GLMR & MOVR Tokens description: A series of guides for using and managing your GLMR & MOVR tokens, including supported wallets, participating in governance and staking, and more. template: main-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/manage/identity/ --- BEGIN CONTENT --- --- title: Managing an Identity description: Learn how to create and manage an on-chain identity, which includes personal information such as your name and social handles, on Moonbeam-based networks. categories: Tokens and Accounts --- # Managing your Account Identity ## Introduction {: #introduction } The [Substrate](/learn/platform/technology/#substrate-framework){target=\_blank} Identity pallet is an out-of-the-box solution for adding personal information to your on-chain account. Personal information can include default fields such as your legal name, display name, website, Twitter handle, Riot (now known as Element) name. You can also take advantage of custom fields to include any other relevant information. Once your identity information is on-chain, you can request verification of your identity from a registrar. A registrar will perform proper due diligence to verify the submitted identity information and based on their findings will provide their judgement on-chain and a green check mark will appear next to your account. This guide will show you how to set an identity, clear it, and request judgement on the Moonbase Alpha TestNet. This guide can also be adapted to be used on Moonbeam and Moonriver. ## General Definitions {: #general-definitions } To store your information on-chain, you must bond some funds, which eventually will be returned once the identity has been cleared. There are two categories of fields: default and custom. If custom fields are used, you will be required to submit an additional deposit for each field. - **Default fields include** - your legal name, display name, website, Twitter handle, Riot (now known as Element) name - **Custom fields include** - any other relevant information. For example, you could include your Discord handle === "Moonbeam" | Variable | Definition | Value | |:---------------------:|:-----------------------------------------------------------------------:|:-----------------------------------------------:| | Basic deposit | The amount held on deposit for setting an identity | {{ networks.moonbeam.identity.basic_dep }} GLMR | | Field deposit | The amount held on deposit per additional field for setting an identity | {{ networks.moonbeam.identity.field_dep }} GLMR | | Max additional fields | Maximum number of additional fields that may be stored in an ID | {{ networks.moonbeam.identity.max_fields }} | === "Moonriver" | Variable | Definition | Value | |:---------------------:|:-----------------------------------------------------------------------:|:------------------------------------------------:| | Basic deposit | The amount held on deposit for setting an identity | {{ networks.moonriver.identity.basic_dep }} MOVR | | Field deposit | The amount held on deposit per additional field for setting an identity | {{ networks.moonriver.identity.field_dep }} MOVR | | Max additional fields | Maximum number of additional fields that may be stored in an ID | {{ networks.moonriver.identity.max_fields }} | === "Moonbase Alpha" | Variable | Definition | Value | |:---------------------:|:-----------------------------------------------------------------------:|:----------------------------------------------:| | Basic deposit | The amount held on deposit for setting an identity | {{ networks.moonbase.identity.basic_dep }} DEV | | Field deposit | The amount held on deposit per additional field for setting an identity | {{ networks.moonbase.identity.field_dep }} DEV | | Max additional fields | Maximum number of additional fields that may be stored in an ID | {{ networks.moonbase.identity.max_fields }} | ## Checking Prerequisites { : #checking-prerequisites } For this guide, you will need the following: - To connect to the [Moonbase Alpha TestNet](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network){target=\_blank} on the Polkadot.js Apps explorer. You can also follow along and adapt the instructions for [Moonbeam](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbeam.network){target=\_blank} or [Moonriver](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonriver.moonbeam.network){target=\_blank}. - To [create or import an account](/tokens/connect/polkadotjs/#creating-or-importing-an-h160-account) into Polkadot.js Apps - Make sure you have funded your account. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} ## Get Started {: #get-started } There are a couple different ways to set and clear an identity using the Polkadot.js Apps, depending on the information to be included. If you intend to register your identity using only the default fields, you can follow the instructions for [Managing an Identity via the Accounts UI](#manage-via-accounts). **This is the recommended way to set and manage your identity**. If you are looking for a more customizable experience and want to add custom fields beyond the default fields, you can follow the instructions for [Managing an Identity via the Extrinsics UI](#manage-via-extrinsics). !!! note Please note that it is recommended to use the **Accounts** UI on Polkadot.js Apps to manage your identity as it provides an easy-to-use interface that enforces character limits. If you use the **Extrinsics** UI, please be aware that your input for each field (i.e, name, email, etc.) must be 32 characters or less, otherwise, your information will be cut off. ## Manage an Identity via Accounts {: #manage-via-accounts } ### Set an Identity {: #set-identity-accounts } To get started with setting an identity using the Accounts UI, head to the [Accounts tab](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/accounts){target=\_blank} on the Polkadot.js Apps explorer. You should already have an account connected, so you can go ahead and click on your account name to verify and take note of your balances. After you send the transaction to set an identity, the deposit(s) you submitted will be moved from your transferable balance to your reserved balance. ![Starting account balances](/images/tokens/manage/identity/identity-1.webp) To set your identity, you'll need to: 1. Click on the 3 vertical dots next to the account you would like to set an identity for 2. A menu will pop up. Click **Set on-chain identity** ![Set on-chain identity](/images/tokens/manage/identity/identity-2.webp) Next, the menu to register and set your identity will pop-up and you can start filling in your information. You are not required to enter information for every single field, you can choose to fill in just one field or all of them, it's up to you. For this example: 1. Set your display name 2. Click on the **include field** toggle for email and then enter in your email 3. Click on the **include field** toggle for Twitter and then enter in your Twitter handle 4. After you're done filling in your information and the deposit amount looks alright to you, click **Set Identity** ![Set your identity](/images/tokens/manage/identity/identity-3.webp) You will then be prompted to sign the transaction. If everything looks good, you can enter your password and click **Sign and Submit** to sign and send the transaction. You should see status notifications pop-up in the top right hand corner. Once the transaction has been confirmed, you can click on your account name again and the panel will slide out on the right side of the page. Your balances will have changed, and you’ll also see your new identity information. ![Updated account balances](/images/tokens/manage/identity/identity-4.webp) If the identity information matches what you entered, you’ve successfully set an identity! Once you clear your identity, the deposit in your reserved balance will get transferred back to your transferable balance. If you need to make changes to your identity, you can go through the process of setting your identity again. Please note that you will need to ensure all fields are re-entered, even if only one field needs to be changed, or they will be overwritten. You will not need to pay another deposit, unless custom fields are used, but you will need to pay gas fees. ### Clear an Identity {: #clear-identity-accounts } To clear your identity from the [Accounts tab](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/accounts){target=\_blank} of the Polkadot.js Apps UI, you'll need to: 1. Click on the 3 vertical dots next to the account you would like to add identity information for 2. A menu will pop up. Click **Set on-chain identity** ![Set on-chain identity](/images/tokens/manage/identity/identity-5.webp) The identity menu will pop-up with your information already filled out. You'll need to click **Clear Identity**. ![Clear identity](/images/tokens/manage/identity/identity-6.webp) You will then be prompted to sign the transaction. If everything looks good, you can enter your password and click **Sign and Submit** to sign and send the transaction. You should see status notifications pop-up in the top right hand corner. Once the transaction has been confirmed, you can click on your account name again and the panel will slide out on the right side of the page. You can see your reserved balance was transferred back to your transferable balance, and your identity information has been removed. That’s it! You’ve successfully cleared your identity. If you want to add a new identity, you can do so at any time. ## Manage an Identity via Extrinsics {: #manage-via-extrinsics } ### Set an Identity {: #set-identity-extrinsics } To register an identity using the extrinsics UI, navigate to the [Extrinsics page](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/extrinsics){target=\_blank} on Polkadot.js Apps. Then, you'll need to: 1. Select your account 2. Select identity from the **submit the following extrinsic** dropdown 3. Then select the **setIdentity(info)** function 4. Start filling in your identity information. Please make sure that for each field, your input does not exceed 32 characters 1. Select the format of the data. For this example, you can use **Raw** data but you also have the option of entering your data in BlackTwo256, Sha256, Keccak256, and ShaThree256 hashed format 2. Enter the data in that format ![Set your identity using the Extrinsics UI](/images/tokens/manage/identity/identity-7.webp) Optionally, if you would like to enter custom fields, you can do so by: 1. Scrolling to the top and clicking on **Add item** 2. Two fields will appear: the first for the field name and the second for the value. Please make sure that for each field and value, your input does not exceed 32 characters. Fill in the field name 1. Select the format of the data for the field name. Again, you can use **Raw** data 2. Enter the field name in the selected format 3. Fill in the value 1. Select the format of the data for the value. Again, you can use **Raw** data 2. Enter the value in the selected format ![Add custom fields](/images/tokens/manage/identity/identity-8.webp) Finally, once all of your identity information has been added, you can scroll to the bottom of the page and click **Submit Transaction**. ![Submit identity information](/images/tokens/manage/identity/identity-9.webp) You will then be prompted to sign the transaction. Remember, there is an additional deposit required for each additional custom field. If everything looks good, you can enter your password and click **Sign and Submit** to sign and send the transaction. You should see status notifications pop-up in the top right hand corner confirming the transaction. If successful, you’ve set an identity! Congratulations! To make sure everything went through and your identity information looks good, next you can confirm your identity. ### Confirm an Identity {: #confirm-identity-extrinsics } To verify the addition of your identity information, you can click on the **Developer** tab and then navigate to [Chain state](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/chainstate){target=\_blank}. On the **Chain State** UI, make sure **Storage** is selected. Then you can start to request your identity information: 1. Set **selected state query** to **identity** 2. Select the **identityOf(AccountId)** function 3. Select your account 4. Click the **+** button to get your identity information ![Request identity information](/images/tokens/manage/identity/identity-10.webp) You can see now that you’ve successfully set an identity! Once you clear your identity, the deposit in your reserved balance will get transferred back to your transferable balance. If you need to make changes to your identity, you can go through the process of setting your identity again. Please note that you will need to ensure all fields are re-entered, even if only one field needs to be changed, or they will be overwritten. You will not need to pay another deposit, unless custom fields are used, but you will need to pay gas fees. ### Clear an Identity {: #clear-identity-extrinsics } To clear your identity from the [Extrinsics tab](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/extrinsics){target=\_blank} of the Polkadot.js Apps UI, you'll need to: 1. Select your account from the **using the selected account** dropdown 2. Select **identity** from the **submit the following extrinsic** dropdown 3. Then select the **clearIdentity()** function 4. Click **Submit Transaction** ![Clear an identity using the Extrinsics UI](/images/tokens/manage/identity/identity-11.webp) You will then be prompted to sign the transaction. If everything looks good, you can enter your password and click **Sign and Submit** to sign and send the transaction. You should see status notifications pop-up in the top right hand corner confirming the transaction. To verify the removal of your identity information, you can follow the steps in the [Confirm an Identity](#confirm-identity-extrinsics) section again. Instead of seeing your identity information, this time you'll get a response of **none**. Meaning, you no longer have any identity information associated with your account. If you check your balances, you should see that the initial deposit for setting your identity has been returned to your transferable balance. That’s it! Your identity has been cleared. ## Identity Judgement {: #identity-judgement } After submitting your identity information, you can request verification of your identity from a registrar. Registrars are tasked with verifying the submitted identity information and can set a fee for their services. When you request judgement, you'll need to specify the registrar you want to verify your information and the maximum fee that you're willing to pay them for providing judgement. The request will only be processed if the selected registrar charges less than the maximum fee that you specified, otherwise the transaction will fail. The fee will be locked until the registrar completes the judgement process and only then will the fee be transferred to the registrar. The registrar fee is in addition to the deposit paid when you initially created your identity. Registrar applicants are appointed via on-chain democracy. If an appointed registrar issues incorrect judgements or proves to be untrustworthy, they can be removed through democracy. A registrar will perform proper due diligence to verify the submitted identity information and based on their findings will provide judgement and assign up to seven levels of confidence: - **Unknown** - no judgement made yet. This is the default value - **Fee Paid** - indicates a user has requested judgement and it is in progress - **Reasonable** - the information appears reasonable, but no in-depth checks were performed using legal identity documents - **Known Good** - the information is correct and is based upon review of legal identity documents - **Out of Date** - the information used to be good, but is now out of date - **Low Quality** - the information is low quality or imprecise, but can be updated as needed - **Erroneous** - the information is erroneous and may indicate malicious intent. This state cannot be modified and can only be removed if the entire identity has been removed ### Current Registrars {: #current-registrars } When requesting identity judgement, you'll need to provide the index of the registrar you want to complete your request. The current registrars are as follows: === "Moonbeam" | Registrar | Operator | Address | Index | |:---------------------------------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------:|:------------------------------------------:|:-----:| | [Registrar #0](https://forum.moonbeam.network/t/referendum-73-identity-registrar-0/208){target=\_blank} | [Moonbeam Foundation](https://moonbeam.foundation){target=\_blank} | 0xbE6E642b25Fa7925AFA1600C48Ab9aA3461DC7f1 | 0 | | [Registrar #1](https://forum.moonbeam.network/t/referendum-82-new-registrar-proposal-registrar-1/319){target=\_blank} | [Chevdor](https://www.chevdor.com){target=\_blank} | 0xeaB597B91b66d9C3EA5E3a39e22C524c287d61a5 | 1 | === "Moonriver" | Registrar | Operator | Address | Index | |:----------------------------------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------:|:------------------------------------------:|:-----:| | [Registrar #0](https://forum.moonbeam.network/t/referendum-120-identity-registrar-0/187){target=\_blank} | [Moonbeam Foundation](https://moonbeam.foundation){target=\_blank} | 0x031590D13434CC554f7257A89B2E0B10d67CCCBa | 0 | | [Registrar #1](https://forum.moonbeam.network/t/referendum-125-new-registrar-proposal-registrar-1/303){target=\_blank} | [Chevdor](https://www.chevdor.com){target=\_blank} | 0x2d18250E01312A155E81381F938B8bA8bb4d97B3 | 1 | === "Moonbase Alpha" | Registrar | Operator | Address | Index | |:------------------------------------------------------------------------------------:|:---------------------------------------------------:|:------------------------------------------:|:-----:| | [Registrar #1](https://www.chevdor.com/post/2020/07/14/reg-updates){target=\_blank} | [Chevdor](https://www.chevdor.com){target=\_blank} | 0x4aD549e07E96BaD335A8b99C8fd32e95EE538904 | 1 | You can get a complete list of the current registrars, including the fees that each registrar charges, by heading to [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network){target=\_blank}, selecting the **Developer** tab, choosing **Chain State** from the dropdown, and taking the following steps: 1. Select the **identity** pallet 2. Choose the **registrars** extrinsic 3. Click the **+** button ![View registrar list](/images/tokens/manage/identity/identity-12.webp) ### Request Identity Judgement {: #request-judgement } To request identity judgement, from the **Extrinsics** page, you can take the following steps: 1. Select your account from the **using the selected account** dropdown 2. Select **identity** from the **submit the following extrinsic** dropdown 3. Then select the **requestJudgement()** function 4. Enter the index of the registrar you want to review and provide judgement on your identity information 5. Enter the maximum fee you're willing to pay in Wei. This must be higher than the fee set by the registrar, otherwise the transaction will fail 6. Click **Submit Transaction** ![Request identity judgement](/images/tokens/manage/identity/identity-13.webp) Once the transaction goes through, the fee will be taken from your free balance and locked until the judgement is complete. After the judgement is complete and you've been successfully verified, a green check mark will appear next to your account. If successful, your identity will be assigned one of these three levels of confidence: low quality, reasonable, or known good. From the **Accounts** page, you can click on your account name to review your identity information and your identity judgement results. ![Identity verified](/images/tokens/manage/identity/identity-14.webp) ### Cancel Identity Judgement Request {: #cancel-judgement-request } If the registrar hasn't completed your judgement, you can cancel the request and receive the locked fee back. To do so, from the **Extrinsics** page, take the following steps: 1. Select your account from the **using the selected account** dropdown 2. Select **identity** from the **submit the following extrinsic** dropdown 3. Then select the **cancelRequest()** function 4. Click **Submit Transaction** ![Cancel judgement request](/images/tokens/manage/identity/identity-15.webp) You'll then be prompted to sign and send the transaction. Once it goes through, your locked funds will be returned to you. --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/manage/ --- BEGIN CONTENT --- --- title: Manage & Secure your Account description: Learn how to manage and secure your account on Moonbeam by creating an on-chain identity, and setting up multisig safes and proxy accounts. dropdown_description: Advanced account and identity services template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/manage/multisig-safe/ --- BEGIN CONTENT --- --- title: Moonbeam Multisig Safe description: Learn how to use and manage funds with the Moonbeam Safe. Create a new multisig safe and receive and send tokens to the safe, as well as ERC-20s, on Moonbeam. categories: Tokens and Accounts --- # Interacting with Moonbeam Safe
## Introduction {: #introduction } A single-signature wallet, or singlesig for short, is a wallet in which only one owner holds the private key, and therefore has control over all the assets that account holds. Moreover, if the private key is lost, then access to the wallet and the funds are lost forever. To solve this problem, multi-signature wallets, or multisig for short, have been introduced. With a multisig wallet there is more than one owner, so one owner could lose their keys and the others would still have access to the wallet and funds. In addition, multisig wallets can require threshold signing, where a proposal is only executed as a transaction if a certain amount of approvals are attained. Therefore creating an extra layer of security. To help manage singlesig and multisig wallets, [Gnosis Safe](https://gnosis-safe.io){target=\_blank} was forked to create [Moonbeam Safe](https://multisig.moonbeam.network){target=\_blank}. The Safe can be configured as a multisig contract that allows two or more owners to hold and transfer funds to and from the Safe. You can also configure the Safe to be a singlesig contract with only one owner. This guide will show you how to create a multisig Safe on the Moonbase Alpha TestNet. You will also learn how to send DEV and ERC-20 tokens to and from the Safe, and how to interact with smart contracts using the Safe. This guide can be adapted for Moonbeam and Moonriver.
The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).
## Checking Prerequisites {: #checking-prerequisites } Before diving into the guide, you'll need to have a few [MetaMask accounts](#metamask-accounts) loaded up with funds, some [ERC-20 tokens](#erc20-tokens) on hand to send to the Safe, and a [deployed smart contract](#deployed-smart-contract) to interact with. ### MetaMask Accounts {: #metamask-accounts } For this guide, you will be creating a Safe on Moonbase Alpha to interact and manage your funds with. To connect to the Safe, you will need to have: - MetaMask installed and [connected to Moonbase Alpha](/tokens/connect/metamask/){target=\_blank} - At least two accounts each loaded with funds. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} You will need at least two accounts because you will be setting up a multisig Safe with 3 owners, and 2/3 confirmations for any transaction to get executed. Therefore, throughout this guide you will need to switch back and forth between at least two of the accounts to be able to confirm and send transactions. This guide will use the following accounts: - **Alice** — 0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac - **Bob** — 0x3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0 - **Charlie** — 0x798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc ### ERC-20 Tokens {: #erc20-tokens } Later on in this guide, you will be learning how to send and receive ERC-20 tokens to and from the Safe. So you will need to have deployed some ERC-20 tokens and added them to your MetaMask account. To do so, you can check out the [Using Remix to Deploy to Moonbeam](/builders/ethereum/dev-env/remix/){target=\_blank} guide, in particular the [Deploying a Contract to Moonbeam](/builders/ethereum/dev-env/remix/#deploying-a-contract-to-moonbeam-using-remix){target=\_blank} and [Interact with a Moonbeam-based ERC-20](/builders/ethereum/dev-env/remix/#interacting-with-a-moonbeam-based-erc-20-from-metamask){target=\_blank} sections will show you how to deploy an ERC-20 token and import it into MetaMask. ### Deployed Smart Contract {: #deployed-smart-contract } Towards the end of this guide, you will be learning how to interact with a smart contract using the Safe. So you will need to have a smart contract deployed to interact with. If you would like detailed instructions, you can refer to the [Deploying a Contract to Moonbeam using Remix](/builders/ethereum/dev-env/remix/#deploying-a-contract-to-moonbeam){target=\_blank} guide. You can head to [Remix](https://remix.ethereum.org){target=\_blank} and create a new file for the following `SetText.sol` contract: ```solidity pragma solidity ^0.8.0; contract SetText { string public text; function setTextData(string calldata _text) public { text = _text; } } ``` This is a simple contract with a single function, `setTextData`, that accepts a string and uses it to set the `text` variable. You will need the contract address and the ABI, so make sure you have copied those somewhere or have access to them for later on. ## Create a Safe {: #create-a-safe } To get started creating a Safe, navigate to the [Moonbeam Safe](https://multisig.moonbeam.network/?chain=mbase){target=\_blank}. For the purpose of this guide, you'll create a Safe on Moonbase Alpha, but you can also adapt the instructions to create a Safe on [Moonbeam](https://multisig.moonbeam.network/?chain=mbeam){target=\_blank} or [Moonriver](https://multisig.moonbeam.network/?chain=mriver){target=\_blank}. To switch networks, simply click the network dropdown in the top right hand corner of the page. ### Connect MetaMask {: #connect-metamask } Once on the [Moonbase Alpha](https://multisig.moonbeam.network/?chain=mbase){target=\_blank} page, you can begin to create a Safe by first connecting your wallet: 1. Click **Connect Wallet** 2. Select a wallet to connect to Moonbeam Safe. For this example you can use MetaMask. If MetaMask doesn't appear in the list of options, click **Show More** and select **MetaMask** ![Connect Wallet to Moonbeam Safe](/images/tokens/manage/multisig-safe/safe-1.webp) If you're not already signed into MetaMask, you will be prompted to sign in. You will then be guided through adding and connecting your accounts, and adding and switching to the Moonbase Alpha network: 1. Select an account and connect to the Safe. You'll want to select at least 2 of the 3 owner accounts and then click **Next**. For this example, Alice, Bob, and Charlie's accounts have all been selected 2. Connect to the selected accounts by clicking **Connect** 3. If you are not connected to Moonbase Alpha, nor do you have the network added to your MetaMask, add Moonbase Alpha as a custom network by clicking **Approve** 4. Switch the network to Moonbase Alpha by click **Switch Network** ![Connect MetaMask to Moonbase Alpha](/images/tokens/manage/multisig-safe/safe-2.webp) Now, in the top right hand corner, you can confirm you are connected to your MetaMask account on the Moonbase Alpha network. If you're using the development accounts, you should see Alice's account address. If not, double check your MetaMask and switch to Alice's account. ### Create New Safe {: #create-new-safe } To create a new Safe on Moonbase Alpha, click **Create new Safe**. You will be taken to a wizard that will walk you through creating your new Safe. By going through these steps and creating your Safe, you are consenting to the terms of use and the privacy policy. So, feel free to look those over before getting started. ![Create Safe](/images/tokens/manage/multisig-safe/safe-3.webp) You will need to give your Safe a name: 1. Enter the name of your new Safe, you can use `moonbeam-tutorial` 2. Click **Start** ![Submit Safe Name](/images/tokens/manage/multisig-safe/safe-4.webp) Next up is the owners and confirmations section of the wizard. In this section, you will add the owners of the Safe and specify the threshold. The threshold determines how many of the owners are required to confirm a transaction before the transaction gets executed. There are many different setups that can be used when creating a Safe. There can be 1 or more owners of the Safe as well as varying threshold levels. Please note that it is not advised to create a Safe with just 1 owner as it creates the possibility of a single point of failure. For this guide, you will create a multisig setup that has 3 owners and requires a threshold of 2, so at least 2 out of the 3 owners keys are required to execute transactions through the Safe. Your account will automatically be prefilled in as the first owner, however this can be changed if you would like to use different accounts. For this example, Alice's account has been prefilled. In addition to Alice, you can also add Bob and Charlie as owners: 1. Click **Add another owner** 2. Enter **Bob** as the second owner, along with his address: `0x3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0` 3. Enter **Charlie** as the third owner, along with his address: `0x798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc` 4. Set the confirmation threshold to **2** out of 3 owners 5. Click **Review** to go to the last step in the wizard ![Enter Safe Owners](/images/tokens/manage/multisig-safe/safe-5.webp) Finally, you can review all of the Safe and owner details and if everything looks ok: 1. Click **Submit** to create your new Safe. The creation of the Safe will cost approximately less than .001 DEV tokens on Moonbase Alpha. MetaMask will pop-up and prompt you to confirm the transaction 2. Click **Confirm** to send the transaction and create the Safe ![Send Transaction to Create Multisig Safe](/images/tokens/manage/multisig-safe/safe-6.webp) It could take a few minutes to process the transaction and create the Safe, but once it has been created you should see a message saying "Your Safe was created successfully". From there, you can click **Get Started** to load your Safe and start interacting with it. ![Safe Created Successfully](/images/tokens/manage/multisig-safe/safe-7.webp) ## Configure Safe {: #configure-safe } You can always manage your Safe and change some of the parameters set when creating it. To do so, you can click on the **Settings** option on the left-hand side menu. ![Modify Safe Settings](/images/tokens/manage/multisig-safe/safe-8.webp) In there you have the following options: - **Safe Details** — allows you to change the Safe name. This is a local action that requires no on-chain interaction - **Owners** — allows you to initiate a on-chain proposal to add/remove owners to the Safe - **Policies** — allows you to initiate a on-chain proposal to change the multisig threshold to execute the proposal as a transaction - **Advanced** — allows you to check other parameters from the Safe, such as the nonce, modules, and transaction guard ## Receive and Send Tokens {: #receive-and-send-tokens } ### Receive Tokens {: #receive-tokens } Now that you have created your Safe, you can start interacting with it. First, load up the Safe by sending some DEV tokens to it. You can send funds to the Safe from any account with DEV tokens. For this example, you can use Alice's account. Hover over **DEV** in the list of assets to reveal the **Send** and **Receive** buttons. Then click **Receive**. ![Receive Tokens to the Safe](/images/tokens/manage/multisig-safe/safe-9.webp) A pop-up will appear with the address of the Safe. Copy the address and click **Done**. ![Copy Safe Address](/images/tokens/manage/multisig-safe/safe-10.webp) Next, open up your MetaMask to initiate a transaction: 1. Click **Send** to send a transaction 2. Paste in the address of the Safe 3. Enter the amount of DEV tokens you would like to send to the Safe. For this example, you can use 2 DEV tokens 4. Click **Next** 5. Review the details of the transaction and click **Confirm** ![Send DEV Tokens to the Safe](/images/tokens/manage/multisig-safe/safe-11.webp) The transaction will be sent and your balance for DEV tokens will be updated on the Safe. ### Send Tokens {: #send-tokens } Now that you have funds in the Safe, you can send funds from the Safe to another account. For this example, you can send 1 DEV token to Bob's address. Hover over **DEV** in the list of assets, and this time click on **Send**. ![Send Tokens from the Safe](/images/tokens/manage/multisig-safe/safe-12.webp) A pop-up will appear where you can enter the recipient and the amount of DEV tokens to send: 1. Enter Bob's Address 2. Select **DEV** from the list of assets 3. Enter 1 DEV token 4. Click **Review** ![Send 1 DEV Token from the Safe to Bob](/images/tokens/manage/multisig-safe/safe-13.webp) 1. Review the details and click **Submit**. MetaMask will pop-up and you'll notice that instead of sending a transaction, you're sending a message 2. Click **Sign** to sign the message ![Submit Transaction and Sign Message](/images/tokens/manage/multisig-safe/safe-14.webp) Now, if you go back to the Safe, under the **Transactions** tab, you should be able to see that there has been a transaction proposal initiated to send 1 DEV tokens to Bob's address. However, you should also see that only 1 out of 2 confirmations have been received and that 1 more owner is required to confirm the transaction before it gets executed. ![Transaction Needs Confirmations](/images/tokens/manage/multisig-safe/safe-15.webp) ### Transaction Confirmation {: #transaction-confirmation } The process of confirming (or rejecting) a transaction proposal is similar for all the use cases of a multisig Safe. One of the owners initiates the proposal to execute an action. The other owners can approve or reject the proposal. Once the signature threshold is reached, any owner can execute the transaction proposal if approved, or discard the transaction proposal if rejected. In this example, if 2 of the 3 owners decided to reject the proposal, then the assets would remain in the Safe. However, in this case, you can confirm the transaction from either Bob's or Charlie's account. Switch accounts in MetaMask to Bob's account (or Charlie's). Then go back to the Safe connected as Bob. The **Confirm** button should now be enabled. As Bob, go ahead and click **Confirm** to meet the threshold and send the transaction. A pop-up will appear for you to approve the transaction: 1. Check the **Execute transaction** box to execute the transaction immediately after confirmation. You can un-check it for the transaction to be executed manually at a later time 2. Click **Submit** 3. MetaMask will pop-up and ask you to confirm the transaction, if everything looks good, you can click **Confirm** !!! note If you receive an error stating the transaction might fail, you may need to increase the gas limit. You can do so either in the **Advanced options** or in MetaMask. ![Submit Transaction Confirmation](/images/tokens/manage/multisig-safe/safe-16.webp) The transaction will be removed from the **QUEUE** tab and a record of the transaction can now be found under the **HISTORY** tab. In addition, Bob's balance has now increased by 1 DEV token, and the Safe's balance for DEV tokens has decreased. ![Successfully Executed Transaction](/images/tokens/manage/multisig-safe/safe-17.webp) Congratulations, you've successfully received and sent DEV tokens to and from the Safe! ## Receive and Send ERC-20 Tokens {: #receive-and-send-erc20-tokens } ### Receive ERC-20 Tokens {: #receive-erc20-tokens } Next up is to receive and send ERC-20s to and from the Safe. You should already have loaded up your MetaMask with **MYTOK** ERC-20 tokens. If not, please refer back to the [ERC-20 Tokens](#erc20-tokens) section of the prerequisites. You should still be connected to Bob's account for this example. So, you'll be sending MYTOK tokens from Bob's account to the Safe. You'll need to get the Safe's address again, you can do so by clicking on the **Copy to clipboard** icon in the top left hand corner. Once you've got your Safe's address copied, open up MetaMask: 1. Switch to the **Assets** tab and select **MYTOK** from the list 2. Click **Send** 3. Paste in the Safe's address 4. Enter amount of MYTOKs to send. You should have minted 8M MYTOK tokens in the [Using Remix to Deploy to Moonbeam](/builders/ethereum/dev-env/remix/){target=\_blank} guide. So for this example, you can enter 1000 MYTOKs for the amount to send 5. Click **Next** 6. Review the transaction details and then click **Confirm** to send the transaction. ![Send ERC-20s to the Safe](/images/tokens/manage/multisig-safe/safe-18.webp) If you navigate back to the Safe, in the list of **Assets** you should now see **MyToken** and a balance of 1000 MYTOKs. It could take a few minutes for **MyToken** to appear, but there is nothing for you to do to add the asset, it will appear on it's own. ### Send ERC-20 Tokens {: #send-erc20-tokens } Now that you have loaded your Safe with MYTOKs, you can send some from the Safe to another account. For this example, you can send 10 MYTOKs to Charlie. Hover over **MyToken** in the list of assets, and this time click on **Send**. ![Send ERC-20s from the Safe](/images/tokens/manage/multisig-safe/safe-19.webp) A pop-up will appear where you can enter the recipient and the amount of MYTOK tokens to send: 1. Enter Charlies's Address 2. Select **MyToken** from the list of assets 3. Enter 10 MYTOK tokens 4. Click **Review** and review the details ![Send ERC-20s to Charlie from the Safe](/images/tokens/manage/multisig-safe/safe-20.webp) If everything looks ok, you can: 1. Click **Submit**. MetaMask will pop-up and you'll notice that instead of sending a transaction, you're sending a message 2. Click **Sign** to sign the message ![Sign Message to Send ERC-20s to Charlie from the Safe](/images/tokens/manage/multisig-safe/safe-21.webp) Now, if you go back to the Safe, under the **Transactions** tab, you should be able to see that there has been a transaction proposal initiated to send 10 MYTOK tokens to Charlie's address. However, you should also see that only 1 out of 2 confirmations have been received and that 1 more owner is required to confirm the transaction before it gets executed. ![Transaction Needs Confirmation](/images/tokens/manage/multisig-safe/safe-22.webp) You will need to switch accounts to Alice or Charlie and confirm the transaction to execute it. You can follow the same steps outlined in the above [Transaction Confirmation](#transaction-confirmation) section. Once the transaction has been confirmed from one of the other two accounts, the transaction will be moved to the **HISTORY** tab. ![Successfully Executed Transaction](/images/tokens/manage/multisig-safe/safe-23.webp) Congratulations! You've successfully received and sent ERC-20 tokens to and from the Safe! ## Interact with a Smart Contract {: #interact-with-a-smart-contract } For this section, you will be interacting with a smart contract using the Safe. You should have already deployed the `SetText.sol` contract using Remix, if not please refer back to the [Deployed Smart Contract](#deployed-smart-contract) section of the prerequisites. You should still be connected to Alice's account for this section of the guide. From the Safe: 1. On the left hand side click on **New Transaction** 2. Then select **Contract interaction** ![New Contract Interaction](/images/tokens/manage/multisig-safe/safe-24.webp) The **Contract interaction** pop-up will appear and you can fill in the contract details: 1. Enter the contract address into the **Contract address** field 2. In the **ABI** text box, paste the ABI 3. A **Method** dropdown will appear. Select the `setTextData` function 4. Then a `_text` input field will appear. You can enter anything you would like, for this example, you can use `polkadots and moonbeams` 5. Click **Review** ![Create Contract Interaction](/images/tokens/manage/multisig-safe/safe-25.webp) If the details look ok, go ahead and: 1. Click **Submit**. MetaMask will pop-up and you'll notice that instead of sending a transaction, you're sending a message 2. Click **Sign** to sign the message ![Submit Contract Interaction](/images/tokens/manage/multisig-safe/safe-26.webp) Now, if you go back to the Safe, under the **Transactions** tab, you should be able to see that there has been a transaction proposal initiated for a **Contract interaction**. However, you should also see that only 1 out of 2 confirmations have been received and that 1 more owner is required to confirm the transaction before it gets executed. ![Transaction Needs Confirmation](/images/tokens/manage/multisig-safe/safe-27.webp) You will need to switch accounts to Bob or Charlie and confirm the transaction to execute it. You can follow the same steps outlined in the above [Transaction Confirmation](#transaction-confirmation) section. Once the transaction has been confirmed from one of the other two accounts, the transaction will be moved to the **HISTORY** tab. ![Transaction History](/images/tokens/manage/multisig-safe/safe-28.webp) To double check that the correct text was set, you can go through the process again except instead of selecting **setTextData** from the **Method** dropdown, you can select **text** to read the `text` value. This will be a call instead of a transaction, so a **Call** button will appear. Click on it and directly within the pop-up, you should see the result of the call, `polkadots and moonbeams`. ![Contract Interaction Call Result](/images/tokens/manage/multisig-safe/safe-29.webp) Congratulations, you've successfully interacted with a smart contract using the Safe! ## Using Moonbeam Safe APIs {: #using-moonbeam-safe-apis } There are APIs available to read from and interact with Moonbeam Safes for Moonbeam, Moonriver, and Moonbase Alpha. === "Moonbeam" ```text {{networks.moonbeam.multisig.api_page }} ``` === "Moonriver" ```text {{networks.moonriver.multisig.api_page}} ``` === "Moonbase Alpha" ```text {{networks.moonbase.multisig.api_page}} ``` As an example of using the API, try retrieving information about Safes from the Moonbeam Safe API. From the Safe page, copy the address of your Safe: ![Contract Interaction Call Result](/images/tokens/manage/multisig-safe/safe-30.webp) Now you can use the API: 1. Open the API page for the corresponding network 2. Scroll down to the **safes** section and click on the **/safes/{address}/** endpoint section to expand its panel 3. Click the **Try it out** button on the right ![Contract Interaction Call Result](/images/tokens/manage/multisig-safe/safe-31.webp) A large **Execute** button should appear in the panel. 1. Paste the address of your Safe into the **address** input 2. Press **Execute** 3. Information about your safe will appear below ![Contract Interaction Call Result](/images/tokens/manage/multisig-safe/safe-32.webp) Congratulations! You have successfully used the API for Moonbeam Safes. There are still many other endpoints to use, either for convenience or to add into your own app.
The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
--- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/manage/proxy-accounts/ --- BEGIN CONTENT --- --- title: Setting up a Proxy Account description: Learn how to set up a proxy account on Moonbeam-based networks so you can keep your underlying account safe in cold storage. categories: Tokens and Accounts --- # Setting up a Proxy Account ## Introduction {: #introduction } Proxy accounts can be set up to perform a limited number of actions on behalf of users and are useful for keeping the underlying accounts safe. They allow users to keep their primary account secured safely in cold storage while enabling the proxy to actively perform functions and participate in the network with the weight of the tokens in the primary account. Proxy accounts can be set up to perform specific Substrate functions such as author mapping, staking, balances, and more. This can allow you to, for example, grant a trusted individual access to perform collator or delegator functions on your behalf. A proxy could also be used to keep a staking account safe in cold storage. This guide will show you how to set up a proxy account on the Moonbase Alpha TestNet for balance transfers and how to execute a proxy transaction. ## Checking Prerequisites {: #checking-prerequisites } To follow along with this tutorial, you will need to have: - [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/explorer){target=\_blank} open and connected to Moonbase Alpha - Create or have two accounts on Moonbase Alpha - At least one of the accounts must be funded with `DEV` tokens. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} If you need help importing your accounts into Polkadot.js Apps, please check out the [Interacting with Moonbeam using Polkadot.js Apps](/tokens/connect/polkadotjs/#creating-or-importing-an-h160-account){target=\_blank} guide. ## General Definitions {: #general-definitions } When setting up a proxy account, a bond for the proxy is taken out of your free balance and moved to your reserved balance. The bond is required as adding a proxy requires on-chain storage space, and it is recalculated for each proxy you add or remove. After all proxies are removed from your account, the bond is returned to your free balance. The deposit is calculated based on a deposit base and a deposit factor: - **Deposit base** - the amount to be reserved for an account to have a proxy list - **Deposit factor** - the additional amount to be reserved for every proxy the primary account has The equation for calculating the deposit is: ```text deposit base + deposit factor * number of proxies ``` === "Moonbeam" | Variable | Value | |:--------------:|:-------------------------------------------------:| | Deposit base | {{ networks.moonbeam.proxy.deposit_base }} GLMR | | Deposit factor | {{ networks.moonbeam.proxy.deposit_factor }} GLMR | | Max proxies | {{ networks.moonbeam.proxy.max_proxies }} proxies | === "Moonriver" | Variable | Value | |:--------------:|:--------------------------------------------------:| | Deposit base | {{ networks.moonriver.proxy.deposit_base }} MOVR | | Deposit factor | {{ networks.moonriver.proxy.deposit_factor }} MOVR | | Max proxies | {{ networks.moonriver.proxy.max_proxies }} proxies | === "Moonbase Alpha" | Variable | Value | |:--------------:|:-------------------------------------------------:| | Deposit base | {{ networks.moonbase.proxy.deposit_base }} DEV | | Deposit factor | {{ networks.moonbase.proxy.deposit_factor }} DEV | | Max proxies | {{ networks.moonbase.proxy.max_proxies }} proxies | ## Proxy Types {: #proxy-types } When creating a proxy account, you must choose a type of proxy which will define how the proxy can be used. The available options are: - **`AuthorMapping`** - this type of proxy account is used by collators to migrate services from one server to another - **`CancelProxy`** - allows the proxy account to reject and remove any announced proxy calls - **`Staking`** - allows the proxy account to perform staking-related transactions, such as collator or delegator functions, including `authorMapping()` - **`Governance`** - allows the proxy account to make transactions related to governance, such as voting or proposing democracy proposals - **`NonTransfer`** - this type of proxy account is allowed to submit any type of transaction with the exception of balance transfers - **`Balances`** - allows the proxy account to only make transactions related to sending funds - **`IdentityJudgement`** - allows the proxy account to request judgement on an [account's identity](/tokens/manage/identity/){target=\_blank} from a registrar. The following judgements can be issued: - **unknown** - (default) no judgement has been made yet - **fee paid** - to indicate a user has requested judgement and it is in progress - **reasonable** - the information appears reasonable, but no in-depth checks (i.e. formal KYC process) were performed - **known good** - the information has been certified as correct - **out of date** - the information used to be good, but is now out of date - **low quality** - the information is low quality or imprecise, but can be fixed with an update - **erroneous** - the information is erroneous and may indicate malicious intent - **`Any`** - allows the proxy account to use any function supported by the proxy pallet For the purposes of this guide, you will be setting up a proxy account using the balances proxy type. Since this type enables the proxy to spend funds on behalf of the primary account, you should exercise caution and only provide access to accounts you trust. The proxy will have access to transfer all of the funds within the primary account, and if not trusted, the proxy could drain the primary account. Also make sure not to forget to remove the proxy as needed. ## Creating a Proxy Account {: #creating-a-proxy-account } ### Via the Moonbeam DApp {: #create-via-the-moonbeam-dapp } It's easy to create a proxy account on [the Moonbeam dApp](https://apps.moonbeam.network/moonbeam/proxy){target=\_blank}. To do so, take the following steps: 1. Toggle the network switcher button to select your desired network 2. Navigate to the **Proxy** page 3. Ensure you're connected with the primary account that you wish to add a proxy of 4. Enter the address you want to delegate proxy control to 5. From the **proxyType** dropdown, choose the desired proxy type, such as a balances proxy 6. Optionally, you can add a time delay using a specified number of blocks, which could allow time for the primary account to review the pending transaction 7. Click **Add Proxy** and confirm the transaction in your wallet ![Add a proxy account via Apps.Moonbeam.Network](/images/tokens/manage/proxy-accounts/proxies-1.webp) ### Via Polkadot.js Apps {: #create-via-polkadot-js-apps } There are a couple of ways you can create proxy accounts in [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network){target=\_blank}, either from the **Extrinsics** page or the **Accounts** page. However, to create a time-delayed proxy, you will need to use the **Extrinsics** page. A time delay provides an additional layer of security to proxies by specifying a delay period based on a number of blocks. This will prevent the proxy account from executing a transaction until the delay period ends. The delay allows time for the primary account that controls the proxy to review pending transactions, potentially for malicious actions, and cancel if necessary before execution. To get started creating your proxy account, head to the **Developer** tab and select [**Extrinsics**](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/extrinsics){target=\_blank} from the dropdown. Next, you will need to take the following steps: 1. Select the primary account 2. From the **submit the following extrinsic** dropdown, select **proxy** 3. Choose the **addProxy** extrinsic 4. Select the **delegate** account for the proxy 5. From the **proxyType** dropdown, choose **Balances** 6. Optionally, you can add a time delay using a specified number of blocks, which could allow time for the primary account to review the pending transaction 7. Click **Submit Transaction** ![Add a proxy account from the Extrinsics page of Polkadot.js Apps.](/images/tokens/manage/proxy-accounts/proxies-2.webp) You will then be prompted to authorize and sign the transaction. Go ahead and click **Sign and Submit** to create the proxy relationship. Once the transaction has been successfully submitted, you will receive some notifications confirming the transaction. As previously mentioned, you can also create a proxy from the **Accounts** page. To do so, navigate to the **Accounts** page, and take the following steps: 1. Select the 3 vertical dots next to the primary account 2. Select **Add proxy** ![Select the Add proxy menu item from the Accounts page of Polkadot.js Apps.](/images/tokens/manage/proxy-accounts/proxies-3.webp) !!! note If the account already has a proxy, **Manage proxies** will be displayed as an option instead of **Add proxy**. A pop-up will appear and you will be able to enter in the required information, such as the proxied/primary account, the proxy account, and type of proxy in order to create a proxy account. First click **Add Proxy**. ![Add a proxy account from the Accounts page of Polkadot.js Apps](/images/tokens/manage/proxy-accounts/proxies-4.webp) Then take the following steps: 1. Select the account you would like to set as a proxy 2. Select the proxy type 3. Click **Submit** and sign the transaction ![Add the details of the proxy account, including the proxy account and type.](/images/tokens/manage/proxy-accounts/proxies-5.webp) In the next section, you will learn how to verify that your proxy account was set up successfully. ## Verifying your Proxy Account {: #verifying-your-proxy-account } ### Via the Moonbeam DApp {: #verify-via-the-moonbeam-dapp } When connected to [the Moonbeam dApp](https://apps.moonbeam.network/moonbeam/proxy){target=\_blank} with your primary account, you can see a list of accounts with proxy control over your connected primary account in the **Your Proxies** section. ![Verify proxy created via apps.moonbeam.network](/images/tokens/manage/proxy-accounts/proxies-6.webp) Alternatively, by connecting the proxy account to [the Moonbeam dApp](https://apps.moonbeam.network/moonbeam/proxy){target=\_blank}, you can see a list of accounts over which the connected account has proxy control in the **Proxied accounts to you** section. ![Verify proxy control accounts via apps.moonbeam.network](/images/tokens/manage/proxy-accounts/proxies-7.webp) ### Via Polkadot.js Apps {: #verify-via-polkadot-js-apps } There are a couple of ways that you can verify your proxy account has been successfully set up. Either through the **Accounts** page or via the **Chain state** page. To check your proxy accounts from the [**Chain state** page](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/chainstate){target=\_blank}, you can take the following steps: 1. From the **selected state query** dropdown, select **proxy** 2. Choose the **proxies** extrinsic 3. Select your primary (proxied) account 4. Click on the **+** button to send the query ![Verify your proxy accounts via the Extrinsics page of Polkadot.js Apps.](/images/tokens/manage/proxy-accounts/proxies-8.webp) The result will appear on the page showing you information about all of your proxies, including the delegate/proxy account address, the proxy type, the delay period if one was specified, and the total bond amount for all of your proxies in Wei. As previously mentioned, you can also check your proxy accounts from the **Accounts** page. To do so, you can navigate to the **Accounts** page and there should be a Proxy symbol next to the primary account. Hover over the icon and click on **Manage proxies** to review your proxies. ![Hover over the proxy icon to manage your proxies via the Accounts page of Polkadot.js Apps.](/images/tokens/manage/proxy-accounts/proxies-9.webp) A pop-up will appear where you can view an overview of all of your proxy accounts. ![Review your proxy accounts.](/images/tokens/manage/proxy-accounts/proxies-10.webp) ## Executing a Proxy Transaction {: #executing-a-proxy-transaction } Now that you have created a proxy account and verified that it was successfully set up, you can execute a transaction using the proxy account on behalf of the primary account. To execute a transaction, navigate back to the [**Extrinsics** page](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/extrinsics){target=\_blank} and take the following steps: 1. Select the proxy account to submit the transaction from the **using the select account** dropdown 2. From the **submit the following extrinsic** menu, select **proxy** 3. Choose the **proxy** extrinsic 4. Select the primary account from the **real** dropdown 5. Select the **balances** call 6. Choose the **transfer** extrinsic 7. In the **dest** field, enter the address you would like to send funds to 8. In the **value** field, enter the amount of funds to send in Wei. For this example, you can send 2 DEV tokens, which will be `2000000000000000000` in Wei 9. Click **Submit Transaction** ![Execute a proxy transaction from the Extrinsics page of Polkadot.js Apps.](/images/tokens/manage/proxy-accounts/proxies-11.webp) A pop-up will appear for you to authorize and sign the transaction. Enter your password for the proxy account and click **Sign and Submit**. If the transaction successfully went through, you should see a couple of notifications pop-up and if you head over to the **Accounts** page, you'll see that the balance of your primary account has decreased. If you check the balance of the account where you sent the funds to, you'll notice the balance there has increased. That's it! You've successfully executed a transaction using a proxy account on behalf of your primary account. ## Removing a Proxy Account {: #removing-a-proxy-account } ### Via the Moonbeam DApp {: #remove-via-the-moonbeam-dapp } To remove a proxy account, connect your primary account to [the Moonbeam dApp](https://apps.moonbeam.network/moonbeam/proxy){target=\_blank} and press **Remove** next to the proxy account that you want to remove. Alternatively, you can remove all proxy accounts of the primary account with **Remove All Proxies**. In either case, you must confirm the transaction in your wallet. ![Remove account via Apps.Moonbeam.Network](/images/tokens/manage/proxy-accounts/proxies-12.webp) ### Via Polkadot.js Apps {: #remove-via-polkadot-js-apps } Similarly to adding a proxy account, there are a couple of ways that you can remove a proxy account, either from the **Extrinsics** page or the **Accounts** page. Regardless of which page you use, you can elect to remove a single proxy account or all proxies associated with your primary account. To remove a proxy from the [**Extrinsics** page](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/extrinsics){target=\_blank}, you can take the following steps: 1. From the **using the selected account** dropdown, select your primary account 2. Then select **proxy** 3. Choose **removeProxy** to remove a single proxy or **removeProxies** to remove all associated proxies 4. If removing a single proxy, enter the proxy account to remove in the **delegate** field 5. Select the **proxyType** to remove, in this case choose **Balances** 6. Optionally, select a delay period in block numbers 7. Click **Submit Transaction** ![Remove a proxy account from the Extrinsics page of Polkadot.js Apps](/images/tokens/manage/proxy-accounts/proxies-13.webp) A pop-up will appear for you to authorize and sign the transaction. While either account can sign transactions generally, removing a proxy must be performed by the primary account. Enter your password and click **Sign and Submit**. You can follow the steps in the [Verifying your Proxy Account](#verifying-your-proxy-account) section to check that the proxy or proxies have been removed. As previously mentioned, you can also remove a proxy from the **Accounts** page. To do so, on the **Accounts** page, select the 3 vertical dots next to the primary account and select **Manage Proxies**. ![Click on the Manage Proxies button to review and manage your proxy accounts.](/images/tokens/manage/proxy-accounts/proxies-14.webp) A pop-up will appear showing an overview of your proxy accounts. To remove a single proxy you can select the **X** button next to the proxy to remove. The proxy will disappear from the list, then you will need to click **Submit**. Next you will be able to enter your password and submit the transaction. Or to remove all proxies you can click on **Clear all**, then you will automatically be prompted to enter your password and submit the transaction. ![Remove a proxy account from the Accounts page of Polkadot.js Apps.](/images/tokens/manage/proxy-accounts/proxies-15.webp) Once the transaction has successfully been submitted, you can review your current proxies or if you removed all proxies you will notice the proxy icon is no longer being displayed next to the primary account. And that's it! You've successfully created a proxy, reviewed all proxy accounts associated with your primary account, executed a proxy transaction, and removed a proxy account! --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/staking/ --- BEGIN CONTENT --- --- title: How to Stake GLMR & MOVR Tokens description: Learn how to delegate collator candidates and stake your GLMR and MOVR tokens to earn staking rewards on Moonbeam and Moonriver. dropdown_description: Stake tokens by delegating to collators template: subsection-index-page.html hide: - toc - feedback --- --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tokens/staking/stake/ --- BEGIN CONTENT --- --- title: How to Stake your MOVR & GLMR Tokens description: A guide that shows how you can stake your tokens and earn rewards on Moonbeam by delegating collator candidates. categories: Staking --- # How to Stake your Tokens ## Introduction {: #introduction } Collator candidates with the highest stake in the network join the active pool of collators (block producers), from which they are selected to offer a block to the relay chain. Token holders can add to candidates' stake using their tokens, a process called delegation (also referred to as staking). When they do so, they are vouching for that specific candidate, and their delegation is a signal of trust. When delegating, tokens are deducted instantly and added to the total amount staked by the user. Exiting a position is divided into a two step operation: scheduling and execution. First, token holders must schedule a request to exit their position, and wait for a given delay or unbonding period, which depends on the network. Once the unbonding period has expired, users can execute their scheduled action. Once a candidate joins the active set of collators, they are eligible to produce blocks and receive partial block rewards as part of the token inflationary model. They share these as staking rewards with their delegators, considering their proportional contribution toward their stake in the network. Delegators can choose to auto-compound their rewards so that a set percentage of their rewards are automatically applied to their total delegation amount. This guide will show you how to stake on Moonbase Alpha via Polkadot.js Apps, but similar steps can be taken for any of the Moonbeam and Moonriver. Token holders that want to easily stake their tokens can use the [Moonbeam dApp](https://apps.moonbeam.network){target=\_blank} to do so. For more general information on staking, please check out the [Staking on Moonbeam](/learn/features/staking/){target=\_blank} overview. ## Extrinsics Definitions {: #extrinsics-definitions } There are many extrinsics related to the staking pallet, you can check out a complete list of them on the [Parachain Staking Pallet](/builders/substrate/interfaces/features/staking/){target=\_blank} page. The following list covers the extrinsics that you'll use in this guide and are associated with the delegation process. !!! note Extrinsics might change in the future as the staking pallet is updated. ### Join the Delegator Set {: #join-or-leave-the-delegator-set } - **delegateWithAutoCompound**(*address* candidate, *uint256* amount, *uint8* autoCompound, *uint256* candidateDelegationCount, *uint256* candidateAutoCompoundingDelegationCount, *uint256* delegatorDelegationCount) - extrinsic to delegate a given amount to a collator. The amount needs to be greater than the minimum delegation stake. This also sets the percentage of rewards to be auto-compounded ### Bond More or Less {: #bond-more-or-less } - **delegatorBondMore**(*address* candidate, *uint256* more) - extrinsic to request to increase the amount of staked tokens for an already delegated collator - **scheduleDelegatorBondLess**(*address* candidate, *uint256* less) - extrinsic to request to reduce the amount of staked tokens for an already delegated collator. The amount must not decrease your overall total staked below the minimum delegation stake. There will be a [bond less delay](/learn/features/staking/#:~:text=Decrease delegation delay){target=\_blank} before you can execute the request via the `executeDelegationRequest` extrinsic - **executeDelegationRequest**(*address* delegator, *address* candidate) - extrinsic to execute and pending delegation requests. This extrinsic should only be used after a request has been scheduled and the exit delay has passed - **scheduleCandidateBondLess**(*uint256* less) - extrinsic that allows a collator candidate to request to decrease their self bond by a given amount. There will be a [bond less delay](/node-operators/networks/collators/activities/#:~:text=Reduce self-delegation){target=\_blank} before you can execute the request via the `executeCandidateBondLess` extrinsic - **executeCandidateBondLess**(*address* candidate) - extrinsic to execute a decrease a candidate's self bond amount. This extrinsic should only be used after a bond request has been scheduled and the exit delay has passed - **cancelCandidateBondLess**() - extrinsic to cancel a scheduled request to increase or decrease the bond for a specific candidate ### Revoke Delegations {: #revoke-delegations } - **scheduleRevokeDelegation**(*address* collator) - extrinsic to schedule to remove an existing delegation entirely. There will be a [revoke delegation delay](/learn/features/staking/#:~:text=Revoke delegations delay){target=\_blank} before you can execute the request via the [`executeDelegationRequest`](#:~:text=executeDelegationRequest(address delegator, address candidate)) extrinsic - **cancelDelegationRequest**(*address* candidate) - extrinsic to cancel a scheduled request to revoke a delegation ### Set or Change Auto-Compounding Percentage {: #set-change-auto-compounding } - **setAutoCompound**(*address* candidate, *uint8* value, *uint256* candidateAutoCompoundingDelegationCount, *uint256* delegatorDelegationCount) - sets an auto-compound value for an existing delegation ## Retrieve Staking Values {: #retrieving-staking-parameters } You can check out any of the constant staking values using Polkadot.js Apps, such as the maximum number of delegations, minimum stake requirements, exit delays for delegation requests, and more. To do so, you can navigate to Polkadot.js Apps **Chain state** UI, and for the purposes of this guide, connect to [Moonbase Alpha](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/chainstate){target=\_blank}. Alternatively, you can connect to [Moonbeam](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbeam.network/#chainstate){target=\_blank} or [Moonriver](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonriver.moonbeam.network/#chainstate){target=\_blank}. Then to retrieve the various staking parameters, select the **Constants** tab on the **Chain state** UI, and take the following steps: 1. From the **selected constant query** dropdown, choose **parachainStaking** 2. Choose any function you would like to get data for. For this example, you can use **maxDelegationsPerDelegator**. This will return the maximum number of candidates you can delegate 3. Click **+** to return the current value ![Retrieving staking parameters](/images/tokens/staking/stake/stake-1.webp) You should then see the maximum delegations per delegator, which can also be found in the [Staking on Moonbeam](/learn/features/staking/#quick-reference){target=\_blank} overview. ## How to Stake & Auto-Compound Rewards via Polkadot.js Apps {: #how-to-delegate-a-candidate } This section goes over the process of delegating collator candidates. The address of the collator candidate on Moonbase Alpha that is used throughout this guide is `{{ networks.moonbase.staking.candidates.address1 }}`. Before staking via Polkadot.js Apps, you need to retrieve some important parameters such as the list of candidates, the delegation count of the candidate you want to delegate, and your number of delegations. To auto-compound your delegation rewards, you'll also need the auto-compounding delegation count of the candidate you want to delegate. ### Retrieve the List of Candidates {: #retrieving-the-list-of-candidates } Before starting to stake tokens, it is important to retrieve the list of collator candidates available in the network. To do so, head to the **Developer** tab, click on **Chain State**, and take the following steps: 1. Choose the pallet to interact with. In this case, it is the **parachainStaking** pallet 2. Choose the state to query. In this case, it is the **selectedCandidates** or **candidatePool** state 3. Send the state query by clicking on the **+** button Each extrinsic provides a different response: - **selectedCandidates** — returns the current active set of collators, that is, the top collator candidates by total tokens staked (including delegations). For example, on Moonbase Alpha it is the top {{ networks.moonbase.staking.max_candidates }} candidates - **candidatePool** — returns the current list of all the candidates, including those that are not in the active set ![Staking Account](/images/tokens/staking/stake/stake-2.webp) ### Get the Candidate Delegation Count {: #get-the-candidate-delegation-count } First, you need to get the `candidateInfo`, which will contain the delegator count, as you'll need to submit this parameter in a later transaction. To retrieve the parameter, make sure you're still on the **Chain State** tab of the **Developer** page, and then take the following steps: 1. Choose the **parachainStaking** pallet to interact with 2. Choose the **candidateInfo** state to query 3. Make sure the **include option** slider is enabled 4. Enter the collator candidate's address 5. Send the state query by clicking on the **+** button 6. Copy the result as you'll need it when initiating a delegation ![Get candidate delegation count](/images/tokens/staking/stake/stake-3.webp) ### Get the Candidate Auto-Compounding Delegation Count {: #get-candidate-auto-compounding-count } The auto-compounding delegation count is the amount of delegations that have auto-compounding configured. To determine the number of delegations that have auto-compounding set up, you can query the auto-compounding delegations for the candidate on [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/js){target=\_blank} using the following snippet: ```js // Simple script to get the number of auto-compounding delegations for a given candidate. // Remember to replace INSERT_CANDIDATE_ADDRESS with the candidate's address you want to delegate. const candidateAccount = 'INSERT_CANDIDATE_ADDRESS'; const autoCompoundingDelegations = await api.query.parachainStaking.autoCompoundingDelegations(candidateAccount); console.log(autoCompoundingDelegations.toHuman().length); ``` To run the snippet, make sure you're on the **JavaScript** page of Polkadot.js Apps (which can be selected from the **Developer** dropdown), and take the following steps: 1. Copy the code from the previous snippet and paste it inside the code editor box 2. (Optional) Click the save icon and set a name for the code snippet, for example, **Get auto-compounding delegation count**. This will save the code snippet locally 3. To execute the code, click on the run button 4. Copy the result as you'll need it when initiating a delegation ![Get candidate auto-compounding delegation count](/images/tokens/staking/stake/stake-4.webp) ### Get your Number of Existing Delegations {: #get-your-number-of-existing-delegations } If you've never made a delegation from your address you can skip this section. However, if you're unsure how many existing delegations you have, you'll want to run the following JavaScript code snippet to get `delegationCount` from within [Polkadot.js](https://polkadot.js.org/apps/?rpc=wss://wss.api.moonbase.moonbeam.network#/js){target=\_blank}: ```js // Simple script to get your number of existing delegations. // Remember to replace INSERT_YOUR_ADDRESS with your delegator address. const yourDelegatorAccount = 'INSERT_YOUR_ADDRESS'; const delegatorInfo = await api.query.parachainStaking.delegatorState(yourDelegatorAccount); if (delegatorInfo.toHuman()) { console.log(delegatorInfo.toHuman()['delegations'].length); } else { console.log(0); } ``` Head to the **Developer** tab and click on **JavaScript**. Then take the following steps: 1. Copy the code from the previous snippet and paste it inside the code editor box 2. (Optional) Click the save icon and set a name for the code snippet, for example, **Get delegation count**. This will save the code snippet locally 3. To execute the code, click on the run button 4. Copy the result as you'll need it when initiating a delegation ![Get existing delegation count](/images/tokens/staking/stake/stake-5.webp) ### Stake your Tokens {: #staking-your-tokens } To access staking features, you need to use the Polkadot.js Apps interface. To do so, you need to import/create an Ethereum-style account first (H160 address), which you can do by following the [Creating or Importing an H160 Account](/tokens/connect/polkadotjs/#creating-or-importing-an-h160-account){target=\_blank} section of the Polkadot.js guide. For this example, an account was imported and named with a super original name: Alice. Alice's address is `0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac`. To delegate a candidate and set up auto-compounding for your staking rewards, take the following steps: 1. Select the account from which you want to stake your tokens 2. Choose the **parachainStaking** pallet 3. Choose the **delegateWithAutoCompound** extrinsic 4. Set the candidate's address to delegate. In this case, it is set to `{{ networks.moonbase.staking.candidates.address1 }}` 5. Set the number of tokens you want to stake 6. Set the percentage of rewards to auto-compound by entering a number 0-100 7. Input the `candidateDelegationCount` you [retrieved previously from querying `candidateInfo`](#get-the-candidate-delegation-count) 8. Input the `candidateAutoCompoundingDelegationCount` you [retrieved previously from querying `autoCompoundingDelegations`](#get-candidate-auto-compounding-count) 9. Input the `delegationCount` [you retrieved from the JavaScript console](#get-your-number-of-existing-delegations). This is `0` if you haven't yet delegated a candidate 10. Click the **Submit Transaction** button and sign the transaction ![Staking Join Delegators Extrinsics](/images/tokens/staking/stake/stake-6.webp) !!! note The parameters used in steps 7-9 are for gas estimation purposes and do not need to be exact. However, they should not be lower than the actual values. ### Verify Delegations {: #verifying-delegations } Once the transaction is confirmed, you can verify your delegation by navigating to **Chain state** under the **Developer** tab. Here, provide the following information: 1. Choose the pallet you want to interact with. In this case, it is the **parachainStaking** pallet 2. Choose the state to query. In this case, it is the **delegatorState** 3. Verify the selected address is correct. In this case, you are looking at Alice's account 4. Make sure to enable the **include option** slider 5. Send the state query by clicking on the **+** button ![Verify delegations](/images/tokens/staking/stake/stake-7.webp) In the response, you should see your account (in this case, Alice's account) with a list of the delegations. Each delegation contains the target address of the candidate and the amount. You can follow the same steps as described to delegate other candidates in the network. ### Verify Auto-Compounding Percentage {: #verifying-auto-compounding-percentage } If you want to verify the percentage of rewards that are set to auto-compound for a specific delegation, you can use the following script that will query the `autoCompoundingDelegations` extrinsic and filter the results based on the delegator's address: ```js // Simple script to verify your auto-compounding percentage for a given candidate. // Remember to replace INSERT_CANDIDATE_ADDRESS with the candidate's address you // want to delegate and replace INSERT_DELEGATOR_ADDRESS with the address used to // delegate with const candidateAccount = 'INSERT_CANDIDATE_ADDRESS'; const delegationAccount = 'INSERT_DELEGATOR_ADDRESS'; const autoCompoundingDelegations = await api.query.parachainStaking.autoCompoundingDelegations(candidateAccount); const delegation = autoCompoundingDelegations.find( (del) => del.delegator == delegationAccount ); console.log(`${delegation.value}%`); ``` In Polkadot.js Apps, you can head to the **Developer** tab and select **JavaScript** from the dropdown. Then you can take the following steps: 1. Copy the code from the previous snippet and paste it inside the code editor box 2. (Optional) Click the save icon and set a name for the code snippet, for example, **Get auto-compounding percentage**. This will save the code snippet locally 3. To execute the code, click on the run button 4. The result is returned in the terminal on the right side ![Verify auto-compounding percentage](/images/tokens/staking/stake/stake-8.webp) ## Set or Change the Auto-Compounding Percentage {: #set-or-change-auto-compounding } If you initially set up your delegation without auto-compounding or if you want to update the percentage on an existing delegation with auto-compounding set up, you can use the `setAutoCompound` function of the Solidity interface. You'll need to [get the number of delegations with auto-compounding set up](#get-candidate-auto-compounding-count) for the candidate you want to set or update auto-compounding for. You'll also need to [retrieve your own delegation count](#get-your-number-of-existing-delegations). Once you have the necessary information, you can click on the **Developer** tab, select **Extrinsics** from the dropdown, and take the following steps: 1. Select the account from which you initially delegated from and want to set or update auto-compounding for 2. Choose the **parachainStaking** pallet 3. Choose the **setAutoCompound** extrinsic 4. Set the candidate's address that you delegated. For this example, it is set to `{{ networks.moonbase.staking.candidates.address1 }}` 5. Set the percentage of rewards to auto-compound by entering a number 0-100 6. For the **candidateAutoCompoundingDelegationHint** field, enter the candidate's number of delegations with auto-compounding configured 7. For the **delegationCountHint** field, enter your number of delegations 8. Click the **Submit Transaction** button and sign the transaction ![Staking Chain State Query](/images/tokens/staking/stake/stake-9.webp) ## How to Stop Delegations {: #how-to-stop-delegations } As of [runtime version 1001](https://moonbeam.network/news/moonriver-technical-update-staking-changes-as-part-of-runtime-upgrade-1001){target=\_blank}, there have been significant changes to the way users can interact with various staking features. Including the way staking exits are handled. If you want to make an exit and stop a delegation, you have to first schedule it, wait an exit delay, and then execute the exit request. If you are already a delegator, you can request to stop your delegations using the `scheduleRevokeDelegation` extrinsic to request to unstake your tokens from a specific collator candidate. Scheduling a request does not automatically revoke your delegations, you must wait an [exit delay](/learn/features/staking/#quick-reference){target=\_blank} and then execute the request by using the `executeDelegationRequest` method. ### Schedule Request to Stop Delegations {: #schedule-request-to-stop-delegations } To schedule a request to revoke your delegation from a specific candidate, navigate to the **Extrinsics** menu under the **Developer** tab. Here, provide the following information: 1. Select the account from which you want to remove your delegation 2. Choose the `parachainStaking` pallet 3. Choose the `scheduleRevokeDelegation` extrinsic 4. Set the candidate's address you want to remove your delegation from. In this case, it is set to `{{ networks.moonbase.staking.candidates.address1 }}` 5. Click the **Submit Transaction** button and sign the transaction ![Staking Schedule Request to Revoke Delegation Extrinsic](/images/tokens/staking/stake/stake-10.webp) !!! note There can only be one pending scheduled request per candidate. Once you have scheduled an exit, you must wait an [exit delay](/learn/features/staking/#quick-reference){target=\_blank} before you can then execute it. If you try to execute it before the exit delay is up the extrinsic will fail and you'll see an error from Polkadot.js Apps for `parachainStaking.PendingDelegationRequest`. ### Execute Request to Stop Delegations {: #execute-request-to-stop-delegations } After the exit delay has passed after initiating the scheduled request, you can go back to the **Developer** tab of the **Extrinsics** menu and follow these steps to execute the request: 1. Select the account to execute the revocation 2. Choose the **parachainStaking** pallet 3. Choose the **executeDelegationRequest** extrinsic 4. Set the delegator's address you want to remove the delegation for. For this example, it will be Alice's address `0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac` 5. Set the candidate's address you want to remove your delegation from. In this case, it is set to `{{ networks.moonbase.staking.candidates.address1 }}` 6. Click the **Submit Transaction** button and sign the transaction ![Staking Execute Revoke Delegation Extrinsic](/images/tokens/staking/stake/stake-11.webp) Once the transaction is confirmed, you can verify that your delegation was removed by going to the **Chain state** option under the **Developer** tab. Here, provide the following information: 1. Choose the **parachainStaking** pallet 2. Choose the **delegatorState** state to query 3. Select your account 4. Make sure to enable the **include options** slider 5. Send the state query by clicking on the **+** button ![Staking Verify Delegation is Revoked](/images/tokens/staking/stake/stake-12.webp) In the response, you should see your account (in this case, Alice's account) with a list of the remaining delegations. Each delegation contains the target address of the candidate, and the amount. There should no longer be an entry for `{{ networks.moonbase.staking.candidates.address1 }}`. If you no longer have any delegations, `` will be returned. To ensure the revocation went through as expected, you can follow the steps in the [Verifying Delegations](#verifying-delegations) section above. ### Cancel Request to Stop Delegations {: #cancel-request-to-stop-delegations } If you scheduled a request to stop delegations but changed your mind, as long as the request has not been executed, you can cancel the request at any time and all of your delegations will remain as is. To cancel the request you can follow these steps: 1. Select the account to cancel the scheduled request for 2. Choose the **parachainStaking** pallet 3. Choose the **cancelDelegationRequest** extrinsic 4. Enter the candidates address that corresponds to the due request you would like to cancel 5. Click the **Submit Transaction** button and sign the transaction ![Staking Cancel Scheduled Request to Revoke Delegation](/images/tokens/staking/stake/stake-13.webp) ## Staking Rewards {: #staking-rewards } As candidates in the active set of collators receive rewards from block production, delegators get rewards as well. A brief overview on how the rewards are calculated can be found in the [Reward Distribution section](/learn/features/staking/#reward-distribution){target=\_blank} of the Staking on Moonbeam overview page. In summary, delegators will earn rewards based on their stake of the total delegations for the collator being rewarded (including the collator's stake as well). Delegators can choose to auto-compound their rewards so that their rewards are automatically applied to their total delegation amount. If a delegator has multiple delegations, auto-compounding will need to be set for each delegation. ## Risks {: #risks } *Holders of MOVR/GLMR tokens should perform careful due diligence on collators before delegating. Being listed as a collator is not an endorsement or recommendation from the Moonbeam Network, the Moonriver Network, or Moonbeam Foundation. Neither the Moonbeam Network, Moonriver Network, nor Moonbeam Foundation has vetted the list collators and assumes no responsibility with regard to the selection, performance, security, accuracy, or use of any third-party offerings. You alone are responsible for doing your own diligence to understand the applicable fees and all risks present, including actively monitoring the activity of your collators.* *You agree and understand that neither the Moonbeam Network, the Moonriver Network, nor Moonbeam Foundation guarantees that you will receive staking rewards and any applicable percentage provided (i) is an estimate only and not guaranteed, (ii) may change at any time and (iii) may be more or less than the actual staking rewards you receive. The Moonbeam Foundation makes no representations as to the monetary value of any rewards at any time.* *Staking MOVR/GLMR tokens is not free of risk.* *Staked MOVR/GLMR tokens are locked up, and retrieving them requires a {{ networks.moonriver.delegator_timings.del_bond_less.days }} day/{{ networks.moonbeam.delegator_timings.del_bond_less.days }} day waiting period .* *Additionally, if a collator fails to perform required functions or acts in bad faith, a portion of their total stake can be slashed (i.e. destroyed). This includes the stake of their delegators. If a collators behaves suspiciously or is too often offline, delegators can choose to unbond from them or switch to another collator. Delegators can also mitigate risk by electing to distribute their stake across multiple collators.* --- END CONTENT --- Doc-Content: https://docs.moonbeam.network/tutorials/eth-api/batch-approve-swap/ --- BEGIN CONTENT --- --- title: Approve & Swap with the Batch Precompile description: Learn how to use the Batch Precompile on Moonbeam to batch an approval and swap into a single call, so you can approve the exact amount of tokens for the swap. categories: Tutorials, Precompiles --- # Use the Batch Precompile to Approve and Swap Tokens in a Single Transaction _by Erin Shaben_ ## Introduction {: #introduction } Token approvals are critical for interacting with smart contracts securely, preventing smart contracts without permission from accessing a user's tokens. When a smart contract is given approval to access a user's tokens, the amount of tokens it has access to is often an unlimited amount, depending on the DApp. One of the reasons why many DApps use an unlimited amount is so that users don't need to continue to sign approval transactions every time they want to move their tokens. This is in addition to the second transaction required to actually swap the tokens. For networks like Ethereum, this can be expensive. However, if the approved smart contract has a vulnerability, it could be exploited and the users' tokens could be transferred at any time without requiring further approval. In addition, if a user no longer wants the DApp's contract to have access to their tokens, they have to revoke the token approval, which requires another transaction to be sent. As a DApp developer on Moonbeam, you can avoid this process entirely, providing users with more control over their assets. This can be done using the [batch precompile](/builders/ethereum/precompiles/ux/batch/){target=\_blank} to batch an approval and swap into a single transaction, instead of the typical two transaction process. This allows for the approval amount to be the exact swap amount instead of having unlimited access to your users' tokens. In this tutorial, we'll dive into the process of batching an approval and swap into one transaction using the `batchAll` function of the batch precompile contract. We'll create and deploy an ERC-20 contract and a simple DEX contract for the swap on the [Moonbase Alpha TestNet](/builders/get-started/networks/moonbase/){target=\_blank} using [Hardhat](/builders/ethereum/dev-env/hardhat/){target=\_blank} and [Ethers](/builders/ethereum/libraries/ethersjs/){target=\_blank}. ## Checking Prerequisites {: #checking-prerequisites } For this tutorial, you'll need the following: - An account with funds. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the [Moonbase Alpha Faucet](https://faucet.moonbeam.network){target=\_blank} - An empty Hardhat project that is configured for the Moonbase Alpha TestNet. For step-by-step instructions, please refer to the [Creating a Hardhat Project](/builders/ethereum/dev-env/hardhat/#creating-a-hardhat-project){target=\_blank} and the [Hardhat Configuration File](/builders/ethereum/dev-env/hardhat/#hardhat-configuration-file){target=\_blank} sections of our Hardhat documentation page - To test out the examples in this guide on Moonbeam or Moonriver, you will need to have your own endpoint and API key, which you can get from one of the supported [Endpoint Providers](/builders/get-started/endpoints/){target=\_blank} ### Install Dependencies {: #install-dependencies } Once you have your [Hardhat project](/builders/ethereum/dev-env/hardhat/){target=\_blank}, you can install the [Ethers plugin](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-ethers){target=\_blank}. This provides a convenient way to use the [Ethers.js](/builders/ethereum/libraries/ethersjs/){target=\_blank} library to interact with the network. You can also install the [OpenZeppelin contracts library](https://docs.openzeppelin.com/contracts){target=\_blank}, as we'll be importing the `ERC20.sol` contract and `IERC20.sol` interface in our contracts. To install the necessary dependencies, run the following command: ```bash npm install @nomicfoundation/hardhat-ethers ethers@6 @openzeppelin/contracts ``` ## Contract Setup {: #contracts } The following are the contracts that we'll be working with today: - `Batch.sol` - one of the precompile contracts on Moonbeam that allows you to combine multiple EVM calls into one. For more information on the available methods, please refer to the [Batch Solidity Interface](/builders/ethereum/precompiles/ux/batch/#the-batch-interface){target=\_blank} documentation - `DemoToken.sol` - an ERC-20 contract for the `DemoToken` (DTOK) token, which on deployment mints an initial supply and assigns them to the contract owner. It's a standard ERC-20 token, you can review the [IERC20 interface](https://docs.openzeppelin.com/contracts/2.x/api/token/erc20#IERC20){target=\_blank} for more information on the available methods - `SimpleDex.sol` - a simple example of a DEX that on deployment deploys the `DemoToken` contract, which mints 1000 DTOKs, and allows you to swap DEV token for DTOKs and vice versa. **This contract is for demo purposes only**. The `SimpleDex` contract contains the following methods: - **token**() - a read-only method that returns the address of the `DemoToken` contract - **swapDevForDemoToken**() - a payable function that accepts DEV tokens in exchange for DTOK tokens. The function checks to make sure there are enough DTOK tokens held in the contract before making the transfer. After the transfer is made, a `Bought` event is emitted - **swapDemoTokenForDev**(*uint256* amount) - accepts the amount of DTOKs to swap for DEV tokens. The function checks to make sure the caller of the function has approved the contract to transfer their DTOKs before swapping the DTOKs back to DEV. After the transfer is made, a `Sold` event is emitted If you don't already have a `contracts` directory in your Hardhat project, you can create a new directory: ```bash mkdir contracts && cd contracts ``` Then, you can create a single file that we'll use to store the code for the `DemoToken` and `SimpleDex` contracts and another file for the batch precompile: ```bash touch SimpleDex.sol Batch.sol ``` In the `SimpleDex.sol` file, you can paste in the following code for the `DemoToken` and `SimpleDex` contracts: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract DemoToken is ERC20 { constructor(uint256 initialSupply) ERC20("DemoToken", "DTOK") { // Assign 500 DTOK tokens to the SimpleDex contract _mint(msg.sender, initialSupply / 2); // Assign 500 DTOK tokens to the EOA that deployed the SimpleDex contract _mint(tx.origin, initialSupply / 2); } } contract SimpleDex { IERC20 public token; event Bought(uint256 amount); event Sold(uint256 amount); // Make constructor payable so that DEV liquidity exists for the contract constructor() payable { // Mint 1000 DTOK tokens. Half will be assigned to the SimpleDex contract // and the other half will be assigned to the EOA that deployed the // SimpleDex contract token = new DemoToken(1000000000000000000000); } // Function to swap DEV for DTOK tokens function swapDevForDemoToken() payable public { // Verify the contract has enough tokens for the requested amount uint256 amountTobuy = msg.value; uint256 dexBalance = token.balanceOf(address(this)); require(amountTobuy > 0, "You need to send some DEV"); require(amountTobuy <= dexBalance, "Not enough tokens in the reserve"); // If enough, swap the DEV to DTOKs token.transfer(msg.sender, amountTobuy); emit Bought(amountTobuy); } // Function to swap DTOK for DEV tokens function swapDemoTokenForDev(uint256 amount) public { // Make sure the requested amount is greater than 0 and the caller // has approved the requested amount of tokens to be transferred require(amount > 0, "You need to sell at least some tokens"); uint256 allowance = token.allowance(msg.sender, address(this)); require(allowance >= amount, "Check the token allowance"); // Transfer the DTOKs to the contract token.transferFrom(msg.sender, address(this), amount); // Transfer the DEV tokens back to the caller payable(msg.sender).transfer(amount); emit Sold(amount); } } ``` In the `Batch.sol` file, you can paste in the Batch Precompile contract. ??? code "Batch.sol" ```solidity // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.3; /// @dev The Batch contract's address. address constant BATCH_ADDRESS = 0x0000000000000000000000000000000000000808; /// @dev The Batch contract's instance. Batch constant BATCH_CONTRACT = Batch(BATCH_ADDRESS); /// @author The Moonbeam Team /// @title Batch precompile /// @dev Allows to perform multiple calls through one call to the precompile. /// Can be used by EOA to do multiple calls in a single transaction. /// @custom:address 0x0000000000000000000000000000000000000808 interface Batch { /// @dev Batch multiple calls into a single transaction. /// All calls are performed from the address calling this precompile. /// /// In case of one subcall reverting following subcalls will still be attempted. /// /// @param to List of addresses to call. /// @param value List of values for each subcall. If array is shorter than "to" then additional /// calls will be performed with a value of 0. /// @param callData Call data for each `to` address. If array is shorter than "to" then /// additional calls will be performed with an empty call data. /// @param gasLimit Gas limit for each `to` address. Use 0 to forward all the remaining gas. /// If array is shorter than "to" then the remaining gas available will be used. /// @custom:selector 79df4b9c function batchSome( address[] memory to, uint256[] memory value, bytes[] memory callData, uint64[] memory gasLimit ) external; /// @dev Batch multiple calls into a single transaction. /// All calls are performed from the address calling this precompile. /// /// In case of one subcall reverting, no more subcalls will be executed but /// the batch transaction will succeed. Use batchAll to revert on any subcall revert. /// /// @param to List of addresses to call. /// @param value List of values for each subcall. If array is shorter than "to" then additional /// calls will be performed with a value of 0. /// @param callData Call data for each `to` address. If array is shorter than "to" then /// additional calls will be performed with an empty call data. /// @param gasLimit Gas limit for each `to` address. Use 0 to forward all the remaining gas. /// If array is shorter than "to" then the remaining gas available will be used. /// @custom:selector cf0491c7 function batchSomeUntilFailure( address[] memory to, uint256[] memory value, bytes[] memory callData, uint64[] memory gasLimit ) external; /// @dev Batch multiple calls into a single transaction. /// All calls are performed from the address calling this precompile. /// /// In case of one subcall reverting, the entire batch will revert. /// /// @param to List of addresses to call. /// @param value List of values for each subcall. If array is shorter than "to" then additional /// calls will be performed with a value of 0. /// @param callData Call data for each `to` address. If array is shorter than "to" then /// additional calls will be performed with an empty call data. /// @param gasLimit Gas limit for each `to` address. Use 0 to forward all the remaining gas. /// If array is shorter than "to" then the remaining gas available will be used. /// @custom:selector 96e292b8 function batchAll( address[] memory to, uint256[] memory value, bytes[] memory callData, uint64[] memory gasLimit ) external; /// Emitted when a subcall succeeds. event SubcallSucceeded(uint256 index); /// Emitted when a subcall fails. event SubcallFailed(uint256 index); } ``` ### Compile & Deploy Contracts {: #compile-deploy-contracts } To compile the contracts, we'll go ahead and run the following Hardhat command: ```bash npx hardhat compile ```
npx hardhat compile Compiled 6 Solidity files successfully (evm target: paris).
After compilation, an `artifacts` directory is created: it holds the bytecode and metadata of the contract, which are `.json` files. It’s a good idea to add this directory to the `.gitignore` file. Next, we can deploy the `SimpleDex` contract, which upon deployment will automatically deploy the `DemoToken` contract and mint 1000 DTOKs and assign half of them to the `SimpleDex` contract and the other half to the address that you're initiating the deployment from. We'll also add some initial liquidity to the contract by passing in a `value` when calling `deploy`. Since the value needs to be in Wei, we can use `ethers.parseEther` to pass in a value such as `"0.5"` DEV and it will convert the value to Wei for us. Before deploying the contract, we'll need to create the deployment script. We'll create a new directory for the script and name it `scripts` and add a new file to it called `deploy.js`: ```bash mkdir scripts && touch scripts/deploy.js ``` In the `deploy.js` script, you can paste in the following code, which will deploy the `SimpleDex` contract and print the address of the contract to the terminal upon successful deployment: ```js async function main() { // Liquidity to add in DEV (i.e., '.5') to be converted to Wei const value = ethers.parseEther('INSERT_AMOUNT_OF_DEV'); // Deploy the SimpleDex contract, which will also automatically deploy // the DemoToken contract and add liquidity to the contract const SimpleDex = await ethers.getContractFactory('SimpleDex',); const simpleDex = await SimpleDex.deploy({ value }) // Wait for the deployment transaction to be included in a block await simpleDex.waitForDeployment(); // Get and print the contract address const myContractDeployedAddress = await simpleDex.getAddress(); console.log(`SimpleDex deployed to ${myContractDeployedAddress}`); } main().catch((error) => { console.error(error); process.exitCode = 1; }); ``` Now we can deploy the `SimpleDex` contract using the `run` command and specifying `moonbase` as the network: ```bash npx hardhat run --network moonbase scripts/deploy.js ``` !!! note If you want to run the script in a standalone fashion using `node