# Deploy a Smart Contract on MANTRA Chain Source: https://docs.mantrachain.io/deploy-smart-contract Learn how to deploy your first smart contract on MANTRA Chain using standard EVM tools MANTRA Chain is fully EVM-compatible, which means you can deploy Solidity smart contracts using familiar tools like Hardhat, Foundry, or Remix. **Full EVM Compatibility**: Deploy Solidity smart contracts using standard EVM tooling - no need to learn new languages! ## Prerequisites Before deploying, make sure you have: * A funded wallet with OM tokens for gas fees * Your contract compiled and ready to deploy * Network configuration set up ## Network Configuration ### Testnet (DuKong) * **RPC URL**: `https://evm.dukong.mantrachain.io` * **Chain ID**: `5887` * **Explorer**: [explorer.dukong.io](https://explorer.dukong.io) ### Mainnet * **RPC URL**: `https://evm.mantrachain.io` * **Chain ID**: `5888` * **Explorer**: [blockscout.mantrascan.io](https://blockscout.mantrascan.io) ## Method 1: Using Hardhat Hardhat is a popular development environment for Ethereum software. ### Setup 1. **Install Node.js** (version 18.0 or higher recommended) 2. **Create a new project**: ```bash theme={null} mkdir my-project cd my-project npm init -y npm install --save-dev hardhat npx hardhat init ``` 3. **Configure Hardhat** for MANTRA Chain by updating `hardhat.config.js`: ```javascript theme={null} require("@nomicfoundation/hardhat-toolbox"); module.exports = { solidity: "0.8.23", networks: { mantra_mainnet: { url: "https://evm.mantrachain.io", chainId: 5888, accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [], }, mantra_testnet: { url: "https://evm.dukong.mantrachain.io", chainId: 5887, accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [], }, }, }; ``` ### Create Deployment Script Create `scripts/deploy.js`: ```javascript theme={null} const hre = require("hardhat"); async function main() { const MyContract = await hre.ethers.getContractFactory("MyContract"); const myContract = await MyContract.deploy(); await myContract.waitForDeployment(); const address = await myContract.getAddress(); console.log("Contract deployed to:", address); console.log("Explorer:", `https://explorer.dukong.io/address/${address}`); } main() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); }); ``` ### Deploy ```bash theme={null} npx hardhat run scripts/deploy.js --network mantra_testnet ``` For more details, see our [Hardhat guide](/developers/evm/using-hardhat). ## Method 2: Using Foundry Foundry is a fast, portable, and modular toolkit for Ethereum application development. ### Setup 1. **Install Foundry**: ```bash theme={null} curl -L https://foundry.paradigm.xyz | bash foundryup ``` 2. **Create a new project**: ```bash theme={null} forge init my-contract cd my-contract ``` ### Deploy with Forge ```bash theme={null} forge create src/MyContract.sol:MyContract \ --rpc-url https://evm.dukong.mantrachain.io \ --private-key $PRIVATE_KEY \ --chain-id 5887 ``` ### Using Scripts Create `script/Deploy.s.sol`: ```solidity theme={null} // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {Script, console} from "forge-std/Script.sol"; import {MyContract} from "../src/MyContract.sol"; contract DeployScript is Script { function run() external { vm.startBroadcast(); MyContract myContract = new MyContract(); console.log("Contract deployed to:", address(myContract)); vm.stopBroadcast(); } } ``` Deploy: ```bash theme={null} forge script script/Deploy.s.sol:DeployScript \ --rpc-url https://evm.dukong.mantrachain.io \ --private-key $PRIVATE_KEY \ --broadcast \ --chain-id 5887 ``` For more details, see our [Foundry guide](/developers/evm/using-foundry). ## Method 3: Using Remix Remix is a web-based IDE that makes it easy to deploy contracts without local setup. ### Steps 1. Go to [Remix IDE](https://remix.ethereum.org) 2. Create or import your Solidity contract 3. Compile your contract 4. Go to the "Deploy & Run" tab 5. Select "Injected Provider" (MetaMask) 6. Make sure MetaMask is connected to MANTRA Chain * Add MANTRA Chain network if needed: * Network Name: MANTRA Chain Testnet * RPC URL: `https://evm.dukong.mantrachain.io` * Chain ID: `5887` * Currency Symbol: OM 7. Deploy your contract ## After Deployment ### Verify Your Contract After deployment, verify your contract on the block explorer. This allows others to view and interact with your contract source code. See our [Verifying Contracts](/developers/evm/verifying-contracts) guide for detailed instructions. ### Interact with Your Contract Once deployed, you can: * View your contract on the [block explorer](https://explorer.dukong.io) * Interact with it using the explorer's contract interaction features * Build a frontend application to interact with your contract ## Next Steps * Learn about [using precompiles](/developers/evm/using-precompiles) to interact with MANTRA Chain's unique features * Explore [EVM development](/developers/evm/getting-started) on MANTRA Chain * Check out our [architecture documentation](/developers/architecture/overview) to understand MANTRA Chain's capabilities * Join our [Discord](https://discord.com/invite/mantrachain) community for support ## Resources * [Deploying Contracts Guide](/developers/evm/deploying-contracts) - Detailed deployment documentation * [EVM Getting Started](/developers/evm/getting-started) - Complete EVM development guide * [Network Details](/resources/network-details) - Network information and endpoints # Address Derivation Source: https://docs.mantrachain.io/developers/architecture/address-derivation Address derivation, coin types, and wallet compatibility ## Coin Types If the derivation path is the map, the **coin type** indicates the city. Coin types define how your private and public keys are generated from the seed phrase: * **Cosmos uses 118** * **EVM chains (like Ethereum) use 60** ## MANTRA Chain Address Derivation When MANTRA Chain moved from coin type 118 to 60, we adopted Ethereum's key type and address derivation. ### What This Means * The old 0x equivalent from the Cosmos wallet still exists but is not used * New addresses use Ethereum-style derivation (coin type 60) * Compatible with standard EVM tooling and wallets ## Wallet Behavior ### Keplr * Automatically selects the latest default coin type * Handles address derivation automatically * Supports both Cosmos and EVM addresses ### Cosmostation You can manually select the coin type: | Coin Type | Blockchain | Derivation Path | | --------- | ---------- | ----------------- | | 0 | Bitcoin | m/44'/0'/0'/0/0 | | 60 | Ethereum | m/44'/60'/0'/0/0 | | 118 | Cosmos | m/44'/118'/0'/0/0 | | 501 | Solana | m/44'/501'/0'/0/0 | ## Derivation Path Format Standard BIP-44 format: `m/44'/{coin_type}'/{account}'/{change}/{address_index}` For MANTRA Chain (EVM): * Coin type: **60** * Derivation path: `m/44'/60'/0'/0/0` ## Address Encoding MANTRA Chain uses standard Ethereum address encoding: * 20-byte addresses * Hexadecimal format (0x...) * Checksummed addresses (EIP-55) ## Migration Notes If you have an old MANTRA wallet using coin type 118: * The old 0x equivalent address still exists * It's not actively used on the EVM side * New addresses use coin type 60 ## Next Steps * Learn about [EVM compatibility](/developers/architecture/evm-compatibility) * Understand [transaction sequencing](/developers/architecture/transaction-sequencing) * Get started with [EVM development](/developers/evm/getting-started) # Cosmos Precompiles Source: https://docs.mantrachain.io/developers/architecture/cosmos-precompiles How EVM communicates with Cosmos SDK modules through precompiles ## How EVM Communicates with Cosmos The EVM communicates with the Cosmos part of the chain through **precompiles** - Go code that directly interacts with other module states (e.g., Bank module). Precompiles are special contract addresses that execute native Go code instead of EVM bytecode, enabling seamless integration between EVM and Cosmos SDK modules. ## Cosmos SDK Precompiles There are **5 Cosmos SDK precompiles** exposed inside the EVM: ### 1. Staking Precompile Interact with the staking module directly from EVM contracts: * **Delegate tokens**: Delegate native tokens to validators * **Undelegate tokens**: Undelegate from validators * **Redelegate tokens**: Move delegation between validators * **Query delegation information**: Get delegation details **Use Cases:** * Automated staking strategies * Liquid staking protocols * Validator selection algorithms ### 2. Distribution Precompile Manage staking rewards from EVM contracts: * **Claim rewards**: Claim staking rewards * **Withdraw rewards**: Withdraw accumulated rewards * **Query reward information**: Get reward details **Use Cases:** * Automated reward claiming * Reward distribution protocols * Staking aggregators ### 3. Slashing Precompile Handle slashing operations and re-staking: * **Re-staking operations**: Manage validator re-staking * **Reward management**: Handle slashing-related rewards * **Validator penalties**: Query and handle penalties **Use Cases:** * Slashing protection protocols * Validator health monitoring * Risk management systems ### 4. Governance Precompile Participate in on-chain governance from EVM contracts: * **Vote on proposals**: Cast votes on governance proposals * **Create proposals**: Submit new governance proposals * **Query proposal information**: Get proposal details and status **Use Cases:** * Automated governance participation * Governance aggregators * Proposal creation tools ### 5. Bank Precompile Transfer native Cosmos tokens from EVM contracts: * **Transfer tokens**: Send native tokens * **Query balances**: Get token balances * **Multi-send operations**: Batch token transfers **Use Cases:** * Token bridges * Payment protocols * Multi-sig wallets ## ERC20 Precompiles Each **TokenFactory token** has its own ERC20 precompile address, allowing: * **Control token balance**: Manage token balances from EVM * **Transfer tokens**: Transfer TokenFactory tokens * **Use tokens in EVM contracts**: Seamless integration This enables TokenFactory tokens (created via Cosmos SDK) to be used directly in EVM contracts without wrapping. ## Using Precompiles Precompiles are called like regular contract calls in Solidity: ```solidity theme={null} // Example: Calling a precompile // (Addresses and interfaces are examples - actual addresses will be documented) interface IStakingPrecompile { function delegate(address validator, uint256 amount) external; } contract MyContract { address constant STAKING_PRECOMPILE = 0x0000000000000000000000000000000000000800; function stake(address validator, uint256 amount) external { IStakingPrecompile(STAKING_PRECOMPILE).delegate(validator, amount); } } ``` ## Precompile Addresses Precompile addresses are fixed and documented. See [Using Precompiles](/developers/evm/using-precompiles) for detailed addresses and interfaces. ## Benefits of Precompiles 1. **Direct Cosmos Integration**: Access Cosmos SDK features from EVM 2. **No Wrapping Required**: Use native Cosmos tokens directly 3. **Atomic Operations**: Precompile calls are part of the transaction 4. **Gas Efficient**: Native Go code execution is more efficient than contract calls ## Next Steps * Learn how to [use precompiles in your contracts](/developers/evm/using-precompiles) * Understand [transaction sequencing](/developers/architecture/transaction-sequencing) * Explore [ERC-20 token creation](/developers/architecture/erc20-tokens) # Cosmos SDK Integration Source: https://docs.mantrachain.io/developers/architecture/cosmos-sdk-integration Cosmos SDK modules and custom MANTRA modules ## Core Cosmos SDK Modules MANTRA Chain uses standard Cosmos SDK modules: * **Auth Module**: Account management and authentication * **Bank Module**: Token transfers and balances * **Staking Module**: Validator staking and delegation * **Distribution Module**: Fee and reward distribution * **Slashing Module**: Validator penalties * **Gov Module**: On-chain governance * **IBC Module**: Inter-Blockchain Communication * **Custom Modules**: MANTRA-specific modules for RWA functionality ## Custom MANTRA Modules ### ERC20 Module * ERC-20 token support * TokenFactory integration * EVM compatibility ## Module Interactions All modules interact through the Cosmos SDK's message routing system, allowing: * Cross-module transactions * Atomic operations * State consistency ## Next Steps * Learn about [Cosmos precompiles](/developers/architecture/cosmos-precompiles) * Understand [transaction sequencing](/developers/architecture/transaction-sequencing) * Explore [interoperability](/developers/architecture/interoperability) # ERC-20 Tokens Source: https://docs.mantrachain.io/developers/architecture/erc20-tokens Two ways to create ERC-20 tokens on MANTRA Chain ## Two Ways to Create ERC-20 Tokens MANTRA Chain supports two methods for creating ERC-20 tokens, each with different use cases and benefits. ## Method 1: Deploy ERC-20 Contract in EVM Deploy a standard ERC-20 contract inside the EVM (same experience as any EVM chain). ### Steps 1. **Write or use a standard ERC-20 contract** * Use OpenZeppelin's ERC20 contract * Or write your own ERC-20 implementation 2. **Deploy using standard EVM tooling** * Hardhat * Foundry * Remix * Or any EVM deployment tool 3. **Optionally, create a mapping to the Bank module** * This enables Cosmos SDK integration * Allows use in Cosmos-native applications ### Use Cases * **Standard ERC-20 tokens**: Simple token requirements * **External (non-MANTRA) developers**: Recommended approach * **Quick deployment**: Fastest way to deploy tokens * **Standard tooling**: Use familiar EVM development tools ### Example ```solidity theme={null} // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract MyToken is ERC20 { constructor() ERC20("MyToken", "MTK") { _mint(msg.sender, 1000000 * 10**decimals()); } } ``` Deploy this contract using Hardhat, Foundry, or Remix - it works exactly like on Ethereum. ## Method 2: TokenFactory with ERC-20 Precompile Create a denom in TokenFactory, which automatically creates a custom ERC-20 precompile address so the token can be used in the EVM. ### Steps 1. **Create token using TokenFactory module** * Use Cosmos SDK's TokenFactory * Configure token parameters 2. **Token automatically gets ERC-20 precompile address** * No additional setup required * Precompile address is deterministic 3. **Use token in EVM contracts seamlessly** * Call precompile from Solidity * Transfer, approve, and query balances ### Use Cases * **MANTRA internal tokens**: Tokens created by MANTRA * **Tokens requiring compliance features**: Access to Bank module compliance * **Tokens that need Bank module integration**: Native Cosmos SDK support * **Regulatory compliance**: Protocol-level compliance features ### Benefits * **Compliance features**: Bank module has access to the token for compliance features * **Seamless integration**: Works in both EVM and Cosmos SDK * **Native protocol support**: Built-in MANTRA Chain features * **No wrapping required**: Direct EVM access via precompile ## Recommendation ### For External Developers **Use Method 1** (deploy standard ERC-20 contract): * Familiar development experience * Standard tooling and libraries * No special setup required * Works identically to other EVM chains ### For MANTRA **Use Method 2** (TokenFactory) because: * Compliance features built inside the protocol (specifically in the Bank module) have access to the token * Seamless integration with Cosmos ecosystem * Native protocol support * Protocol-level compliance features ## TokenFactory ERC-20 Precompiles Each TokenFactory token automatically gets: * **ERC-20 precompile address**: Deterministic address based on token denom * **Balance control**: Manage token balances from EVM * **Transfer functionality**: Standard ERC-20 transfer operations * **EVM contract compatibility**: Use in any EVM contract ### Using TokenFactory Tokens in EVM ```solidity theme={null} // Example: Using a TokenFactory token in EVM // The precompile address is deterministic based on the token denom interface ITokenFactoryERC20 { function transfer(address to, uint256 amount) external returns (bool); function balanceOf(address account) external view returns (uint256); } contract MyContract { // Precompile address for a specific TokenFactory token address constant TOKEN_PRECOMPILE = 0x0000000000000000000000000000000000000801; function transferToken(address to, uint256 amount) external { ITokenFactoryERC20(TOKEN_PRECOMPILE).transfer(to, amount); } } ``` ## Comparison | Feature | Method 1: EVM Contract | Method 2: TokenFactory | | ---------------------- | ---------------------- | ---------------------- | | Development Experience | Standard EVM | Cosmos SDK + EVM | | Compliance Features | Limited | Full protocol support | | Cosmos Integration | Optional mapping | Native integration | | Recommended For | External developers | MANTRA internal tokens | | Setup Complexity | Low | Medium | | Tooling | Standard EVM tools | Cosmos SDK + EVM | ## Next Steps * Learn about [address derivation](/developers/architecture/address-derivation) * Understand [transaction sequencing](/developers/architecture/transaction-sequencing) * Get started with [EVM development](/developers/evm/getting-started) # EVM Compatibility Source: https://docs.mantrachain.io/developers/architecture/evm-compatibility Full EVM compatibility with all opcodes and precompiles ## Is MANTRA Chain Fully EVM Compatible? **Yes.** MANTRA Chain has all of the opcodes and precompiles that a developer would expect on any other EVM chain, including: * Ethereum * Base * Polygon * Arbitrum * And other EVM-compatible chains ## What This Means ### Deploy Without Modification Deploy contracts written for Ethereum without any modifications. Standard Solidity code works as-is. ### Use Standard Tooling All standard EVM tooling works out of the box: * **Hardhat**: Full support * **Foundry**: Full support * **Remix**: Full support * **Web3.js / Ethers.js**: Standard libraries work ### Leverage Existing Libraries * OpenZeppelin contracts * Standard Solidity libraries * Existing EVM frameworks * DeFi protocol integrations ### Standard Gas Mechanics * Same gas costs as Ethereum * Standard gas estimation * Familiar gas optimization patterns ## Testing Compatibility All standard EVM opcodes and precompiles are available and behave identically to other EVM chains. ### Supported Opcodes All standard EVM opcodes including: * Arithmetic operations * Logical operations * Memory operations * Storage operations * Control flow * And more ### Supported Precompiles Standard Ethereum precompiles plus MANTRA-specific Cosmos precompiles: * ECRecover * SHA256 * RIPEMD160 * Identity * ModExp * BN256Add * BN256Mul * BN256Pairing * Bls12-381 * **Plus Cosmos SDK precompiles** (see [Cosmos Precompiles](/developers/architecture/cosmos-precompiles)) ## Migration from Other EVM Chains Migrating from other EVM chains is straightforward: 1. **Update RPC endpoint** to MANTRA Chain 2. **Update chain ID** to `5888` (mainnet) or `5887` (testnet) 3. **Deploy contracts** using your existing deployment scripts 4. **No code changes required** ## Example: Deploying a Standard ERC-20 ```solidity theme={null} // Standard ERC-20 contract - works as-is // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract MyToken is ERC20 { constructor() ERC20("MyToken", "MTK") { _mint(msg.sender, 1000000 * 10**decimals()); } } ``` This contract works identically on MANTRA Chain as it would on Ethereum, Base, or any other EVM chain. ## Next Steps * Learn about [Cosmos precompiles](/developers/architecture/cosmos-precompiles) for unique MANTRA features * See [EVM module details](/developers/architecture/evm-module) * Get started with [EVM development](/developers/evm/getting-started) # EVM Module Source: https://docs.mantrachain.io/developers/architecture/evm-module EVM module implementation and integration details ## Overview The EVM Module implements the Ethereum Virtual Machine standard for Cosmos SDK-based chains, enabling full EVM compatibility on MANTRA Chain. ## Key Features ### Turing-Complete Any computation possible within gas limits, enabling complex smart contract logic. ### Bytecode Execution Uniform contract execution across all EVM-compatible chains, ensuring consistency. ### Gas Mechanism * Prevents abuse through computational limits * Adds transaction fees * Ensures network security ### Security and Isolation Protects the network from malicious code execution through isolated execution environments. ## Integration with Cosmos SDK The EVM module integrates seamlessly with Cosmos SDK modules, allowing: * Cross-module interactions through precompiles * Native token transfers via Bank module * Governance participation through Gov module * Staking operations through Staking module ## Architecture The EVM module sits alongside Cosmos SDK modules, communicating through: * **Precompiles**: Direct Go code execution * **Message routing**: Cosmos SDK message system * **State management**: Shared state between modules ## Technical Specifications ### Chain ID * **Mainnet**: 5888 * **Testnet**: 5887 ### RPC Endpoints * **Mainnet**: `https://evm.mantrachain.io` * **Testnet**: `https://evm.dukong.mantrachain.io` ### Network Parameters * **Block Time**: \~3 seconds (timeout\_commit) * **Gas Price**: Dynamic based on network conditions * **Gas Limit**: Per-block gas limit varies ## Next Steps * Learn about [EVM compatibility](/developers/architecture/evm-compatibility) * Understand [Cosmos precompiles](/developers/architecture/cosmos-precompiles) * Explore [EVM development](/developers/evm/getting-started) # Interoperability Source: https://docs.mantrachain.io/developers/architecture/interoperability Cross-chain communication and bridge architecture ## Hyperlane Integration Hyperlane is MANTRA Chain's main lock and mint bridge: * Recommended for market makers * Recommended for large transactions (\$1k+) * Lock and mint mechanism ## Squid Integration Squid is MANTRA Chain's liquidity bridge: * Recommended for transactions below \$1k * Easier to use * Cheaper and faster than Hyperlane ## IBC Protocol Inter-Blockchain Communication (IBC) enables: * Communication with 50+ Cosmos chains * Native token transfers * Cross-chain applications **Note:** Users should only use IBC if bridging from a Cosmos chain to MANTRA Chain. ## Bridge Architecture MANTRA Chain supports multiple bridge types: * **Hyperlane**: Lock & mint (large transactions) * **Squid**: Liquidity bridge (small transactions \<\$1k) * **IBC**: Cosmos chain interoperability ## Cross-Chain Communication The EVM module and Cosmos SDK work together to enable: * Cross-chain token transfers * Cross-chain smart contract calls * Interoperable DeFi applications ## Next Steps * Learn about [bridging options](/resources/bridging/overview) * Understand [EVM compatibility](/developers/architecture/evm-compatibility) * Explore [Cosmos precompiles](/developers/architecture/cosmos-precompiles) # Architecture Overview Source: https://docs.mantrachain.io/developers/architecture/overview Technical deep dive into MANTRA Chain's architecture ## Core Components MANTRA Chain is built on a modular architecture combining: * **Cosmos SDK**: Flexible, scalable, and modular framework * **EVM Module**: Ethereum Virtual Machine compatibility * **CometBFT**: Consensus layer for validator set management * **IBC**: Inter-Blockchain Communication protocol ## Virtual Machines A **Virtual Machine (VM)** emulates a computer system, enabling code to run securely. In the context of blockchain, VMs serve as the runtime environment where smart contract code is executed, ensuring: * **Secure execution**: Isolated from the host system * **Deterministic behavior**: Same input always produces same output * **Isolated execution**: Contracts cannot interfere with each other ## How VMs Coexist The EVM Module was developed to implement the EVM standard for Cosmos SDK-based chains. ### Why Add EVM? Adding an EVM module to Cosmos SDK allows us to: * **Attract Solidity developers**: The majority of developers in the space use Solidity/EVM * **Further develop the ecosystem**: Enable existing EVM tooling and libraries * **Enable EVM-compatible smart contracts**: Deploy contracts written for Ethereum without modification ## Data Flow The EVM module integrates seamlessly with Cosmos SDK modules through: 1. **Precompiles**: Go code that directly interacts with Cosmos SDK module states 2. **Message routing**: Cosmos SDK's message routing system 3. **State management**: Shared state between EVM and Cosmos modules ## Module Interactions All modules interact through the Cosmos SDK's message routing system, allowing: * **Cross-module transactions**: Messages can interact with multiple modules * **Atomic operations**: All messages in a transaction succeed or fail together * **State consistency**: Guaranteed consistency across module states ## Architecture Diagram ```mermaid theme={null} graph TB subgraph "Application Layer" RWA[RWA dApps] DeFi[DeFi dApps] end subgraph "MANTRA Chain" EVM[EVM Module] Cosmos[Cosmos SDK] Precompiles[Precompiles] end subgraph "Interoperability" Hyperlane[Hyperlane] IBC[IBC] Other[Other EVM Chains] end RWA --> EVM DeFi --> EVM EVM --> Precompiles Precompiles --> Cosmos EVM --> Hyperlane Cosmos --> IBC EVM --> Other ``` ## Next Steps * Learn about [EVM module details](/developers/architecture/evm-module) * Understand [EVM compatibility](/developers/architecture/evm-compatibility) * Explore [Cosmos precompiles](/developers/architecture/cosmos-precompiles) # Transaction Sequencing Source: https://docs.mantrachain.io/developers/architecture/transaction-sequencing How EVM transactions are sequenced on MANTRA Chain ## Transaction Composition in Cosmos In Cosmos, a transaction is composed of **multiple messages** (think of it as native multicall), with the caller deciding how they want to sequence their messages in the transaction. The signature is done on the entire Cosmos transaction. This allows for atomic operations where multiple actions can be combined in a single transaction. ## EVM Transactions ### EVM Message Format * **Must be alone in a transaction** * Cannot be combined with other Cosmos message types * This is due to the signature being done on the EVM message (equivalent to a normal EVM transaction in Ethereum) instead of the entire Cosmos transaction * Signature follows Ethereum's EIP-155 format **Example:** ```typescript theme={null} // EVM transaction structure const evmTransaction = { from: "0x...", // Sender address to: "0x...", // Contract address (or null for contract creation) value: "0x0", // Amount in wei data: "0x...", // Contract call data gasLimit: "0x5208", // Gas limit gasPrice: "0x3b9aca00", // Gas price nonce: 0, // Transaction nonce chainId: 0x1388, // Chain ID (EIP-155) // Signature is applied to this transaction object // Cannot be combined with Cosmos messages in the same transaction }; ``` ## Why This Design? ### EVM Transaction Format EVM transactions use Ethereum's transaction format: * Signature is on the EVM transaction itself * Follows EIP-155 signature scheme * Compatible with Ethereum tooling and wallets * Standard EVM transaction behavior ## Transaction Sequencing Transaction sequencing is solely dependent on the **block proposer**, but the default is **FIFO** (First In, First Out). ### Block Proposer Role The block proposer (validator) decides: * Which transactions to include * The order of transactions * Transaction prioritization ### Default Behavior By default, transactions are processed in FIFO order: 1. Transactions are added to the mempool 2. Block proposer selects transactions in order 3. Transactions execute sequentially ## EVM Transaction Isolation EVM transactions are isolated: * Each EVM transaction is independent * Cannot combine with other message types * Standard Ethereum transaction behavior * Each transaction executes atomically (succeeds or reverts entirely) ## Practical Implications ### For Developers **EVM:** * One operation per transaction * Standard Ethereum behavior * Compatible with existing EVM tooling * Use multicall contracts for batching multiple operations ### For Users **EVM:** * One operation per transaction * Familiar Ethereum experience * Standard gas costs * Predictable transaction behavior ## Example Scenario ### Swap and Stake (EVM) ```solidity theme={null} // Requires two separate transactions // Transaction 1: Swap swap(); // Transaction 2: Stake stake(); // Each transaction executes atomically ``` ### Using Multicall for Batching For batching multiple operations, consider using a multicall contract: ```solidity theme={null} // Multicall pattern for batching operations multicall([ swapCall, stakeCall ]); ``` ## Best Practices ### For EVM Developers * Design contracts to minimize transaction dependencies * Use standard EVM patterns * Consider using multicall contracts for batching operations * Each transaction executes atomically (succeeds or reverts entirely) ## Next Steps * Learn about [Cosmos precompiles](/developers/architecture/cosmos-precompiles) * Understand [ERC-20 token creation](/developers/architecture/erc20-tokens) * Explore [EVM development](/developers/evm/getting-started) # Address Conversion Source: https://docs.mantrachain.io/developers/evm/address-conversion Convert between Bech32 and EVM address formats on MANTRA Chain MANTRA Chain uses the **Bech32 address format** for native chain addresses (addresses start with `mantra1`) and standard **hexadecimal format** for EVM addresses (addresses start with `0x`). With the same private key, you can derive both EVM address and Bech32 address using coin type **60**. **IMPORTANT**: Address conversion only works if the key type is `cosmos.evm.crypto.v1.ethsecp256k1.PubKey`. **How to check your key type:** 1. Go to [mantrascan.io](https://mantrascan.io) and search for your `mantra1...` address 2. Look at the "Auth Information" section on the address page 3. Check the `@type` field - it must show `cosmos.evm.crypto.v1.ethsecp256k1.PubKey` **If your key type is different** (e.g., `cosmos.crypto.secp256k1.PubKey`): * Your address was created with a non-EVM compatible key * EVM wallets (like MetaMask) cannot derive this address * **Solution**: Create a new wallet using MetaMask or another EVM wallet, then transfer your assets to the new address **Best practice**: Use MetaMask or an EVM-compatible wallet from the start if you plan to interact with EVM contracts. ## Using the CLI Download the latest binary from [MANTRA Chain Releases](https://github.com/MANTRA-Chain/mantrachain/releases). ### Bech32 to EVM Address Basic command: ```bash theme={null} mantrachaind debug addr mantra19nj8hate4y2w0va698uygf2jj4y6xq42k8a7ed ``` Output: ``` Address: [44 228 123 245 121 169 20 231 179 186 41 248 68 37 82 149 73 163 2 170] Address (hex): 2CE47BF579A914E7B3BA29F84425529549A302AA Bech32 Acc: mantra19nj8hate4y2w0va698uygf2jj4y6xq42k8a7ed Bech32 Val: mantravaloper19nj8hate4y2w0va698uygf2jj4y6xq42juus4g Bech32 Con: mantravalcons19nj8hate4y2w0va698uygf2jj4y6xq42x00vef ``` Command with formatted output: ```bash theme={null} mantrachaind debug addr mantra19nj8hate4y2w0va698uygf2jj4y6xq42k8a7ed | grep "Address (hex):" | awk '{print "0x"$3}' ``` Output: ``` 0x2CE47BF579A914E7B3BA29F84425529549A302AA ``` ### EVM Address to Bech32 Remove the `0x` prefix before converting: ```bash theme={null} mantrachaind debug addr 2CE47BF579A914E7B3BA29F84425529549A302AA ``` Output: ``` Address: [44 228 123 245 121 169 20 231 179 186 41 248 68 37 82 149 73 163 2 170] Address (hex): 2CE47BF579A914E7B3BA29F84425529549A302AA Bech32 Acc: mantra19nj8hate4y2w0va698uygf2jj4y6xq42k8a7ed Bech32 Val: mantravaloper19nj8hate4y2w0va698uygf2jj4y6xq42juus4g Bech32 Con: mantravalcons19nj8hate4y2w0va698uygf2jj4y6xq42x00vef ``` ## JavaScript Implementation ```javascript theme={null} import { bech32 } from "bech32"; const mantraAddressPrefix = 'mantra'; /** * Convert EVM address to MANTRA address. * @param {string} evmAddress - EVM address with or without 0x prefix * @returns {string} MANTRA Bech32 address */ export const convertEVMAddressToMantraAddress = (evmAddress) => { const evmAddressBuffer = Buffer.from(evmAddress.slice(2), 'hex'); const evmAddressBytes = Array.from(evmAddressBuffer); const bz = convertBits(evmAddressBytes, 8, 5); return bech32.encode(mantraAddressPrefix, bz); } /** * Convert MANTRA address to EVM address. * @param {string} mantraAddress - MANTRA Bech32 address * @returns {string} EVM address with 0x prefix */ export const convertMantraAddressToEVMAddress = (mantraAddress) => { const decoded = bech32.decode(mantraAddress); const hexBytes = convertBits(decoded.words, 5, 8, false); return `0x${Buffer.from(hexBytes).toString('hex')}`; } /** * General power-of-2 base conversion. * @param {Array} data - Input data as an array of integers * @param {number} fromBits - Number of bits in source representation * @param {number} toBits - Number of bits in target representation * @param {boolean} pad - Whether to pad a result if needed * @returns {Array|null} - Converted data or null if conversion fails */ export const convertBits = (data, fromBits, toBits, pad = true) => { let acc = 0; let bits = 0; const ret = []; const maxv = (1 << toBits) - 1; const max_acc = (1 << (fromBits + toBits - 1)) - 1; for (const value of data) { if (value < 0 || (value >> fromBits)) { return null; } acc = ((acc << fromBits) | value) & max_acc; bits += fromBits; while (bits >= toBits) { bits -= toBits; ret.push((acc >> bits) & maxv); } } if (pad) { if (bits > 0) { ret.push((acc << (toBits - bits)) & maxv); } } else if (bits >= fromBits || ((acc << (toBits - bits)) & maxv)) { return null; } return ret; } ``` ## Python Implementation ### From Bech32 to EVM Address ```python theme={null} import bech32 bech32_address = "mantra1z3yty3yswenj4ngk0wg5qmqf25ssr3wfqayuhv" _, bz = bech32.bech32_decode(bech32_address) hexbytes = bytes(bech32.convertbits(bz, 5, 8)) eth_address = '0x' + hexbytes.hex() print(eth_address) ``` ### From EVM Address to Bech32 ```python theme={null} import bech32 eth_address = "0x1448b2449076672acd167b91406c09552101c5c9" eth_address_bytes = bytes.fromhex(eth_address[2:]) bz = bech32.convertbits(eth_address_bytes, 8, 5) bech32_address = bech32.bech32_encode("mantra", bz) print(bech32_address) ``` ## References * [BIP-0173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki) - Bech32 specification * [Address Conversion Examples](https://docs.cronos.org/for-dapp-developers/chain-integration/adress-conversion) ## Next Steps * Learn about [EVM compatibility](/developers/architecture/evm-compatibility) * Get started with [EVM development](/developers/evm/getting-started) * Understand [address derivation](/developers/architecture/address-derivation) # Deploying Contracts Source: https://docs.mantrachain.io/developers/evm/deploying-contracts Quick reference for deploying smart contracts on MANTRA Chain For a comprehensive step-by-step guide including setup instructions, see our [Deploy a Smart Contract](/deploy-smart-contract) tutorial. Deploy your EVM smart contracts to MANTRA Chain using standard EVM deployment tools. ## Network Configuration | Network | RPC URL | Chain ID | Explorer | | -------------------- | ----------------------------------- | -------- | ------------------------------------------------------------ | | **Mainnet** | `https://evm.mantrachain.io` | `5888` | [blockscout.mantrascan.io](https://blockscout.mantrascan.io) | | **Testnet (DuKong)** | `https://evm.dukong.mantrachain.io` | `5887` | [explorer.dukong.io](https://explorer.dukong.io) | ## Prerequisites * A funded wallet with OM tokens for gas fees ([Testnet Faucet](/developers/getting-started/testnet-faucet)) * Your contract compiled and ready to deploy * Network configuration set up (see [Getting Started](/developers/evm/getting-started)) ## Quick Deploy Commands ### Using Foundry ```bash theme={null} forge create src/MyContract.sol:MyContract \ --rpc-url https://evm.dukong.mantrachain.io \ --private-key $PRIVATE_KEY \ --chain-id 5887 ``` ### Using Hardhat ```bash theme={null} npx hardhat run scripts/deploy.js --network mantra_testnet ``` ### Using Remix 1. Go to [Remix IDE](https://remix.ethereum.org) 2. Compile your contract 3. Select "Injected Provider" (MetaMask) 4. Ensure MetaMask is connected to MANTRA Chain 5. Deploy your contract ## After Deployment After deployment, verify your contract on the block explorer. See [Verifying Contracts](/developers/evm/verifying-contracts) for details. ## Related Guides * [Deploy a Smart Contract](/deploy-smart-contract) - Complete tutorial with setup * [Using Foundry](/developers/evm/using-foundry) - Foundry-specific guide * [Using Hardhat](/developers/evm/using-hardhat) - Hardhat-specific guide * [Verifying Contracts](/developers/evm/verifying-contracts) - Contract verification * [Using Precompiles](/developers/evm/using-precompiles) - Access native chain features # Getting Started with EVM Source: https://docs.mantrachain.io/developers/evm/getting-started Get started building and deploying EVM smart contracts on MANTRA Chain MANTRA Chain's EVM module provides full Ethereum Virtual Machine compatibility, enabling you to deploy Solidity smart contracts using standard EVM tooling. ## Overview MANTRA Chain supports smart contracts written in Solidity and deployed via the EVM module. The EVM module provides seamless integration with native chain modules. The EVM Module on MANTRA Chain is under constant development and audit cycles. For the latest versioning, see our [GitHub repository](https://github.com/MANTRA-Chain/evm). ## Wallet Setup (MetaMask) ### MetaMask Add one (or both) networks to MetaMask: | Network | RPC URL | Chain ID | Currency | Explorer | | ---------------- | ----------------------------------- | -------: | -------- | ---------------------------------- | | Mainnet | `https://evm.mantrachain.io` | `5888` | `OM` | `https://blockscout.mantrascan.io` | | Testnet (DuKong) | `https://evm.dukong.mantrachain.io` | `5887` | `OM` | `https://explorer.dukong.io` | ## Network Endpoints | Endpoint | URL | | ----------------- | ------------------------------------ | | Mainnet RPC | `https://evm.mantrachain.io` | | Mainnet WebSocket | `wss://evm.mantrachain.io/ws` | | Testnet RPC | `https://evm.dukong.mantrachain.io` | | Testnet WebSocket | `wss://evm.dukong.mantrachain.io/ws` | ## Faucets (testnet) * **OM Faucet**: [faucet.dukong.mantrachain.io](https://faucet.dukong.mantrachain.io/) — Get testnet OM for gas fees * **ERC-20 Faucet**: [ERC-20 Testnet Faucet](https://faucet-for-common-erc-20s-j8va3o4ic-bounceybytes-projects.vercel.app/) — Mint testnet versions of common tokens (tUSDC, tUSDT, tmantraUSD, twMANTRA) ## Block Explorers | Network | Explorer | | ------- | ------------------------------------------------------------ | | Mainnet | [blockscout.mantrascan.io](https://blockscout.mantrascan.io) | | Testnet | [explorer.dukong.io](https://explorer.dukong.io) | ## Development Tools MANTRA Chain supports standard EVM development tools: | Tool | Description | | ----------- | ------------------------------------------------------------------------------------------------------------------------------ | | **Hardhat** | Development environment for Ethereum software. Helps manage and automate tasks involved in building smart contracts and dApps. | | **Foundry** | Fast development toolkit for Ethereum smart contracts. Known for speed and Solidity-native testing. | ## Quick Start 1. **Choose your development tool**: [Hardhat](/developers/evm/using-hardhat) or [Foundry](/developers/evm/using-foundry) 2. **Configure your network**: Use the endpoints above 3. **Deploy your contract**: Follow our [deployment guide](/developers/evm/deploying-contracts) 4. **Verify your contract**: Use our [verification guide](/developers/evm/verifying-contracts) ## Key Features * **Full EVM Compatibility**: All opcodes and precompiles supported * **Standard Tooling**: Works with Hardhat, Foundry, Remix, and other EVM tools * **Extended Precompiles**: Access additional chain features via [precompiles](/developers/evm/using-precompiles) ## Next Steps * Learn about [EVM compatibility](/developers/architecture/evm-compatibility) * Set up [Hardhat](/developers/evm/using-hardhat) or [Foundry](/developers/evm/using-foundry) * Explore [precompiles](/developers/evm/using-precompiles) for extended functionality # Using Foundry Source: https://docs.mantrachain.io/developers/evm/using-foundry Deploy and test smart contracts on MANTRA Chain using Foundry Foundry is a fast, Solidity-native development toolkit for Ethereum smart contracts. It's known for its blazing-fast speed and Solidity-centric approach, making it a great alternative to JavaScript-based tools like Hardhat. **Foundry Tutorial Resources:** * [Foundry Book - Creating a New Project](https://book.getfoundry.sh/projects/creating-a-new-project) * [QuickNode - Intro to Foundry](https://www.quicknode.com/guides/ethereum-development/smart-contracts/intro-to-foundry) ## Installation Foundry installation is straightforward. Install using the official installer: ```bash theme={null} curl -L https://foundry.paradigm.xyz | bash ``` After running the installer, follow the instructions to re-open your terminal (or use `source` to reload environment variables), then run: ```bash theme={null} foundryup ``` Running `foundryup` will automatically install the latest stable version of the precompiled binaries: * `forge` - Build, test, and deploy tool * `cast` - CLI for interacting with contracts * `anvil` - Local testnet node * `chisel` - Solidity REPL ## Creating a New Project Initialize a new Foundry project: ```bash theme={null} forge init my-project cd my-project ``` This creates a standard Foundry project structure with: * `src/` - Your Solidity contracts * `test/` - Your test files * `script/` - Deployment scripts * `foundry.toml` - Configuration file ## Configuring for MANTRA Chain Update `foundry.toml` to configure MANTRA Chain networks: ```toml theme={null} [rpc_endpoints] mantra_mainnet = "https://evm.mantrachain.io" mantra_testnet = "https://evm.dukong.mantrachain.io" [profile.default] src = "src" out = "out" libs = ["lib"] solc_version = "0.8.23" [profile.mantra_mainnet] chain_id = 5888 rpc_url = "https://evm.mantrachain.io" [profile.mantra_testnet] chain_id = 5887 rpc_url = "https://evm.dukong.mantrachain.io" ``` ## Building Contracts Build your contracts: ```bash theme={null} forge build ``` ## Testing Write tests in Solidity and run them: ```bash theme={null} forge test ``` ## Deploying Deploy to MANTRA Chain testnet: ```bash theme={null} forge create MyContract \ --rpc-url https://evm.dukong.mantrachain.io \ --private-key $PRIVATE_KEY \ --chain-id 5887 ``` ## Deployment walkthrough (legacy pattern) If you prefer keeping deployment config in a `.env` file (handy for scripts/CI), you can use a pattern like: ```bash theme={null} FOUNDRY_PROFILE=mantra_testnet FOUNDRY_PK= RPC_URL_MANTRA_EVM=https://evm.dukong.mantrachain.io ``` Then: ```bash theme={null} source .env forge create --rpc-url "$RPC_URL_MANTRA_EVM" --private-key "$FOUNDRY_PK" src/Counter.sol:Counter ``` ## Next Steps * Learn about [deploying contracts](/developers/evm/deploying-contracts) * Understand [contract verification](/developers/evm/verifying-contracts) * Explore [EVM development](/developers/evm/getting-started) # Using Hardhat Source: https://docs.mantrachain.io/developers/evm/using-hardhat Deploy and test smart contracts on MANTRA Chain using Hardhat Hardhat is a development environment for Ethereum software that helps developers manage and automate recurring tasks involved in building smart contracts and decentralized applications (dApps). **Hardhat Tutorial:** For new users, the [Hardhat tutorial](https://hardhat.org/getting-started/) provides step-by-step instructions and explains essential concepts for developing smart contracts. ## Prerequisites ### Node.js Install Node.js following the [official documentation](https://nodejs.org/en/download). MANTRA Chain requires Node.js ≥ **18.0**, but we recommend using the latest LTS version (currently v22). `nvm` is an excellent tool to easily manage multiple Node.js versions on your local machine. More details [here](https://github.com/nvm-sh/nvm)! ## Installation Create a new Hardhat project: ```bash theme={null} mkdir my-project cd my-project npm init -y npm install --save-dev hardhat npx hardhat init ``` Follow the prompts to set up your project. Choose: * **JavaScript** or **TypeScript** project * **Create a sample project** to get started quickly ## Configuring for MANTRA Chain Update `hardhat.config.js` (or `hardhat.config.ts`) to add MANTRA Chain networks: ```javascript theme={null} require("@nomicfoundation/hardhat-toolbox"); module.exports = { solidity: "0.8.23", networks: { mantra_mainnet: { url: "https://evm.mantrachain.io", chainId: 5888, accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [], }, mantra_testnet: { url: "https://evm.dukong.mantrachain.io", chainId: 5887, accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [], }, }, }; ``` ## Building Contracts Compile your contracts: ```bash theme={null} npx hardhat compile ``` ## Testing Run tests: ```bash theme={null} npx hardhat test ``` ## Deploying Create a deployment script in `scripts/deploy.js`: ```javascript theme={null} async function main() { const MyContract = await ethers.getContractFactory("MyContract"); const myContract = await MyContract.deploy(); await myContract.waitForDeployment(); console.log("Contract deployed to:", await myContract.getAddress()); } main() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); }); ``` Deploy to testnet: ```bash theme={null} npx hardhat run scripts/deploy.js --network mantra_testnet ``` ## Hardhat Ignition (recommended for structured deployments) Hardhat Ignition is useful when you want repeatable deployments as “modules”. 1. Add a network entry (example using Hardhat config vars): ```javascript theme={null} require("@nomicfoundation/hardhat-toolbox"); const { vars } = require("hardhat/config"); const TEST_PRIVATE_KEY = vars.get("TEST_PRIVATE_KEY"); module.exports = { solidity: "0.8.23", networks: { mantra_testnet: { url: "https://evm.dukong.mantrachain.io", chainId: 5887, accounts: [TEST_PRIVATE_KEY], }, }, }; ``` 2. Set the private key (interactive): ```bash theme={null} npx hardhat vars set TEST_PRIVATE_KEY ``` 3. Deploy an Ignition module: ```bash theme={null} npx hardhat ignition deploy ./ignition/modules/Token.js --network mantra_testnet ``` ## Example Project Check out our [example project](https://github.com/MANTRA-Chain/tutorial) and follow the README for a complete walkthrough. ## Next Steps * Learn about [deploying contracts](/developers/evm/deploying-contracts) * Understand [contract verification](/developers/evm/verifying-contracts) * Explore [EVM development](/developers/evm/getting-started) # Using Precompiles Source: https://docs.mantrachain.io/developers/evm/using-precompiles Practical guide to using precompiles in EVM contracts ## Overview Precompiles allow EVM contracts to interact directly with native chain modules. Precompiles are special contract addresses that execute native Go code instead of EVM bytecode. ## All Standard EVM Precompiles **MANTRA Chain supports all standard EVM precompiles** that are available on Ethereum and other EVM-compatible chains. These precompiles work identically to how they work on Ethereum, Base, Polygon, Arbitrum, and other EVM chains. ### Standard Ethereum Precompiles All of the following standard EVM precompiles are available and fully functional: 1. **ECRecover** (0x01) - Elliptic curve signature recovery 2. **SHA256** (0x02) - SHA-256 hash function 3. **RIPEMD160** (0x03) - RIPEMD-160 hash function 4. **Identity** (0x04) - Data copying function 5. **ModExp** (0x05) - Modular exponentiation 6. **BN256Add** (0x06) - Elliptic curve addition on the BN256 curve 7. **BN256Mul** (0x07) - Elliptic curve scalar multiplication on the BN256 curve 8. **BN256Pairing** (0x08) - Bilinear pairing on the BN256 curve 9. **Bls12-381** (0x09-0x0F) - BLS12-381 curve operations These precompiles behave exactly as they do on Ethereum and other EVM chains, ensuring full compatibility with existing EVM contracts and libraries. ## Additional Cosmos SDK Precompiles In addition to all standard EVM precompiles, MANTRA Chain exposes **additional precompiles that let developers interact with the CosmWasm (CW) side of the chain**. These precompiles enable seamless integration between EVM contracts and Cosmos SDK modules. The EVM communicates with the Cosmos part of the chain through these precompiles - Go code that directly interacts with other module states (e.g., Bank module). Precompiles are special contract addresses that execute native Go code instead of EVM bytecode, enabling seamless integration between EVM and Cosmos SDK modules. ### Cosmos SDK Precompiles There are **5 Cosmos SDK precompiles** exposed inside the EVM: #### 1. Staking Precompile Interact with the staking module directly from EVM contracts: * **Delegate tokens**: Delegate native tokens to validators * **Undelegate tokens**: Undelegate from validators * **Redelegate tokens**: Move delegation between validators * **Query delegation information**: Get delegation details **Use Cases:** * Automated staking strategies * Liquid staking protocols * Validator selection algorithms #### 2. Distribution Precompile Manage staking rewards from EVM contracts: * **Claim rewards**: Claim staking rewards * **Withdraw rewards**: Withdraw accumulated rewards * **Query reward information**: Get reward details **Use Cases:** * Automated reward claiming * Reward distribution protocols * Staking aggregators #### 3. Slashing Precompile Handle slashing operations and re-staking: * **Re-staking operations**: Manage validator re-staking * **Reward management**: Handle slashing-related rewards * **Validator penalties**: Query and handle penalties **Use Cases:** * Slashing protection protocols * Validator health monitoring * Risk management systems #### 4. Governance Precompile Participate in on-chain governance from EVM contracts: * **Vote on proposals**: Cast votes on governance proposals * **Create proposals**: Submit new governance proposals * **Query proposal information**: Get proposal details and status **Use Cases:** * Automated governance participation * Governance aggregators * Proposal creation tools #### 5. Bank Precompile Transfer native Cosmos tokens from EVM contracts: * **Transfer tokens**: Send native tokens * **Query balances**: Get token balances * **Multi-send operations**: Batch token transfers **Use Cases:** * Token bridges * Payment protocols * Multi-sig wallets ### ERC20 Precompiles Each **TokenFactory token** has its own ERC20 precompile address, allowing: * **Control token balance**: Manage token balances from EVM * **Transfer tokens**: Transfer TokenFactory tokens * **Use tokens in EVM contracts**: Seamless integration This enables TokenFactory tokens (created via Cosmos SDK) to be used directly in EVM contracts without wrapping. ## Precompile Addresses The following precompile addresses are fixed on MANTRA Chain and can be used directly in your Solidity contracts: ```solidity theme={null} // Cosmos SDK Precompile Addresses address constant STAKING_PRECOMPILE = 0x0000000000000000000000000000000000000800; address constant DISTRIBUTION_PRECOMPILE = 0x0000000000000000000000000000000000000801; address constant SLASHING_PRECOMPILE = 0x0000000000000000000000000000000000000802; address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000803; address constant BANK_PRECOMPILE = 0x0000000000000000000000000000000000000804; ``` TokenFactory ERC20 precompile addresses are deterministic based on the token denom. See the [TokenFactory Denoms](/resources/tokenfactory-denoms) page for available tokens. ## Using Precompiles ### Basic Pattern Precompiles are called like regular contract calls: ```solidity theme={null} // Call a precompile IPrecompileInterface(precompileAddress).functionName(params); ``` ### Example: Staking Precompile ```solidity theme={null} // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IStakingPrecompile { function delegate(address validator, uint256 amount) external returns (bool); function undelegate(address validator, uint256 amount) external returns (bool); function redelegate( address validatorSrc, address validatorDst, uint256 amount ) external returns (bool); } contract StakingContract { address constant STAKING_PRECOMPILE = 0x0000000000000000000000000000000000000800; function delegateToValidator(address validator, uint256 amount) external { IStakingPrecompile(STAKING_PRECOMPILE).delegate(validator, amount); } function undelegateFromValidator(address validator, uint256 amount) external { IStakingPrecompile(STAKING_PRECOMPILE).undelegate(validator, amount); } } ``` ### Example: Bank Precompile ```solidity theme={null} interface IBankPrecompile { function send( address to, string memory denom, uint256 amount ) external returns (bool); function balanceOf( address account, string memory denom ) external view returns (uint256); } contract PaymentContract { address constant BANK_PRECOMPILE = 0x0000000000000000000000000000000000000804; function sendNativeToken( address to, string memory denom, uint256 amount ) external { IBankPrecompile(BANK_PRECOMPILE).send(to, denom, amount); } function getBalance( address account, string memory denom ) external view returns (uint256) { return IBankPrecompile(BANK_PRECOMPILE).balanceOf(account, denom); } } ``` ### Example: Governance Precompile ```solidity theme={null} interface IGovernancePrecompile { function vote( uint256 proposalId, uint8 option ) external returns (bool); function createProposal( string memory title, string memory description, // ... other proposal parameters ) external returns (uint256); } contract GovernanceContract { address constant GOVERNANCE_PRECOMPILE = 0x0000000000000000000000000000000000000803; function voteOnProposal(uint256 proposalId, uint8 option) external { IGovernancePrecompile(GOVERNANCE_PRECOMPILE).vote(proposalId, option); } } ``` ## TokenFactory ERC20 Precompiles TokenFactory tokens automatically get ERC20 precompile addresses: ```solidity theme={null} interface ITokenFactoryERC20 { function transfer(address to, uint256 amount) external returns (bool); function balanceOf(address account) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); } contract TokenContract { // Precompile address for a specific TokenFactory token // Address is deterministic based on token denom address constant TOKEN_PRECOMPILE = 0x0000000000000000000000000000000000000805; function transferToken(address to, uint256 amount) external { ITokenFactoryERC20(TOKEN_PRECOMPILE).transfer(to, amount); } } ``` ## Best Practices ### Error Handling Always check return values from precompiles: ```solidity theme={null} function safeDelegate(address validator, uint256 amount) external { bool success = IStakingPrecompile(STAKING_PRECOMPILE).delegate(validator, amount); require(success, "Delegation failed"); } ``` ### Gas Considerations Precompiles execute native Go code, which is generally more gas-efficient than contract calls, but still consider: * Gas costs for precompile calls * Batch operations when possible * Optimize for frequently called functions ### Security * Validate inputs before calling precompiles * Use access controls for precompile calls * Test precompile interactions thoroughly ## Next Steps * Learn more about [Cosmos precompiles architecture](/developers/architecture/cosmos-precompiles) * Understand [transaction sequencing](/developers/architecture/transaction-sequencing) * Explore [EVM development guides](/developers/evm/getting-started) # Verifying Contracts Source: https://docs.mantrachain.io/developers/evm/verifying-contracts Verify your smart contracts on MANTRA Chain block explorers After deploying your contract, verify it on the block explorer to make the source code publicly available and enable users to interact with it. ## Block Explorers ### Testnet (DuKong) * **EVM Explorer**: [explorer.dukong.io](https://explorer.dukong.io) ### Mainnet * **EVM Explorer**: [blockscout.mantrascan.io](https://blockscout.mantrascan.io) ## Using Hardhat ### Hardhat Verify Plugin Install the verification plugin: ```bash theme={null} npm install --save-dev @nomicfoundation/hardhat-verify ``` Add to `hardhat.config.js`: ```javascript theme={null} require("@nomicfoundation/hardhat-verify"); module.exports = { // ... other config etherscan: { apiKey: { mantra_testnet: "your-api-key", // Not always required }, customChains: [ { network: "mantra_testnet", chainId: 5887, urls: { apiURL: "https://explorer.dukong.io/api", browserURL: "https://explorer.dukong.io" } } ] } }; ``` Verify your contract: ```bash theme={null} npx hardhat verify --network mantra_testnet ``` ## Using Foundry ### Forge Verify ```bash theme={null} forge verify-contract \ src/MyContract.sol:MyContract \ --chain-id 5887 \ --etherscan-api-key \ --constructor-args ``` ## Manual Verification 1. Go to the block explorer 2. Navigate to your contract address 3. Click "Verify and Publish" 4. Fill in the verification form: * Compiler version * Optimization settings * Source code * Constructor arguments (if any) ## Verification Requirements * Contract source code * Compiler version used * Optimization settings * Constructor arguments (if applicable) * Contract address ## Next Steps * Learn about [deploying contracts](/developers/evm/deploying-contracts) * Explore [EVM development](/developers/evm/getting-started) * Understand [using precompiles](/developers/evm/using-precompiles) # Testnet Faucet Source: https://docs.mantrachain.io/developers/getting-started/testnet-faucet Get testnet tokens for development on MANTRA Chain Get testnet tokens for development and testing on MANTRA Chain's Dukong testnet. Request testnet OM tokens for gas fees from the official MANTRA Dukong Faucet Mint testnet versions of common ERC-20 tokens (tUSDC, tUSDT, tmantraUSD, twMANTRA) ## Step-by-Step Instructions 1. **Navigate to the Faucet**: Open your web browser and go to the official MANTRA Dukong Faucet page: [https://faucet.dukong.mantrachain.io/](https://faucet.dukong.mantrachain.io/) 2. **Select Network**: Ensure that "mantra-dukong-1" is selected as the network. 3. **Enter Wallet Address**: Provide your MANTRA wallet address or the EVM wallet address in the designated field. 4. **Request Tokens**: Click on the "Request Token" button. The testnet tokens will then be sent to your wallet. # Build on MANTRA Chain Source: https://docs.mantrachain.io/developers/overview Welcome to MANTRA Chain development. Build EVM-compatible smart contracts and dApps. Welcome to MANTRA Chain! An EVM-compatible Layer 1 blockchain designed for Real-World Asset (RWA) tokenization. Build with familiar tools and unlock the power of native Cosmos modules. ## Quick Start Complete guide to building and deploying EVM smart contracts Understand MANTRA Chain's architecture and how EVM integrates with native modules Full EVM compatibility with all opcodes and precompiles Access native chain modules directly from EVM contracts Create ERC-20 tokens on MANTRA Chain Step-by-step guide to building your first dApp Index MANTRA data with Goldsky's instant GraphQL APIs ## What You Can Build MANTRA Chain supports standard EVM development with your favorite tools: * **Smart Contracts**: Deploy Solidity contracts using Hardhat, Foundry, or Remix * **dApps**: Build decentralized applications with standard Web3 libraries (Web3.js, Ethers.js) * **DeFi Protocols**: Create DeFi applications leveraging native module precompiles * **RWA Applications**: Tokenize and manage real-world assets on-chain ## Next Steps * Get started with [EVM Development](/developers/evm/getting-started) * Read the [Architecture Overview](/developers/architecture/overview) * Learn about [EVM Compatibility](/developers/architecture/evm-compatibility) and [Cosmos Precompiles](/developers/architecture/cosmos-precompiles) # SDKs & Libraries Source: https://docs.mantrachain.io/developers/reference/sdks-libraries Software development kits and libraries for building on MANTRA Chain ## Overview MANTRA Chain supports both EVM and Cosmos SDK development. This page covers the available SDKs and libraries for each ecosystem. ## EVM Libraries These libraries work with MANTRA Chain's EVM module for Solidity smart contract development. ### Ethers.js (Recommended) Ethers.js is a complete and compact library for interacting with the Ethereum blockchain. It's the most popular choice for modern dApp development. **Installation:** ```bash theme={null} npm install ethers ``` **Basic Usage:** ```javascript theme={null} import { ethers } from 'ethers'; // Connect to MANTRA Chain const provider = new ethers.JsonRpcProvider('https://evm.mantrachain.io'); // Create wallet instance const wallet = new ethers.Wallet(privateKey, provider); // Get balance const balance = await provider.getBalance(wallet.address); console.log('Balance:', ethers.formatEther(balance), 'OM'); // Send transaction const tx = await wallet.sendTransaction({ to: recipientAddress, value: ethers.parseEther('1.0') }); await tx.wait(); ``` **Resources:** * [Ethers.js v6 Documentation](https://docs.ethers.org/v6/) * [GitHub Repository](https://github.com/ethers-io/ethers.js) ### Viem Viem is a modern, lightweight alternative to ethers.js with better TypeScript support and modular architecture. **Installation:** ```bash theme={null} npm install viem ``` **Basic Usage:** ```typescript theme={null} import { createPublicClient, createWalletClient, http } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; // Define MANTRA Chain const mantraChain = { id: 5888, name: 'MANTRA Chain', nativeCurrency: { name: 'OM', symbol: 'OM', decimals: 18 }, rpcUrls: { default: { http: ['https://evm.mantrachain.io'] }, }, blockExplorers: { default: { name: 'Blockscout', url: 'https://blockscout.mantrascan.io' }, }, }; // Create clients const publicClient = createPublicClient({ chain: mantraChain, transport: http(), }); const account = privateKeyToAccount(privateKey); const walletClient = createWalletClient({ account, chain: mantraChain, transport: http(), }); // Get balance const balance = await publicClient.getBalance({ address: account.address }); ``` **Resources:** * [Viem Documentation](https://viem.sh/) * [GitHub Repository](https://github.com/wevm/viem) ### Web3.js Web3.js is a collection of libraries for interacting with Ethereum nodes. It's widely used but heavier than alternatives. **Installation:** ```bash theme={null} npm install web3 ``` **Basic Usage:** ```javascript theme={null} import Web3 from 'web3'; const web3 = new Web3('https://evm.mantrachain.io'); // Get balance const balance = await web3.eth.getBalance(address); console.log('Balance:', web3.utils.fromWei(balance, 'ether'), 'OM'); // Send transaction const tx = await web3.eth.sendTransaction({ from: senderAddress, to: recipientAddress, value: web3.utils.toWei('1', 'ether'), }); ``` **Resources:** * [Web3.js Documentation](https://docs.web3js.org/) * [GitHub Repository](https://github.com/web3/web3.js) *** ## Cosmos SDK Libraries These libraries interact with MANTRA Chain's native Cosmos SDK modules. ### CosmJS CosmJS is the official JavaScript library for Cosmos SDK chains. Use it for native token transfers, staking, governance, and IBC operations. **Installation:** ```bash theme={null} npm install @cosmjs/stargate @cosmjs/proto-signing ``` **Basic Usage:** ```javascript theme={null} import { SigningStargateClient, StargateClient } from '@cosmjs/stargate'; import { DirectSecp256k1HdWallet } from '@cosmjs/proto-signing'; // Connect (read-only) const client = await StargateClient.connect('https://rpc.mantrachain.io'); // Get balance const balance = await client.getBalance('mantra1...', 'uom'); console.log('Balance:', balance); // Create signing client const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { prefix: 'mantra', }); const signingClient = await SigningStargateClient.connectWithSigner( 'https://rpc.mantrachain.io', wallet ); // Send tokens const result = await signingClient.sendTokens( senderAddress, recipientAddress, [{ denom: 'uom', amount: '1000000' }], 'auto' ); ``` **Resources:** * [CosmJS Documentation](https://cosmos.github.io/cosmjs/) * [GitHub Repository](https://github.com/cosmos/cosmjs) ### Keplr Wallet Integration Integrate with Keplr wallet for user authentication and transaction signing. **Installation:** ```bash theme={null} npm install @keplr-wallet/types ``` **Basic Usage:** ```javascript theme={null} // Suggest MANTRA Chain to Keplr await window.keplr.experimentalSuggestChain({ chainId: 'mantra-1', chainName: 'MANTRA Chain', rpc: 'https://rpc.mantrachain.io', rest: 'https://api.mantrachain.io', bip44: { coinType: 118 }, bech32Config: { bech32PrefixAccAddr: 'mantra', bech32PrefixAccPub: 'mantrapub', bech32PrefixValAddr: 'mantravaloper', bech32PrefixValPub: 'mantravaloperpub', bech32PrefixConsAddr: 'mantravalcons', bech32PrefixConsPub: 'mantravalconspub', }, currencies: [{ coinDenom: 'OM', coinMinimalDenom: 'uom', coinDecimals: 6 }], feeCurrencies: [{ coinDenom: 'OM', coinMinimalDenom: 'uom', coinDecimals: 6 }], stakeCurrency: { coinDenom: 'OM', coinMinimalDenom: 'uom', coinDecimals: 6 }, }); // Enable chain await window.keplr.enable('mantra-1'); // Get signer const offlineSigner = window.keplr.getOfflineSigner('mantra-1'); ``` **Resources:** * [Keplr Documentation](https://docs.keplr.app/) * [GitHub Repository](https://github.com/chainapsis/keplr-wallet) *** ## Go Libraries ### Cosmos SDK For building custom modules or interacting with MANTRA Chain programmatically in Go. ```go theme={null} import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/types" ) ``` **Resources:** * [Cosmos SDK Documentation](https://docs.cosmos.network/) * [MANTRA Chain GitHub](https://github.com/MANTRA-Chain/mantrachain) *** ## Python Libraries ### Web3.py Python library for EVM interactions. **Installation:** ```bash theme={null} pip install web3 ``` **Basic Usage:** ```python theme={null} from web3 import Web3 w3 = Web3(Web3.HTTPProvider('https://evm.mantrachain.io')) # Check connection print(w3.is_connected()) # Get balance balance = w3.eth.get_balance('0x...') print(f'Balance: {w3.from_wei(balance, "ether")} OM') ``` **Resources:** * [Web3.py Documentation](https://web3py.readthedocs.io/) ### CosmPy Python library for Cosmos SDK chains. **Installation:** ```bash theme={null} pip install cosmpy ``` **Resources:** * [CosmPy Documentation](https://docs.fetch.ai/cosmpy/) * [GitHub Repository](https://github.com/fetchai/cosmpy) *** ## Network Configuration Quick Reference | Network | EVM RPC | Cosmos RPC | Chain ID (EVM) | Chain ID (Cosmos) | | ------- | ----------------------------------- | ----------------------------------- | -------------- | ----------------- | | Mainnet | `https://evm.mantrachain.io` | `https://rpc.mantrachain.io` | `5888` | `mantra-1` | | Testnet | `https://evm.dukong.mantrachain.io` | `https://rpc.dukong.mantrachain.io` | `5887` | `mantra-dukong-1` | ## Next Steps * [Deploy a Smart Contract](/deploy-smart-contract) - Get started with EVM development * [Network Details](/resources/network-details) - Full endpoint reference * [EVM Getting Started](/developers/evm/getting-started) - Complete EVM development guide # Deploying Frontend Source: https://docs.mantrachain.io/developers/tutorials/zero-to-hero-dapp/deploying-frontend Hosting options for your dApp frontend As we have described the sample dApp in this guide, we have only run the frontend project on a local development server. That is more than sufficient to get an full understanding of what it means to develop a dApp including the Solidity contracts and a frontend. However, in a production scenario you will want to deploy your dApp frontend to a production hosting environment. There are several options available to you including [Vercel](https://vercel.com/home). Which hosting environment you use will determine how environment variables are managed. This may in turn require some changes to your dApp's code to consume those environment variables. You should refer to the documentation of your selected hosting service. Above all else, when developing dApps you should have security at the front of mind. That is, both yours and your users. Proper key management, and use of sensitive in environment variables should be carefully considered. There is no substitute for good security practice in Web3. # Deployment Source: https://docs.mantrachain.io/developers/tutorials/zero-to-hero-dapp/deployment Deploying your smart contracts to the Dukong Testnet Now that we've built and tested our Solidity contracts, it's time to deploy them to to the Dukong testnet. Again, Foundry makes this a straightforward process with its scripting capabilities. Foundry's deployment script provides a declarative deployment process which we can use to deploy all of our contracts at once. To deploy your compiled contracts you'll need an Dukong testnet account that has been funded with OM. If you've skipped that step go back and do it now. Foundry script files have the following naming convention `ScriptFileName.s.sol`. Here's our Foundry deployment script: ### DeployWhitelistAndFactory.s.sol ```solidity theme={null} // SPDX-License-Identifier: MIT pragma solidity ^0.8.30; import "forge-std/Script.sol"; import {Whitelist} from "../src/Whitelist.sol"; import {RealEstateFactory} from "../src/RealEstateFactory.sol"; contract DeployWhitelistAndFactory is Script { function run() external { uint256 deployerPk = vm.envUint("PRIVATE_KEY"); vm.startBroadcast(deployerPk); // 1) Deploy Whitelist (owner = deployer) Whitelist wl = new Whitelist(); // 2) Deploy Factory wired to the Whitelist RealEstateFactory factory = new RealEstateFactory(address(wl)); vm.stopBroadcast(); console2.log("Whitelist:", address(wl)); console2.log("Factory :", address(factory)); } } ``` As you can see, it is quite simple. It basically does three things: 1. Deploys the `Whitelist` contract with `Whitelist wl = new Whitelist();` 2. Deploys the `RealEstateFactory` contract with `RealEstateFactory factory = new RealEstateFactory(address(wl));` 3. Outputs the deployed contract addresses to the console. You'll notice that the `wl` variable is assigned the address of the deployed `Whitelist` contract, which can then be passed to the constructor of the `RealEstateToken` contract. This establishes the link between these two contracts for whitelist management. You can run the deployment script with: ```bash theme={null} forge script --chain 5887 script/DeployWhitelistAndFactory.s.sol:DeployWhitelistAndFactory --rpc-url $DUKONG_RPC_URL --broadcast -vvv --interactives 1 ``` The `--chain 5887` parameter we set up earlier in the Foundry's `foundry.toml` configuration file. You'll also notice the `$DUKONG_RPC_URL` environment variable used to pass the url of the Dukong RPC endpoint. The `--broadcast` flag is responsible for publishing your transaction to the network. And the final piece of magic, the `--interactives 1` will cause the script to prompt you for the private key of the account being used for the deployment. Script execution will pause and you'll be asked to enter the private key. **Warning** Foundry provides more sophisticated methods to manage private keys for deployments. We use a simple method here for demonstration. However, we strongly suggest reading the Foundry documentation on production grade private key management capabilities. You should see something like this when you execute the deployment script: Now head over to the [MANTRASCAN Dukong Testnet explorer](https://mantrascan.io/dukong) and verify that your contracts have been deployed. # Frontend dApp Source: https://docs.mantrachain.io/developers/tutorials/zero-to-hero-dapp/frontend-dapp Building the frontend with RainbowKit and interacting with your contracts ## Setting Up Rainbowkit For the sample project we've used Rainbowkit to simplify wallet connections. Rainbowkit gives our frontend project out-of-the-box wallet management for our dapp. It also handles the connection and disconnection of wallets, and supports numerous wallets, swaps connection chains, displays balances and more! If you're a serious builder, we suggest you [read more about creating dApps with Rainbowkit](https://rainbowkit.com/). Unfortunately, the MANTRA Dukong Testnet is not yet supported by Rainbowkit. But, don't lose heart; we can easily provide the configuration that it needs to work with the Dukong testnet. The sample project is already configured and ready to go. ## Chains All we need to do to get Rainbowkit to work with our dApp, is provide the chain configuration. For our sample dApp, you'll find that configuration in the `/frontend/src/chains/mantra.ts` file. We configure Dukong like this: ```typescript theme={null} import { Chain } from 'wagmi' export const dukong: Chain = { id: 5887, name: 'MANTRACHAIN Testnet', network: 'dukong', nativeCurrency: { name: 'OM', symbol: 'OM', decimals: 18, }, rpcUrls: { default: { http: ['https://evm.dukong.mantrachain.io'] }, public: { http: ['https://evm.dukong.mantrachain.io'] }, webSocket: ['wss://evm.dukong.mantrachain.io/ws'] }, blockExplorers: { default: { name: 'MantraScan Dukong', url: 'https://mantrascan.io/dukong' } }, testnet: true, } ``` Next, all we need to do is import the `dukong` chain into the `wagmi.ts` configuration file, and add it to the chains array: ```typescript theme={null} import { getDefaultConfig } from '@rainbow-me/rainbowkit'; import { arbitrum, base, mainnet, optimism, polygon, sepolia, } from 'wagmi/chains'; import { dukong } from './chains/mantra'; export const config = getDefaultConfig({ appName: 'RainbowKit App', projectId: 'YOUR_PROJECT_ID', chains: [ mainnet, polygon, optimism, arbitrum, base, dukong, ...(process.env.NEXT_PUBLIC_ENABLE_TESTNETS === 'true' ? [sepolia] : []), ], ssr: true, }); ``` ## Contract Addresses Our frontend project should now be ready to interact with our deployed contracts. There's just one more step to complete the configuration, adding our contract addresses. We can do that with local environment variables. First, create a file in the frontend root directory named `.env.local`. There are two entries that we need: ```bash theme={null} NEXT_PUBLIC_WHITELIST_ADDRESS=0x0 NEXT_PUBLIC_FACTORY_ADDRESS=0x0 ``` Where `0x0` is the address of your deployed `Whitelist` and `RealEstateFactory` contracts. With environment variables named in this way, they will be made available to our dApp when running locally. There are various methods of providing these values in production environments. It is beyond the scope of this guide to delve into that as it may vary between hosting services. To get access to these environment variables in our dApp, we get their values and export some constants that we can use when we need to interact with our contracts. We've added a file named `addresses.ts` with the following content to our project's `lib` directory: ```typescript theme={null} export const WHITELIST_ADDRESS = process.env.NEXT_PUBLIC_WHITELIST_ADDRESS as `0x${string}`; export const FACTORY_ADDRESS = process.env.NEXT_PUBLIC_FACTORY_ADDRESS as `0x${string}`; ``` ## Interacting With Contracts Now, let's take a look at how we interact with our deployed contracts. It is beyond the scope of this guide to go into this in detail. For a detailed explanation with examples, we recommend reading the [Rainbowkit](https://rainbowkit.com/docs/introduction) and [wagmi](https://wagmi.sh/) documentation. Our dApp uses functions provided by `wagmi` to interact with the Dukong testnet, our connected wallet, and our contracts. The sample app provides several hooks, found in the `/frontend/hooks` directory. These hooks are used to both read and write transactions on our deployed contracts. For example, here is the hook for the `Whitelist`: ```typescript theme={null} import { useMemo } from 'react'; import { useAccount, useReadContract, useWriteContract, useWaitForTransactionReceipt } from 'wagmi'; import { whitelistAbi } from '../lib/abis/whitelist'; import { WHITELIST_ADDRESS } from '../lib/addresses'; export function useWhitelist() { const { address: connected } = useAccount(); const { data: owner } = useReadContract({ address: WHITELIST_ADDRESS, abi: whitelistAbi, functionName: 'owner', }); const isOwner = useMemo( () => !!connected && !!owner && connected.toLowerCase() === (owner as string).toLowerCase(), [connected, owner] ); const { writeContract, data: hash, isPending } = useWriteContract(); const receipt = useWaitForTransactionReceipt({ hash }); const approve = (project: `0x${string}`, investor: `0x${string}`) => writeContract({ address: WHITELIST_ADDRESS, abi: whitelistAbi, functionName: 'approve', args: [project, investor] }); const revoke = (project: `0x${string}`, investor: `0x${string}`) => writeContract({ address: WHITELIST_ADDRESS, abi: whitelistAbi, functionName: 'revoke', args: [project, investor] }); return { owner, isOwner, hash, isPending, receipt, approve, revoke }; } ``` You will notice the `useAccount`, `useReadContract`, `useWriteContract`, and `useWaitForTransactionReceipt` functions that allow us to get the connected account, send read and write transactions, and wait for our transaction receipts. We can then use this hook (and the others) in our dApps components to provide a meaningful user interface for our users to interact with out contracts. As an example, below is the `ContractInfo` component that we use in our dApp to display information about the `Whitelist` contract: ```typescript theme={null} import { useAccount } from 'wagmi'; import { WHITELIST_ADDRESS } from '../../lib/addresses'; import { useWhitelist } from '../../hooks/useWhitelist'; export default function ContractInfo() { const { address } = useAccount(); const { owner, isOwner } = useWhitelist(); return (

Whitelist: {WHITELIST_ADDRESS}

Owner: {owner ?? '—'}

You: {address ?? 'Not connected'}

{isOwner ? 'You are the owner' : 'You are not the owner'}

); } ``` You can see that we have imported the `useWhitelist` hook which we use to get the `owner` address, and a check `isOwner` to indicate if the connected account is the owner of the `Whitelist` contract. We will leave you to read through the other hooks and components to see how we read from our contracts and send transactions. But, as quick example, here is the `useDeployProject` hook which is used to send a transaction executing the `deployProject()` function of our `RealEstateFactory` contract: ```typescript theme={null} import { useCallback } from 'react'; import { useWriteContract, useWaitForTransactionReceipt, } from 'wagmi'; import { decodeEventLog } from 'viem'; import { FACTORY_ADDRESS } from '../lib/addresses'; import { factoryAbi } from '../lib/abis/factory'; export function useDeployProject() { const { writeContract, data: hash, isPending, error: writeError } = useWriteContract(); const { data: receipt, isLoading: confirming, isSuccess } = useWaitForTransactionReceipt({ hash }); const deploy = useCallback((args: { name: string; symbol: string; propertyId: string; jurisdiction: string; metadataUri: string; }) => { writeContract({ address: FACTORY_ADDRESS, abi: factoryAbi, functionName: 'deployProject', args: [ args.name, args.symbol, args.propertyId, args.jurisdiction, args.metadataUri, ], }); }, [writeContract]); // extract new project address if available let newProject: `0x${string}` | undefined; if (isSuccess && receipt?.logs?.length) { for (const log of receipt.logs) { try { const parsed = decodeEventLog({ abi: factoryAbi, data: log.data, topics: log.topics, }); if (parsed.eventName === 'ProjectCreated') { newProject = parsed.args.projectAddress as `0x${string}`; break; } } catch {} } } return { deploy, txHash: hash, newProject, isPending, confirming, isSuccess, writeError, }; } ``` This hook is used in the `NewProjectForm` component to provide the user interface for deploying `RealEstateToken` contracts. ## The Completed dApp With the configuration in place, and our dApp's components, and hooks etc in place, we can run the dApp locally with the development server. In a terminal you can start the development server with: ```bash theme={null} npm run dev ``` The dApp might take some time to compile but, when it is finished the dApp should be available to use on `https://localhost:3000`. You should see something like this: ### Whitelist administration The dApp provides a whitelist administration interface where you can approve and revoke investor addresses. ### Create RealEstateToken projects You can create new RealEstateToken projects through the dApp interface. ### Manage RealEstateToken projects The dApp allows you to manage your RealEstateToken projects, view project details, and mint tokens for approved investors. Of course, yours won't be immediately populated with data. You will have no whitelisted investor addresses, and no projects. The account that you used to deploy the contracts with Foundry will be the owner of the `Whitelist` and `RealEstateFactory` contracts. If you have that account selected in your MetaMask wallet (its address should be shown on the connection button badge in the top right), then you will be able to approve and revoke account addresses as investors. Any of your accounts should be able to create a new RealEstateToken project. Just provide the required details and hit `Create Project`. From there, you can head over to the `Manage Projects` page and mint tokens for your approved investors. The `Manage Projects` page will display details of the project and the investors and their holdings. # Introduction Source: https://docs.mantrachain.io/developers/tutorials/zero-to-hero-dapp/introduction Welcome to the MANTRA Zero to Hero dApp Development Guide Welcome to the MANTRA Zero to Hero dApp Development Guide This guide will walk you through building and deploying a complete decentralized application (dApp) on **MANTRA's EVM-compatible Dukong Testnet** from smart contract creation to frontend deployment. **Disclaimer** The source code of the example dApp used in this guide is for demonstration purposes only. It may contain security flaws and bugs. It is incomplete for production ready code. But, for the purposes of this guide, demonstrating how to build on MANTRA Chain, it is more than adequate. ## Who Is This Guide For This guide is for anyone that is planning on building on MANTRA Chain with EVM, or anyone that is simply curious. Given that MANTRA Chain is fully EVM compatible, developers that are experienced building on other EVM chains should find building on MANTRA Chain straightforward. Throughout this guide, we will presume some prior knowledge and experience. We will be using MetaMask for interacting with our dApp, and so, we presume that you have some experience with using and configuring MetaMask. If you don't have MetaMask installed, you can install if you wish to follow along with this guide. Instructions to install MetaMask wallet for your browser can be found here: [https://metamask.io/download](https://metamask.io/download) In developing the Solidity contracts we have used Foundry. You could also use Hardhat if you wish. Foundry is a newer means to manage smart contract deployments for EVM. It's blazing-fast speed and solidity-centric approach makes it a great alternative to the bulkier, Javascript-based Hardhat. You can find the Foundry docs to get you started here: [https://getfoundry.sh/introduction/getting-started](https://getfoundry.sh/introduction/getting-started) ## What We'll Be Building For the purpose of this guide we've put together a simple demo project of Solidity smart contracts and a frontend. The demo dApp is a basic example of RWA tokenization we've named RealEstateToken. You can find the project's GitHub repository here: [https://github.com/dkillen/real-estate-token](https://github.com/dkillen/real-estate-token) ## Getting Started Before we begin building our dApp, let's get a wallet set up to use the Dukong Testnet. This will help us to deploy our contracts to the MANTRA Dukong testnet and interact with our dApp once we've deployed it. Follow the instructions to set up your MetaMask wallet here: [Wallet Setup Instructions - Dukong testnet](/developers/evm/getting-started) ### Getting Testnet OM If you're following along with this guide, we recommend creating 3 or 4 accounts that you can use to deploy the contracts and then interact with the dApp. Once you've created your accounts you need to fund them. You'll find the Dukong OM faucet here: [https://faucet.dukong.mantrachain.io/](https://faucet.dukong.mantrachain.io/) The faucet will give you 10 OM per day to play with. That will be more than enough to follow along here. ## Next Steps Next, we'll get our Foundry project set up to build and deploy the Solidity contracts. # Project Setup Source: https://docs.mantrachain.io/developers/tutorials/zero-to-hero-dapp/project-setup Setting up your development environment for building dApps on MANTRA Chain ## Foundry - Smart Contracts Foundry's installation and setup is simple and straightforward. We will need to configure our Foundry project for the MANTRA Chain Dukong testnet but, we'll get to that later. ## Next.js + Rainbowkit - Frontend For this guide we've chosen to use [Rainbowkit](https://rainbowkit.com/docs/introduction) in building the frontend. Rainbowkit gives us out-of-the-box wallet management for our dapp. Aside from handling the connection and disconnection of wallets, RainbowKit supports numerous wallets, swaps connection chains, resolves address to ENS, displays balance and much more! Rainbowkit is a React library and, as such, needs Node.js to be installed. In building the dApp for this guide the current stable version (v24.11) was used. To make it easy to install and switch between Node versions, the [Node Version Manager](https://github.com/nvm-sh/nvm) (NVM) is a very helpful tool. ## Foundry Configuration In the `contracts` directory of the [RealEstateToken](https://github.com/dkillen/real-estate-token) sample project you'll find the Foundry project. There is not much configuration required to get ready for building and deploying the Solidity contracts. This configuration is already present in the sample project. First, create a `.env` file in the `contracts` directory with the following content: ```bash theme={null} DUKONG_RPC_URL=https://evm.dukong.mantrachain.io ``` and then in a terminal `source` the `.env` file to make the `DUKONG_RPC_URL` environment variable available. This step is merely a convenience used in command to deploy the contracts. It's not strictly necessary. Next, open the `foundry.toml` file in your favourite editor. We need to add just a single line here that allows us to deploy our contracts with a Foundry script. You only need to add the following: ```bash theme={null} [profile.5887] ``` just after the default Foundry configuration. Your `foundry.toml` file should look like this: ```bash theme={null} [profile.default] src = "src" out = "out" libs = ["lib"] [profile.5887] # See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options ``` This small addition will allow us to refer to the Dukong testnet by its chain ID when deploying the compiled contracts. # Smart Contracts Source: https://docs.mantrachain.io/developers/tutorials/zero-to-hero-dapp/smart-contracts Building and testing your Solidity smart contracts ## Compiling and Testing Contracts The three Solidity contracts that form the RealEstateToken project are set out in full here: 1. [Whitelist](#whitelist-contract) - manages the Whitelist of approved investors. 2. [RealEstateFactory](#realestatefactory-contract) - deploys RealEstateToken contracts. 3. [RealEstateToken](#realestatetoken-contract) - Tokenization of a real estate development project. Compiling and testing these contracts is simple. Foundry with it's Solidity centric test scripts, and builtin helpers and assertions, make it straightforward to write unit tests for our contracts. The example project has a basic suite of tests for each contract. ## Building To build the Solidity contracts are built simply with: ```bash theme={null} forge build ``` ## Testing Foundry unit tests are found in the `test` directory. There are a number of ways in which you can structure your tests. For simplicity, we've written one test script per contract. Test scripts are written in Solidity and the filename must have the form `FileName.t.sol`. You can read more about testing with Foundry here: [https://getfoundry.sh/forge/tests/overview](https://getfoundry.sh/forge/tests/overview) You can run your unit tests in Foundry with a simple: ```bash theme={null} forge test ``` This will run all test scripts int the `test` directory. The sample project includes the following tests scripts: ### Whitelist.t.sol ```solidity theme={null} // SPDX-License-Identifier: MIT pragma solidity ^0.8.30; import "forge-std/Test.sol"; import {Whitelist} from "../src/Whitelist.sol"; contract WhitelistTest is Test { Whitelist wl; address INVESTOR_A = vm.addr(1); address INVESTOR_B = vm.addr(2); address PROJECT_A = address(0xA1); address PROJECT_B = address(0xB2); event Approved(address indexed project, address indexed investor); event Revoked(address indexed project, address indexed investor); function setUp() public { wl = new Whitelist(); } function test_defaultFalse() public view { assertFalse(wl.isApproved(PROJECT_A, INVESTOR_A)); assertFalse(wl.isApproved(PROJECT_A, INVESTOR_B)); } function test_approve() public { vm.expectEmit(true, true, false, false); emit Approved(PROJECT_A, INVESTOR_A); wl.approve(PROJECT_A, INVESTOR_A); assertTrue(wl.isApproved(PROJECT_A, INVESTOR_A)); } function test_revoke() public { wl.approve(PROJECT_A, INVESTOR_A); vm.expectEmit(true, true, false, false); emit Revoked(PROJECT_A, INVESTOR_A); wl.revoke(PROJECT_A, INVESTOR_A); assertFalse(wl.isApproved(PROJECT_A, INVESTOR_A)); } } ``` ### RealEstateFactory.t.sol ```solidity theme={null} // SPDX-License-Identifier: MIT pragma solidity ^0.8.30; import "forge-std/Test.sol"; import {RealEstateFactory} from "../src/RealEstateFactory.sol"; import {RealEstateToken} from "../src/RealEstateToken.sol"; interface IWhiteList { function isApproved(address, address) external view returns (bool); } contract MockWhitelistAlwaysTrue is IWhiteList { function isApproved(address, address) external pure returns (bool) { return true; } } contract RealEstateFactoryTest is Test { RealEstateFactory factory; MockWhitelistAlwaysTrue wl; address INVESTOR_A = vm.addr(1); // used as issuer in one test address INVESTOR_B = vm.addr(2); string NAME = "Project A"; string SYMBOL = "PJA"; string PROPERTY_ID = "PJA-001"; string JURIS = "AU"; string META_URI = "ipfs://cid-a"; function setUp() public { wl = new MockWhitelistAlwaysTrue(); factory = new RealEstateFactory(address(wl)); } function test_constructor() public view { assertEq(factory.whitelist(), address(wl)); assertEq(factory.owner(), address(this)); } function test_deployProject() public { address tokenAddr = factory.deployProject( NAME, SYMBOL, PROPERTY_ID, JURIS, META_URI ); assertTrue(tokenAddr != address(0)); address[] memory all = factory.getAllProjects(); assertEq(all.length, 1); assertEq(all[0], tokenAddr); RealEstateToken t = RealEstateToken(tokenAddr); assertEq(t.name(), NAME); assertEq(t.symbol(), SYMBOL); assertEq(t.propertyId(), PROPERTY_ID); assertEq(t.jurisdiction(), JURIS); assertEq(t.metadataUri(), META_URI); assertEq(address(t.whitelist()), address(wl)); assertEq(t.owner(), address(this)); } function test_multipleDeployers() public { vm.prank(INVESTOR_A); address a = factory.deployProject("A", "A", "A", "AU", "ipfs://a"); vm.prank(INVESTOR_B); address b = factory.deployProject("B", "B", "B", "AU", "ipfs://b"); address[] memory all = factory.getAllProjects(); assertEq(all.length, 2); assertEq(RealEstateToken(a).owner(), INVESTOR_A); assertEq(RealEstateToken(b).owner(), INVESTOR_B); } } ``` ### RealEstateToken.t.sol ```solidity theme={null} // SPDX-License-Identifier: MIT pragma solidity ^0.8.30; import "forge-std/Test.sol"; import {RealEstateToken} from "../src/RealEstateToken.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; interface IWhiteList { function isApproved( address project, address investor ) external view returns (bool); } contract MockWhitelist is IWhiteList { mapping(address => mapping(address => bool)) public approved; function set(address project, address investor, bool ok) external { approved[project][investor] = ok; } function isApproved( address project, address investor ) external view returns (bool) { return approved[project][investor]; } } contract RealEstateTokenTest is Test { MockWhitelist wl; RealEstateToken token; address INVESTOR_A = vm.addr(1); address INVESTOR_B = vm.addr(2); string NAME = "Project A"; string SYMBOL = "PJA"; string PROPERTY_ID = "PJA-001"; string JURIS = "AU"; string META_URI = "ipfs://cid-a"; function setUp() public { wl = new MockWhitelist(); token = new RealEstateToken( NAME, SYMBOL, address(wl), PROPERTY_ID, JURIS, META_URI, address(this) // project owner ); } function test_metadata() public view { assertEq(token.name(), NAME); assertEq(token.symbol(), SYMBOL); assertEq(token.propertyId(), PROPERTY_ID); assertEq(token.jurisdiction(), JURIS); assertEq(token.metadataUri(), META_URI); assertEq(token.decimals(), 0); assertEq(token.MAX_SUPPLY(), 100); assertEq(address(token.whitelist()), address(wl)); assertEq(token.owner(), address(this)); } function test_mintWhenApproved() public { wl.set(address(token), INVESTOR_A, true); token.mint(INVESTOR_A, 10); assertEq(token.totalSupply(), 10); assertEq(token.balanceOf(INVESTOR_A), 10); assertTrue(token.isShareholder(INVESTOR_A)); } function test_mintWhenNotApprovedReverts() public { vm.expectRevert(bytes("Investor not approved for this project.")); token.mint(INVESTOR_A, 1); } function test_transferRequiresWhitelist() public { wl.set(address(token), INVESTOR_A, true); wl.set(address(token), INVESTOR_B, true); token.mint(INVESTOR_A, 5); vm.prank(INVESTOR_A); token.transfer(INVESTOR_B, 3); assertEq(token.balanceOf(INVESTOR_A), 2); assertEq(token.balanceOf(INVESTOR_B), 3); assertTrue(token.isShareholder(INVESTOR_B)); } function test_transferToUnapprovedReverts() public { wl.set(address(token), INVESTOR_A, true); token.mint(INVESTOR_A, 1); // INVESTOR_B not approved vm.prank(INVESTOR_A); vm.expectRevert(bytes("Recipient is not approved for this project")); token.transfer(INVESTOR_B, 1); } function test_adminBurnOnlyOwner() public { wl.set(address(token), INVESTOR_A, true); token.mint(INVESTOR_A, 4); // non-owner cannot call adminBurn vm.prank(INVESTOR_A); vm.expectRevert( abi.encodeWithSelector( Ownable.OwnableUnauthorizedAccount.selector, INVESTOR_A ) ); token.adminBurn(INVESTOR_A, 1); // owner can burn token.adminBurn(INVESTOR_A, 2); assertEq(token.totalSupply(), 2); assertEq(token.balanceOf(INVESTOR_A), 2); } } ``` ## Whitelist Contract The `Whitelist` contract is responsible for managing the account addressed of approved investors. This is intended to represent a basic KYC/AML process. Only the dApp owner can `approve`, and `revoke` an investor's account address. The 'Whitelist`contract is the first to be deployed as its contract address is needed by the`RealEstateFactory\` constructor. ### Whitelist ```solidity theme={null} // SPDX-License-Identifier: MIT pragma solidity ^0.8.30; import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol"; // import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; // A simple whitelist for real estate tokenisation projects // Provides a whitelist of investor accounts for real estate projects (identified by contract address) // WARNING: This contract is an example only - do not use in production contract Whitelist is Ownable2Step { // Mapping of project => investor => approved? mapping(address => mapping(address => bool)) private _approved; // Emitted when an investor is approved for a project event Approved(address indexed project, address indexed investor); // Emitted when an investor approval is revoked event Revoked(address indexed project, address indexed investor); constructor() Ownable(msg.sender) {} // Add an investor's account address to the whitelist for a specified project function approve(address project, address investor) external onlyOwner { _approved[project][investor] = true; emit Approved(project, investor); } // Remove an investor's account address from the whitelist for a specified project function revoke(address project, address investor) external onlyOwner { _approved[project][investor] = false; emit Revoked(project, investor); } // Check if an investor's account address is whitelisted for a specified project function isApproved( address project, address investor ) external view returns (bool) { return _approved[project][investor]; } } ``` ## RealEstateFactory Contract The `RealEstateFactory` contract is responsible for deploying new `RealEstateToken` contracts with the `deployProject()` function. It keeps a record of deployed `RealEstateToken` contracts deployed in the `allProjects` state variable which can be accessed by the `getAllProjects()` function. The `Whitelist` contract must be deployed before the `RealEstateFactory` contract. `RealEstateFactory` requires the address of the deployed `Whitelist` contract that manages approved investor addresses. ### RealEstateFactory ```solidity theme={null} //SPDX-License-Identifier: MIT pragma solidity ^0.8.30; import {RealEstateToken} from "./RealEstateToken.sol"; import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol"; // A factory contract to deploy new RealEstateToken contracts // Factory deploys RealEstateToken contracts representing tokenisation of a real estate assets // WARNING: This contract is an example only - do not use in production contract RealEstateFactory is Ownable2Step { // Address of the deployed Whitelist contract address public whitelist; // Array of all RealEstateToken contract addresses address[] public allProjects; // Event emitted when a new RealEstateToken contract is deployed event ProjectCreated( address indexed projectAddress, address indexed issuer, string projectName, string projectSymbol, string propertyId, string jurisdiction, string metadataUri ); constructor(address whiteListAddress) Ownable(msg.sender) { whitelist = whiteListAddress; } // Factory function to deploy a new RealEstateToken contract /// Returns the address of the deployed RealEstateToken contract function deployProject( string memory name, string memory symbol, string memory propertyId, string memory jurisdiction, string memory metadataUri ) external returns (address) { RealEstateToken token = new RealEstateToken( name, symbol, whitelist, propertyId, jurisdiction, metadataUri, msg.sender ); allProjects.push(address(token)); emit ProjectCreated( address(token), msg.sender, name, symbol, propertyId, jurisdiction, metadataUri ); return address(token); } // Get an array of all deployed RealEstateToken contracts function getAllProjects() external view returns (address[] memory) { return allProjects; } } ``` ## RealEstateToken Contract The `RealEstateToken` contract represents a Real World Asset (RWA). Real estate, in this instance. It is a basic example of RWA tokenization. It allows the owner/adminstrator of the project to mint tokens that represent a share in a real estate devlopment project. The `RealEstateToken` is a modified `ERC20` token. It overrides some of the standard behaviours of an ERC20 token. In particular, your attention is directed to the `mint()`, `adminBurn`, `decimals()`, and `_update()` functions. Essentially, the changes mean 1 token is a 1% share of the project. There are no fractional shares. Only the owner/admin of the project can mint tokens to an approved investor's account address. And, a token holder is restricted to transferring their tokens to other approved investors. Finally, given the nature of the tokens and what they are intended to represent, only the owner/admin can burn tokens. They cannot be burned by the token holder. ### RealEstateToken ```solidity theme={null} //SPDX-License-Identifier: MIT pragma solidity ^0.8.30; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol"; // Interface for the Whitelist contract isApproved function interface IWhiteList { function isApproved( address project, address investor ) external view returns (bool); } // A modified ERC20 token representing 100 shares in a real estate project // RealEstateToken represents shares in a real estate project // WARNING: This contract is an example only - do not use in production contract RealEstateToken is ERC20, Ownable2Step { IWhiteList public whitelist; // Issuer's property identifier string public propertyId; // The legal jurisdiction of the real estate string public jurisdiction; // IPFS CID to legal documents (unused) string public metadataUri; // Hard cap: 100 tokens max supply. Each token = 1 whole share of the property. uint256 public constant MAX_SUPPLY = 100; mapping(address => bool) private _isShareholder; address[] private _shareholders; // The number of investors that hold tokens in the project uint256 public shareholderCount; constructor( string memory name, string memory symbol, address whiteListAddress, string memory _propertyId, string memory _jurisdiction, string memory _metadataUri, address projectOwner ) ERC20(name, symbol) Ownable(projectOwner) { whitelist = IWhiteList(whiteListAddress); propertyId = _propertyId; jurisdiction = _jurisdiction; metadataUri = _metadataUri; } // Check whether an address is an investor in this project // Returns true if the address is an investor, otherwise false function isShareholder(address account) external view returns (bool) { return _isShareholder[account]; } // Get a list of shareholders in this project // Returns an array of the investor account addresses for this project function getShareholders() external view returns (address[] memory) { return _shareholders; } // Check whether an investor's address is on the whitelist // Returns true if the address is whitelisted, otherwise false function isApprovedHolder(address investor) external view returns (bool) { return whitelist.isApproved(address(this), investor); } // Mints new tokens to a specified address. There are 100 tokens only. Only the issuer (owner) can mint function mint(address to, uint256 amount) external onlyOwner { require(to != address(0), "Invalid recipient"); // Investor (to) must be approved require( whitelist.isApproved(address(this), to), "Investor not approved for this project." ); // Enforce hard cap (MAX_SUPPLY = 100 tokens) require( totalSupply() + amount <= MAX_SUPPLY, "Maximum shares exceeded." ); _mint(to, amount); } // Admin burn. This is the only way to reduce supply. // Used in emergency/problem circumstances (fraud, regulatory unwind etc) function adminBurn(address from, uint256 amount) external onlyOwner { require(from != address(0), "Invalid from address."); _burn(from, amount); } // Override decimals to ensure 1 token = 1 whole share. No fractional shares function decimals() public pure override returns (uint8) { return 0; } // Override some behaviours of the regular _update function for this specific use case // Burn only allowed if msg.sender is contract owner (via adminBurn). // Mint and transfer sender and recipients must be whitelisted for THIS project function _update( address from, address to, uint256 value ) internal override { bool isMint = (from == address(0)); bool isBurn = (to == address(0)); if (isBurn) { require(msg.sender == owner(), "Burn restricted to administrator."); } // Whitelist enforcement // Sender must be approved if it's not mint if (!isMint) { // from is a real holder in transfer OR burn require( whitelist.isApproved(address(this), from), "Sender not approved for this project" ); } // Recipient must be approved if it's not burn if (!isBurn) { // to is a real holder in transfer OR mint require( whitelist.isApproved(address(this), to), "Recipient is not approved for this project" ); } // Snapshot balances before uint256 fromBalanceBefore = isMint ? 0 : balanceOf(from); uint256 toBalanceBefore = isBurn ? 0 : balanceOf(to); // Execute state update super._update(from, to, value); // Snapshot balances after transfer uint256 fromBalanceAfter = isMint ? 0 : balanceOf(from); uint256 toBalanceAfter = isBurn ? 0 : balanceOf(to); // Shareholder bookkeeping // Recipient becomes a shareholder if (!isBurn) { if ( toBalanceBefore == 0 && toBalanceAfter > 0 && !_isShareholder[to] ) { _isShareholder[to] = true; _shareholders.push(to); shareholderCount += 1; } } // Sender ceases to be a shareholder if (!isMint) { if ( fromBalanceBefore > 0 && fromBalanceAfter == 0 && _isShareholder[from] ) { _isShareholder[from] = false; shareholderCount -= 1; // We do not prune shareholders for gas saving reasons } } } } ``` # How to Move OM Between MANTRA Cosmos and MANTRA EVM Source: https://docs.mantrachain.io/how-to-move-om-between-mantra-cosmos-and-mantra-evm Use move.mantrachain.io to move OM between your Cosmos wallet and EVM wallet on MANTRA Chain. `move.mantrachain.io` is the official interface for moving OM between **MANTRA’s Cosmos environment** (your Keplr/Leap wallet) and **MANTRA’s EVM environment** (your MetaMask/Rabby wallet). **Move OM now**: Visit [move.mantrachain.io](https://move.mantrachain.io). ## What you’re actually moving * **Cosmos side**: native OM (Cosmos SDK coin, commonly shown as `OM` / `uom`) * **EVM side**: OM’s ERC-20 representation on MANTRA EVM (commonly shown as `wOM`) You can confirm the canonical `wOM` contract addresses here: [Canonical ERC-20 Contracts](/resources/canonical-token-contracts). ## Prerequisites * A Cosmos wallet (Keplr or Leap) connected to MANTRA Chain * An EVM wallet (MetaMask, Rabby, etc.) configured for MANTRA Chain * A small amount of OM available for network fees If you need RPCs/chain IDs/explorers for setup, see: [Network Details](/resources/network-details). ## Cosmos → EVM (receive `wOM` in your EVM wallet) 1. Open [move.mantrachain.io](https://move.mantrachain.io) 2. Connect your **Cosmos wallet** (Keplr/Leap) 3. Connect your **EVM wallet** (MetaMask/Rabby) 4. Choose the direction **Cosmos → EVM** 5. Enter the amount of OM to move 6. Review the destination address and amounts shown in the UI 7. Confirm the transactions in your wallets After completion, your EVM wallet balance should reflect the moved amount as `wOM`. ## EVM → Cosmos (receive native OM in your Cosmos wallet) 1. Open [move.mantrachain.io](https://move.mantrachain.io) 2. Connect your **EVM wallet** (MetaMask/Rabby) 3. Connect your **Cosmos wallet** (Keplr/Leap) 4. Choose the direction **EVM → Cosmos** 5. Enter the amount of `wOM` to move 6. Review the destination address and amounts shown in the UI 7. Confirm the transactions in your wallets After completion, your Cosmos wallet balance should reflect the moved amount as OM. ## Troubleshooting * **Wrong network**: Ensure your wallets are on the correct MANTRA network (Mainnet vs Dukong Testnet). See [Network Details](/resources/network-details). * **Can’t see `wOM`**: Check the canonical contract address and add/import the token in your EVM wallet. See [Canonical ERC-20 Contracts](/resources/canonical-token-contracts). * **Tx succeeded but balance hasn’t updated**: Verify the transaction on an explorer (links are in [Network Details](/resources/network-details)). Always double-check wallet addresses and network selection before confirming transactions. Blockchain transactions are typically irreversible. # How to Stake OM Source: https://docs.mantrachain.io/how-to-stake-om Learn how to stake your OM tokens and earn rewards on MANTRA Chain Staking OM allows you to delegate your OM coins to validators who help secure the MANTRA blockchain. By staking, you actively participate in the network's security and earn rewards in return. **Stake OM now**: Visit [mantra.zone/stake](https://mantra.zone/stake) to start staking and earning rewards! ## Prerequisites * A MANTRA Chain wallet (Keplr or Leap) * OM tokens in your wallet ## Step 1: Connect Your Wallet Before you can start staking OM, you need to ensure your MANTRA wallet is connected to the staking interface. 1. **Prepare your wallet**: Make sure you have a MANTRA Chain wallet set up. You can use wallets like **Leap** or **Keplr**. 2. **Connect your wallet**: Visit [mantra.zone/stake](https://mantra.zone/stake) and click on the wallet connection button. Select your wallet from the available options. ## Step 2: Stake Your OM Now that your wallet is connected, follow these steps to stake your OM coins. ### Pick a Validator You can view a list of active validators along with their details such as: * Commission rates * APR (Annual Percentage Rate) * Staking volume Choose a validator you want to stake with based on these factors. Alternatively, if you have already staked with a validator, you can hover over it in your staking positions and click "Stake More" to add additional funds. ### Input the Amount to Stake Enter the amount of OM you wish to stake. Review your balance, staking position, and the validator's details to help you decide how much to stake. ### Accept Terms and Conditions Make sure to accept the risk disclaimers, terms and conditions, and privacy policy before proceeding. ### Approve the Transaction Confirm the staking transaction in your wallet. You'll see a confirmation message with transaction details, including a transaction hash that you can use to view your transaction in the explorer. ## Step 3: Claim Your Rewards You can easily claim your OM rewards in the Staking dashboard. ### Claim All Rewards Click the "Claim" button in the Staking dashboard under the rewards section (this will be enabled if you have claimable rewards). ### Claim from a Specific Validator Hover over your staking position with that validator and select "Claim Rewards". ### Review and Confirm You'll see a summary of the claim details, including which validators the rewards are from. You also have the option to re-stake your claimed rewards for further gains. If you decide to stake, simply click the Claim & Stake button and follow the staking process. ## Step 4: Manage Your Staking Positions ### Redelegate to Another Validator You can easily transfer your staked OM from one validator to another: 1. Hover over your staking positions to choose the validator you want to redelegate from 2. Pick a new validator from the list 3. Enter the amount to redelegate 4. Confirm the redelegation transaction in your wallet ### Unstake Your OM If you want to unstake your OM coins: 1. Hover over your staking positions to choose the validator from which you want to unstake 2. Enter the amount you want to unstake 3. Confirm the unstake transaction in your wallet **Unbonding Period**: Unstaking is subject to an unbonding period, which is the time it takes for your funds to become available in your wallet. During this period, you won't earn rewards. ## Benefits of Staking * **Earn Rewards**: Receive OM rewards for helping secure the network * **Support Decentralization**: Contribute to network security and stability * **Flexible Management**: Easily redelegate, claim rewards, or unstake as needed ## Next Steps * Learn more about [MANTRA Chain's staking mechanism](/operators/overview/what-are-validator-nodes) * Explore other features on [MANTRA Zone](https://mantra.zone) * Join our [Discord](https://discord.com/invite/mantrachain) community for support # Getting Started Source: https://docs.mantrachain.io/index Participate in MANTRA Chain's integrated DeFi ecosystem Build and deploy DeFi protocols with advanced infrastructure Run validators, oracles, relayers, and infrastructure nodes ## Learn More Explore the technical concepts that make MANTRA unique Access APIs, SDKs, and development resources ## Our Vision MANTRA Chain aims to become the leader in the RWA tokenization sector by developing a **full end-to-end ecosystem** for the entire lifecycle of Real World Assets (RWAs). Unlike general-purpose Layer-1 blockchains, MANTRA focuses on carving out a **specialized, high-value niche** in the RWA space. ## MANTRA Chain is The RWA Layer 1 MANTRA Chain is a modular Layer-1 blockchain engineered for **decentralized finance (DeFi)** and **real-world asset (RWA) tokenization**, with a foundational commitment to regulatory compliance. **First RWA L1 Testnet:** Launched November 2023, MANTRA Chain pioneered the first dedicated RWA Layer 1 blockchain testnet. ## Why Build on MANTRA Chain? MANTRA Chain delivers key advantages for developers: 1. **Native cross-chain interoperability** - Seamless asset transfers across different blockchains 2. **High performance & low costs** - Optimized for DeFi and RWA applications 3. **Flexible infrastructure** - Supports both permissionless and permissioned use cases 4. **Compliance-ready** - Build regulatory-compliant applications without sacrificing developer freedom ## Full EVM Compatibility With the [MANTRA Chain v5.0.0 Abunnati Upgrade](https://github.com/MANTRA-Chain/mantrachain/releases/tag/v5.0.0), we added our own [EVM module](https://github.com/MANTRA-Chain/evm) that opens up the design space for RWA developers. **What this means for you:** * Deploy **Solidity smart contracts** using standard EVM tooling * Use familiar development tools (Hardhat, Foundry, Remix) * Leverage existing Ethereum libraries and frameworks * No need to learn new languages or paradigms ## The Permissionless + Permissioned Advantage MANTRA Chain operates as a **permissionless blockchain** while supporting **permissioned applications** that can adhere to real-world regulatory requirements. **Regulatory Future:** We believe regulated onchain finance will require: * **KYC/KYB** (Know Your Customer / Know Your Business) * **KYT** (Know Your Transaction) * **KYV** (Know Your Validator) - *MANTRA Chain is the only RWA L1 that enables this* This unique positioning makes MANTRA Chain ideal for: * **Institutional adoption** - Long-term strategic fit for regulated entities * **Specialized RWA applications** - Focused on high-value, compliance-critical use cases * **Hybrid ecosystems** - Support both open DeFi and regulated tokenization # null Source: https://docs.mantrachain.io/operators/governance/draft-a-proposal/cancel-software-upgrade The cancel software upgrade proposal attempts to roll back or prevent from initiating a previously accepted software upgrade proposal. Selecting `cancel-software-upgrade` for `proposal type` after executing the `draft-proposal` command will request the following parameters: * **Proposal title:** the distinguishing name of the proposal, typically the way the that explorers list proposals. * **Proposal author(s):** the person(s) making the proposal. * **Proposal summary:** a high level, brief overview of the proposal. * **Proposal details:** a detailed, expansive explanation of the proposal. * **Proposal forum url:** the web location which contains more detail and where people can engage in discussion regarding the proposal. * **Proposal vote option context:** The option set of a proposal refers to the set of choices a participant can choose from when casting its vote. The initial option set includes the following options: `Yes`, `No`, `NoWithVeto`, `Abstain`. The`NoWithVeto` counts as `No` but also adds a `Veto` vote. `Abstain` option allows voters to signal that they do not intend to vote in favour or against the proposal but accept the result of the vote. * **Proposal deposit:** the amount of AUM deposited in order for the proposal to be considered. The minimum amount required my MANTRA Chain is 100 OM. (100\_000\_000 uom). * **Msg's authority:** This is the wallet that has the authority to submit the software update. This is typically the same wallet submitting the proposal. ``` $mantrachaind tx gov draft-proposal ✔ cancel-software-upgrade Enter proposal's title: Example cancel software upgrade proposal Enter proposal's authors: Martin Halford ✔ Enter proposal's summary: This is an example cancel █oftware upgrade proposal in order to demonstrate the proposal governance mechanism on MANTRA Chain. Enter proposal's details: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eleifend non magna sit amet efficitur. Enter proposal's proposal forum url: https://forum.mantrachain.io/proposal-002 Enter proposal's vote option context: Yes, No, NoTWithVeto, Abstain Enter proposal deposit: 1000000000uom Enter msg's authority: mantra10d07y265gmmuvt4z0w9aw880jnsr700j3fep4f The draft proposal has successfully been generated. Proposals should contain off-chain metadata, please upload the metadata JSON to IPFS. Then, replace the generated metadata field with the IPFS CID. ``` The `draft-proposal` command will generate two (2) files: Example `draft_proposal.json` ``` { "messages": [ { "@type": "/cosmos.upgrade.v1beta1.MsgCancelUpgrade", "authority": "mantra10d07y265gmmuvt4z0w9aw880jnsr700j3fep4f" } ], "metadata": "ipfs://CID", "deposit": "1000000000uom", "title": "Example cancel software upgrade proposal", "summary": "This is an example cancel software upgrade proposal in order to demonstrate the proposal governance mechanism on MANTRA Chain." } ``` Example `draft_metadata.json` ``` { "title": "Example cancel software upgrade proposal", "authors": [ "Martin Halford" ], "summary": "This is an example cancel software upgrade proposal in order to demonstrate the proposal governance mechanism on MANTRA Chain.", "details": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eleifend non magna sit amet efficitur.", "proposal_forum_url": "https://forum.mantrachain.io/proposal-002", "vote_option_context": "Yes, No, NoTWithVeto, Abstain" } ``` Of the two (2) files, the `draft_proposal.json` file is submitted to the MANTRA Chain as part of the `submit-proposal` transaction. The file `draft_metadata.json` is referenced within the `draft_proposal.json` in the attribute `"metadata": "ipfs://CID"`. Upload the `draft_metadata.json` to an IPFS location and edit the `draft_proposal.json` attribute with the uploaded files IPFS location details. Example `draft_proposal.json` with edited IPFS location: ``` { "messages": [ { "@type": "/cosmos.upgrade.v1beta1.MsgCancelUpgrade", "authority": "mantra10d07y265gmmuvt4z0w9aw880jnsr700j3fep4f" } ], "metadata": "ipfs://QmatNt96KnybCiuwBNyVBXiicaZJbu54ocUtznegin1zNt", "deposit": "1000000000uom", "title": "Example cancel software upgrade proposal", "summary": "This is an example cancel software upgrade proposal in order to demonstrate the proposal governance mechanism on MANTRA Chain." } ``` # null Source: https://docs.mantrachain.io/operators/governance/draft-a-proposal/community-spend-proposal ### Community Pool Spend The Community Pool Spend proposal is a special type of proposal that allows the community to collectively vote on how funds are spent from the community pool. Selecting `community-pool-spend` for `proposal type` after executing the `draft-proposal` command will request the following parameters: * **Proposal title:** the distinguishing name of the proposal, typically the way the that explorers list proposals. * **Proposal author(s):** the person(s) making the proposal. * **Proposal summary:** a high level, brief overview of the proposal. * **Proposal details:** a detailed, expansive explanation of the proposal. * **Proposal forum url:** the web location which contains more detail and where people can engage in discussion regarding the proposal. * **Proposal vote option context:** The option set of a proposal refers to the set of choices a participant can choose from when casting its vote. The initial option set includes the following options: `Yes`, `No`, `NoWithVeto`, `Abstain`. The`NoWithVeto` counts as `No` but also adds a `Veto` vote. `Abstain` option allows voters to signal that they do not intend to vote in favour or against the proposal but accept the result of the vote. * **Proposal deposit:** the amount of AUM deposited in order for the proposal to be considered. The minimum amount required my MANTRA Chain is 100 OM. (100\_000\_000 uom). * **Msg's authority:** This is the wallet that has the authority to spend the funds. This is typically the same wallet submitting the proposal. * **Msg's recipient:** This is the recipient wallet address where funds will be sent, if the proposal is accepted. ``` $ mantrachaind tx gov draft-proposal ✔ community-pool-spend Enter proposal's title: Example community spend proposal Enter proposal's authors: Martin Halford Enter proposal's summary: This is an example community proposal in order to demonstrate the proposal governance mechanism on MANTRA Chain. Enter proposal's details: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eleifend non magna sit amet efficitur. Enter proposal's proposal forum url: https://forum.mantrachain.io/proposal-002 Enter proposal's vote option context: Yes, No, NoTWithVeto, Abstain Enter proposal deposit: 1000000000uom Enter msg's authority: mantra10d07y265gmmuvt4z0w9aw880jnsr700j3fep4f Enter msg's recipient: mantra1q40588gdedqncyt0a77mvfmjvyngcr3vh0lsmj The draft proposal has successfully been generated. Proposals should contain off-chain metadata, please upload the metadata JSON to IPFS. Then, replace the generated metadata field with the IPFS CID. ``` The `draft-proposal` command will generate two (2) files: Example `draft_proposal.json` ``` { "messages": [ { "@type": "/cosmos.distribution.v1beta1.MsgCommunityPoolSpend", "authority": "mantra10d07y265gmmuvt4z0w9aw880jnsr700j3fep4f", "recipient": "mantra1q40588gdedqncyt0a77mvfmjvyngcr3vh0lsmj", "amount": [] } ], "metadata": "ipfs://CID", "deposit": "1000000000uom", "title": "Example community spend proposal", "summary": "This is an example community proposal in order to demonstrate the proposal governance mechanism on MANTRA Chain." } ``` Example `draft_metadata.json` ``` { "title": "Example community spend proposal", "authors": [ "Martin Halford" ], "summary": "This is an example community proposal in order to demonstrate the proposal governance mechanism on MANTRA Chain.", "details": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eleifend non magna sit amet efficitur.", "proposal_forum_url": "https://forum.mantrachain.io/proposal-002", "vote_option_context": "Yes, No, NoTWithVeto, Abstain" } ``` Of the two (2) files, the `draft_proposal.json` file is submitted to the MANTRA Chain as part of the `submit-proposal` transaction. The file `draft_metadata.json` is referenced within the `draft_proposal.json` in the attribute `"metadata": "ipfs://CID"`. Upload the `draft_metadata.json` to an IPFS location and edit the `draft_proposal.json` attribute with the uploaded files IPFS location details. Example `draft_proposal.json` with edited IPFS location: ``` { "messages": [ { "@type": "/cosmos.distribution.v1beta1.MsgCommunityPoolSpend", "authority": "mantra10d07y265gmmuvt4z0w9aw880jnsr700j3fep4f", "recipient": "mantra1q40588gdedqncyt0a77mvfmjvyngcr3vh0lsmj", "amount": [] } ], "metadata": "ipfs://QmatNt96KnybCiuwBNyVBXiicaZJbu54ocUtznegin1zNt", "deposit": "1000000000uom", "title": "Example community spend proposal", "summary": "This is an example community proposal in order to demonstrate the proposal governance mechanism on MANTRA Chain." } ``` **Note:** IPFS (InterPlanetary File System) is beyond the scope of this document. To learn more about IPS, see [https://docs.ipfs.tech](https://docs.ipfs.tech). In order to get started with IPFS and be able to upload and download files, you can try [https://docs.ipfs.tech/install/ipfs-desktop/](https://docs.ipfs.tech/install/ipfs-desktop/) for Windows, Mac and Linux. # null Source: https://docs.mantrachain.io/operators/governance/draft-a-proposal/draft-a-proposal Prior to sending the transaction that submits your proposal on-chain, you must create a set of JSON files. These file will contain the information that will be stored on-chain as the governance proposal. The best and easiest way to generate the proposal files, is to use the convenient `draft-proposal` command, as follows: ``` mantrachaind tx gov draft-proposal ``` This will prompt a selection from one of the following options: ``` Use the arrow keys to navigate: ↓ ↑ → ← ? Select proposal type: ▸ text community-pool-spend software-upgrade cancel-software-upgrade other ``` # null Source: https://docs.mantrachain.io/operators/governance/draft-a-proposal/software-upgrade The software upgrade proposal allows the community to vote on the acceptance, or not, of an update the `mantrachaind` binary. This upgrade could be for whatever reason, as specified by the MANTRA Chain Developers / Maintainers. Selecting `software-upgrade` for `proposal type` after executing the `draft-proposal` command will request the following parameters: * **Proposal title:** the distinguishing name of the proposal, typically the way the that explorers list proposals. * **Proposal author(s):** the person(s) making the proposal. * **Proposal summary:** a high level, brief overview of the proposal. * **Proposal details:** a detailed, expansive explanation of the proposal. * **Proposal forum url:** the web location which contains more detail and where people can engage in discussion regarding the proposal. * **Proposal vote option context:** The option set of a proposal refers to the set of choices a participant can choose from when casting its vote. The initial option set includes the following options: `Yes`, `No`, `NoWithVeto`, `Abstain`. The`NoWithVeto` counts as `No` but also adds a `Veto` vote. `Abstain` option allows voters to signal that they do not intend to vote in favour or against the proposal but accept the result of the vote. * **Proposal deposit:** the amount of AUM deposited in order for the proposal to be considered. The minimum amount required my MANTRA Chain is 100 OM. (100\_000\_000 uom). * **Msg's authority:** This is the wallet that has the authority to submit the software update. This is typically the same wallet submitting the proposal. ``` $ mantrachaind tx gov draft-proposal ✔ software-upgrade Enter proposal's title: Example software upgrade proposal ✔ Enter proposal's authors: Martin Halford█ Enter proposal's summary: This is an example software upgrade proposal in order to demonstrate the proposal governance mechanism on MANTRA Chain. Enter proposal's details: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eleifend non magna sit amet efficitur. Enter proposal's proposal forum url: https://forum.mantrachain.io/proposal-002 Enter proposal's vote option context: Yes, No, NoTWithVeto, Abstain Enter proposal deposit: 1000000000uom Enter msg's authority: mantra10d07y265gmmuvt4z0w9aw880jnsr700j3fep4f The draft proposal has successfully been generated. Proposals should contain off-chain metadata, please upload the metadata JSON to IPFS. Then, replace the generated metadata field with the IPFS CID. ``` The `draft-proposal` command will generate two (2) files: Example `draft_proposal.json` ``` { "messages": [ { "@type": "/cosmos.upgrade.v1beta1.MsgSoftwareUpgrade", "authority": "mantra10d07y265gmmuvt4z0w9aw880jnsr700j3fep4f", "plan": { "name": "", "time": "0001-01-01T00:00:00Z", "height": "0", "info": "", "upgraded_client_state": null } } ], "metadata": "ipfs://CID", "deposit": "1000000000uom", "title": "Example software upgrade proposal", "summary": "This is an example software upgrade proposal in order to demonstrate the proposal governance mechanism on MANTRA Chain." } ``` Edit the `draft_proposal.json` and update the `plan` which informs Validators regarding when they are expected to perform the update to their nodes and the location from where they can retrieve the binary. Example `draft_metadata.json` ``` { "title": "Example software upgrade proposal", "authors": [ "Martin Halford" ], "summary": "This is an example software upgrade proposal in order to demonstrate the proposal governance mechanism on MANTRA Chain.", "details": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eleifend non magna sit amet efficitur.", "proposal_forum_url": "https://forum.mantrachain.io/proposal-002", "vote_option_context": "Yes, No, NoTWithVeto, Abstain" } ``` If proposals are of type `SoftwareUpgradeProposal`, then nodes need to upgrade their software to the new version that was voted. This process is divided in two steps. Of the two (2) files, the `draft_proposal.json` file is submitted to the MANTRA Chain as part of the `submit-proposal` transaction. The file `draft_metadata.json` is referenced within the `draft_proposal.json` in the attribute `"metadata": "ipfs://CID"`. Upload the `draft_metadata.json` to an IPFS location and edit the `draft_proposal.json` attribute with the uploaded files IPFS location details. Example `draft_proposal.json` with edited `plan` and IPFS location: ``` { "messages": [ { "@type": "/cosmos.upgrade.v1beta1.MsgSoftwareUpgrade", "authority": "mantra10d07y265gmmuvt4z0w9aw880jnsr700j3fep4f", "plan": { "name": "", "time": "0001-01-01T00:00:00Z", "height": "0", "info": "", "upgraded_client_state": "ipfs://QmatNt96KnybCiuwBNyVBXiicaZJbu54ocUtznegin1zNt" } } ], "metadata": "ipfs://QmatNt96KnybCiuwBNyVBXiicaZJbu54ocUtznegin1zNt", "deposit": "1000000000uom", "title": "Example software upgrade proposal", "summary": "This is an example software upgrade proposal in order to demonstrate the proposal governance mechanism on MANTRA Chain." } ``` **Note:** IPFS (InterPlanetary File System) is beyond the scope of this document. To learn more about IPS, see [https://docs.ipfs.tech](https://docs.ipfs.tech). In order to get started with IPFS and be able to upload and download files, you can try [https://docs.ipfs.tech/install/ipfs-desktop/](https://docs.ipfs.tech/install/ipfs-desktop/) for Windows, Mac and Linux. **Signal** After a `software-upgrade` proposal is accepted, validators are expected to download and install the new version of the software while continuing to run the previous version. Once a validator has downloaded and installed the upgrade, it will start signaling to the network that it is ready to switch by including the proposal's `proposalID` in its *precommits*. Note: There is only one signal slot per *precommit*. If several `software-upgrade` proposal are accepted in a short timeframe, a pipeline will form and they will be implemented one after the other in the order that they were accepted. **Switch** Once a block contains more than 2/3rd *precommits* where a common`software-upgrade` proposal is signaled, all the nodes (including validator nodes, non-validating full nodes and light-nodes) are expected to switch to the new version of the software. # null Source: https://docs.mantrachain.io/operators/governance/draft-a-proposal/text-proposal Text proposals are used by delegators to agree to a certain strategy, plan, commitment, future upgrade, or any other statement in the form of text. Aside from having a record of the proposal outcome on the MANTRA Chain, a text proposal has no direct effect on the change MANTRA Chain. Selecting `text` for `proposal type` after executing the `draft-proposal` command will request the following parameters: * **Proposal title:** the distinguishing name of the proposal, typically the way the that explorers list proposals. * **Proposal author(s):** the person(s) making the proposal. * **Proposal summary:** a high level, brief overview of the proposal. * **Proposal details:** a detailed, expansive explanation of the proposal. * **Proposal forum url:** the web location which contains more detail and where people can engage in discussion regarding the proposal. * **Proposal vote option context:** The option set of a proposal refers to the set of choices a participant can choose from when casting its vote. The initial option set includes the following options: `Yes`, `No`, `NoWithVeto`, `Abstain`. The`NoWithVeto` counts as `No` but also adds a `Veto` vote. `Abstain` option allows voters to signal that they do not intend to vote in favour or against the proposal but accept the result of the vote. * **Proposal deposit:** the amount of AUM deposited in order for the proposal to be considered. The minimum amount required my MANTRA Chain is 100 OM. (100\_000\_000 uom). ``` $ mantrachaind tx gov draft-proposal ✔ text Enter proposal's title: Example Text Proposal Enter proposal's authors: Martin Halford Enter proposal's summary: This is a sample text proposal in order to demonstrate the proposal governance mechanism on MANTRA Chain. Enter proposal's details: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eleifend non magna sit amet efficitur. Nullam et est sapien. Phasellus interdum a nisi eu mattis. Enter proposal's proposal forum url: https://forum.mantrachain.io/proposal-001 Enter proposal's vote option context: Yes, No, NoWithVeto, Abstain ✔ Enter proposal deposit: 1000000000uom█ The draft proposal has successfully been generated. Proposals should contain off-chain metadata, please upload the metadata JSON to IPFS. Then, replace the generated metadata field with the IPFS CID. ``` The `draft-proposal` command will generate two (2) files: Example `draft_proposal.json` ``` { "metadata": "ipfs://CID", "deposit": "1000000000uom", "title": "Example Text Proposal", "summary": "This is a sample text proposal in order to demonstrate the proposal governance mechanism on MANTRA Chain." } ``` Example `draft_metadata.json` ``` { "title": "Example Text Proposal", "authors": [ "Martin Halford" ], "summary": "This is a sample text proposal in order to demonstrate the proposal governance mechanism on MANTRA Chain.", "details": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eleifend non magna sit amet efficitur. Nullam et est sapien. Phasellus interdum a nisi eu mattis.", "proposal_forum_url": "https://forum.mantrachain.io/proposal-001", "vote_option_context": "Yes, No, NoWithVeto, Abstain" ``` Of the two (2) files, the `draft_proposal.json` file is submitted to the MANTRA Chain as part of the `submit-proposal` transaction. The file `draft_metadata.json` is referenced within the `draft_proposal.json` in the attribute `"metadata": "ipfs://CID"`. Upload the `draft_metadata.json` to an IPFS location and edit the `draft_proposal.json` attribute with the uploaded files IPFS location details. Example `draft_proposal.json` with edited IPFS location: ``` { "metadata": "ipfs://QmatNt96KnybCiuwBNyVBXiicaZJbu54ocUtznegin1zNt", "deposit": "1000000000uom", "title": "Example Text Proposal", "summary": "This is a sample text proposal in order to demonstrate the proposal governance mechanism on MANTRA Chain." } ``` **Note:** IPFS (InterPlanetary File System) is beyond the scope of this document. To learn more about IPS, see [https://docs.ipfs.tech](https://docs.ipfs.tech). In order to get started with IPFS and be able to upload and download files, you can try [https://docs.ipfs.tech/install/ipfs-desktop/](https://docs.ipfs.tech/install/ipfs-desktop/) for Windows, Mac and Linux. # null Source: https://docs.mantrachain.io/operators/governance/execute-proposal/depositing-funds Sometimes a proposal is submitted without having the minimum token amount deposited yet. In these cases you would want to be able to deposit more tokens to get the proposal into the voting stage. In order to deposit tokens, you'll need to know what your proposal ID is after you've submitted your proposal. You can query all proposals by the following command: ``` mantrachaind q gov proposals ``` If there are a lot of proposals on the chain already, you can also filter by your own address. For the proposal above, that would be: ``` mantrachaind q gov proposals --depositor mantra1hxv7mpztvln45eghez6evw2ypcw4vjmsmr8cdx ``` Once you have the proposal ID, this is the command to deposit extra tokens: ``` mantrachaind tx gov deposit \ --from \ --chain-id \ --gas \ --gas-adjustment \ --gas-prices= ``` e.g. ``` mantrachaind tx gov deposit 5 1000000000.0000uom \ --from=fluffy-duck-keys \ --chain-id=mantra-dukong-1 \ --gas-prices="0.01uom" \ --gas-adjustment=2 \ --gas="auto" ``` In our case above, the `` would be 5 as queried earlier. The `` is written as `500000uom`, just like the example above. # null Source: https://docs.mantrachain.io/operators/governance/execute-proposal/submitting-a-proposal Submit a proposal using the `mantrachaind tx gov submit-proposal` command. This is best done by a person with command-line access to a fully synchronised MANTRA Chain node running the `mantrachaind` service. ``` mantrachaind tx gov submit-proposal \ --from \ --chain-id \ --gas \ --gas-adjustment \ --gas-prices= \ --node ``` A specific example is given here: ``` mantrachaind tx gov submit-proposal $HOME/draft_proposal.json \ --from shaggy-dog-keys \ --chain-id mantra-dukong-1 \ --gas="auto" \ --gas-adjustment 2 \ --gas-prices="0.01uom" \ --node https://rpc.dukong.mantrachain.io:443 ``` If `` is left blank, the type will be a Text proposal. Otherwise, it can be set to `param-change` or `community-pool-spend`. Use `--help` to get more info from the tool. 1. `mantrachaind` is the command-line interface client that is used to send transactions and query the MANTRA Chain. 2. `tx gov submit-proposal community-pool-spend` indicates that the transaction is submitting a community pool spend proposal. 3. `--~/community_spend_proposal.json` indicates the file containing the proposal details. 4. `--from validator-01-wallet` is the account key that pays the transaction fee and deposit amount. This account key must be already saved in the keyring on your device and it must be an address you control. 5. `--gas 500000` is the maximum amount of gas permitted to be used to process the transaction. * The more content there is in the description of your proposal, the more gas your transaction will consume * If this number isn't high enough and there isn't enough gas to process your transaction, the transaction will fail. * The transaction will only use the amount of gas needed to process the transaction. 6. `--fees` is a flat-rate incentive for a validator to process your transaction. * The network still accepts zero fees, but many nodes will not transmit your transaction to the network without a minimum fee. * Many nodes (including the Figment node) use a minimum fee to disincentivize transaction spamming. * 7500uom is equal to 0.0075 OM. 7. `--chain-id mantra-dukong-1` is MANTRA Hongbai Chain (Testnet). 8. `--node https://rpc.dukong.mantrachain.io:443` is using an established node to send the transaction to the MANTRA Chain network. **Note**: be careful what you use for `--fees`. A mistake here could result in spending hundreds or thousands of OMs accidentally, which cannot be recovered. # Verifying your transaction Source: https://docs.mantrachain.io/operators/governance/execute-proposal/verifying-your-transaction How to verify a governance transaction via mantrachaind or Mintscan. After posting your transaction, your command line interface (mantrachaind) will provide you with the transaction's hash, which you can either query using mantrachaind or by searching the transaction hash using [Mintscan Explorer (opens new window)](https://www.mintscan.io/mantra-testnet/). The hash should look something like this: `0506447AE8C7495DE970736474451CF23536DF8EA837FAF1CF6286565589AB57` # null Source: https://docs.mantrachain.io/operators/governance/execute-proposal/voting-on-a-proposal In order to vote on a proposal, submit the following command from the console of an Validator in the active set. Use the `mantrachaind tx gov vote` command below to cast a governance vote by specifying the proposal ID, your vote option (e.g., `yes`), and the key/address you’re voting from, then broadcasting the transaction to the network. ``` mantrachaind tx gov vote --from \ --gas-prices="0.01uom" --gas \ --gas-adjustment \ --gas-prices= ``` e.g. ``` mantrachaind tx gov vote 5 "yes" --from=fluffy-duck-keys --gas-prices="0.0002uom" --gas-adjustment=2 --gas="auto" ``` Use the following command to see the vote tally. ``` mantrachaind q gov votes ``` To see how a particular Validator voted, use the following command. ``` mantrachaind query gov vote ``` e.g. ``` mantrachaind query gov vote 5 mantra1layehd68atc9ny7dj96gunxnh3ryqzxa3ggwq6 ``` # null Source: https://docs.mantrachain.io/operators/node-setup-and-deployment/validator-nodes/becoming-a-validator ## Synced Node Before creating a validator, ensure you have first followed the instructions on how to [Setup & Run a Node](/operators/node-setup-and-deployment/validator-nodes/running-a-node). ## Initialize Wallet Keyring If you decide you want to turn your node into a validator, you will first need to add a wallet to your keyring. While you can add an existing wallet through a seed phrase or importing a private key, the example shows how to create a new wallet (replace `$KEY_NAME` with a name of your choosing): ```bash theme={null} mantrachaind keys add $KEY_NAME ``` The above command will produce the following output: ``` - address: mantra1q55nrzygas0nespfu8mwt2yntq8gxll3kyug82 name: validator-mchain-test-node-keys pubkey: '{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A/YebpAX8AqUNcNXcqIy53fJo8BGFCSaQA5A0XQWMlCG"}' type: local **Important** write this mnemonic phrase in a safe place. It is the only way to recover your account if you ever forget your password. expect kid unfair uniform calm debris meadow despair vintage arrive walnut vast upset cart step funny truth vault naive note capable spray shine human ``` Ensure you write down the mnemonic as you can not recover the wallet without it. To ensure your wallet was saved to your keyring, you can verify that the wallet is listed by using the following command: ```bash theme={null} mantrachaind keys list ``` ### **Import keys** Alternatively, if you already have an existing mnemonic that you'd like to use, then run the following: ```bash theme={null} mantrachaind keys add $KEY_NAME --recover ``` **KEEP THE MNEMONIC PHRASE IN A SAFE PLACE!** ### View Validator Public Key The last thing needed before initialising the validator is to obtain your validator public key which was created when you first initialized your node. To obtain your validator pubkey: ``` mantrachaind tendermint show-validator ``` ## Create Validator Command Ensure you have a small amount of OM on the wallet address you are using on your keyring in order to successfully send a transaction. Once you have have a balance on the address on your keyring, you can now send the `create-validator` transaction. Here is the same command but with example values and an example of how certain parameters can be loaded from an external file, i.e. `validator.json`: ```bash theme={null} echo "{ \"pubkey\": $(mantrachaind tendermint show-validator), \"amount\": \"10000uom\", \"moniker\": \"MANTRA Chain Foundation\", \"identity\": \"xxxxxx\", \"website\": \"https://mantrachain.io\", \"security\": \"security@mantrachain.io\", \"details\": \"MANTRA is a purpose-built RWA Layer 1 Blockchain, capable of adherence to real world regulatory requirements.\", \"commission-rate\": \"0.1\", \"commission-max-rate\": \"0.2\", \"commission-max-change-rate\": \"0.01\", \"min-self-delegation\": \"1\" } " > validator.json mantrachaind tx staking create-validator validator.json --from $KEY_NAME --chain-id mantra-dukong-1 --gas="auto" --gas-adjustment 2 --gas-prices="0.01uom" ``` If you need further explanation for each of these command flags: * the `from` flag is the `$KEY_NAME` you created when initialising the key on your keyring * the `amount` flag is the amount you will place in your own validator in `uom` * the `pubkey` is the validator public key found earlier * the `moniker` is a human readable name you choose for your validator * the `security-contact` is an email your delegates are able to contact you at * the `chain-id` is the active chain with to which you will connect (i.e. `mantra-1` for mainnet, `mantra-dukong-1` for public testnet.) * the `commission-rate` is the rate you will charge your delegates for the privilege of running the validator on their behalf * the `commission-max-rate` is the most you are allowed to charge your delegates * the `commission-max-change-rate` is how much you can increase your commission rate in a 24 hour period * the `min-self-delegation` is the lowest amount of personal funds the validator is required to have in their own validator to stay bonded * the `gas-prices` is the amount of gas used to send this `create-validator` transaction # null Source: https://docs.mantrachain.io/operators/node-setup-and-deployment/validator-nodes/configuring-mantrachain systemd is a system and service manager for Linux operating systems that serves as the init system for initialising user space and managing system processes. # Configuring Mantrachain with Systemd The best way to run `mantrachaind` as a daemon service is by also leveraging Cosmovisor. [Cosmovisor](https://docs.cosmos.network/main/build/tooling/cosmovisor#installation) is a tool designed for managing and upgrading Cosmos SDK-based blockchain nodes. It simplifies the process of running a validator or full node by handling automatic upgrades and minimizing downtime ## Pre-Requisites ### Go Requirement You will need to be running, at minimum, go `1.20` to run Cosmovisor. ```bash theme={null} wget -q -O - https://git.io/vQhTU | bash -s -- --remove wget -q -O - https://git.io/vQhTU | bash -s -- --version 1.20 ``` ## Set Up Cosmovisor Set up cosmovisor to ensure any future upgrades happen flawlessly. To install Cosmovisor: ``` go install cosmossdk.io/tools/cosmovisor/cmd/cosmovisor@latest ``` (You may also refer to the Cosmovisor [installation instructions](https://github.com/cosmos/cosmos-sdk/tree/main/tools/cosmovisor#installation).) Create the required directories: ``` mkdir -p ~/.mantrachaind/cosmovisor mkdir -p ~/.mantrachaind/cosmovisor/genesis mkdir -p ~/.mantrachaind/cosmovisor/genesis/bin mkdir -p ~/.mantrachaind/cosmovisor/upgrades ``` ## Configure `mantrachaind` as a Service The `systemd` service manager allows the `mantrachaind` binary to run as a service, instead of as a command-line application. (See [https://systemd.io](https://systemd.io) for more information.) ```bash theme={null} sudo tee /etc/systemd/system/mantrachaind.service > /dev/null << EOF [Unit] Description=Mantrachaind Service After=network-online.target [Service] User=$USER ExecStart=$(which cosmovisor) run start Restart=on-failure RestartSec=3 LimitNOFILE=10000 Environment="DAEMON_NAME=mantrachaind" Environment="DAEMON_HOME=$HOME/.mantrachain" Environment="DAEMON_ALLOW_DOWNLOAD_BINARIES=true" Environment="DAEMON_RESTART_AFTER_UPGRADE=true" Environment="UNSAFE_SKIP_BACKUP=true" [Install] WantedBy=multi-user.target EOF ``` ### Starting, Stopping and Restarting `mantrachaind` ```bash theme={null} # Reload daemon inventory, Enable the new Service and Start sudo systemctl daemon-reload sudo systemctl enable mantrachaind sudo systemctl start mantrachaind # Stop Service sudo systemctl stop mantrachaind # Restart sudo systemctl restart mantrachaind # Logging sudo journalctl -xefu mantrachaind # Logging - filtered on block height lines sudo journalctl -xefu mantrachaind -g ".*txindex" ``` Once started, the node will take some time to sync with the blockchain. Visit [https://explorer.mantrachain.io](https://explorer.mantrachain.io) to see the current height of the blockchain. You can use the `journalctl` command to check on the node's progress. # Connect sidecar Source: https://docs.mantrachain.io/operators/node-setup-and-deployment/validator-nodes/connect-sidecar Run the Connect sidecar and wire it into your validator's oracle configuration ## Run Connect sidecar Choose one of the following distribution methods: * **Binary release**: `https://github.com/MANTRA-Chain/connect/releases/tag/v2.3.0-mantra-1.2` * **Container image**: `ghcr.io/mantra-chain/connect-sidecar:2.3.0-mantra-1.2` To run Connect (default port: `8080`): ```bash theme={null} connect --market-map-endpoint=":" ``` If you run Connect and your validator on the same host: ```bash theme={null} connect --market-map-endpoint=localhost:9090 ``` ## Verify Connect ```bash theme={null} curl 'http://localhost:8080/connect/oracle/v2/prices' | jq . ``` You should see JSON output similar to: ```json theme={null} { "prices": { "ATOM/USD": "4308207537", "BTC/USD": "6693024042", "ETH/USD": "2602324302", "OM/USD": "1501599", "OSMO/USD": "53054083", "USDT/USD": "999750064", "USDY/USD": "1054483" }, "timestamp": "2024-10-17T12:09:39.899360574Z", "version": "v2.0.1" } ``` ## Update validator config Add the following under `[oracle]` in your `app.toml` (adjust `oracle_address` to point to your Connect sidecar): ```toml theme={null} [oracle] enabled = "true" # if you are not running a validator node, set this to "false" oracle_address = ":8080" # use localhost if running on the same server as the validator client_timeout = "2s" metrics_enabled = "true" price_ttl = "0s" interval = "1.5s" ``` Restart your validator after applying the change. For more details, see the upstream quickstart at `https://docs.skip.build/connect/validators/quickstart#run-connect-sidecar`. # null Source: https://docs.mantrachain.io/operators/node-setup-and-deployment/validator-nodes/download-nodes-snapshots On this page, you can find links to download pre-built nodes with blockchain history included, which will save you time when setting up your node. \ You can choose from different node combinations: Node types: * Fullnode: contains pruned blocks (lighter) * Archive: contains full blockchain data (heavier) * Choose this if you need the complete history for historical analysis, etc. Database: * pebbledb (recommended) * goleveldb Network: * Mainnet * Testnet ## URLs ### Mainnet (Mantra-1) | Node type | Database type | Height | URL | | --------- | ------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Full node | pebbledb | 10611934 | [https://snapshots.mantrachain.io/mantra-1\_pebbledb\_fullnode\_latest.tar.lz4](https://snapshots.mantrachain.io/mantra-1_pebbledb_fullnode_latest.tar.lz4) | | Full node | goleveldb | 10592003 | [https://snapshots.mantrachain.io/mantra-1\_goleveldb\_fullnode\_latest.tar.lz4](https://snapshots.mantrachain.io/mantra-1_goleveldb_fullnode_latest.tar.lz4) | | Archive | goleveldb | 10418948 | [https://snapshots.mantrachain.io/mantra-1\_goleveldb\_archive\_latest.tar.lz4](https://snapshots.mantrachain.io/mantra-1_goleveldb_archive_latest.tar.lz4) | ### Testnet (Mantra-Dukong-1) | Node type | Database type | Height | URL | | --------- | ------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Full node | pebbledb | 10188764 | [https://snapshots.mantrachain.io/mantra-dukong-1\_pebbledb\_fullnode\_latest.tar.lz4](https://snapshots.mantrachain.io/mantra-dukong-1_pebbledb_fullnode_latest.tar.lz4) | | Full node | goleveldb | 10188763 | [https://snapshots.mantrachain.io/mantra-dukong-1\_goleveldb\_fullnode\_latest.tar.lz4](https://snapshots.mantrachain.io/mantra-dukong-1_goleveldb_fullnode_latest.tar.lz4) | | Archive | goleveldb | 10064580 | [https://snapshots.mantrachain.io/mantra-dukong-1\_goleveldb\_archive\_latest.tar.lz4](https://snapshots.mantrachain.io/mantra-dukong-1_goleveldb_archive_latest.tar.lz4) | # null Source: https://docs.mantrachain.io/operators/node-setup-and-deployment/validator-nodes/initial-setup Running your own node provides you various benefits, opens new possibilities, and helps to support the ecosystem. This page will guide you through spinning up your own node and taking part. # Node Setup & Deployment We aim to achieve a diversified group of validator nodes and ecosystem infrastructure, allowing us to maintain the four "**MANTRAs**" of Platform Engineering: Availability, Scalability, Resiliency, and Performance. In the pages following - we will guide you on recommended deployment configurations and steps in order to ensure properly-functioning full, archive, and validator nodes on MANTRA Chain. # Node System Requirements ## Pre-Requisites You should understand what a blockchain node is and why you might want to run a client. This is covered in [.](./ "mention"). ## Selecting an Approach The first step in spinning up your node is choosing your approach. Based on requirements and various possibilities, you must select the environment (hardware, system), and the parameters for client settings. This page will guide you through these decisions and help you find the most suitable way to run on MANTRA Chain. ## Environment and hardware ### **Local or cloud** The MANTRA Chain binary is able to run on consumer grade systems and doesn't require any special hardware. Therefore, you have various options for deploying the node based on your needs. To simplify, let's think about running a node on both a local physical machine and a cloud server: * Cloud * Providers offer high server uptime and static public IP addresses * Getting dedicated or virtual server can be more comfortable than building your own * Trade off is trusting a third party - server provider * Because of the ever-increasing requirements for storage and memory, the price of a rented server might get high * Own hardware * More trust-less and sovereign approach * One time investment * You have to physically prepare, maintain, and potentially troubleshoot the machine and networking Both options have different advantages summed up above. If you are looking for a cloud solution, in addition to many traditional cloud computing providers, there are also services focused on deploying nodes. We are working to provide a selection of Nodes-as-a-Service in the future! ## **Hardware** ### **Requirements** Hardware requirements differ by client but generally are not that high since the node just needs to stay synced. Don't confuse it with mining, which requires much more computing power. Sync time and performance do improve with more powerful hardware however. Before installing any client, please ensure your computer has enough resources to run it. You can find the minimum and recommended requirements below. The bottleneck for your hardware is mostly disk space. It is best to have a **solid-state drive (SSD)** or **NVME drive**. The size of the database and speed of the initial synchronization depends on the age of the chain and the chosen sync strategy. Also make sure your internet connection is not limited by a [bandwidth cap](https://wikipedia.org/wiki/Data_cap). It's recommended to use an unmetered connection since initial sync and data broadcasted to the network could exceed your limit. ### **Operating system** The MANTRA Chain binary supports all major operating systems - Linux, MacOS, Windows as well as the two primary architecture to-date: AMD64 (also including Intel x86) and ARM64. Make sure your OS is up to date to avoid potential issues and security vulnerabilities. #### **Minimum requirements** * CPU with 4+ cores * 16 GB RAM * 500GB+ SSD, 5000+ IOPS * 25+ Mbps bandwidth **Recommended specifications (validators)** * Fast CPU with 4+ cores, ≥3.5 GHz base clock * 32 GB RAM * 2TB+ NVMe SSD, 10,000+ IOPS * 100+ Mbps stable connection Bare metal servers are recommended over cloud VMs for optimal validator performance. # null Source: https://docs.mantrachain.io/operators/node-setup-and-deployment/validator-nodes/oracle-setup # Connect sidecar ## Run Connect Sidecar Please find the connect binary or image based on your deployment preference From binary: [https://github.com/MANTRA-Chain/connect/releases/tag/v2.3.0-mantra-1.2](https://github.com/MANTRA-Chain/connect/releases/tag/v2.3.0-mantra-1.2)\ From image: [ghcr.io/mantra-chain/connect-sidecar:2.3.0-mantra-1.2](https://github.com/MANTRA-Chain/connect/pkgs/container/connect-sidecar/409228036?tag=2.3.0-mantra-1.2)\\ To run Connect, which starts the service on the default port of `8080`, enter the following command: ```shell theme={null} connect --market-map-endpoint=":" ``` If you are running connect and validator in the same server, it should be like ``` connect --market-map-endpoint=localhost:9090 ``` ### Verify Connect To verify Connect is working, run the following command: ```shell theme={null} curl 'http://localhost:8080/connect/oracle/v2/prices' | jq . ``` The output of the command should look similar to this: ```json theme={null} { "prices": { "ATOM/USD": "4308207537", "BTC/USD": "6693024042", "ETH/USD": "2602324302", "OM/USD": "1501599", "OSMO/USD": "53054083", "USDT/USD": "999750064", "USDY/USD": "1054483" }, "timestamp": "2024-10-17T12:09:39.899360574Z", "version": "v2.0.1" } ``` ## Update Validator Config[​](https://docs.skip.build/connect/validators/quickstart#run-application-node) In order for the application to get prices from Connect, we need to add the following lines under the `[oracle]` heading in the `app.toml`. Remember to change the `oracle_address` value to the address of your Connect sidecar. code title="app.toml" ```toml theme={null} [oracle] enabled = "true" # if you are not running a validator node, set this to "false" oracle_address = ":8080" # YOUR_CONNECT_SIDECAR should localhost if running on the same server as validator client_timeout = "2s" metrics_enabled = "true" price_ttl = "0s" interval = "1.5s" ``` Lastly, restart your validator.\ \ For more information, please check [https://docs.skip.build/connect/validators/quickstart#run-connect-sidecar](https://docs.skip.build/connect/validators/quickstart#run-connect-sidecar) # null Source: https://docs.mantrachain.io/operators/node-setup-and-deployment/validator-nodes/running-a-node In this section, the application we are running is called mantrachaind. We will walk through how to set up and configure the app - along with integrating the application as a system service. Recommended Readings * [Anatomy of a Cosmos SDK Application](https://docs.cosmos.network/main/learn/beginner/app-anatomy) * [Setting up a keyring](https://docs.cosmos.network/main/user/run-node/keyring) ## Download latest release Latest chain release binaries can be found on [GitHub Releases](https://github.com/MANTRA-Chain/mantrachain/releases). **Current Versions:** * **Mainnet (mantra-1)**: See [Chain Parameters](/resources/chain-parameters) for the latest mainnet version * **Testnet (mantra-dukong-1)**: Running latest release candidate for testing upcoming upgrades You can download the `mantrachaind` executable and place it in a standard binary folder, such as `/usr/local/bin/` or similar. Remember to make it executable by running `sudo chmod +x mantrachaind`. ### Binary Check Each `mantrachaind` binary is deployed with a corresponding .sha256 file that you can download, to verify the integrity of the build. Download the `sha256sum.txt` and verify the hash. **Build From Source** If you would like to build from source instead of using the release binary, you can compile and install the binary. [go](https://go.dev/dl/) will be needed for this install ```bash theme={null} make install ``` ## Initialize the Chain Before actually running the node, we need to initialize the chain, and most importantly its genesis file. This is done with the `init` subcommand: #### Public Testnet/Mainnet Chains We will have regularly updating public testnet chains along with our mainnet chain: `mantra-1`. Available networks to integrate with along with their requisite genesis files can be found [here](https://github.com/MANTRA-Chain/mantrachain/tree/main/networks). ``` mantrachaind init --chain-id ``` Arguments: * `moniker`: the custom username of your node, it should be human-readable. * `chain-id`: The id of an existing chain that you want to join. Examples: * Testnet: `mantra-dukong-1` * Mainnet: `mantra-1` \ The command above creates all the configuration files needed for your node to run, as well as a default genesis file, which defines the initial state of the network. Reminder to overwrite the default genesis if you're planning to exist to an existing chain!! **TIP** All these configuration files are in `~/.mantrachain` by default, but you can overwrite the location of this folder by passing the `--home` flag to each commands, or set an `$APPD_HOME` environment variable (where `APPD` is the name of the binary). The `~/.mantrachain` folder has the following structure: * `config.toml`: used to configure the CometBFT, learn more on [CometBFT's documentation](https://docs.cometbft.com/v0.37/core/configuration), * `app.toml`: generated by the Cosmos SDK, and used to configure your app, such as state pruning strategies, telemetry, gRPC and REST servers configuration, state sync... Both files are heavily commented, please refer to them directly to tweak your node. ``` . # ~/.mantrachain |- data # Contains the databases used by the node. |- config/ |- app.toml # Application-related configuration file. |- config.toml # CometBFT-related configuration file. |- genesis.json # The genesis file. |- node_key.json # Private key to use for node authentication in the p2p protocol. |- priv_validator_key.json # Private key to use as a validator in the consensus protocol. ``` ## Connect to existing chains #### I) Download the `genesis.json` In order to connect to an existing public chain, we need to reuse an existing `genesis.json` 1. Go to [MANTRA-Chain/net](https://github.com/MANTRA-Chain/net) repository 2. Download the `genesis.json` of the chain you want to connect to, and put it into `~/.mantrachain/config` #### II) Update configuration file 1. Install prerequisites tools before proceeding, ensure that `wget` is installed on your system, as it is required for running a Node. Having `wget` installed ensures seamless execution of the below script, allowing it to fetch necessary external resources without interruption. 2. Create a bash script with the following content: ```bash theme={null} #!/usr/bin/env bash CONFIG_TOML="$HOME/.mantrachain/config/config.toml" APP_TOML="$HOME/.mantrachain/config/app.toml" PERSISTENT_PEERS="" # Can be empty. Fill this one if you need to connect to particular peers SEEDS="" # configure minimum gas prices sed -i.bak -e "s/^minimum-gas-prices *=.*/minimum-gas-prices = \"0.01uom\"/g" $APP_TOML # enable the api server sed -i.bak '/\[api\]/,+3 s/enable = false/enable = true/' $APP_TOML # configure optimised peering configuration sed -i.bak -e "s/^persistent_peers *=.*/persistent_peers = \"$PERSISTENT_PEERS\"/" $CONFIG_TOML sed -i.bak -e "s/^seeds =.*/seeds = \"$SEEDS\"/" $CONFIG_TOML external_address=$(wget -qO- eth0.me) sed -i.bak -e "s/^external_address *=.*/external_address = \"$external_address:26656\"/" $CONFIG_TOML sed -i.bak -e "s/^filter_peers *=.*/filter_peers = \"true\"/" $CONFIG_TOML # expose monitoring metrics via prometheus sed -i.bak -e "s/^prometheus *=.*/prometheus = true/" $CONFIG_TOML ``` 3. Update the `SEEDS` environment variable Testnet (mantra-dukong-1): * `SEEDS="7e061edecef73a700b699c785f61a44ca981ff7f@34.150.103.79:26656"` Mainnet (mantra-1): * `SEEDS="32276da966637722914411e16ca91bd37dcd1c28@35.220.157.87:26656,9f5235b418c87af4302619705d0bf4748249ca6b@34.18.33.96:26656"` * Note: more seeds can be found at (Github)\[[https://github.com/cosmos/chain-registry/blob/master/mantrachain/chain.json](https://github.com/cosmos/chain-registry/blob/master/mantrachain/chain.json)] The seeds format is `node-id@ip:port,node-id@ip:port,...` 4. Run the script: `bash .sh` ## Optional: start from an existing snapshot When the node starts, it needs to sync all the data from other nodes, which could be time-consuming. In order to quicken the process, we are providing some existing data snapshots at [here](/operators/node-setup-and-deployment/validator-nodes/download-nodes-snapshots) **Warning**: If you are starting the node, please follow the procedure here in order to stop the current service and backup the important data: [https://www.polkachu.com/tendermint\_snapshots/mantra](https://www.polkachu.com/tendermint_snapshots/mantra) 1. Download the snapshot from: \ [here](/operators/node-setup-and-deployment/validator-nodes/download-nodes-snapshots) 2. Install lz4 1. Macos (homebrew) : `brew install lz4` 2. Linux: [more info here](https://www.tecmint.com/install-lz4-linux/) 3. Decompress the snapshot ```bash theme={null} lz4 -c -d .tar.lz4 | tar -x -C $HOME/.mantrachain ``` 5. Update the file `~/.mantrachain/config/config.toml` 1. Replace the value of `db_backend` by `pebbledb`, so it will looks like`db_backend = "pebbledb"` ## Testing the setup ```bash theme={null} mantrachaind start ``` This command will start the node, which will sync its local data from the existing nodes Wait for a few couple of seconds, and if you see the height growing: **success!** 🎉 ## Client Interaction[​](https://docs.cosmos.network/main/user/run-node/run-node#client-interaction) When instantiating a node, GRPC and REST are defaulted to localhost to avoid unknown exposure of your node to the public. It is recommended to not expose these endpoints without a proxy that can handle load balancing or authentication is setup between your node and the public. # null Source: https://docs.mantrachain.io/operators/node-setup-and-deployment/validator-nodes/secure-validator Validators are charged with protecting the network against denial-of-service attacks. A recommended strategy is to use a 'sentry node architecture.' ### **Sentry Node Protection** Sentry nodes, also known as relay nodes or gateway nodes, are an important component in the infrastructure of a blockchain network. They serve as intermediaries between the validator nodes and the rest of the network, providing enhanced security and network efficiency. * Validator nodes should only connect to trusted full-nodes. * Typically, a validator node will run in a data center, which often has direct links to major cloud providers. * Validators can use these links to connect to sentry nodes in the cloud, shifting the burden of attacks to the sentry nodes. * Sentry nodes can be quickly adjusted or created to fend off attacks. * The links to the sentry nodes are in private IP space, protecting them from internet-based disturbances. By using this architecture, validator block proposals and votes are ensured to reach the rest of the network, maintaining the stability and integrity of MANTRA Chain. ### **Key Management** Key management plays a crucial role in securing and controlling access to your accounts and assets. Some important aspects of key management are: 1. **Key Generation:** To interact with the MANTRA network, you need a cryptographic key pair consisting of a public key and a private key. The private key should be kept securely and should not be shared with anyone. 2. **Wallets and Key Storage:** Wallet applications or software provide a user-friendly interface for managing your keys and interacting with the network. These wallets often use secure storage mechanisms to protect your private keys, such as encrypted databases or hardware wallets. 3. **Backups and Recovery:** It's crucial to create backups of your private keys and store them securely. Losing access to your private key can result in permanent loss of funds or assets. You should follow best practices for backing up your keys, such as creating offline or encrypted backups, and storing them in multiple secure locations. 4. **Key Security:** Protecting your private key is paramount. Ensure that your devices, including computers and mobile devices, are secure, updated with the latest security patches, and free from malware or keyloggers. Be cautious when entering your private key, especially on shared or public computers. 5. **Key Sharing and Delegation:** In some cases, you may want to delegate your stake to a validator or authorize someone else to manage your assets on your behalf. It's important to exercise caution when sharing your private key or granting access to your accounts. 6. **Hardware Security Modules (HSMs):** HSMs provide dedicated hardware-based security measures and extra layers of protection against key theft or unauthorized access. Utilizing hardware security modules (HSMs) is a key strategy in safeguarding a validator's key and mitigating the risk of compromising the entire delegated stake, as it significantly reduces the likelihood of an attacker successfully stealing the key. # Getting Started Source: https://docs.mantrachain.io/operators/overview/getting-started Get started as an operator on MANTRA Chain Ensure your system meets these minimum requirements: * **CPU**: 4+ cores (≥3.5 GHz recommended for validators) * **RAM**: 16GB minimum (32GB recommended for validators) * **Storage**: 500GB+ SSD, 5000+ IOPS (2TB+ NVMe recommended for validators) * **Network**: 25+ Mbps (100+ Mbps recommended for validators) Bare metal servers are recommended over cloud VMs for optimal performance. See [Chain Parameters](/resources/chain-parameters#system-requirements) for detailed requirements. Follow our [Running a Node](/operators/node-setup-and-deployment/validator-nodes/running-a-node) guide to set up your MANTRA Chain full node. Operators can run various infrastructure components: * **Validators**: [Become a Validator](/operators/node-setup-and-deployment/validator-nodes/becoming-a-validator) to join the active set * **Oracles**: [Set up Oracle](/operators/node-setup-and-deployment/validator-nodes/oracle-setup) to provide price feeds * **For Relayers**: IBC and ICQ relayer documentation coming soon # What are Validator Nodes? Source: https://docs.mantrachain.io/operators/overview/what-are-validator-nodes Overview on how Validator Nodes and Delegated Proof-of-Stake works on MANTRA Chain # Validators & DPoS MANTRA Chain relies on a team of validators who are tasked with adding new blocks to the blockchain. Here's how the process works and some critical details about its structure: **Validators and Consensus Protocol:** Validators play a key role in the consensus protocol by casting votes, which include cryptographic signatures from their private keys. They are essentially responsible for confirming the transactions. **Bonding and Delegating Network Tokens:** Potential validators can bond their own tokens. Others can also stake, or 'delegate,' their tokens to these candidates. The validators are chosen based on the total number of tokens delegated to them. **Earning Tokens and Transaction Fees:** Both validators and their delegators earn tokens through block provisions and tokens through transaction fees. This is achieved by executing the Tendermint consensus protocol. Validators can even set a commission percentage on the fees to incentivize their delegators. **Overview of Validators:** You can find details about all current validators and their voting power on Mintscan. **Penalties for Misconduct:** If validators act inappropriately (e.g., double-signing or being offline too long), they and their delegators can face penalties. The severity of the penalty depends on the violation's seriousness. **Defending Against Attacks:** Validators are charged with protecting the network against denial-of-service attacks. A recommended strategy is to use a 'sentry node architecture.' **Sentry Node Architecture Explained:** * Validator nodes should only connect to trusted full-nodes. * Typically, a validator node will run in a data centre, which often has direct links to major cloud providers. * Validators can use these links to connect to sentry nodes in the cloud, shifting the burden of attacks to the sentry nodes. * Sentry nodes can be quickly adjusted or created to fend off attacks. * The links to the sentry nodes are in private IP space, protecting them from internet-based disturbances. By using this architecture, validator block proposals and votes are ensured to reach the rest of the network, maintaining the stability and integrity of MANTRA Chain. # Hyperlane Source: https://docs.mantrachain.io/resources/bridging/hyperlane Lock & mint bridging (recommended for larger transfers / market makers) Hyperlane is typically used for **lock & mint** style bridging routes. Bridging routes, token lists, and supported chains change frequently. Always confirm the latest information in the bridge UI. ## When to use Hyperlane * Larger transfers * Market makers / repeated bridging flows * When you want a more “canonical” lock & mint route ## What to do next * Start from the [Bridging overview](/resources/bridging/overview) # IBC (Cosmos → MANTRA) Source: https://docs.mantrachain.io/resources/bridging/ibc Minimal IBC guidance for bridging from Cosmos chains into MANTRA Chain Use IBC when bridging from **Cosmos chains** into MANTRA Chain. This page is intentionally minimal. For chain-specific channels, routes, and token denoms, use: `resources/network-details`, `resources/endpoints`, and `resources/chain-registry`. ## Checklist * Confirm the source chain supports IBC transfers * Confirm MANTRA Chain channel/route details in the chain registry * Send a small test transfer before moving larger amounts # Bridging overview Source: https://docs.mantrachain.io/resources/bridging/overview How to choose a bridge into MANTRA Chain (high-level decision guide) This section is a **high-level decision guide** for bridging assets into MANTRA Chain. Exact supported routes can change over time, so always cross-check the bridge UI for the latest networks and tokens. ## Which bridge should I use? * **Hyperlane (lock & mint)**: recommended for **market makers / larger transfers** * **Squid (liquidity routing)**: recommended for **smaller transfers** and convenience * **IBC (Cosmos → MANTRA)**: use when bridging from **Cosmos ecosystems** into MANTRA ## Next steps * Read [Hyperlane bridging](/resources/bridging/hyperlane) * Read [Squid bridging](/resources/bridging/squid) * Read [IBC bridging (Cosmos → MANTRA)](/resources/bridging/ibc) # Squid Source: https://docs.mantrachain.io/resources/bridging/squid Liquidity-based bridging (recommended for smaller, convenient transfers) Squid is typically used for **liquidity routing** bridging flows. Bridging routes, token lists, and supported chains change frequently. Always confirm the latest information in the bridge UI. ## When to use Squid * Smaller transfers * Convenience / best-effort routing where speed and UX matter ## What to do next * Start from the [Bridging overview](/resources/bridging/overview) # Canonical ERC-20 Contracts Source: https://docs.mantrachain.io/resources/canonical-token-contracts MANTRA Chain source of truth for which ERC-20 contracts should be trusted for major tokens. This page is the MANTRA Chain source of truth for **which ERC-20 contracts should be trusted** for major tokens. ## Mainnet | Token | Contract | Explorer | | --------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | | wOM | `0xE3047710EF6cB36Bcf1E58145529778eA7Cb5598` | [Blockscout](https://blockscout.mantrascan.io/token/0xE3047710EF6cB36Bcf1E58145529778eA7Cb5598?tab=holders) | | USDC | `0x5E76be0F4e09057D75140216F70fd4cE3365bb29` | [Blockscout](https://blockscout.mantrascan.io/token/0x5E76be0F4e09057D75140216F70fd4cE3365bb29?tab=holders) | | USDT | `0x3806640578b710d8480910bF51510bc538d2F51A` | [Blockscout](https://blockscout.mantrascan.io/address/0x3806640578b710d8480910bF51510bc538d2F51A) | | mantraUSD | `0xd2b95283011E47257917770D28Bb3EE44c849f6F` | [Blockscout](https://blockscout.mantrascan.io/address/0xd2b95283011E47257917770D28Bb3EE44c849f6F?tab=contract_code) | | wBTC | `0xABb5E5b46112Ca652481d1117459dc289a1Ee282` | [Blockscout](https://blockscout.mantrascan.io/address/0xABb5E5b46112Ca652481d1117459dc289a1Ee282) | | wETH | `0xa901E6974C8F0fCc2f44451B0e788CD6957E02E2` | [Blockscout](https://blockscout.mantrascan.io/address/0xa901E6974C8F0fCc2f44451B0e788CD6957E02E2) | | HYPE | `0x2d01885f395186903ac76D0C67b94f1F8BcE6727` | [Blockscout](https://blockscout.mantrascan.io/address/0x2d01885f395186903ac76D0C67b94f1F8BcE6727) | ## Testnet | Token | Contract | Explorer | | --------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | | wOM | `0x10d26F0491fA11c5853ED7C1f9817b098317DC46` | [Blockscout](https://explorer.dukong.io/token/0x10d26F0491fA11c5853ED7C1f9817b098317DC46?tab=contract) | | USDC | `0x49b163c575948F0b95e0c459C301995147f27866` | [Blockscout](https://explorer.dukong.io/address/0x49b163c575948f0b95e0c459c301995147f27866?tab=read_write_contract) | | USDT | `0x21E56013a76a7F1F86cF7ee95c0a5670C7b7e44D` | [Blockscout](https://explorer.dukong.io/address/0x21e56013a76a7f1f86cf7ee95c0a5670c7b7e44d?tab=read_write_contract) | | mantraUSD | `0x4B545d0758eda6601B051259bD977125fbdA7ba2` | [Blockscout](https://explorer.dukong.io/address/0x4b545d0758eda6601b051259bd977125fbda7ba2?tab=read_write_contract) | # Chain Parameters Source: https://docs.mantrachain.io/resources/chain-parameters MANTRA Chain parameters and configurations ## Token Denominations **Understanding Denoms:** * **Mainnet** uses `uom` (micro-OM): 1 OM = 1,000,000 uom * **Testnet** uses `amantra` (atto-MANTRA): 1 MANTRA = 10^18 amantra The testnet uses a different denomination for clear separation between test and production tokens. When developing, ensure you're using the correct denom for your target network. ## Mainnet (mantra-1) Below are the current parameters for the `mantra-1` mainnet chain: | Name | Value | | ------------------ | --------------------------- | | chain-id | `mantra-1` | | denom | `uom` | | minimum-gas-prices | `0.01uom` | | timeout\_commit | `3s` | | genesis\_time | `2024-10-10T19:30:00+08:00` | ## Binary Information The release binary information is provided below: | Item | Description | | -------------- | ----------------------------------------------------------------------- | | GitHub repo | [MANTRA-Chain/mantrachain](https://github.com/MANTRA-Chain/mantrachain) | | Latest release | \[v6.1.3] | ## Genesis File The genesis file information is provided below: | Item | Description | | ------- | -------------------------------------------------------------------------------------------------------- | | Genesis | [genesis.json](https://raw.githubusercontent.com/MANTRA-Chain/net/refs/heads/main/mantra-1/genesis.json) | ## DuKong Testnet (mantra-dukong-1) Below are the current parameters for the `mantra-dukong-1` testnet chain: | Name | Value | | ------------------ | --------------------------- | | chain-id | `mantra-dukong-1` | | denom | `aMANTRA` | | minimum-gas-prices | `40000000000amantra` | | timeout\_commit | `3s` | | genesis\_time | `2024-10-07T23:15:00+08:00` | ## Binary Information The testnet is running the latest release candidate and is used for testing prior to mainnet upgrades. The release binary information is provided below: | Item | Description | | :------------- | :---------------------------------------------------------------------- | | GitHub repo | [MANTRA-Chain/mantrachain](https://github.com/MANTRA-Chain/mantrachain) | | Latest release | \[v7.0.0-rc3] | ## Genesis File The genesis file information is provided below: | Item | Description | | :------ | :-------------------------------------------------------------------------------------------------------------- | | Genesis | [genesis.json](https://raw.githubusercontent.com/MANTRA-Chain/net/refs/heads/main/mantra-dukong-1/genesis.json) | ## System Requirements ### Minimum Requirements | Component | Specification | | --------- | ---------------------- | | CPU | 4+ cores | | RAM | 16 GB | | Storage | 500GB+ SSD, 5000+ IOPS | | Network | 25+ Mbps | | OS | Ubuntu 20.04+ or macOS | ### Recommended (Validators) | Component | Specification | | --------- | ----------------------------- | | CPU | 4+ cores, ≥3.5 GHz base clock | | RAM | 32 GB | | Storage | 2TB+ NVMe SSD, 10,000+ IOPS | | Network | 100+ Mbps stable connection | | OS | Ubuntu 20.04+ | Bare metal servers are recommended over cloud VMs for optimal validator performance. ### Building from Source * Go 1.23.x required for building from source # Chain Registry Source: https://docs.mantrachain.io/resources/chain-registry Information about MANTRA Chain in the Cosmos Chain Registry MANTRA Chain is registered in the [Cosmos Chain Registry](https://github.com/cosmos/chain-registry), providing standardized information about the chain for wallets, explorers, and tools in the Cosmos ecosystem. ## Registry Information | Resource | URL | | ------------------ | -------------------------------------------------------------------------------------------------------- | | Chain Registry | [chains.cosmos.directory/mantrachain](https://chains.cosmos.directory/mantrachain) | | Chain.json | [chains.cosmos.directory/mantrachain/chain](https://chains.cosmos.directory/mantrachain/chain) | | Assetlist | [chains.cosmos.directory/mantrachain/assetlist](https://chains.cosmos.directory/mantrachain/assetlist) | | Validator Registry | [validators.cosmos.directory/chains/mantrachain](https://validators.cosmos.directory/chains/mantrachain) | ## Chain Configuration | Item | Value | | -------------- | -------------------- | | Chain ID | `mantra-1` | | Bech32 Prefix | `mantra` | | Slip44 | `60` | | Key Algorithms | `eth_secp256k1` | | Daemon Name | `mantrachaind` | | Node Home | `$HOME/.mantrachain` | ## Native Assets | Symbol | Description | Type | | ------ | --------------------------- | ------ | | OM | MANTRA Chain's native token | Native | ## Fee Tokens MANTRA Chain supports the following tokens for paying transaction fees: ```json theme={null} [ "uom" ] ``` ## Chain Registry JSON Below is a simplified version of the chain.json information. For the full and most up-to-date version, refer to the [Cosmos Chain Registry repository](https://github.com/cosmos/chain-registry/blob/master/mantrachain/chain.json). ```json theme={null} { "$schema": "../chain.schema.json", "chain_name": "mantrachain", "status": "live", "network_type": "mainnet", "pretty_name": "MANTRA", "chain_type": "cosmos", "chain_id": "mantra-1", "bech32_prefix": "mantra", "daemon_name": "mantrachaind", "node_home": "$HOME/.mantrachain", "key_algos": [ "ethsecp256k1" ], "extra_codecs": [ "ethermint" ], "slip44": 60, "fees": { "fee_tokens": [ { "denom": "uom", "fixed_min_gas_price": 0.01, "low_gas_price": 0.01, "average_gas_price": 0.01, "high_gas_price": 0.03 } ] }, "staking": { "staking_tokens": [ { "denom": "uom" } ], "lock_duration": { "time": "691200s" } }, "codebase": { "git_repo": "https://github.com/MANTRA-Chain/mantrachain", "recommended_version": "v6.1.3", "compatible_versions": [ "v6.1.0", "v6.1.1", "v6.1.2", "v6.1.3" ], "consensus": { "type": "cometbft", "version": "v0.38.19" }, "sdk": { "type": "cosmos", "version": "v0.53.4", "repo": "https://github.com/MANTRA-Chain/cosmos-sdk", "tag": "v0.53.4-mantra" }, "cosmwasm": { "version": "v0.61.1", "enabled": true }, "ibc": { "type": "go", "version": "v10.4.0" }, "genesis": { "genesis_url": "https://raw.githubusercontent.com/MANTRA-Chain/net/refs/heads/main/mantra-1/genesis.json" } }, "peers": { "seeds": [ { "id": "32276da966637722914411e16ca91bd37dcd1c28", "address": "35.220.157.87:26656" }, { "id": "9f5235b418c87af4302619705d0bf4748249ca6b", "address": "34.18.33.96:26656" }, { "id": "b0acfd505bb4bc0c39d095663d310c253de18210", "address": "34.130.121.222:26656" }, { "id": "f153213f0fe5d3cbe6e1f75d7ac0b4a27e70d31b", "address": "seed-mantra.r93axnodes.cloud:13156" }, { "id": "ebc272824924ea1a27ea3183dd0b9ba713494f83", "address": "mantrachain-mainnet-seed.autostake.com:27536", "provider": "AutoStake 🛡️ Slash Protected" }, { "id": "8542cd7e6bf9d260fef543bc49e59be5a3fa9074", "address": "seed.publicnode.com:26656", "provider": "Allnodes ⚡️ Nodes & Staking" }, { "id": "16ab08754dd0dc8b4d9202db16cb354ff618e3d9", "address": "mantra-mainnet-seed.itrocket.net:22656", "provider": "ITRocket" } ], "persistent_peers": [ { "id": "ebc272824924ea1a27ea3183dd0b9ba713494f83", "address": "mantrachain-mainnet-peer.autostake.com:27536", "provider": "AutoStake 🛡️ Slash Protected" }, { "id": "5cb41a850a2d41a28ff908e0e984a2a8deb7498a", "address": "mantra-mainnet-peer.itrocket.net:22656", "provider": "ITRocket" }, { "id": "0e7fddfd9a398dbda4f7773a00ea377304a03527", "address": "mantra-m.peer.stavr.tech:36056", "provider": "🔥STAVR🔥" } ] }, "apis": { "rpc": [ { "address": "https://rpc.mantrachain.io", "provider": "MANTRACHAIN" }, { "address": "https://mantra-mainnet-rpc.itrocket.net:443", "provider": "ITRocket" }, { "address": "https://mantra.rpc.m.stavr.tech", "provider": "🔥STAVR🔥" } ], "rest": [ { "address": "https://api.mantrachain.io", "provider": "MANTRACHAIN" }, { "address": "https://mantra-mainnet-api.itrocket.net", "provider": "ITRocket" }, { "address": "https://mantra.api.m.stavr.tech", "provider": "🔥STAVR🔥" } ], "grpc": [ { "address": "https://grpc.mantrachain.io", "provider": "MANTRACHAIN" }, { "address": "mantra-mainnet-grpc.itrocket.net:443", "provider": "ITRocket" }, { "address": "mantra.grpc.m.stavr.tech:3601", "provider": "🔥STAVR🔥" } ], "evm-http-jsonrpc": [ { "address": "https://evm.mantrachain.io", "provider": "MANTRACHAIN" } ] }, "logo_URIs": { "png": "https://raw.githubusercontent.com/cosmos/chain-registry/master/mantrachain/images/OM-Prim-Col.png", "svg": "https://raw.githubusercontent.com/cosmos/chain-registry/master/mantrachain/images/OM-Prim-Col.svg" }, "explorers": [ { "kind": "Chainroot", "url": "https://explorer.chainroot.io/mantra", "tx_page": "https://explorer.chainroot.io/mantra/transactions/${txHash}", "account_page": "https://explorer.chainroot.io/mantra/accounts/${accountAddress}" }, { "kind": "mintscan", "url": "https://www.mintscan.io/mantra", "tx_page": "https://mintscan.io/mantra/txs/${txHash}", "account_page": "https://mintscan.io/mantra/account/${accountAddress}" }, { "kind": "ITRocket", "url": "https://mainnet.itrocket.net/mantra", "tx_page": "https://mainnet.itrocket.net/mantra/transaction/${txHash}", "account_page": "https://mainnet.itrocket.net/mantra/account/${accountAddress}" }, { "kind": "mantrascan", "url": "https://mantrascan.io/mainnet", "tx_page": "https://mantrascan.io/mainnet/tx/${txHash}", "account_page": "https://mantrascan.io/mainnet/address/${accountAddress}" }, { "kind": "🔥STAVR🔥", "url": "https://explorer.stavr.tech/Mantra-Mainnet", "tx_page": "https://explorer.stavr.tech/Mantra-Mainnet/transaction/${txHash}", "account_page": "https://explorer.stavr.tech/Mantra-Mainnet/account/${accountAddress}" } ], "keywords": [ "rwa", "wasm", "evm", "staking" ], "images": [ { "image_sync": { "chain_name": "mantrachain", "base_denom": "uom" }, "png": "https://raw.githubusercontent.com/cosmos/chain-registry/master/mantrachain/images/OM-Prim-Col.png", "svg": "https://raw.githubusercontent.com/cosmos/chain-registry/master/mantrachain/images/OM-Prim-Col.svg", "theme": { "circle": true } } ] } ``` ## Using Chain Registry Information Chain Registry information can be used to: 1. Configure wallets to support MANTRA Chain 2. Set up nodes with correct parameters 3. Integrate MANTRA Chain into ecosystem tools and explorers 4. Access standardized information about IBC connections For developers building on MANTRA Chain, this information is essential for ensuring compatibility with ecosystem tools. # Mainnet Contracts Source: https://docs.mantrachain.io/resources/contracts/mainnet Deployed protocol contract addresses for MANTRA mainnet (mantra-1) This page lists contract deployments for MANTRA mainnet. ## QuickSwap (Algebra V4) QuickSwap on MANTRA is powered by Algebra Protocol V4, a concentrated liquidity DEX. These are the deployed EVM contract addresses. ### Core Contracts | Contract | Address | | ----------------------- | -------------------------------------------- | | AlgebraPoolDeployer | `0xd7cB0E0692f2D55A17bA81c1fE5501D66774fC4A` | | AlgebraFactory | `0x10253594A832f967994b44f33411940533302ACb` | | AlgebraCommunityVault | `0x4439199c3743161ca22bB8F8B6deC5bF6fF65b04` | | AlgebraVaultFactoryStub | `0x955B95b8532fe75DDCf2161f61127Be74A768158` | | PluginFactory | `0xFe3BEcd788320465ab649015F34F7771220A88b2` | ### Periphery Contracts | Contract | Address | | ---------------------------------- | -------------------------------------------- | | SwapRouter | `0x3012E9049d05B4B5369D690114D5A5861EbB85cb` | | NonfungiblePositionManager | `0x69D57B9D705eaD73a5d2f2476C30c55bD755cc2F` | | NonfungibleTokenPositionDescriptor | `0xD637cbc214Bc3dD354aBb309f4fE717ffdD0B28C` | | Proxy | `0x6AD6A4f233F1E33613e996CCc17409B93fF8bf5f` | | Quoter | `0x03f8B4b140249Dc7B2503C928E7258CCe1d91F1A` | | QuoterV2 | `0xa77aD9f635a3FB3bCCC5E6d1A87cB269746Aba17` | ### Farming Contracts | Contract | Address | | --------------------- | -------------------------------------------- | | AlgebraEternalFarming | `0x50FCbF85d23aF7C91f94842FeCd83d16665d27bA` | | FarmingCenter | `0x658E287E9C820484f5808f687dC4863B552de37D` | ### Utility Contracts | Contract | Address | | ------------------------- | -------------------------------------------- | | EntryPoint | `0x4A3BC48C156384f9564Fd65A53a2f3D534D8f2b7` | | TickLens | `0x13fcE0acbe6Fb11641ab753212550574CaD31415` | | AlgebraInterfaceMulticall | `0xB4F9b6b019E75CBe51af4425b2Fc12797e2Ee2a1` | *** ## MANTRA DEX (CosmWasm) These are CosmWasm contract deployments for the native MANTRA DEX. | Contract | Code ID | Address | | ------------- | ------- | ------------------------------------------------------------------- | | Fee Collector | `5` | `mantra1ufs3tlq4umljk0qfe8k5ya0x6hpavn897u2cnf9k0en9jr7qarqq4ha9c7` | | Pool Manager | `34` | `mantra1466nf3zuxpya8q9emxukd7vftaf6h4psr0a07srl5zw74zh84yjqagspfm` | For detailed MANTRA DEX contract documentation including Epoch Manager and Farm Manager, see [MANTRA DEX](/resources/contracts/mantra-dex). # MANTRA Claimdrop Source: https://docs.mantrachain.io/resources/contracts/mantra-claimdrop Claimdrop contract overview and references MANTRA Claimdrop is a smart contract system used to **distribute tokens to a set of recipients** (e.g., airdrops) in a controlled way. ## Versions * **V1**: Merkle-tree based distribution (proof-based claims). * **V2**: Batch-upload allocations + authorized wallets (allowlist) for admin operations. ## Legacy docs (source) This content was previously documented in GitBook and is the current source we used to restore these pages: * **Claimdrop Contract V1**: `_tmp_gitbook/mantra-smart-contracts/claimdrop_contract_v1.md` * **Claimdrop Contract V2**: `_tmp_gitbook/mantra-smart-contracts/claimdrop_contract_v2.md` ## Contract reference * [Claimdrop V1 reference](/resources/contracts/mantra-claimdrop-v1) * [Claimdrop V2 reference](/resources/contracts/mantra-claimdrop-v2) ## Deployments See: * `resources/contracts/mainnet` for mainnet code IDs (and any published addresses) * `resources/contracts/testnet` for testnet deployment addresses (when available) # Claimdrop V1 Source: https://docs.mantrachain.io/resources/contracts/mantra-claimdrop-v1 Merkle-proof based token distribution contract The Claimdrop Contract V1 distributes tokens to recipients using a **Merkle tree** (proof-based claims). The Merkle root is stored on the campaign and used to verify proofs submitted by recipients. ## Features * Merkle-tree based distribution * Lump sum and/or linear vesting distribution (two distribution types can be used simultaneously) * Linear vesting may include an optional cliff * One campaign per contract * Campaign can be closed to retrieve unclaimed funds and restart with a new contract/campaign ## Generating airdrop data You can generate the merkle root and proofs using the JS scripts in the contract repository. 1. Prepare a CSV file (header required) with columns: `contract_addr,address,amount`. ```csv theme={null} contract_addr,address,amount mantra1j28m8g0afvfr23423k5wypfykqrxsu94xhxvxdeyrfc4jkqm7zhqckdf5w,mantra1x5nk33zpglp4ge6q9a8xx3zceqf4g8nvaggjmc,100 mantra1j28m8g0afvfr23423k5wypfykqrxsu94xhxvxdeyrfc4jkqm7zhqckdf5w,mantra1rj2n3hge32n5u6zzw0u7clrys76srapulsvv39,200 mantra1j28m8g0afvfr23423k5wypfykqrxsu94xhxvxdeyrfc4jkqm7zhqckdf5w,mantra18mv5sz7nj2arpsqjc2aeslhh3v475np8ng6tt5,300 mantra1j28m8g0afvfr23423k5wypfykqrxsu94xhxvxdeyrfc4jkqm7zhqckdf5w,mantra16qtk5fnm4se6362yaah0scdmatx0qvp70fhej2,400 ``` 2. Generate: * `node merkle_root.js` → generates the merkle root * `node merkle_proof.js` → generates the proofs Only a single claim entry per address should exist in the CSV. If an address has multiple entries, consolidate them first. ## How it works * Contract owner can create a campaign (optionally appointing a different campaign owner). * Campaign owner can top up a campaign before it ends. * Users claim by submitting a **valid Merkle proof**. * Contract owner or campaign owner can close a campaign, returning unclaimed funds to the campaign owner. ## Instantiate ```json theme={null} { "owner": "mantra1..." } ``` | Key | Type | Description | | ------- | ---------------- | -------------------------------------------------------------------- | | `owner` | `Option` | Contract owner. If omitted, the instantiating address becomes owner. | ## ExecuteMsg ### ManageCampaign Actions: * **CreateCampaign**: create a new campaign (contract owner only) * **TopUpCampaign**: add funds (campaign owner only) * **CloseCampaign**: close and refund remaining funds (contract owner or campaign owner) #### CreateCampaign ```json theme={null} { "manage_campaign": { "action": { "create_campaign": { "params": { "owner": "mantra1...", "name": "Airdrop", "description": "This is an airdrop description.", "reward_asset": { "denom": "uom", "amount": "888888888888" }, "distribution_type": [ { "lump_sum": { "percentage": "0.25", "start_time": 1571797419 } }, { "linear_vesting": { "percentage": "0.75", "start_time": 1572402219, "end_time": 1573007019, "cliff_duration": 86400 } } ], "start_time": 1571797419, "end_time": 1573007019, "merkle_root": "b32b978b07b56e8f10de1f098390407017daa61c90da6a6875ca0f2d655b6107" } } } } } ``` The `reward_asset` must be sent with this transaction. #### TopUpCampaign ```json theme={null} { "manage_campaign": { "action": { "top_up_campaign": {} } } } ``` Send the same denom as `reward_asset`. You can’t top up a closed campaign. #### CloseCampaign ```json theme={null} { "manage_campaign": { "action": { "close_campaign": {} } } } ``` ### Claim ```json theme={null} { "claim": { "total_claimable_amount": "88888", "receiver": "mantra1...", "proof": [ "1b20d6e1fa2e464d3a94fabdf28add25b6152663aa19efe1b6da2f28f50412cd", "27c16d1dd47dedab5c9d394d02b507e3abd01ef11f753ffc3148b04bd1aa0487" ] } } ``` ## QueryMsg ### Campaign ```json theme={null} { "campaign": {} } ``` ### Rewards ```json theme={null} { "rewards": { "total_claimable_amount": "8888", "receiver": "mantra1...", "proof": [ "1b20d6e1fa2e464d3a94fabdf28add25b6152663aa19efe1b6da2f28f50412cd", "27c16d1dd47dedab5c9d394d02b507e3abd01ef11f753ffc3148b04bd1aa0487" ] } } ``` ### Claimed ```json theme={null} { "claimed": { "address": "mantra1...", "start_from": "mantra1...", "limit": 50 } } ``` # Claimdrop V2 Source: https://docs.mantrachain.io/resources/contracts/mantra-claimdrop-v2 Batch allocations + authorized wallets (allowlist) token distribution contract Claimdrop Contract V2 distributes tokens to a list of addresses using **batch uploaded allocations** (rather than Merkle proofs), and introduces an **authorized wallet (allowlist)** model for admin actions. This page is adapted from the legacy GitBook source: `_tmp_gitbook/mantra-smart-contracts/claimdrop_contract_v2.md`. ## Features * Batch upload allocations (only before campaign starts) * Lump sum and/or linear vesting distribution (both can be used simultaneously) * One campaign per contract * Owner-only campaign creation * Anyone can top up campaign by sending funds (via `BankMsg`) * Owner can close campaign at any time before it ends (refunds remaining tokens) * Single claim entry per address * Address replacement and removal in allocation registry * Blacklist addresses (cannot claim) * Authorized wallet management (allowlist) * Partial claims supported ## How it works * Each contract hosts a **single campaign**. * The **owner** (and authorized wallets) can perform admin actions like creating/closing campaigns, managing allocations, and blacklisting. * The **owner** is the only actor that can manage the allowlist itself. ## Instantiate (example) ```json theme={null} { "owner": "mantra1...", "action": { "create_campaign": { "params": { "name": "Airdrop", "description": "This is an airdrop description.", "type": "Campaign label", "reward_denom": "uom", "total_reward": { "denom": "uom", "amount": "888888888888" }, "distribution_type": [ { "lump_sum": { "percentage": "0.25", "start_time": 1571797419 } }, { "linear_vesting": { "percentage": "0.75", "start_time": 1572402219, "end_time": 1573007019, "cliff_duration": 86400 } } ], "start_time": 1571797419, "end_time": 1573007019 } } } } ``` If you create a campaign during instantiation, the `total_reward` must be provided with the instantiation transaction. ## ExecuteMsg (high-level) * `ManageCampaign` (create / close) * `Claim` * `AddAllocations` * `ReplaceAddress` * `RemoveAddress` * `BlacklistAddress` * `ManageAuthorizedWallets` * `UpdateOwnership` (cw\_ownable) ### Claim (example) ```json theme={null} { "claim": { "receiver": "mantra1...", "amount": "88888" } } ``` ### AddAllocations (example) ```json theme={null} { "add_allocations": { "allocations": [ ["mantra1...", "100000"], ["mantra1...", "200000"] ] } } ``` ## QueryMsg (high-level) * `Campaign` * `Rewards` * `Claimed` * `Allocations` * `IsBlacklisted` * `IsAuthorized` * `AuthorizedWallets` * `Ownership` (cw\_ownable) ## Deployments See: * `resources/contracts/mainnet` * `resources/contracts/testnet` # MANTRA Dex Source: https://docs.mantrachain.io/resources/contracts/mantra-dex MANTRA Swap is a decentralized exchange (DEX) protocol that allows for permissionless pool and farm creation. The protocol is built around singleton contracts, which makes it easier to manage and integrate with other protocols. MANTRA Swap is based on [White Whale V2](https://github.com/White-Whale-Defi-Platform/white-whale-core). The following is the architecture of MANTRA Swap, and a general description of each contract: ## MANTRA Swap ```mermaid theme={null} flowchart P[Pool Manager] <--> I[Farm Manager] P -.->|swap fees| P P -->|protocol fees| F[Fee Collector] I <--> E[Epoch Manager] I -->|protocol fees| F ``` The direction of the arrows represents the dependencies between the contracts. ### Pool Manager The Pool Manager is the contract that manages the pools in MANTRA Swap. It is responsible for creating pool and handling swaps. Pool creation is permisionless, meaning anyone can create a pool if the fee is paid. The Pool Manager depends on the Farm Manager and the Fee Collector. **Reference:** [Pool Manager](/resources/contracts/mantra-dex/pool-manager) ### Farm Manager The Farm Manager is the contract that manages the farms in the protocol. It is responsible for creating and distributing farms on pools. Farm creation is permissionless, meaning anyone can create a farm if the fee is paid. The Farm Manager depends on the Epoch Manager, as farm rewards are distributed based on epochs. **Reference:** [Farm Manager](/resources/contracts/mantra-dex/farm-manager) ### Fee Collector The Fee Collector collects the fees accrued by the protocol. Whenever a pool or a farm is created, a fee is sent to the Fee Collector. As of now, the Fee Collector does not have any other function. **Reference:** [Fee Collector](/resources/contracts/mantra-dex/fee-collector) ### Epoch Manager The Epoch Manager is the contract that manages the epochs in the protocol. Its single responsibility is to be the clock of the system, which is used by the Farm Manager for distributing farm rewards. **Reference:** [Epoch Manager](/resources/contracts/mantra-dex/epoch-manager) ## Instantiation Based on the dependencies between the contracts, the instantiation of the contracts follows the following order: * Epoch Manager * Fee Collector * Farm Manager * Pool Manager Note: **Since there's a circular dependency between the Farm Manager and the Pool Manager, instantiate the Farm Manager by passing an empty address as the pool manager and once the contract is instantiated, invoke the UpdateConfig message with the right value (unless created with instantiate2)**. # Epoch Manager Source: https://docs.mantrachain.io/resources/contracts/mantra-dex/epoch-manager Epoch clock contract used by MANTRA DEX (MANTRA Swap) The Epoch Manager acts as a clock for other contracts (notably the Farm Manager) by defining epochs that are derived from a genesis epoch and a duration. An **epoch** is a period of time defined by `EpochConfig.duration`. ## Instantiate ```json theme={null} { "owner": "mantra1...", "epoch_config": { "duration": "86400", "genesis_epoch": "1571797" } } ``` | Key | Type | Description | | -------------- | ----------- | -------------------- | | `owner` | String | Contract owner. | | `epoch_config` | EpochConfig | Epoch configuration. | ## ExecuteMsg ### UpdateConfig ```json theme={null} { "update_config": { "epoch_config": { "duration": "86400", "genesis_epoch": "1571797" } } } ``` ### UpdateOwnership (::cw\_ownable) This is a `cw_ownable` message. ## QueryMsg ### Config ```json theme={null} { "config": {} } ``` ### CurrentEpoch ```json theme={null} { "current_epoch": {} } ``` ### Epoch ```json theme={null} { "epoch": { "id": 100 } } ``` ### Ownership (::cw\_ownable) This is a `cw_ownable` query. ```json theme={null} { "ownership": {} } ``` ## MigrateMsg ```json theme={null} {} ``` # Farm Manager Source: https://docs.mantrachain.io/resources/contracts/mantra-dex/farm-manager Farms, positions, and reward distribution for MANTRA DEX (MANTRA Swap) The Farm Manager is a monolithic contract that handles all farms-related logic for pools. ## How it works The Farm Manager has two main concepts: * **Farm**: a reward to be distributed * **Position**: a user's liquidity in a pool, locked in the contract Users can optionally lock LP shares when providing liquidity; those shares are managed by the Farm Manager. ### Farms Farms are permissionless and can be perpetual (expanded forever). Identifiers: * Auto-generated farms: `f-` * Custom farms: `m-` #### Topping up a farm Farm owner calls `ManageFarm` with `Fill`. Farm can only be topped up with the same reward token, and the amount must be a multiple of the original reward amount. Farms expire after `farm_expiration_time` has passed since farm end; expired farms can’t be expanded and may be auto-closed. #### Closing a farm Farm owner or contract owner calls `ManageFarm` with `Close`. #### Reward distribution Rewards distribute every epoch. The emission rate is tokens per epoch. $$ \\text{user rewards} = \\sum_{lp=a}^{N_{denoms}} \\sum_{f=b}^{N_{farms}} \\sum_{e=start}^{current} \\frac{u\\,lpw_e}{t\\,lpw_e} \\cdot r_e $$ If a user has pending rewards when a farm is closed, they may lose the ability to claim those tokens (unclaimed tokens are reimbursed to the farm owner). ### Positions Positions can be created, expanded, closed, and withdrawn via `ManagePosition`. Identifiers: * Auto-generated positions: `p-` * Custom positions: `u-` Unlocking duration determines position weight (and rewards). One day ≈ 1x; max 365 days ≈ 16x. Unlocking duration is how long you must wait after calling `Close` to be able to withdraw. It is not the same as “how long LP is locked for farming”. #### Withdrawing and emergency unlock You can withdraw after the unlocking duration passes. You can also emergency withdraw immediately (penalty applies; part goes to farm owners, part to Fee Collector). Emergency unlock renounces unclaimed rewards for that position. ## Instantiate ```json theme={null} { "owner": "mantra1...", "epoch_manager_addr": "mantra1...", "fee_collector_addr": "mantra1...", "pool_manager_addr": "mantra1...", "create_farm_fee": { "denom": "uom", "amount": "1000000000" }, "max_concurrent_farms": 7, "max_farm_epoch_buffer": 14, "min_unlocking_duration": 86400, "max_unlocking_duration": 31536000, "farm_expiration_time": 2629746, "emergency_unlock_penalty": "0.01" } ``` ## ExecuteMsg ### ManageFarm Actions: * **Fill**: create or expand a farm * **Close**: close a farm #### Fill (example) ```json theme={null} { "manage_farm": { "action": { "fill": { "params": { "lp_denom": "factory/mantra1.../LP", "start_epoch": 10, "preliminary_end_epoch": 24, "curve": "linear", "farm_asset": { "denom": "uom", "amount": "1000000000" }, "farm_identifier": "farm_identifier" } } } } } ``` #### Close (example) ```json theme={null} { "manage_farm": { "action": { "close": { "farm_identifier": "farm_identifier" } } } } ``` ### ManagePosition Actions: Create / Expand / Close / Withdraw #### Create (example) ```json theme={null} { "manage_position": { "action": { "create": { "identifier": "position_identifier", "unlocking_duration": 86400, "receiver": "mantra1..." } } } } ``` #### Expand (example) ```json theme={null} { "manage_position": { "action": { "expand": { "identifier": "position_identifier" } } } } ``` #### Close (example) ```json theme={null} { "manage_position": { "action": { "close": { "identifier": "position_identifier", "lp_asset": { "denom": "factory/mantra1.../LP", "amount": "1000000000" } } } } } ``` #### Withdraw (example) ```json theme={null} { "manage_position": { "action": { "withdraw": { "identifier": "position_identifier", "emergency_unlock": true } } } } ``` ### Claim ```json theme={null} { "claim": {} } ``` ### UpdateConfig ```json theme={null} { "update_config": { "fee_collector_addr": "mantra1...", "epoch_manager_addr": "mantra1...", "pool_manager_addr": "mantra1...", "create_farm_fee": { "denom": "uom", "amount": "1000000000" }, "max_concurrent_farms": 7, "max_farm_epoch_buffer": 14, "min_unlocking_duration": 86400, "max_unlocking_duration": 31536000, "farm_expiration_time": 2629746, "emergency_unlock_penalty": "0.01" } } ``` ### UpdateOwnership (::cw\_ownable) This is a `cw_ownable` message. ## QueryMsg ### Config ```json theme={null} { "config": {} } ``` ### Farms / Positions / Rewards / LpWeight / Ownership This page preserves the legacy schema and examples. For additional example payloads and response shapes, see: * `_tmp_gitbook/mantra-smart-contracts/mantra-swap/farm-manager.md` ## MigrateMsg ```json theme={null} {} ``` # Fee Collector Source: https://docs.mantrachain.io/resources/contracts/mantra-dex/fee-collector Protocol fee collection for MANTRA DEX (MANTRA Swap) The Fee Collector collects fees accrued by the protocol. When pools or farms are created (and for certain operations like swaps/emergency unlock), fees are routed to this contract. ```mermaid theme={null} graph LR A[Pool Manager] --> B[Create Pool] A --> D[Perform Swap] H[Farm Manager] --> I[Create farm] H --> L[User emergency withdraw] B --> J{Fee Collected} J --> K[Fee Collector] D --> J L --> J I --> J ``` ## Instantiate ```json theme={null} {} ``` ## ExecuteMsg ### UpdateOwnership (::cw\_ownable) This is a `cw_ownable` message. ```json theme={null} { "update_ownership": { "transfer_ownership": { "new_owner": "mantra1...", "expiry": { "at_height": "424242424242" } } } } ``` ## QueryMsg ### Ownership (::cw\_ownable) This is a `cw_ownable` query. ```json theme={null} { "ownership": {} } ``` ## MigrateMsg ```json theme={null} {} ``` # Pool Manager Source: https://docs.mantrachain.io/resources/contracts/mantra-dex/pool-manager Liquidity pools, swaps, and routing for MANTRA DEX (MANTRA Swap) The Pool Manager is a contract that handles liquidity pools in the MANTRA DEX. It facilitates the creation and management of different pool types, liquidity provision, swaps, and multi-hop operations across pools. Pool creation is permissionless (a fee is required to prevent spam). Multiple pools can exist for the same asset pair, each with a unique identifier. ## Pool types There are two pool types: constant product (XYK) and stableswap. ### XYK Pool The XYK pool uses a constant product invariant: $$ XY = k $$ Where **X** and **Y** are the reserves for each token, and **k** is constant. $$ XY = k = (X + \Delta x)(Y - \Delta y) $$ To determine the ask asset amount (\Delta y) given the offered asset (\Delta x): $$ \Delta y = \\frac{Y\\Delta x}{X + \\Delta x} $$ The spread between executed and expected trade is: $$ spread = (Y\\Delta x/X) - (Y\\Delta x/(X + \\Delta x)) $$ ### Stableswap Implements the StableSwap curve described by Curve: `https://curve.fi/files/stableswap-paper.pdf`. Supports 2–4 assets and is designed for low slippage stable-asset trading. ## Instantiate ```json theme={null} { "fee_collector_addr": "mantra1...", "farm_manager_addr": "mantra1...", "pool_creation_fee": { "denom": "uom", "amount": "1000000000" } } ``` | Key | Type | Description | | -------------------- | ------ | ------------------------------- | | `fee_collector_addr` | String | Fee collector contract address. | | `farm_manager_addr` | String | Farm manager contract address. | | `pool_creation_fee` | Coin | Cost to create a pool. | ## ExecuteMsg ### CreatePool Creates a new pool with assets, decimals, fees, pool type, and identifier. Pool identifiers: * Auto-assigned pools get prefix `p.` (e.g. `p.1`) * Custom identifiers get prefix `o.` (e.g. `o.my_pool`) #### XYK example ```json theme={null} { "create_pool": { "asset_denoms": ["uom", "uusdc"], "asset_decimals": [6, 6], "pool_fees": { "protocol_fee": { "share": "0.001" }, "swap_fee": { "share": "0.002" }, "burn_fee": { "share": "0" }, "extra_fees": [{ "share": "0.001" }] }, "pool_type": "constant_product", "pool_identifier": "uom.uusdy.pool" } } ``` #### Stableswap example ```json theme={null} { "create_pool": { "asset_denoms": ["uusdt", "uusdc"], "asset_decimals": [6, 6], "pool_fees": { "protocol_fee": { "share": "0.0002" }, "swap_fee": { "share": "0.0003" }, "burn_fee": { "share": "0" }, "extra_fees": [] }, "pool_type": { "stable_swap": { "amp": 85 } }, "pool_identifier": "uusdt.uusdc.pool" } } ``` | Key | Type | Description | | ----------------- | --------------- | ------------------------------------------------------- | | `asset_denoms` | Vec\ | Asset denoms. | | `asset_decimals` | Vec\ | Decimals for each denom (same order as `asset_denoms`). | | `pool_fees` | PoolFee | Pool fees. | | `pool_type` | PoolType | Constant product or stableswap. | | `pool_identifier` | Option\ | Pool identifier (optional). | ### ProvideLiquidity Provides liquidity to a pool. If `lock_position_identifier` is set, LP tokens are locked in the farm manager for the specified duration; otherwise they are sent to the receiver. It’s only possible to lock an LP position for the same user providing liquidity (not on behalf of another user). ```json theme={null} { "provide_liquidity": { "slippage_tolerance": "0.01", "max_spread": "0.1", "receiver": "mantra1...", "pool_identifier": "uom.uusdy.pool", "unlocking_duration": 2678400, "lock_position_identifier": "lp.lock.identifier" } } ``` | Key | Type | Description | | -------------------------- | ---------------- | ------------------------------------------------- | | `slippage_tolerance` | Option\ | Max acceptable slippage. | | `max_spread` | Option\ | Max spread allowed. | | `receiver` | Option\ | Receiver of LP tokens. | | `pool_identifier` | String | Pool identifier. | | `unlocking_duration` | Option\ | Duration (seconds) for farm lock/unlock behavior. | | `lock_position_identifier` | Option\ | Position identifier to lock (if any). | ### Swap Swaps an offer asset to an ask asset in a specific pool. Offer amount is provided in `info.funds`. ```json theme={null} { "swap": { "ask_asset_denom": "uusdc", "belief_price": "0.5", "max_spread": "5000", "receiver": "mantra1...", "pool_identifier": "uom.uusdy.pool" } } ``` | Key | Type | Description | | ----------------- | ---------------- | ------------------------------- | | `ask_asset_denom` | String | Return asset denom. | | `belief_price` | Option\ | Belief price. | | `max_spread` | Option\ | Maximum spread. | | `receiver` | Option\ | Recipient (defaults to sender). | | `pool_identifier` | String | Pool identifier. | ### WithdrawLiquidity Withdraws liquidity from a pool. LP tokens must be sent with the transaction. ```json theme={null} { "withdraw_liquidity": { "pool_identifier": "uom.uusdy.pool" } } ``` | Key | Type | Description | | ----------------- | ------ | ---------------- | | `pool_identifier` | String | Pool identifier. | ### ExecuteSwapOperations Executes multiple swap operations (multi-hop). Routes are computed off-chain. ```json theme={null} { "execute_swap_operations": { "operations": [ { "mantra_swap": { "token_in_denom": "uluna", "token_out_denom": "uom", "pool_identifier": "uluna_uom_pool" } }, { "mantra_swap": { "token_in_denom": "uom", "token_out_denom": "uusdc", "pool_identifier": "uom.uusdy.pool" } } ], "minimum_receive": "1000000", "receiver": "mantra1...", "max_spread": "0.1" } } ``` | Key | Type | Description | | ----------------- | ------------------- | ------------------------ | | `operations` | Vec\ | Operations in order. | | `minimum_receive` | Option\ | Minimum amount received. | | `receiver` | Option\ | Final recipient. | | `max_spread` | Option\ | Max spread per swap. | ### UpdateConfig ```json theme={null} { "update_config": { "fee_collector_addr": "mantra1...", "farm_manager_addr": "mantra1...", "pool_creation_fee": { "denom": "uom", "amount": "1000000000" }, "feature_toggle": { "withdrawals_enabled": true, "deposits_enabled": true, "swaps_enabled": true } } } ``` ### UpdateOwnership (::cw\_ownable) This is a `cw_ownable` message. ## QueryMsg ### Config ```json theme={null} { "config": {} } ``` ### AssetDecimals ```json theme={null} { "asset_decimals": { "pool_identifier": "om-usdc-1", "denom": "uom" } } ``` ### Simulation ```json theme={null} { "simulation": { "offer_asset": { "denom": "uom", "amount": "1000000" }, "ask_asset_denom": "uusdc", "pool_identifier": "om-usdc-1" } } ``` ### ReverseSimulation ```json theme={null} { "reverse_simulation": { "ask_asset": { "denom": "uusdc", "amount": "990000" }, "offer_asset_denom": "uom", "pool_identifier": "om-usdc-1" } } ``` ### SimulateSwapOperations / ReverseSimulateSwapOperations See legacy examples in `_tmp_gitbook/mantra-smart-contracts/mantra-swap/pool-manager.md` (ported here verbatim in structure). ### Pools ```json theme={null} { "pools": { "pool_identifier": "om-usdc-1", "start_after": null, "limit": 10 } } ``` ### Ownership (::cw\_ownable) This is a `cw_ownable` query. ## MigrateMsg ```json theme={null} {} ``` # Testnet Contracts Source: https://docs.mantrachain.io/resources/contracts/testnet Deployed protocol contract addresses for MANTRA Dukong testnet (mantra-dukong-1) This page lists contract deployments for MANTRA Dukong testnet. ## QuickSwap (fork of Algebra V4) QuickSwap on MANTRA is powered by Algebra Protocol V4, a concentrated liquidity DEX. These are the deployed EVM contract addresses. ### Core Contracts | Contract | Address | | ----------------------- | -------------------------------------------- | | AlgebraPoolDeployer | `0xd7cB0E0692f2D55A17bA81c1fE5501D66774fC4A` | | AlgebraFactory | `0x10253594A832f967994b44f33411940533302ACb` | | AlgebraCommunityVault | `0x4439199c3743161ca22bB8F8B6deC5bF6fF65b04` | | AlgebraVaultFactoryStub | `0x955B95b8532fe75DDCf2161f61127Be74A768158` | | PluginFactory | `0xFe3BEcd788320465ab649015F34F7771220A88b2` | ### Periphery Contracts | Contract | Address | | ---------------------------------- | -------------------------------------------- | | SwapRouter | `0x3012E9049d05B4B5369D690114D5A5861EbB85cb` | | NonfungiblePositionManager | `0x69D57B9D705eaD73a5d2f2476C30c55bD755cc2F` | | NonfungibleTokenPositionDescriptor | `0xD637cbc214Bc3dD354aBb309f4fE717ffdD0B28C` | | Proxy | `0x6AD6A4f233F1E33613e996CCc17409B93fF8bf5f` | | Quoter | `0x03f8B4b140249Dc7B2503C928E7258CCe1d91F1A` | | QuoterV2 | `0xa77aD9f635a3FB3bCCC5E6d1A87cB269746Aba17` | ### Utility Contracts | Contract | Address | | ------------------------- | -------------------------------------------- | | EntryPoint | `0x4A3BC48C156384f9564Fd65A53a2f3D534D8f2b7` | | TickLens | `0x13fcE0acbe6Fb11641ab753212550574CaD31415` | | AlgebraInterfaceMulticall | `0xB4F9b6b019E75CBe51af4425b2Fc12797e2Ee2a1` | *** ## LOTUS (fork of Uniswap V3) LOTUS is a concentrated liquidity DEX on MANTRA, built as a fork of [Uniswap V3](https://docs.uniswap.org/contracts/v3/overview). These are the deployed EVM contract addresses. | Contract | Address | | -------------------------- | -------------------------------------------- | | LotusV3Factory | `0x17E1ebf15BE528b179d34148fB9aB2466555F605` | | LotusV3PoolDeployer | `0x41B1E93A249d9635b12344E7976Ff8E4dD2CC9c1` | | SwapRouter | `0xae52Aa627D6eFAce03Fecd41a79DEEcbc168cb0c` | | NonfungiblePositionManager | `0x84fb9302f2232050bB30D0C15Cef44823153De6f` | *** ## MANTRA DEX (MANTRA Swap) These are CosmWasm contract deployments. Source: GitBook legacy deployments (`_tmp_gitbook/mantra-smart-contracts/mantra-swap/deployments.md`). | Contract | Code ID | Address | | ------------- | ------- | ------------------------------------------------------------------- | | Epoch Manager | `90` | `mantra128evmx0gxlam8jlmjq6f39z04dugl9wqxuayqmuctq56p4p8ruksn30429` | | Farm Manager | `109` | `mantra1n8eczspq08pphp0xsfusecherwha570qpzt5cfzkgym45efchj2s8jrqf4` | | Fee Collector | `54` | `mantra1mfp8jd8p9jyrt5pgkzn6jpf4ng0stc68jmpw3t35lqtgkkrv2fhs569tlr` | | Pool Manager | `532` | `mantra1us7rryvauhpe82fff0t6gjthdraqmtm5gw8c808f6eqzuxmulacqzkzdal` | ## MANTRA Claimdrop No claimdrop contract deployment details were present in the legacy GitBook deployments snapshot. # IBC Denominations Source: https://docs.mantrachain.io/resources/ibc-denoms IBC token denominations available on MANTRA Chain This page lists the IBC denominations available on MANTRA Chain networks. These tokens have been bridged from other chains in the Cosmos ecosystem through IBC (Inter-Blockchain Communication) channels. Additional details can also be found om the [Mintscan Explorer Assets Page](https://www.mintscan.io/mantra/assets) ## Mainnet (mantra-1) | Symbol | IBC Denom | | ------ | ---------------------------------------------------------------------- | | USDC | `ibc/65D0BEC6DAD96C7F5043D1E54E54B6BB5D5B3AEC3FF6CEBB75B9E059F3580EA3` | | USDY | `ibc/6749D16BC09F419C090C330FC751FFF1C96143DB7A4D2FCAEC2F348A3E17618A` | | ATOM | `ibc/A4DB47A9D3CF9A068D454513891B526702455D3EF08FB9EB558C561F9DC2B701` | | OSMO | `ibc/ED07A3391A112B175915CD8FAF43A2DA8E4790EDE12566649D0C2F97716B8518` | | STARS | `ibc/16E817E682AD1A73FD748BC989574B2702E109C4105550498086531FA3D6B050` | ## Using IBC Denoms To specify an IBC token in transactions or queries, use the full IBC denom format. For example: ```bash theme={null} # Query USDC balance mantrachaind query bank balances mantra123... --denom=ibc/65D0BEC6DAD96C7F5043D1E54E54B6BB5D5B3AEC3FF6CEBB75B9E059F3580EA3 # Send ATOM tokens mantrachaind tx bank send \ my-wallet recipient-address \ 1000000ibc/A4DB47A9D3CF9A068D454513891B526702455D3EF08FB9EB558C561F9DC2B701 \ --chain-id mantra-1 \ --gas auto \ --gas-adjustment 1.2 ``` ## IBC Relayers IBC tokens are transferred and maintained by IBC relayers that process packet data between MANTRA and other chains. The primary relayers for MANTRA include: 1. MANTRA Chain Association relayers 2. Community relayers (Cosmostation, Lavenderfive, CryptoCrew, Polkachu, etc.) 3. Third-party commercial relayers ## Fee Tokens Some IBC tokens can be used to pay for transaction fees on MANTRA Chain. The current list of supported fee tokens includes: * `uom` (Native OM) # Goldsky Source: https://docs.mantrachain.io/resources/indexing/goldsky Index MANTRA data with instant, queryable GraphQL APIs Goldsky handles the hard parts of building on crypto rails: real-time data and reliable connectivity, so you can ship better products, faster. Subgraphs give you instant, queryable APIs for MANTRA data. Define the events and entities you care about, and Goldsky handles the indexing, hosting, and maintenance, delivering a production-ready GraphQL endpoint with zero infrastructure overhead. ## Why Goldsky? Scalable infra built to handle data challenges as your app grows. Easily integrate without being slowed down by complex data engineering. Get [support](https://docs.goldsky.com/getting-support) when you need to fix bugs or optimize deployments. ## Deploy Subgraphs Instant GraphQL APIs for blockchain data with zero maintenance. * **Fast Queries**: Optimized for low latency and high throughput. * **Customizable**: Tailor indexing logic to your app's exact needs. * **Developer Experience**: Webhooks, tagging, and versioning keep data clean as your project grows. **Typical Use Cases**: dApps, NFT marketplaces, gaming, DAOs, or any app needing reliable onchain data. ## Getting Started Check out the [Goldsky MANTRA documentation](https://goldsky.com/chains/mantra) to start indexing today. Build smarter, scale faster, and deliver seamless experiences to your users. # Network Details Source: https://docs.mantrachain.io/resources/network-details MANTRA Chain network details, public endpoints, and configurations ## Chain Details | | | | ------------- | ---------- | | EVM Chain ID | `5888` | | Full Chain ID | `mantra-1` | ## EVM Endpoints | Provider | Endpoint | Status | | :--------------------------------- | :----------------------------------------------------------------------------------------------------------------- | :-------- | | MANTRA Chain Association | [https://evm.mantrachain.io](https://evm.mantrachain.io)
wss\://evm.mantrachain.io/ws | Available | | MANTRA Chain Association (Archive) | [https://evm.archive.mantrachain.io](https://evm.archive.mantrachain.io)
wss\://evm.archive.mantrachain.io/ws | Available | ## Explorers | Explorer | | ------------------------------------------------------------ | | [mantrascan.io/mainnet](https://mantrascan.io/mainnet) | | [blockscout.mantrascan.io](https://blockscout.mantrascan.io) | | Type | Endpoint | | -------- | -------------------------------------------------------- | | RPC | [https://rpc.mantrachain.io](https://rpc.mantrachain.io) | | REST API | [https://api.mantrachain.io](https://api.mantrachain.io) | | GRPC | grpc.mantrachain.io:443 | Archive endpoints available at `*.archive.mantrachain.io`
## Chain Details | | | | ------------- | ----------------- | | EVM Chain ID | `5887` | | Full Chain ID | `mantra-dukong-1` | ## EVM Endpoints | Provider | Endpoint | Status | | :--------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------- | :-------- | | MANTRA Chain Association | [https://evm.dukong.mantrachain.io](https://evm.dukong.mantrachain.io)
wss\://evm.dukong.mantrachain.io/ws | Available | | MANTRA Chain Association (Archive) | [https://evm.archive.dukong.mantrachain.io](https://evm.archive.dukong.mantrachain.io)
wss\://evm.archive.dukong.mantrachain.io/ws | Available | ## Explorers | Explorer | | ------------------------------------------------------------- | | [mantrascan.io/dukong](https://mantrascan.io/dukong) | | [explorer.dukong.io](https://explorer.dukong.io) (Blockscout) | ## Faucet Get testnet OM tokens at [faucet.dukong.mantrachain.io](https://faucet.dukong.mantrachain.io) | Type | Endpoint | | -------- | ---------------------------------------------------------------------- | | RPC | [https://rpc.dukong.mantrachain.io](https://rpc.dukong.mantrachain.io) | | REST API | [https://api.dukong.mantrachain.io](https://api.dukong.mantrachain.io) | | GRPC | grpc.dukong.mantrachain.io:443 | Archive endpoints available at `*.archive.dukong.mantrachain.io`
# Peers Source: https://docs.mantrachain.io/resources/peers Seed nodes and persistent peers for connecting to MANTRA Chain networks This page lists peer information for connecting to MANTRA Chain networks. ## Mainnet (mantra-1) ### Seed Nodes ``` 32276da966637722914411e16ca91bd37dcd1c28@seed0.mantrachain.io:26656 9f5235b418c87af4302619705d0bf4748249ca6b@seed1.mantrachain.io:26656 b0acfd505bb4bc0c39d095663d310c253de18210@seed2.mantrachain.io:26656 f153213f0fe5d3cbe6e1f75d7ac0b4a27e70d31b@seed-mantra.r93axnodes.cloud:13156 16ab08754dd0dc8b4d9202db16cb354ff618e3d9@mantra-mainnet-seed.itrocket.net:22656 ``` ### Additional P2P Peers ## Configuration To add these peers to your node configuration: 1. Edit your `config.toml` file: ```bash theme={null} nano ~/.mantrachain/config/config.toml ``` 2. Add the seed nodes: ```toml theme={null} # Comma separated list of seed nodes to connect to seeds = "" ``` 3. Optionally, add some persistent peers: ```toml theme={null} # Comma separated list of nodes to keep persistent connections to persistent_peers = "" ``` ## Addrbook You can also bootstrap your node with a pre-existing addrbook: ```bash theme={null} wget -O ~/.mantrachain/config/addrbook.json https://raw.githubusercontent.com/MANTRA-Chain/net/main/mantra-1/addrbook.json ``` ## Testnet (mantra-dukong-1) ### Seed Nodes ``` 7e061edecef73a700b699c785f61a44ca981ff7f@seed0.dukong.mantrachain.io:26656 ``` ### Additional P2P Peers ## Configuration To add these peers to your node configuration: 1. Edit your `config.toml` file: ```bash theme={null} nano ~/.mantrachain/config/config.toml ``` 2. Add the seed nodes: ```toml theme={null} # Comma separated list of seed nodes to connect to seeds = "" ``` 3. Optionally, add some persistent peers: ```toml theme={null} # Comma separated list of nodes to keep persistent connections to persistent_peers = "" ``` ## Addrbook You can also bootstrap your node with a pre-existing addrbook: ```bash theme={null} wget -O ~/.mantrachain/config/addrbook.json https://raw.githubusercontent.com/MANTRA-Chain/net/main/mantra-dukong-1/addrbook.json ``` ### # Safe Multisigs Source: https://docs.mantrachain.io/resources/safe-multisig Create and manage Safe multisig accounts on MANTRA Chain ## Overview Use the Safe frontend to create and manage **Safe multisig accounts** on MANTRA Chain. * **Safe frontend (Protofire-hosted partner site)**: [`https://app.safe.protofire.io/welcome`](https://app.safe.protofire.io/welcome) ## Getting started 1. Open the Safe frontend: [`https://app.safe.protofire.io/welcome`](https://app.safe.protofire.io/welcome) 2. Connect your wallet. 3. Create a new Safe account (multisig) or open an existing Safe. ## Notes * Always verify you’re on the correct URL and connected to the intended MANTRA network (see [Network Details](/resources/network-details)). # TokenFactory Denoms Source: https://docs.mantrachain.io/resources/tokenfactory-denoms TokenFactory-created denominations available on MANTRA Chain This page lists tokens created using the TokenFactory module on MANTRA, which allows smart contracts to create native tokens with custom denominations. ## Mainnet (mantra-1) | Symbol | TokenFactory Denom | | ------------------ | ------------------------------------------------------------------------------------------------ | | wstETH | `factory/mantra1ug740qrkquxzrk2hh29qrlx3sktkfml3je7juusc2te7xmvsscns0n2wry/wstETH` | | BIKE | `factory/mantra1vtpg8z82gz9qe3adf7t9z0qwuvkpzmqu9ds4ej/BIKE` | | OM/USDY LP | `factory/mantra1466nf3zuxpya8q9emxukd7vftaf6h4psr0a07srl5zw74zh84yjqagspfm/o.uom.ausdy.LP` | | OM/USDC LP | `factory/mantra1466nf3zuxpya8q9emxukd7vftaf6h4psr0a07srl5zw74zh84yjqagspfm/o.uom.uusdc.LP` | | OSMO/USDC LP | `factory/mantra1466nf3zuxpya8q9emxukd7vftaf6h4psr0a07srl5zw74zh84yjqagspfm/o.uosmo.uusdc.LP` | | USDY/USDC LP | `factory/mantra1466nf3zuxpya8q9emxukd7vftaf6h4psr0a07srl5zw74zh84yjqagspfm/o.ausdy.uusdc.LP` | | USDY/USDC LP (XYK) | `factory/mantra1466nf3zuxpya8q9emxukd7vftaf6h4psr0a07srl5zw74zh84yjqagspfm/o.ausdy.uusdc.xyk.LP` | | ATOM/USDC LP | `factory/mantra1466nf3zuxpya8q9emxukd7vftaf6h4psr0a07srl5zw74zh84yjqagspfm/o.uatom.uusdc.LP` | | BIKE/USDC LP | `factory/mantra1466nf3zuxpya8q9emxukd7vftaf6h4psr0a07srl5zw74zh84yjqagspfm/o.bike.uusdc.LP` | ## Using TokenFactory Denoms To interact with TokenFactory tokens, use the full denomination format. For example: ```bash theme={null} # Query wstETH balance mantrachaind query bank balances mantra123... --denom="factory/mantra1ug740qrkquxzrk2hh29qrlx3sktkfml3je7juusc2te7xmvsscns0n2wry/wstETH" # Send wstETH tokens mantrachaind tx bank send \ my-wallet recipient-address \ 1000000factory/mantra1ug740qrkquxzrk2hh29qrlx3sktkfml3je7juusc2te7xmvsscns0n2wry/wstETH \ --chain-id mantra-1 \ --gas auto \ --gas-adjustment 1.2 ``` ## Creating TokenFactory Denoms Smart contracts on MANTRA Chain can create their own TokenFactory denominations by using the TokenFactory module. This is particularly useful for applications that need to: 1. Create wrapped versions of existing tokens 2. Mint liquidity provider tokens 3. Create synthetic assets 4. Create governance tokens To create a TokenFactory denom from a smart contract, the contract code needs to invoke the appropriate messages from the TokenFactory module. ## Fee Tokens **COMING SOON!** Some TokenFactory tokens can be used to pay for transaction fees on MANTRA Chain. The current list of supported TokenFactory fee tokens includes