# Getting Started (/docs) Mandala Chain is an Ethereum Layer 2 built on the Arbitrum Orbit stack. Chain ID `20010`, AnyTrust data availability, native gas token KPG (Kepeng), settles to Ethereum L1. Pick your path. ## Mandala at a glance [#mandala-at-a-glance] | Detail | Value | | :------------------- | :-------------------------------------------------------------------------------------------------------- | | **Chain ID** | `20010` | | **Stack** | Arbitrum Orbit, AnyTrust DA | | **Settlement** | Ethereum L1 | | **Gas token** | KPG (Kepeng), 18 decimals | | **Block production** | On demand, only when there is a transaction | | **RPC** | `https://rpc1-mainnet.mandalachain.io` | | **Explorer** | [explorer.mandalachain.io](https://explorer.mandalachain.io) (Blockscout) | | **Bridge** | [Arbitrum Portal](https://portal.arbitrum.io/bridge?destinationChain=mandala-chain\&sourceChain=ethereum) | | **Testnet** | Chain ID `20011`, settles to Sepolia. See [Testnet](/docs/network/testnet/network-details) | ## What's different about Mandala [#whats-different-about-mandala] Three Mandala-specific facts worth knowing before you start. * **Gas is paid in KPG, not ETH.** Same gwei units, different underlying token. Budget separately. * **Blocks are produced on demand.** No fixed slot time. Do not use `block.number` as a clock; use `block.timestamp` deltas. * **Withdrawals to Ethereum take \~7 days.** Standard optimistic-rollup challenge window. Plan UX accordingly. The [Differences from Ethereum](/docs/build/differences-from-ethereum) page covers the full list with code. ## Help [#help] * **Community channels and reporting**: [Getting Help](/docs/support/getting-help) * **FAQ**: [Frequently Asked Questions](/docs/support/faq) * **GitHub**: [github.com/MandalaChain](https://github.com/MandalaChain) # Differences from Ethereum (/docs/build/differences-from-ethereum) Mandala is EVM-equivalent. Everything that compiles on Ethereum compiles here, with the same opcodes, the same ABI, the same wallets. Five things behave differently, and missing them costs time. ## Gas is paid in KPG, not ETH [#gas-is-paid-in-kpg-not-eth] Every transaction fee is denominated in KPG. Your wallet shows balances in KPG, your gas price is in KPG-gwei, your dApp fee estimates are KPG. KPG and ETH are different tokens with different USD values. Budget accordingly. Full fee mechanics: [Gas & Fees](/docs/learn/gas-and-fees). ## Blocks are produced on demand [#blocks-are-produced-on-demand] There is no fixed block time. The sequencer emits a block when at least one transaction has been submitted. If the chain is idle, no blocks are produced. For your contracts: * Do not use `block.number` as a clock. It does not advance at a fixed rate. * `block.timestamp` can jump by seconds, minutes, or hours between adjacent blocks. Time-based logic should use `block.timestamp` deltas and be tested under irregular intervals. * Per-block emission rates (`X tokens per block`) behave differently from a fixed-slot chain. Convert to per-second where possible. * On-chain randomness from `block.timestamp` or `blockhash` is even less reliable than usual. Use VRF or commit-reveal. Full block model: [Block Production & Finality](/docs/learn/block-production-and-finality). ## Withdrawals to Ethereum take \~7 days [#withdrawals-to-ethereum-take-7-days] Standard optimistic-rollup challenge window. Funds bridged from Mandala to Ethereum are released on L1 after the dispute period passes. Plan UX for users who expect L1 funds. Third-party fast bridges sell the wait time at a fee. The canonical bridge does not have a fast path. [Withdraw to Ethereum](/docs/network/bridge/withdraw-to-ethereum) covers both. ## L2-to-L1 messages go through ArbSys [#l2-to-l1-messages-go-through-arbsys] To send a message from a Mandala contract to Ethereum L1, call the `ArbSys` precompile at `0x0000000000000000000000000000000000000064`. Same address on every Arbitrum Orbit chain. ```solidity interface ArbSys { function sendTxToL1(address destination, bytes calldata data) external payable returns (uint256); } ArbSys(0x0000000000000000000000000000000000000064) .sendTxToL1(myL1Contract, payload); ``` After the \~7-day challenge window, anyone can finalize the message on L1 through the Outbox at `0x004eF39261cee56409Dbd26040a33Eca8326490C`. Full ArbSys API: [Arbitrum's precompiles reference](https://docs.arbitrum.io/build-decentralized-apps/precompiles/02-reference#arbsys). ## The sequencer is centralized today [#the-sequencer-is-centralized-today] A single sequencer operated by the Mandala team and AltLayer orders transactions. It cannot steal funds. It can censor. If your transaction is censored or the sequencer is down, submit directly to the L1 Inbox at `0x62DfD05c460C7E55DA85B39EaD3eBc6e0CcdD0d5`. After a delay, anyone can force-include the transaction via the SequencerInbox at `0x325acf46079d3f750D5D7E6182E094B1fD0AC2F4`. Full trust model: [Trust & Security Model](/docs/learn/trust-and-security-model). ## What does not change [#what-does-not-change] Solidity, EVM opcodes, ABI encoding, function selectors, event topics, ERC standards, wallet flows, the gas-accounting shape, and every standard precompile (`ecrecover`, `sha256`, modular exponentiation). If you do not see it on this page, assume it works the same as Ethereum. # Foundry (/docs/build/foundry) Foundry is the fastest path from zero to deployed contract on Mandala. One config file, one deploy command, one verify command. ## Install [#install] ```bash curl -L https://foundry.paradigm.xyz | bash foundryup ``` This installs `forge`, `cast`, `anvil`, and `chisel`. ## New project [#new-project] ```bash forge init my-project && cd my-project ``` Foundry scaffolds `src/`, `test/`, `script/`, and `foundry.toml`. ## Configure [#configure] Append Mandala endpoints to `foundry.toml`: ```toml [profile.default] src = "src" out = "out" libs = ["lib"] solc = "0.8.24" [rpc_endpoints] mandala = "https://rpc1-mainnet.mandalachain.io" mandala_testnet = "https://rpc1-testnet.mandalachain.io" [etherscan] mandala = { key = "empty", url = "https://explorer.mandalachain.io:443/api/", chain = 20010 } mandala_testnet = { key = "empty", url = "https://explorer.testnet.mandalachain.io:443/api/", chain = 20011 } ``` Blockscout uses an Etherscan-compatible API. The `"empty"` placeholder is required by Foundry but Blockscout does not validate it. Put your private key in `.env`: ```bash echo "PRIVATE_KEY=0xyour..." > .env echo ".env" >> .gitignore source .env ``` ## Deploy [#deploy] For a single contract, `forge create` is the one-liner: ```bash forge create src/Counter.sol:Counter \ --rpc-url mandala_testnet \ --private-key $PRIVATE_KEY \ --broadcast ``` For multi-contract deploys, write a Forge script at `script/Deploy.s.sol`: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "forge-std/Script.sol"; import "../src/Counter.sol"; contract DeployScript is Script { function run() external { vm.startBroadcast(); new Counter(); vm.stopBroadcast(); } } ``` Run it: ```bash forge script script/Deploy.s.sol --rpc-url mandala_testnet --broadcast ``` ## Verify [#verify] ```bash forge verify-contract \ --rpc-url mandala_testnet \ --verifier blockscout \ --verifier-url https://explorer.testnet.mandalachain.io:443/api/ \ 0xYourAddress \ src/Counter.sol:Counter ``` For contracts with constructor arguments: ```bash forge verify-contract \ --rpc-url mandala_testnet \ --verifier blockscout \ --verifier-url https://explorer.testnet.mandalachain.io:443/api/ \ --constructor-args $(cast abi-encode "constructor(uint256)" 42) \ 0xYourAddress \ src/Counter.sol:Counter ``` For mainnet, swap `mandala_testnet` for `mandala` and the verifier URL to `https://explorer.mandalachain.io:443/api/`. ## Common errors [#common-errors] **`Error: chain id 20010 not found`.** Add the `[rpc_endpoints]` and `[etherscan]` blocks above to `foundry.toml`. **`Insufficient funds for gas`.** You need KPG (mainnet) or KPGT (testnet) at the deploying address. **`Failed to verify: contract was already verified`.** Not an error. Blockscout reports this when the source matches an already-verified deployment of the same bytecode. **`Compiler run failed`** during verification. Compiler version or optimizer mismatch. Set `solc` and `optimizer` in `foundry.toml` to the values you used at deploy time. # Frontend integration (/docs/build/frontend-integration) Mandala is EVM-equivalent. Any frontend stack that talks to Ethereum talks to Mandala by swapping the chain config. This page walks through viem and wagmi, the two most common stacks. ethers.js gets a short section at the bottom. ## Install [#install] ```bash npm install viem wagmi @tanstack/react-query ``` Or with bun: ```bash bun add viem wagmi @tanstack/react-query ``` ## Define the chain [#define-the-chain] viem and wagmi both accept a chain object. Define Mandala once and reuse: ```ts // lib/chains.ts import { defineChain } from "viem"; export const mandala = defineChain({ id: 20010, name: "Mandala Chain", nativeCurrency: { name: "Kepeng", symbol: "KPG", decimals: 18 }, rpcUrls: { default: { http: ["https://rpc1-mainnet.mandalachain.io"] }, }, blockExplorers: { default: { name: "Mandala Explorer", url: "https://explorer.mandalachain.io", }, }, }); export const mandalaTestnet = defineChain({ id: 20011, name: "Mandala Testnet", nativeCurrency: { name: "Kepeng Test", symbol: "KPGT", decimals: 18 }, rpcUrls: { default: { http: ["https://rpc1-testnet.mandalachain.io"] }, }, blockExplorers: { default: { name: "Mandala Testnet Explorer", url: "https://explorer.testnet.mandalachain.io", }, }, testnet: true, }); ``` ## Configure wagmi [#configure-wagmi] ```ts // lib/wagmi.ts import { createConfig, http } from "wagmi"; import { injected, metaMask } from "wagmi/connectors"; import { mandala, mandalaTestnet } from "./chains"; export const config = createConfig({ chains: [mandala, mandalaTestnet], connectors: [injected(), metaMask()], transports: { [mandala.id]: http(), [mandalaTestnet.id]: http(), }, }); ``` Wrap your app in the providers: ```tsx // app/providers.tsx "use client"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { WagmiProvider } from "wagmi"; import { config } from "@/lib/wagmi"; const queryClient = new QueryClient(); export function Providers({ children }: { children: React.ReactNode }) { return ( {children} ); } ``` ## Connect a wallet [#connect-a-wallet] ```tsx // components/ConnectButton.tsx "use client"; import { useAccount, useConnect, useDisconnect } from "wagmi"; export function ConnectButton() { const { address, isConnected } = useAccount(); const { connect, connectors } = useConnect(); const { disconnect } = useDisconnect(); if (isConnected) { return ( ); } return ( ); } ``` When users click Connect, their wallet prompts to switch to (or add) Mandala if it is not already configured. ## Get a contract ABI [#get-a-contract-abi] Two paths. **From your build artifacts.** Hardhat writes ABIs to `artifacts/contracts/Counter.sol/Counter.json`. Foundry writes them to `out/Counter.sol/Counter.json`. Import the `abi` field directly. **From the explorer.** For contracts you do not own, open the contract on [explorer.mandalachain.io](https://explorer.mandalachain.io), click the **Contract** tab, and copy the ABI from the **ABI** sub-tab. The contract must be verified for the ABI to be available there. ## Read from a contract [#read-from-a-contract] ```tsx "use client"; import { useReadContract } from "wagmi"; import { mandala } from "@/lib/chains"; const counterAbi = [ { name: "count", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "uint256" }], }, ] as const; export function CounterValue({ address }: { address: `0x${string}` }) { const { data, isPending, error } = useReadContract({ chainId: mandala.id, address, abi: counterAbi, functionName: "count", }); if (isPending) return

Loading...

; if (error) return

Error: {error.message}

; return

Count: {data?.toString()}

; } ``` `useReadContract` is a thin wrapper over viem's `publicClient.readContract`. The `as const` on the ABI gives full TypeScript inference for arguments and return types. ## Write to a contract [#write-to-a-contract] ```tsx "use client"; import { useWriteContract, useWaitForTransactionReceipt } from "wagmi"; const counterAbi = [ { name: "increment", type: "function", stateMutability: "nonpayable", inputs: [], outputs: [], }, ] as const; export function IncrementButton({ address }: { address: `0x${string}` }) { const { writeContract, data: hash, isPending } = useWriteContract(); const { isLoading: isMining, isSuccess } = useWaitForTransactionReceipt({ hash }); return (
{isSuccess &&

Done.

}
); } ``` The user's wallet handles network switching to Mandala automatically. `useWaitForTransactionReceipt` polls the chain until the transaction lands. ## viem without wagmi [#viem-without-wagmi] If you do not need React hooks, use viem clients directly: ```ts import { createPublicClient, createWalletClient, custom, http } from "viem"; import { mandala } from "./chains"; const publicClient = createPublicClient({ chain: mandala, transport: http(), }); const walletClient = createWalletClient({ chain: mandala, transport: custom(window.ethereum!), }); const count = await publicClient.readContract({ address: "0xYourContract", abi: counterAbi, functionName: "count", }); const hash = await walletClient.writeContract({ account: "0xYourAddress", address: "0xYourContract", abi: counterAbi, functionName: "increment", }); ``` ## ethers.js [#ethersjs] ethers.js works against any EVM chain via a custom provider: ```ts import { JsonRpcProvider, Contract } from "ethers"; const provider = new JsonRpcProvider("https://rpc1-mainnet.mandalachain.io", { name: "Mandala Chain", chainId: 20010, }); const counter = new Contract("0xYourContract", counterAbi, provider); const value = await counter.count(); ``` Read/write APIs are identical to ethers on Ethereum. # Hardhat (/docs/build/hardhat) Hardhat works against Mandala with two additions: a `networks` entry for the RPC, and an `etherscan.customChains` block for verification via Blockscout's Etherscan-compatible API. ## Install [#install] ```bash mkdir my-project && cd my-project npm init -y npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox dotenv npx hardhat init ``` Pick "Create a TypeScript project". Hardhat scaffolds `contracts/`, `scripts/`, `test/`, and `hardhat.config.ts`. ## Configure [#configure] Replace `hardhat.config.ts`: ```ts import "dotenv/config"; import { HardhatUserConfig } from "hardhat/config"; import "@nomicfoundation/hardhat-toolbox"; const config: HardhatUserConfig = { solidity: "0.8.24", networks: { mandala: { url: "https://rpc1-mainnet.mandalachain.io", chainId: 20010, accounts: [process.env.PRIVATE_KEY!], }, mandalaTestnet: { url: "https://rpc1-testnet.mandalachain.io", chainId: 20011, accounts: [process.env.PRIVATE_KEY!], }, }, etherscan: { apiKey: { mandala: "empty", mandalaTestnet: "empty", }, customChains: [ { network: "mandala", chainId: 20010, urls: { apiURL: "https://explorer.mandalachain.io:443/api/", browserURL: "https://explorer.mandalachain.io", }, }, { network: "mandalaTestnet", chainId: 20011, urls: { apiURL: "https://explorer.testnet.mandalachain.io:443/api/", browserURL: "https://explorer.testnet.mandalachain.io", }, }, ], }, }; export default config; ``` Blockscout exposes an Etherscan-compatible API; the `"empty"` string is required by `hardhat-verify` but Blockscout does not validate it. Set `PRIVATE_KEY` in `.env`: ```bash echo "PRIVATE_KEY=0xyour..." > .env echo ".env" >> .gitignore ``` ## Deploy [#deploy] A minimal deploy script at `scripts/deploy.ts`: ```ts import { ethers } from "hardhat"; async function main() { const counter = await ethers.deployContract("Counter"); await counter.waitForDeployment(); console.log("Counter deployed at:", await counter.getAddress()); } main().catch((err) => { console.error(err); process.exit(1); }); ``` Run it: ```bash npx hardhat run scripts/deploy.ts --network mandalaTestnet ``` The script prints the contract address. Open it in [explorer.testnet.mandalachain.io](https://explorer.testnet.mandalachain.io). For larger deploys, Hardhat Ignition modules (in `ignition/modules/`) give you idempotent deployments with state tracking. ## Verify [#verify] `hardhat-toolbox` already includes `hardhat-verify`. Run: ```bash npx hardhat verify --network mandalaTestnet 0xYourAddress ``` For contracts with constructor arguments: ```bash npx hardhat verify --network mandalaTestnet 0xYourAddress "0xConstructorArg" 42 ``` For contract collisions (multiple contracts with the same name), pass the fully-qualified contract path: ```bash npx hardhat verify --network mandalaTestnet --contract contracts/Counter.sol:Counter 0xYourAddress ``` After verification succeeds, the Code tab on the explorer shows your source. ## Common errors [#common-errors] **`Error HH101: Hardhat was set to use chain id 20010, but connected to a chain with id ...`.** Your RPC and config disagree. Verify Chain ID is `20010` (mainnet) or `20011` (testnet). **`Error: insufficient funds for gas`.** Bridge KPG via the [Arbitrum Portal](https://portal.arbitrum.io/bridge?destinationChain=mandala-chain\&sourceChain=ethereum) or get KPGT for testnet. **`Bytecode does not match`** during verification. Compiler version, optimizer runs, or EVM target mismatch. Make sure your local `solidity` settings match what was used at deploy time. **`Already verified`.** Not an error. Blockscout sometimes reports this when the source matches an already-verified deployment of the same bytecode. # Quickstart (/docs/build/quickstart) Five minutes from now you have a contract on Mandala. The path: install your tool, fund a wallet with testnet KPGT, run one command. ## The chain at a glance [#the-chain-at-a-glance] | Detail | Mainnet | Testnet | | :------------- | :----------------------------------------------------------- | :--------------------------------------------------------------------------- | | **Chain ID** | `20010` | `20011` | | **RPC** | `https://rpc1-mainnet.mandalachain.io` | `https://rpc1-testnet.mandalachain.io` | | **Gas token** | KPG | KPGT | | **Settles to** | Ethereum L1 | Sepolia | | **Explorer** | [explorer.mandalachain.io](https://explorer.mandalachain.io) | [explorer.testnet.mandalachain.io](https://explorer.testnet.mandalachain.io) | This quickstart uses **testnet** so you do not spend real KPG. Get KPGT from the [Faucet](/docs/network/testnet/faucet), or bridge Sepolia ETH through the Arbitrum Portal. ## The contract [#the-contract] `Counter.sol`: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; contract Counter { uint256 public count; function increment() external { count += 1; } } ``` ## Deploy [#deploy] ```bash # Install Foundry (one-time) curl -L https://foundry.paradigm.xyz | bash && foundryup # New project forge init counter && cd counter # Replace src/Counter.sol with the contract above, then deploy forge create src/Counter.sol:Counter \ --rpc-url https://rpc1-testnet.mandalachain.io \ --private-key $PRIVATE_KEY \ --broadcast ``` ```bash # New project mkdir counter && cd counter npm init -y npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox dotenv npx hardhat init # pick "Create a TypeScript project" ``` Replace `hardhat.config.ts`: ```ts import "dotenv/config"; import { HardhatUserConfig } from "hardhat/config"; import "@nomicfoundation/hardhat-toolbox"; const config: HardhatUserConfig = { solidity: "0.8.24", networks: { mandalaTestnet: { url: "https://rpc1-testnet.mandalachain.io", chainId: 20011, accounts: [process.env.PRIVATE_KEY!], }, }, }; export default config; ``` Put `PRIVATE_KEY=0x...` in `.env`, save `Counter.sol` to `contracts/Counter.sol`, then: ```bash npx hardhat ignition deploy ignition/modules/Counter.ts --network mandalaTestnet ``` The address that comes back is your contract. Open it in [explorer.testnet.mandalachain.io](https://explorer.testnet.mandalachain.io) and you have proof of deployment. That is the whole 5-minute path. The rest of this section covers the same flow in more depth, plus verification and frontend integration. # Reference (/docs/build/reference) Address book and pointers, in one place. ## Network values [#network-values] | Detail | Mainnet | Testnet | | :----------------- | :-------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------- | | **Chain ID** | `20010` | `20011` | | **Network name** | Mandala Chain | Mandala Testnet | | **RPC** | `https://rpc1-mainnet.mandalachain.io` | `https://rpc1-testnet.mandalachain.io` | | **WebSocket** | `wss://rpc1-mainnet.mandalachain.io/ws` | `wss://rpc1-testnet.mandalachain.io/ws` | | **Gas token** | KPG (Kepeng) | KPGT (Kepeng Test) | | **Decimals** | 18 | 18 | | **Settles to** | Ethereum L1 | Sepolia | | **Block explorer** | [explorer.mandalachain.io](https://explorer.mandalachain.io) | [explorer.testnet.mandalachain.io](https://explorer.testnet.mandalachain.io) | | **Bridge** | [Arbitrum Portal](https://portal.arbitrum.io/bridge?destinationChain=mandala-chain\&sourceChain=ethereum) | Arbitrum Portal (testnet route) | ## L1 (Ethereum) contracts [#l1-ethereum-contracts] The Mandala core contracts on Ethereum L1. | Contract | Address | | :------------------ | :------------------------------------------- | | **Rollup** | `0x218D35154D1efEBFC46D64451C9495288219b275` | | **SequencerInbox** | `0x325acf46079d3f750D5D7E6182E094B1fD0AC2F4` | | **Inbox (delayed)** | `0x62DfD05c460C7E55DA85B39EaD3eBc6e0CcdD0d5` | | **Outbox** | `0x004eF39261cee56409Dbd26040a33Eca8326490C` | | **Bridge** | `0x65DB181838b53f32428ce106fA5355b7e4806b79` | For trust implications, see [Trust & Security Model](/docs/learn/trust-and-security-model). ## L2 (Mandala) addresses [#l2-mandala-addresses] | Contract | Address | | :-------------------- | :------------------------------------------- | | **ArbSys precompile** | `0x0000000000000000000000000000000000000064` | | **Multicall** | `0x7Bb2526e78c03Ec31BFb1478DF5795C580f77538` | For the full ArbSys API and other Arbitrum precompiles available on every Orbit chain, see [Arbitrum's precompiles reference](https://docs.arbitrum.io/build-decentralized-apps/precompiles/02-reference). ## Upstream documentation [#upstream-documentation] Everything Mandala inherits from upstream Arbitrum lives here. Use these for anything not chain-specific. * **Arbitrum core docs**: [docs.arbitrum.io](https://docs.arbitrum.io) * **How Arbitrum works**: [a gentle introduction](https://docs.arbitrum.io/how-arbitrum-works/a-gentle-introduction) * **Precompiles reference**: [docs.arbitrum.io/build-decentralized-apps/precompiles/02-reference](https://docs.arbitrum.io/build-decentralized-apps/precompiles/02-reference) * **Inside AnyTrust**: [docs.arbitrum.io/how-arbitrum-works/inside-anytrust](https://docs.arbitrum.io/how-arbitrum-works/inside-anytrust) * **Gas and fees**: [docs.arbitrum.io/how-arbitrum-works/gas-fees](https://docs.arbitrum.io/how-arbitrum-works/gas-fees) * **L1-to-L2 messaging**: [docs.arbitrum.io/how-arbitrum-works/l1-to-l2-messaging](https://docs.arbitrum.io/how-arbitrum-works/l1-to-l2-messaging) ## Tooling docs [#tooling-docs] * **viem**: [viem.sh](https://viem.sh) * **wagmi**: [wagmi.sh](https://wagmi.sh) * **Foundry book**: [book.getfoundry.sh](https://book.getfoundry.sh) * **Hardhat docs**: [hardhat.org/docs](https://hardhat.org/docs) * **Blockscout verification**: [docs.blockscout.com/devs/verification](https://docs.blockscout.com/devs/verification) ## Code repositories [#code-repositories] * **Mandala GitHub**: [github.com/MandalaChain](https://github.com/MandalaChain) * **Arbitrum Nitro**: [github.com/OffchainLabs/nitro](https://github.com/OffchainLabs/nitro) * **Arbitrum Orbit SDK**: [github.com/OffchainLabs/arbitrum-orbit-sdk](https://github.com/OffchainLabs/arbitrum-orbit-sdk) ## Help [#help] For chain-specific questions and community channels, see [Getting Help](/docs/support/getting-help). # Verify a contract (/docs/build/verify-contract) Verifying a contract publishes its source code to Blockscout so users can read it, decode calls, and interact with the contract directly from the explorer. Three paths, pick the one that matches your toolchain. ## With Hardhat [#with-hardhat] If you used the `etherscan.customChains` config from the [Hardhat](/docs/build/hardhat#configure) page: ```bash npx hardhat verify --network mandalaTestnet 0xYourAddress ``` With constructor arguments: ```bash npx hardhat verify --network mandalaTestnet 0xYourAddress "0xArg1" 42 ``` For mainnet, swap `mandalaTestnet` for `mandala`. ## With Foundry [#with-foundry] If you used the `[etherscan]` config from the [Foundry](/docs/build/foundry#configure) page: ```bash forge verify-contract \ --rpc-url mandala_testnet \ --verifier blockscout \ --verifier-url https://explorer.testnet.mandalachain.io:443/api/ \ 0xYourAddress \ src/Counter.sol:Counter ``` For mainnet, swap `mandala_testnet` for `mandala` and the verifier URL to `https://explorer.mandalachain.io:443/api/`. ## With the explorer UI [#with-the-explorer-ui] When the CLI flow fails or you only have the source files, use Blockscout directly. 1. Open your contract address on [explorer.mandalachain.io](https://explorer.mandalachain.io) (or the testnet equivalent). 2. Click the **Contract** tab. 3. Click **Verify and Publish**. 4. Pick the verification method: flattened source, multi-part files, or Sourcify metadata. 5. Provide source, compiler version, optimizer settings, and constructor arguments. 6. Submit. Blockscout compiles the source and compares the bytecode. If they match, the contract is verified and the source appears in the Code tab. ## Sourcify [#sourcify] Blockscout accepts Sourcify metadata. If your CI publishes to [Sourcify](https://sourcify.dev), the contract is auto-verified on Mandala once the metadata propagates. See [Blockscout's Sourcify integration docs](https://docs.blockscout.com/devs/verification/sourcify-method) for the wiring. ## When verification fails [#when-verification-fails] The most common cause is a mismatched build environment. Verification recompiles your source and compares bytecode byte-for-byte against the deployed contract. Anything that changes the compiler output breaks it: * Wrong compiler version * Wrong optimizer runs setting * Different EVM target version (`paris` vs `cancun`, etc.) * Missing or extra imports * File order in multi-file verification Use the exact build settings from when you deployed. If you do not own the deploy environment (a colleague deployed, the CI pipeline is gone), pull the source from Sourcify if available, or reconstruct the original `solidity` settings from your version control. # Accounts & Wallets (/docs/learn/accounts-and-wallets) This page is short because most of the answer is "the same as Ethereum." Mandala is EVM-equivalent and inherits Ethereum's account model, address format, and wallet ecosystem. ## EOAs [#eoas] Externally-owned accounts (EOAs) on Mandala work exactly as on Ethereum. Same secp256k1 keys, same address derivation, same signing. If you have an Ethereum address, you have a Mandala address; the same private key controls both. A few practical implications: * An address that holds ETH on Ethereum holds 0 KPG on Mandala by default, until you bridge or someone sends to that address on L2. * The same wallet seed signs both Ethereum and Mandala transactions. No new mnemonic, no new derivation path. * Address checksumming follows EIP-55; lowercase and checksummed forms address the same account. ## Smart-contract accounts [#smart-contract-accounts] ERC-4337 (account abstraction) works on Mandala. You can deploy entry points, bundlers, and paymasters using the standard ERC-4337 contracts. There is no chain-specific bundler infrastructure that needs custom configuration. Smart-contract wallets (Safe, Argent, and similar) work as long as their factories are deployed on Mandala. The deterministic deployer at `0x4e59b44847b379578588920ca78fbf26c0b4956c` is available, so contracts deployed deterministically on other EVM chains land at the same address on Mandala. ## Wallet support [#wallet-support] Any EVM wallet that lets you add a custom RPC works with Mandala. The most common paths: | Wallet | Setup | | ------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | **MetaMask** | Add a custom network with chain ID `20010` and RPC `https://rpc1-mainnet.mandalachain.io`. | | **Rabby** | Add as a custom chain with the same parameters; Rabby auto-detects most fields after the first connection. | | **WalletConnect-compatible wallets** | Connect via your dApp; the dApp passes the chain config. | | **Hardware wallets (Ledger, Trezor)** | Work behind MetaMask or Rabby. No firmware update needed. | Step-by-step setup walkthroughs live in the Network section: [MetaMask](/docs/network/wallet-setup/metamask), [Rabby](/docs/network/wallet-setup/rabby), and the [bridge](/docs/network/bridge/overview). ## ENS resolution [#ens-resolution] ENS names resolve on Ethereum, not on Mandala. To resolve `vitalik.eth` from a Mandala dApp, your client should query the L1 ENS registry. There is no chain-specific name service on Mandala today. ## What does not change [#what-does-not-change] To save you time looking for it: the following work identically on Mandala and Ethereum mainnet, and you do not need a Mandala-specific wallet, signer, or library. * Transaction signing (legacy, EIP-2930, EIP-1559). * Personal sign and EIP-712 typed-data signing. * ethers.js, viem, web3.js (point them at the Mandala RPC). * ABIs, function selectors, event topics. * Common precompiles (`ecrecover`, `sha256`). The Arbitrum-specific precompiles (`ArbSys` and friends) are documented in the Arbitrum docs. Arbitrum's [precompiles reference](https://docs.arbitrum.io/build-decentralized-apps/precompiles/01-overview) lists the Arbitrum-specific precompiles available on every Orbit chain, including Mandala. # Block Production & Finality (/docs/learn/block-production-and-finality) Two facts about Mandala that surprise builders coming from other L2s. 1. Mandala produces blocks **on demand**. There is no fixed block time. 2. There are **three different "finalities"** for a Mandala transaction. Which one matters depends on what you are doing. ## On-demand block production [#on-demand-block-production] The sequencer waits for at least one transaction. When a transaction arrives, the sequencer orders it and emits a block. If the chain is idle, no blocks are produced. Period. This is unusual. Ethereum has a 12-second slot, Arbitrum One has a \~250ms block, most L2s have something between. Mandala has none of those; the chain's clock is event-driven. The reasoning is straightforward: empty blocks cost L1 gas (the batch poster has to advance the chain) and provide no value. Skipping them keeps the chain cheap when traffic is low. For builders, three implications. Mandala's `block.timestamp` can move forward by seconds, minutes, or hours between two consecutive blocks, depending on traffic. If your contract uses `block.timestamp` for accounting, vesting, or rate-limiting, validate the math under irregular intervals. If your contract uses `block.number` as a clock, it will count more slowly than you expect. * **Time-based logic should use `block.timestamp`, not `block.number`.** Block numbers do not advance at a fixed rate. * **Per-block accounting (e.g. "X tokens minted per block") behaves differently** than on a fixed-slot chain. Convert to per-second accounting where you can. * **On-chain randomness from `block.timestamp` or `blockhash` is even less reliable than usual.** Use a verifiable randomness source (Chainlink VRF, on-chain commit-reveal) for any application that depends on randomness. ## Three flavors of finality [#three-flavors-of-finality] Mandala has three confirmation states, each with a different guarantee and a different latency. | Stage | Latency | What it guarantees | Who provides the guarantee | | ----------------------------------- | ---------- | ---------------------------------------------------------------------------------- | -------------------------------- | | **Soft (sequencer)** | Sub-second | The sequencer has ordered your tx and will include it in the next block. | The sequencer's word. | | **Hard (L1 batch posted)** | Minutes | Your tx is in a batch posted to L1. It cannot be re-ordered. | Ethereum's L1 finality. | | **Final (challenge window passed)** | \~7 days | The state root containing your tx has cleared the dispute window. Trust-minimized. | The Arbitrum dispute game on L1. | For most application use cases (token transfers, dApp interactions), **soft confirmation is enough**. The sequencer cannot include transactions you did not sign and cannot censor without giving you the L1 force-inclusion escape hatch. For **on-chain composability** between Mandala and other L2s or rollups, soft confirmation is also usually enough, because the other chain trusts Mandala's sequencer in the same way Mandala does. For **withdrawals to Ethereum**, you need **final confirmation**: the L1 Bridge contract enforces the challenge window before releasing funds. ## Visual timeline [#visual-timeline] The 7-day final-confirmation window is not a Mandala parameter; it is the standard Arbitrum optimistic-rollup challenge period. The [Trust & Security Model](/docs/learn/trust-and-security-model) page covers why it is what it is. ## Withdrawals back to Ethereum [#withdrawals-back-to-ethereum] To withdraw KPG or ETH back to Ethereum: 1. Submit an L2-to-L1 message via the L2 `ArbSys` precompile at `0x0000000000000000000000000000000000000064`. The Arbitrum Portal does this for you. 2. The message is included in a batch and posted to L1. 3. After the \~7-day challenge window, you (or anyone) can call `executeTransaction` on the L1 Bridge contract to release the funds. Step 3 is permissionless. Anyone can pay the L1 gas to execute your withdrawal once the challenge window has passed. If you need a faster withdrawal, third-party fast bridges sell the wait time at a discount. They are not part of the Mandala protocol; they take the credit risk on themselves. Arbitrum's [L1-to-L2 and L2-to-L1 messaging](https://docs.arbitrum.io/how-arbitrum-works/l1-to-l2-messaging) covers the messaging protocol, including how `ArbSys` interacts with the L1 outbox. # Gas & Fees (/docs/learn/gas-and-fees) Gas on Mandala is paid in **KPG** (Kepeng), not ETH. KPG is the native token of the chain; there is no separate fee token. If you have used Arbitrum One, the fee model is the same shape, with two changes: the units are KPG instead of ETH, and the L1 component is dramatically smaller because of AnyTrust. ## What you pay for [#what-you-pay-for] Every Mandala transaction pays two things, bundled into one fee. **L2 execution fee.** The cost of running your transaction's compute and storage on Mandala. Same shape as Ethereum gas, denominated in KPG-wei. EVM opcodes have the standard gas costs. ArbOS adds a small set of Arbitrum-specific operations. **L1 batch posting fee.** The cost of getting your transaction back to Ethereum. The batch poster pays Ethereum gas to submit a batch header (and a DAC certificate) to the L1 SequencerInbox, and that cost is amortized across all transactions in the batch. Each user pays their share. In rollup-mode chains, the L1 fee is the dominant cost: most of it is paying Ethereum to store full transaction calldata. In Mandala's AnyTrust mode, the L1 fee shrinks because only the batch header lands on L1; the bulk of the data lives in the DAC. This is the order-of-magnitude saving over standard rollups. ## Denomination conventions [#denomination-conventions] Gas prices in tooling (wallets, block explorers, ethers, viem) are typically labelled in "gwei." On Mandala, those numbers represent **KPG-gwei**, not ETH-gwei. The unit symbol does not change; the unit's underlying token does. * 1 KPG = 1018 KPG-wei. * 1 KPG-gwei = 109 KPG-wei. * A "20 gwei" gas price on Mandala means 20 KPG-gwei = 0.00000002 KPG per gas. If your tooling shows the gas price as "gwei" without a token label, assume it means KPG. A gas estimate of "0.0001" on Mandala means 0.0001 **KPG**, not 0.0001 ETH. KPG and ETH have different USD values; budget for them separately. ## A worked example [#a-worked-example] For a basic ERC-20 transfer: | Step | Value | | ------------------------------------ | ---------------------------------------- | | Gas used (typical ERC-20 `transfer`) | \~50,000 | | Gas price | varies with traffic and L1 base fee | | **Total fee** | gas used × gas price, denominated in KPG | These numbers are illustrative. The chain's actual gas price changes with L1 base fee, traffic, and batch posting cost. Use a wallet's live estimate before sending; do not budget production costs from this table. ## Fee distribution [#fee-distribution] Fees collected by the chain are split between: * **L1 reimbursement** to the batch poster, covering Ethereum gas spent posting batches and DAC certificates. * **L2 reimbursement** to the sequencer and validators, covering operating cost. * A protocol-level surplus that goes to the chain treasury. The exact split and what the treasury does with surplus KPG are part of the broader tokenomics, which the Learn section stays out of by design. Arbitrum's [gas and fees reference](https://docs.arbitrum.io/how-arbitrum-works/gas-fees) covers the full Arbitrum fee model, including the L2 execution component, the L1 amortization formula, and ArbOS's specific fee accounting. The same model applies to Mandala, with KPG instead of ETH. # Glossary (/docs/learn/glossary) Terms used across the Mandala docs, defined once. Alphabetical. A data availability mode for Arbitrum Orbit chains. Transaction data is stored by a Data Availability Committee (DAC) instead of being posted in full to Ethereum. The chain assumes at least two DAC members remain honest and online. Cheaper than full rollup mode, with a different trust assumption. Mandala uses AnyTrust. See [L2 & Arbitrum Orbit](/docs/learn/l2-and-arbitrum-orbit). The system-level operating layer of an Arbitrum or Arbitrum Orbit chain. Sits on top of the EVM and adds Arbitrum-specific behaviors (precompiles, gas accounting, retryables, L1-L2 messaging). Mandala runs ArbOS40. An Arbitrum precompile contract at L2 address `0x0000000000000000000000000000000000000064`. Contracts call it to send messages from L2 to L1, query block info, and access other L2-side helpers. Same address on every Orbit chain. The component that bundles sequenced transactions and posts them to Ethereum. On Mandala, the batch poster sends a header to the L1 SequencerInbox and the full payload to the DAC. The L1 contract that holds funds bridged from Ethereum to Mandala and releases funds withdrawn from Mandala to Ethereum. Mandala's bridge proxy is at `0x65DB181838b53f32428ce106fA5355b7e4806b79`. The \~7-day period after a state root is asserted on L1, during which validators can dispute it. Withdrawals from Mandala to Ethereum cannot finalize until this window passes. Standard Arbitrum optimistic-rollup parameter. See [Block Production & Finality](/docs/learn/block-production-and-finality). The set of operators who store transaction data in AnyTrust mode and sign availability certificates. On Mandala, the DAC is operated by the Mandala team and AltLayer. See [Trust & Security Model](/docs/learn/trust-and-security-model). An Ethereum-style account controlled by a private key, as opposed to a smart-contract account. EOAs on Mandala work identically to Ethereum: same addresses, same signing. The last of three Mandala confirmation stages. The state root containing your transaction has cleared the L1 challenge window and is trust-minimized. Required for withdrawing funds back to Ethereum. \~7 days after submission. See [Block Production & Finality](/docs/learn/block-production-and-finality). The mechanism by which a user can submit a transaction directly to the L1 Inbox if the Mandala sequencer is down or censoring. After a delay, anyone can finalize inclusion via the SequencerInbox, and the transaction lands on L2 whether or not the sequencer cooperates. The escape hatch from sequencer centralization. The unit of computational and storage cost on Mandala. Paid in KPG. Same shape as Ethereum gas: each EVM opcode has a fixed cost. The total fee is gas used multiplied by gas price, plus a small L1 amortization cost for posting the transaction back to Ethereum. See [Gas & Fees](/docs/learn/gas-and-fees). The middle of three Mandala confirmation stages. Your transaction is in a batch posted to L1 and cannot be re-ordered. Provides Ethereum-grade ordering guarantees. Reached in minutes after submission. The L1 contract where users submit transactions when the Mandala sequencer is unresponsive. After a delay, anyone can finalize inclusion via the SequencerInbox. Mandala's Inbox is at `0x62DfD05c460C7E55DA85B39EaD3eBc6e0CcdD0d5`. The native gas token of Mandala Chain. 18 decimals. Named after the traditional Balinese kepeng coin. All Mandala transaction fees are paid in KPG. **L1**: Layer 1, the base settlement chain (Ethereum, in Mandala's case). **L2**: Layer 2, a chain that derives its security from an L1; Mandala is an L2. **L3**: A chain that settles to an L2. Mandala is not an L3, but Orbit chains can be deployed as L3s on top of Mandala. An Ethereum Layer 2 built on the Arbitrum Orbit stack, using AnyTrust DA, settling to Ethereum L1. Chain ID `20010`. Native gas token KPG (Kepeng). The Arbitrum execution layer. Compiles Solidity-equivalent EVM bytecode and provides ArbOS on top. Mandala runs Nitro `v3.9.5-66e42c4`. Mandala's block production mode: blocks are produced only when at least one transaction has been submitted. No empty blocks, no fixed slot time. See [Block Production & Finality](/docs/learn/block-production-and-finality). The toolkit for launching custom L2s and L3s on top of the Arbitrum Nitro stack. Orbit chains run upstream Nitro and ArbOS but customize parameters: gas token, DA mode, settlement chain, validator set. Mandala is an Orbit chain. A type of L2 that posts transaction data and state commitments back to L1, where they can be challenged through a dispute game during a challenge window. Mandala is an optimistic rollup, in AnyTrust DA mode. The Mandala component that receives, orders, and produces blocks of transactions. Currently centralized, run by the Mandala team and AltLayer. Sequencer address: `0x445d701bd15c7207723e203a7f0cb850a5a39e60`. The L1 contract where the batch poster posts batch headers and DAC certificates. Force-inclusion (when the sequencer is unresponsive) is finalized via this contract after the user has first submitted to the L1 Inbox. Mandala's SequencerInbox is at `0x325acf46079d3f750D5D7E6182E094B1fD0AC2F4`. The chain that an L2 posts state commitments to. For Mandala, the settlement chain is Ethereum L1. An account controlled by a smart contract instead of a private key. Includes ERC-4337 wallets (Safe, Argent, and similar). Smart accounts work on Mandala identically to Ethereum. The first of three Mandala confirmation stages. The sequencer has acknowledged ordering your transaction. Sub-second latency, sufficient for most application use cases. Trust assumption: the sequencer. A framework from L2BEAT for evaluating L2 decentralization. Stage 0 means the L2 has training wheels and trusts a small operator set. Stage 1 means it has security council oversight. Stage 2 is fully trust-minimized. Mandala is Stage 0 today. # How Mandala is Built (/docs/learn/how-mandala-is-built) This page is the mechanical view: what is actually running and where it lives. Trade-offs and trust assumptions live on the [Trust & Security Model](/docs/learn/trust-and-security-model) page; the fee and finality details have their own pages. This one just lays out the parts. ## The components [#the-components] Mandala is an Arbitrum Orbit chain in AnyTrust mode. Five components, in the order a transaction touches them. | Component | What it does | Run by | | ------------------------------------- | ------------------------------------------------------------------------------------------------------ | ---------------------------------------------- | | **Sequencer** | Receives user transactions, orders them, produces L2 blocks. | Mandala team and AltLayer (centralized today). | | **Execution engine (Nitro)** | Runs the EVM, with ArbOS40 on top. | Same as the sequencer. | | **Batch poster** | Bundles sequenced transactions and posts them to L1: header to SequencerInbox, full data to the DAC. | Mandala team and AltLayer. | | **Data Availability Committee (DAC)** | Stores batch data and signs availability certificates that the batch poster includes in the L1 header. | Mandala team and AltLayer. | | **Validators** | Watch L2 state, post assertions to the L1 Rollup contract, dispute bad assertions. | Mandala team. | ArbOS40 and Nitro `v3.9.5-66e42c4` run the show. These are the same execution layers that power Arbitrum One; Mandala does not fork or modify them. ## The transaction lifecycle [#the-transaction-lifecycle] A transaction's path from user to finalized state, end to end. A few things to flag from the diagram. The sequencer's "soft confirmation" is not a finality guarantee; it is the sequencer saying "I have ordered your transaction and will include it in the next block." The hard guarantee comes when the batch header lands on L1. The trust-minimized guarantee comes after the challenge window. All three are covered on the [Block Production & Finality](/docs/learn/block-production-and-finality) page. ## Where things live on L1 [#where-things-live-on-l1] These addresses pin the chain. Anything claiming to be "Mandala on Ethereum" should match these. | Contract | Address | | ------------------- | -------------------------------------------- | | **Rollup** | `0x218D35154D1efEBFC46D64451C9495288219b275` | | **SequencerInbox** | `0x325acf46079d3f750D5D7E6182E094B1fD0AC2F4` | | **Inbox (delayed)** | `0x62DfD05c460C7E55DA85B39EaD3eBc6e0CcdD0d5` | | **Outbox** | `0x004eF39261cee56409Dbd26040a33Eca8326490C` | | **Bridge** | `0x65DB181838b53f32428ce106fA5355b7e4806b79` | The full surface, including the ERC-20 gateway/router contracts, lives in [Network Details](/docs/network/network-details). Withdrawals out of Mandala go through the L1 Bridge after the challenge window. Force-inclusion of L2 transactions, when the sequencer is unresponsive, starts at the L1 Inbox; after a delay anyone can finalize the inclusion via the SequencerInbox. On the L2 side, the standard Arbitrum precompile `ArbSys` lives at `0x0000000000000000000000000000000000000064`. That is what your contracts call to initiate L2-to-L1 messages. ## What is standard Orbit, and what isn't [#what-is-standard-orbit-and-what-isnt] The chain is standard Orbit + AnyTrust. Mandala's customization is in the parameters, not the protocol. * **Native gas token:** KPG instead of ETH. * **DA mode:** AnyTrust (instead of full rollup mode). * **Block production:** on demand (no empty blocks). * **Sequencer + DAC operators:** Mandala + AltLayer. Everything else (Nitro, ArbOS40, fraud proofs, retryable tickets, the L1 inbox model) is upstream Arbitrum protocol. The Arbitrum docs are the authoritative reference for those. Arbitrum's [How Arbitrum works: a gentle introduction](https://docs.arbitrum.io/how-arbitrum-works/a-gentle-introduction) walks through the Nitro architecture and the L1 inbox model in depth. # Introduction to Mandala Chain (/docs/learn/introduction-to-mandala-chain) Mandala Chain is an Ethereum Layer 2 built on the Arbitrum Orbit stack. It posts batches to Ethereum, settles via AnyTrust, and uses KPG (Kepeng) as its native gas token. If you can deploy on Arbitrum One, you can deploy on Mandala with the same toolchain, the same Solidity, and the same wallets pointed at a different RPC. Kepeng (KPG) takes its name from the traditional Balinese *kepeng* coin, a perforated bronze coin still used in temple offerings and village governance across Bali. The native token of an Indonesia-rooted L2 carries that name forward. | Detail | Value | | -------------------- | ------------------------------------------------------------------------- | | **Chain ID** | `20010` | | **Native gas token** | KPG (Kepeng), 18 decimals | | **Stack** | Arbitrum Orbit (Nitro), AnyTrust DA | | **Settlement** | Ethereum L1 | | **Block production** | On demand, only when there is a transaction | | **RPC** | `https://rpc1-mainnet.mandalachain.io` | | **Explorer** | [explorer.mandalachain.io](https://explorer.mandalachain.io) (Blockscout) | ## How it fits together [#how-it-fits-together] Three layers, one transaction path. Your dApp talks to Mandala. Mandala batches transactions, hands the data to a Data Availability Committee (DAC), and posts a small batch header back to Ethereum. Three things to notice in that picture: 1. **The DAC stores the bulk of transaction data**, not Ethereum. That is what makes Mandala roughly an order of magnitude cheaper than rollups that post full data to Ethereum calldata. 2. **The sequencer is on demand.** It produces a block when at least one transaction has arrived. There are no empty blocks and no fixed slot time. 3. **Withdrawals back to Ethereum still go through a challenge window.** Funds bridged out of Mandala finalize on Ethereum after the standard Arbitrum dispute period. The pages that follow expand on each of those. # L2 & Arbitrum Orbit (/docs/learn/l2-and-arbitrum-orbit) This page is short. Its job is to give you just enough vocabulary to read the rest of the Learn section. The Arbitrum docs cover each of these concepts in much greater depth, and we link out throughout. If you already know what an L2, an optimistic rollup, Arbitrum Orbit, and AnyTrust are, skip ahead to [How Mandala is Built](/docs/learn/how-mandala-is-built). ## What is an L2? [#what-is-an-l2] A Layer 2 (L2) is a blockchain that derives its security from a Layer 1 (Ethereum, in our case) instead of from its own consensus. Users send transactions to the L2, the L2 executes them, and the L2 periodically posts a summary of what it did back to the L1. If the L2 misbehaves, the L1 can reject its summary. The point is throughput. Ethereum is a global settlement layer with global consensus, and that is expensive. An L2 inherits Ethereum's security guarantees while running its own execution, which means cheaper transactions and faster confirmations without asking every Ethereum validator to re-execute every transaction. ## What is an optimistic rollup? [#what-is-an-optimistic-rollup] An optimistic rollup is a specific kind of L2. The "optimistic" part means it assumes the L2 sequencer is honest by default and only checks for fraud if someone challenges. The "rollup" part means it posts both transaction data and state commitments back to L1, so anyone can independently re-execute the chain. After each L2 state assertion, there is a window (typically 7 days on Ethereum) during which validators can dispute the assertion. If no one disputes within that window, the assertion is final. If someone does dispute, the disagreement is resolved on L1 by an interactive proving game. The challenge window is why withdrawals from optimistic rollups to Ethereum take \~7 days. It is the time the system gives validators to spot and dispute a bad state root before funds are released. Arbitrum's [gentle introduction to BoLD and fraud proofs](https://docs.arbitrum.io/how-arbitrum-works/bold/gentle-introduction) covers the dispute game in depth. We do not duplicate it here. ## What is Arbitrum Orbit? [#what-is-arbitrum-orbit] Arbitrum Orbit is the toolkit Arbitrum publishes for launching custom L2s and L3s on top of the Arbitrum stack. An Orbit chain runs the same Nitro execution layer that powers Arbitrum One, but with parameters of its own choosing: gas token, DA mode, settlement chain, validator set, fee distribution, and more. Mandala is one of those Orbit chains. It runs Nitro for execution, settles to Ethereum L1, uses KPG as the gas token, and operates in AnyTrust mode for data availability. The [Orbit gentle introduction](https://docs.arbitrum.io/launch-orbit-chain/orbit-gentle-introduction) walks through Orbit's customization surface and the kinds of chains it is meant for. ## What is AnyTrust? [#what-is-anytrust] AnyTrust is a data availability mode that Orbit chains can choose. In standard rollup mode, the full transaction payload goes to Ethereum calldata or blobs, where it lives forever and any Ethereum node can serve it. In AnyTrust mode, the payload goes to a Data Availability Committee (DAC) instead, and only a small header plus the DAC's signature goes to Ethereum. The trade-off is what makes AnyTrust cheaper: instead of paying Ethereum gas for every byte of every transaction, the chain pays for a fixed-size header. The cost is a trust assumption. In AnyTrust mode, the chain assumes that **at least two members of the DAC remain honest and online** to serve the data when asked. The [Trust & Security Model](/docs/learn/trust-and-security-model) page covers the AnyTrust assumption in detail, including failure modes and how the chain behaves if the DAC misbehaves. Arbitrum's [Inside AnyTrust](https://docs.arbitrum.io/how-arbitrum-works/inside-anytrust) page explains the DAC certificate format, the threshold honesty assumption, and the on-chain enforcement that keeps the DAC honest. # Trust & Security Model (/docs/learn/trust-and-security-model) This is the most important page in the Learn section. Read it carefully if you intend to deposit funds or build production applications on Mandala. Mandala launched recently and runs in a centralized configuration that is standard for new Arbitrum Orbit chains. The L2BEAT framework calls this **Stage 0**. That is the honest assessment. The roadmap covers the path to Stage 1 and beyond; today is Stage 0. Plan accordingly. ## The three trust assumptions [#the-three-trust-assumptions] Three groups of operators, three different failure modes, three different mitigations. ### 1. The sequencer [#1-the-sequencer] Mandala runs a single sequencer at address `0x445d701bd15c7207723e203a7f0cb850a5a39e60`, operated by the Mandala team in coordination with AltLayer. This is consistent with how new Orbit chains launch. A centralized sequencer **cannot steal your funds**. It cannot forge transactions on your behalf, and it cannot include transactions you did not sign. The worst it can do is **censor**: refuse to include your transaction, or order transactions in a way that disadvantages you. If the sequencer goes down or starts censoring, you can submit your transaction directly to the L1 Inbox at `0x62DfD05c460C7E55DA85B39EaD3eBc6e0CcdD0d5`. After a delay, anyone can finalize the inclusion via the L1 SequencerInbox at `0x325acf46079d3f750D5D7E6182E094B1fD0AC2F4`, and the transaction lands on L2 whether or not the sequencer cooperates. Force-inclusion is the escape hatch and it works even if the sequencer is offline. ### 2. The Data Availability Committee (DAC) [#2-the-data-availability-committee-dac] Mandala uses AnyTrust DA. Transaction data is stored by the DAC, not by Ethereum. The DAC is currently operated by the Mandala team and AltLayer. The AnyTrust assumption is that **at least two members of the DAC remain honest and online**. As long as that holds, anyone can retrieve transaction data from the DAC, the chain can be re-executed by independent observers, and validators can detect bad state assertions. If the DAC fails (fewer than two members will serve data), the protocol falls back: the chain stops accepting new state assertions until the data becomes retrievable. The chain does not advance into a state nobody can verify. This is the AnyTrust safety property, enforced on L1. What the DAC cannot do, even if every member colludes: * Forge transactions or sign for users. * Move funds. * Finalize a state root that is not derived from posted batch data. What the DAC can do if it misbehaves: * Refuse to serve data, halting the chain's progress until governance can rotate the committee. Members beyond the operating umbrella are TBC and will be listed here when published. ### 3. The validator set [#3-the-validator-set] Validators watch L2 execution and post state assertions to the L1 Rollup contract. If a validator posts a wrong assertion, any other validator can challenge it through the BoLD dispute game, and the wrong assertion is rejected on L1. The validator set on Mandala is currently allowlisted to operators run by the Mandala team. The transition to a permissionless validator set follows the upstream Arbitrum BoLD timeline. This page will be updated when that state changes. ## Withdrawal challenge window [#withdrawal-challenge-window] Funds bridged from Mandala back to Ethereum take **\~7 days** to finalize. This is not a Mandala-specific choice; it is the standard Arbitrum optimistic-rollup challenge window. It is the time the system gives validators to dispute a bad state root before withdrawals release on L1. For deposits (Ethereum → Mandala), there is no challenge window. Deposits finalize as soon as the L1 transaction confirms. If you need faster withdrawals than 7 days, third-party bridges (fast bridges, intent-based bridges) can give you instant withdrawals at the cost of paying a fee to a liquidity provider. They are not part of Mandala's canonical bridge. ## Failure modes, in one table [#failure-modes-in-one-table] | If this fails... | The chain... | You can... | | ------------------------------------- | ----------------------------------------------- | ------------------------------------ | | Sequencer is offline | Stops producing L2 blocks | Force-include via L1 Inbox | | Sequencer is censoring | Refuses your transaction | Force-include via L1 Inbox | | DAC has fewer than two honest members | Stops advancing state until data is retrievable | Wait; the chain is safe but halted | | A validator posts a bad state root | Bad root is rejected during challenge window | Nothing; the dispute game handles it | | Bridge contract bug | Funds at risk depending on the bug | Watch for security disclosures | * The [L2BEAT stages framework](https://l2beat.com/scaling/risk) explains Stage 0/1/2 in detail. * Arbitrum's [Inside AnyTrust](https://docs.arbitrum.io/how-arbitrum-works/inside-anytrust) covers DAC enforcement on L1. * Arbitrum's [BoLD gentle introduction](https://docs.arbitrum.io/how-arbitrum-works/bold/gentle-introduction) covers the dispute game. # Why Mandala Chain? (/docs/learn/why-mandala-chain) Three reasons, in plain order. **EVM-equivalent.** Solidity, Hardhat, Foundry, MetaMask, Rabby, ethers, viem. Anything that runs on Arbitrum One runs on Mandala against a different RPC. You do not learn a new language, a new account model, or a new wallet flow. **Cheap by construction.** AnyTrust DA moves the bulk of transaction data off Ethereum calldata and into a Data Availability Committee (DAC). The L1 cost per transaction drops to the cost of posting a header plus a signature, not the full payload. In practice this is roughly an order of magnitude cheaper than rollup chains that put full data on Ethereum. **On-demand block production.** No empty blocks. The sequencer waits for at least one transaction, orders it, and emits a block. For traffic that comes in bursts, which is most application chains, this means the chain is never doing busywork to keep a fixed block clock running. That covers the technical pitch. The harder question is "why deploy here instead of Arbitrum One, or Base, or any other Ethereum L2?" The answer is mostly about fit. ## Mandala vs Arbitrum One vs a generic Ethereum L2 [#mandala-vs-arbitrum-one-vs-a-generic-ethereum-l2] | Feature | Mandala | Arbitrum One | Generic Ethereum L2 | | ------------------------------- | -------------------------------- | --------------------------- | --------------------- | | **Gas token** | KPG | ETH | ETH | | **Data availability** | AnyTrust (DAC) | Ethereum calldata + blobs | Varies | | **Block model** | On demand | Fixed slot (\~250ms) | Fixed slot | | **Settlement** | Ethereum L1 | Ethereum L1 | Ethereum L1 | | **Sequencer (today)** | Centralized (Mandala + AltLayer) | Centralized (Offchain Labs) | Varies | | **Withdrawal challenge window** | \~7 days | \~7 days | \~7 days (optimistic) | | **EVM compatibility** | EVM-equivalent | EVM-equivalent | Varies | Mandala makes a different DA bet than Arbitrum One. Arbitrum One pays full Ethereum DA cost in exchange for the strongest possible data-availability guarantee. Mandala pays a DAC trust assumption in exchange for an order-of-magnitude lower L1 fee. Both choices are reasonable. They are reasonable for *different* applications, which is the section below. ## Who Mandala is for [#who-mandala-is-for] Three application shapes that fit Mandala particularly well. * **High-frequency, low-value transactions.** Loyalty, rewards, ticketing, in-app payments, gaming. Anything where a fraction-of-a-cent base fee per transaction is the difference between viable and not viable. AnyTrust pricing makes this work. * **Real-world assets and identity.** Verifiable claims, supply-chain attestations, asset registries. The on-demand block model means low-traffic state stays cheap to maintain because the chain stops producing blocks when there is nothing to do. * **Indonesia and Southeast Asia.** Mandala is built and operated out of Indonesia. Local fintech, payments, and consumer apps are a primary audience, and KPG (Kepeng) anchors the chain in that context. # Block Explorer (/docs/network/block-explorer) Mandala uses Blockscout as its block explorer. | Network | URL | | :---------- | :--------------------------------------------------------------------------- | | **Mainnet** | [explorer.mandalachain.io](https://explorer.mandalachain.io) | | **Testnet** | [explorer.testnet.mandalachain.io](https://explorer.testnet.mandalachain.io) | Blockscout dashboard overview ## Finding data [#finding-data] The search bar at the top of the page accepts addresses (`0x...`), transaction hashes, block numbers, and ENS names (resolved via L1). The explorer auto-detects the input type and routes you to the appropriate page. ## Inspecting transactions [#inspecting-transactions] A transaction page shows status (success or failure), gas used, gas price actually paid, the value transferred, and every event emitted during execution. Failed transactions usually surface their revert reason in the Logs section, which is the first place to look when debugging. Blockscout transaction page ## Viewing accounts [#viewing-accounts] Searching for a wallet or contract address gives you the full transaction history, KPG balance, internal transactions, and held tokens. The **Tokens** tab shows ERC-20 holdings; **NFTs** shows ERC-721 and ERC-1155. Blockscout address page ## Inspecting deployed contracts [#inspecting-deployed-contracts] Searching for a contract address takes you to its contract page. The tabs that matter: * **Transactions**: every interaction with the contract, including its creation. * **Token Transfers**: ERC-20/721/1155 transfers in or out, if applicable. * **Logs**: every event emitted, filterable by signature. * **Contract**: bytecode and (if verified) source code. Blockscout contract page ## Verifying your contract [#verifying-your-contract] Verification publishes your source so Blockscout can decode calls and let users interact with the contract directly from the explorer. The standard flow: 1. Go to your contract's address page and open the **Contract** tab. 2. Click **Verify and Publish**. 3. Choose your verification method (Solidity flattened, multi-part files, Sourcify, or hardhat-verify / foundry). 4. Match the compiler version exactly to your deployment build. If the bytecode matches, the explorer marks the contract verified and shows the source code. Blockscout contract verification form For detailed verification guides covering Sourcify, Foundry, Hardhat, and API-based methods, see the [Blockscout verification documentation](https://docs.blockscout.com/devs/verification). ## API access [#api-access] Blockscout exposes an Etherscan-compatible REST API at `https://explorer.mandalachain.io:443/api/`. Common uses: programmatic verification, transaction monitoring, and indexing. Refer to the [Blockscout API docs](https://docs.blockscout.com/devs/apis) for the full surface. # Network Details (/docs/network/network-details) The canonical reference for adding Mandala to wallets, RPC clients, and dApps. Pin these values; they should not change. ## Mainnet [#mainnet] Use these settings to connect any EVM tool (MetaMask, Rabby, Hardhat, Foundry, ethers, viem) to Mandala mainnet. | Detail | Value | | :------------------- | :-------------------------------------- | | **Network Name** | Mandala Chain | | **Chain ID** | `20010` | | **RPC URL** | `https://rpc1-mainnet.mandalachain.io` | | **WebSocket URL** | `wss://rpc1-mainnet.mandalachain.io/ws` | | **Block Explorer** | `https://explorer.mandalachain.io` | | **Native Currency** | KPG (Kepeng) | | **Decimals** | `18` | | **Settlement chain** | Ethereum L1 | For step-by-step wallet setup, see [MetaMask](/docs/network/wallet-setup/metamask) or [Rabby](/docs/network/wallet-setup/rabby). ## Testnet [#testnet] For development and testing, Mandala maintains a separate testnet that settles to Sepolia. Connection values live on the [Testnet Network Details](/docs/network/testnet/network-details) page, and you can claim free KPGT from the [Faucet](/docs/network/testnet/faucet). ## L1 (Ethereum) contracts [#l1-ethereum-contracts] These are the Mandala core contracts deployed on Ethereum L1. They are the trust-relevant addresses: any reference to "Mandala on Ethereum" should match this set. | Contract | Address | Purpose | | :------------------ | :------------------------------------------- | :------------------------------------------------------------------------------------------------ | | **Rollup** | `0x218D35154D1efEBFC46D64451C9495288219b275` | State assertions and dispute game. | | **SequencerInbox** | `0x325acf46079d3f750D5D7E6182E094B1fD0AC2F4` | Where the batch poster posts batches. Force-inclusion is finalized here. | | **Inbox (delayed)** | `0x62DfD05c460C7E55DA85B39EaD3eBc6e0CcdD0d5` | Where users submit transactions when the sequencer is unresponsive (force-inclusion entry point). | | **Outbox** | `0x004eF39261cee56409Dbd26040a33Eca8326490C` | Where L2-to-L1 messages are released after the challenge window. | | **Bridge** | `0x65DB181838b53f32428ce106fA5355b7e4806b79` | Holds bridged ETH and routes deposits/withdrawals. | For the trust assumptions tied to these contracts, see [Trust & Security Model](/docs/learn/trust-and-security-model). ## L2 (Mandala) contracts [#l2-mandala-contracts] Helpful addresses on the L2 side of Mandala. | Contract | Address | Purpose | | :------------ | :------------------------------------------- | :-------------------------------------------------------------------------------------------------------- | | **ArbSys** | `0x0000000000000000000000000000000000000064` | Arbitrum precompile. Contracts call it to send messages from L2 to L1. Same address on every Orbit chain. | | **Multicall** | `0x7Bb2526e78c03Ec31BFb1478DF5795C580f77538` | Standard Multicall, useful for batched read calls. | ## Bridge [#bridge] The official bridge UI is hosted by Arbitrum Portal: [portal.arbitrum.io/bridge](https://portal.arbitrum.io/bridge?destinationChain=mandala-chain\&sanitized=true\&sourceChain=ethereum). For the deposit and withdrawal flows, see [Bridge Overview](/docs/network/bridge/overview). # Frequently Asked Questions (/docs/support/faq) ## What is Mandala Chain? [#what-is-mandala-chain] An Ethereum Layer 2 built on the Arbitrum Orbit stack. EVM-equivalent execution, AnyTrust data availability, settles to Ethereum L1. Chain ID `20010`, native gas token KPG (Kepeng). ## When did Mandala launch? [#when-did-mandala-launch] Mainnet genesis was February 23, 2026. The testnet runs in parallel and settles to Sepolia. ## Who runs Mandala? [#who-runs-mandala] The Mandala team operates the sequencer, batch poster, and validators today, in coordination with AltLayer as the rollup-as-a-service provider. The chain is in Stage 0 of L2BEAT's decentralization framework. Full breakdown in [Trust & Security Model](/docs/learn/trust-and-security-model). ## Is Mandala open source? [#is-mandala-open-source] Mandala runs upstream Arbitrum Nitro and ArbOS, both open source under the Arbitrum license. Mandala-specific operational code and configuration are at [github.com/MandalaChain](https://github.com/MandalaChain). ## What is KPG? [#what-is-kpg] KPG (Kepeng) is the native gas token of Mandala Chain. 18 decimals. Every transaction fee is paid in KPG. Named after the traditional Balinese kepeng coin. ## How do I get KPG? [#how-do-i-get-kpg] Bridge ETH or KPG from Ethereum through the [Arbitrum Portal](https://portal.arbitrum.io/bridge?destinationChain=mandala-chain\&sourceChain=ethereum). Bridged ETH lands on Mandala as ETH (useful for cross-chain accounting but not used for gas); bridged KPG arrives as your gas balance. ## Is there a testnet faucet? [#is-there-a-testnet-faucet] Yes. The [Mandala Chain Faucet](https://faucet.mandalachain.io/) sends 10 KPGT per address per day. See the [Faucet](/docs/network/testnet/faucet) page for the full walkthrough. ## Does KPG have utility beyond gas? [#does-kpg-have-utility-beyond-gas] Paying gas is the primary utility today. Further roles such as governance, staking, and fee distribution are part of the broader tokenomics and will be detailed once the relevant docs ship. ## Which wallets work with Mandala? [#which-wallets-work-with-mandala] Any EVM wallet that supports adding a custom RPC. MetaMask, Rabby, Coinbase Wallet, Frame, and hardware wallets (Ledger, Trezor) behind any of those. Step-by-step guides for [MetaMask](/docs/network/wallet-setup/metamask) and [Rabby](/docs/network/wallet-setup/rabby). ## Can I use Hardhat and Foundry? [#can-i-use-hardhat-and-foundry] Yes. Both work against Mandala by adding a network entry pointing at the RPC. Configurations and deploy snippets in [Hardhat](/docs/build/hardhat) and [Foundry](/docs/build/foundry). ## Can I port my Ethereum dApp to Mandala? [#can-i-port-my-ethereum-dapp-to-mandala] In most cases yes, with two changes: point your RPC at Mandala and update your wallet's chain configuration. The EVM, Solidity compiler output, opcodes, and standard precompiles behave identically. The small list of things that do change lives in [Differences from Ethereum](/docs/build/differences-from-ethereum). ## How do I bridge funds to Mandala? [#how-do-i-bridge-funds-to-mandala] The [Arbitrum Portal](https://portal.arbitrum.io/bridge?destinationChain=mandala-chain\&sourceChain=ethereum) is the canonical bridge UI. Deposits land on Mandala in minutes after the L1 transaction confirms. Walkthrough: [Deposit from Ethereum](/docs/network/bridge/deposit-from-ethereum). ## Why do withdrawals to Ethereum take \~7 days? [#why-do-withdrawals-to-ethereum-take-7-days] Standard optimistic-rollup challenge window. After you initiate a withdrawal on L2, the state assertion containing it has to clear the dispute period before the L1 Bridge releases your funds. Third-party fast bridges sell the wait time at a fee but are not part of the Mandala protocol. Walkthrough: [Withdraw to Ethereum](/docs/network/bridge/withdraw-to-ethereum). ## What is AnyTrust? [#what-is-anytrust] A data availability mode for Arbitrum Orbit chains. Transaction data is stored by a Data Availability Committee (DAC) instead of being posted in full to Ethereum, which makes the chain roughly an order of magnitude cheaper than rollup-mode chains. The trade-off is a trust assumption: at least two DAC members must remain honest and online for data to remain retrievable. Full picture in [L2 & Arbitrum Orbit](/docs/learn/l2-and-arbitrum-orbit#what-is-anytrust). ## Why is the gas token KPG instead of ETH? [#why-is-the-gas-token-kpg-instead-of-eth] Arbitrum Orbit lets each chain pick its own native gas token. Mandala chose KPG for tokenomics and cultural identity reasons (the Balinese kepeng coin). The mechanics of paying fees are identical to ETH-based chains; only the denominating token differs. ## How fast is finality on Mandala? [#how-fast-is-finality-on-mandala] Three flavors of finality. Soft confirmation from the sequencer is sub-second. Hard finality (your transaction is in a batch posted to L1) is minutes. Trust-minimized finality (the L1 state root has cleared the challenge window) is \~7 days. Full picture in [Block Production & Finality](/docs/learn/block-production-and-finality). ## What's the block time on Mandala? [#whats-the-block-time-on-mandala] There is no fixed block time. Blocks are produced on demand when at least one transaction has been submitted, so consecutive blocks can be seconds, minutes, or hours apart depending on traffic. Implications for builders: do not use `block.number` as a clock. See [Block Production & Finality](/docs/learn/block-production-and-finality) for the full builder guide. ## Where do I report a security issue? [#where-do-i-report-a-security-issue] Do not open a public issue. Email `security@mandalachain.io` with a reproduction and severity assessment. Full process in [Getting Help](/docs/support/getting-help#security-disclosures). # Getting Help (/docs/support/getting-help) ## Community channels [#community-channels] ## Bug reports [#bug-reports] For bugs in the chain, the bridge, the explorer, or these docs: 1. Reproduce the bug. Capture the network (mainnet or testnet), affected addresses or transaction hashes, expected behavior, and the actual output. 2. Report through Discord or Telegram (links above) with the details from step 1. 3. If the bug affects funds, liveness, or user data, follow the [security disclosure](#security-disclosures) path instead. ## Security disclosures [#security-disclosures] For vulnerabilities that put funds, user data, or the chain's liveness at risk, do not open a public issue. Report privately to `security@mandalachain.io`. Include in your report: * Affected component (chain, bridge, specific contract address, etc.) * Reproduction steps or proof of concept * Severity assessment in your own words * A disclosure timeline you propose The Mandala team acknowledges receipt, triages, and coordinates fix and disclosure. A public security advisory is published once the fix ships. ## How to ask a useful question [#how-to-ask-a-useful-question] The faster a maintainer or community member can reproduce your problem, the faster you get an answer. * **What you are trying to do**, in one sentence. * **What you tried**, with the exact command or code. * **What happened**, with the exact error message. * **Where**, including chain (mainnet or testnet) and any relevant addresses or transaction hashes. A useful question: > Deploying `Counter.sol` to testnet (chain `20011`) with Foundry. `forge create` fails with `Error: chain id 20011 not found`. My `foundry.toml` has the testnet RPC under `[rpc_endpoints]`. What am I missing? A question that takes longer to answer: > Hi, my contract doesn't work, can someone help ## What this page does not cover [#what-this-page-does-not-cover] * **Finance, accounting, or regulatory questions.** Out of scope. Talk to your own counsel. * **Token price, market, or trading questions.** Out of scope. These belong in community channels, not docs. * **Validator-set, DAC membership, or partnership inquiries.** These go through the Mandala team directly. Reach out via Discord or Telegram and ask for the appropriate contact. # Deposit from Ethereum (/docs/network/bridge/deposit-from-ethereum) Deposits go from Ethereum L1 down to Mandala. They settle in minutes and have no challenge window. Once the L1 transaction is confirmed and the sequencer picks it up, the funds are on Mandala. ## Before you start [#before-you-start] * A wallet with both Ethereum mainnet and Mandala Chain (Chain ID `20010`) added. See [MetaMask](/docs/network/wallet-setup/metamask) or [Rabby](/docs/network/wallet-setup/rabby). * Funds on Ethereum L1 to bridge. ETH, KPG, or any ERC-20. * Extra ETH on L1 to pay for the deposit transaction's L1 gas. ## Steps [#steps] 1. Open the Arbitrum Portal Mandala bridge: [portal.arbitrum.io/bridge → Ethereum to Mandala](https://portal.arbitrum.io/bridge?destinationChain=mandala-chain\&sanitized=true\&sourceChain=ethereum) 2. **Connect** your wallet. Make sure it is on **Ethereum** as the source. 3. Confirm the source/destination: * Source: **Ethereum** * Destination: **Mandala Chain** 4. **Pick the token** to bridge (ETH, KPG, or an ERC-20). 5. **Enter the amount.** The Portal previews the L1 gas cost and any L2 execution gas required to credit the deposit on Mandala. 6. **Confirm in your wallet.** The deposit transaction goes to your wallet for signature; once signed and broadcast, it lands on Ethereum L1. 7. **Wait for the L1 confirmation.** Typically 1-2 minutes after submission, depending on Ethereum's gas market. 8. **Check your balance on Mandala.** The matching balance appears on L2 within a few minutes of the L1 confirmation. ## What lands on Mandala [#what-lands-on-mandala] | Token bridged | Balance on Mandala | | :------------ | :---------------------------------------------------------------------------------------------------------------------- | | **ETH** | ETH balance on Mandala. Useful for contracts and bridges; not used for gas. | | **KPG** | Native KPG balance. This is the gas token. | | **ERC-20** | The ERC-20 mirrored on Mandala via the canonical token gateway. Custom gateways are routed automatically by the Portal. | ## Confirmations [#confirmations] Deposits do not have a challenge window. They finalize as soon as the L1 transaction is included in a block, plus a short propagation delay while the sequencer picks up the deposit message. The first time you bridge a particular ERC-20, the gateway may need to register it on Mandala. The Portal handles this automatically; the first deposit of a new token can take slightly longer than subsequent ones. ## Tracking the deposit [#tracking-the-deposit] * **L1 side:** the deposit transaction shows up in your wallet's history and on Etherscan. * **L2 side:** [explorer.mandalachain.io](https://explorer.mandalachain.io) will show the matching transaction credited to your address once the sequencer has included it. ## Troubleshooting [#troubleshooting] **Funds not showing up on Mandala after 10+ minutes.** Confirm the L1 transaction was successful (not failed) on Etherscan. If it succeeded, refresh the Portal. It tracks pending L1-to-L2 messages and surfaces them under "History" or the equivalent tab. **Wrong network in wallet.** The Portal expects you to be on Ethereum L1 to deposit. Switch your wallet network and reload. **Custom ERC-20 not in the dropdown.** The Portal supports adding tokens by L1 contract address; look for an "import token" option, or paste the L1 address. # Overview (/docs/network/bridge/overview) Bridging means moving funds between Ethereum L1 and Mandala. There are two directions, with very different timing profiles, and Mandala uses the standard Arbitrum optimistic-rollup bridge model with no chain-specific quirks at the user-facing level. ## Two directions, two timelines [#two-directions-two-timelines] | Direction | Timing | What happens | | :--------------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------ | | **Ethereum → Mandala** | Minutes | Funds lock in the L1 Bridge contract, the sequencer picks up the deposit, and the matching balance appears on Mandala. No challenge window. | | **Mandala → Ethereum** | \~7 days | You initiate on L2. After the optimistic-rollup challenge window passes on L1, you (or anyone) can claim the funds on Ethereum. | The 7-day window is not a Mandala parameter; it is the standard Arbitrum dispute period. For why it exists, see [Trust & Security Model](/docs/learn/trust-and-security-model#withdrawal-challenge-window). ## Use the Arbitrum Portal [#use-the-arbitrum-portal] The official Mandala bridge UI is hosted at the Arbitrum Portal: [**portal.arbitrum.io/bridge** (Mandala route)](https://portal.arbitrum.io/bridge?destinationChain=mandala-chain\&sanitized=true\&sourceChain=ethereum) Arbitrum Portal bridge with Mandala selected as destination The Portal handles both deposits and withdrawals, supports ETH plus arbitrary ERC-20s through the canonical token gateways, and routes claim transactions on L1 once a withdrawal's challenge window has passed. The Mandala team does not host its own bridge UI. The Portal is the canonical interface. ## What you can bridge [#what-you-can-bridge] * **ETH**: lands on Mandala as ETH balance. * **KPG**: lands on Mandala as native KPG, which is the gas token of the chain. * **ERC-20 tokens**: routed through the standard or custom token gateway, depending on whether the project has registered a custom gateway. The Portal handles the routing automatically. ## L1 contracts behind the bridge [#l1-contracts-behind-the-bridge] The Portal is a UI in front of these L1 contracts: | Contract | Address | | :------------------ | :------------------------------------------- | | **Bridge** | `0x65DB181838b53f32428ce106fA5355b7e4806b79` | | **Inbox (delayed)** | `0x62DfD05c460C7E55DA85B39EaD3eBc6e0CcdD0d5` | | **Outbox** | `0x004eF39261cee56409Dbd26040a33Eca8326490C` | Deposits go through the Inbox. Withdrawals are released by the Outbox after the challenge window passes. The Bridge holds the underlying funds. ## Faster withdrawals [#faster-withdrawals] Third-party fast bridges (intent-based, liquidity-provider-backed) can give you instant withdrawals at the cost of paying a fee to a liquidity provider. They take the credit risk on themselves and front you the funds while the canonical 7-day withdrawal completes in the background. These services are not part of Mandala's protocol. Use them if the timing trade-off is worth the fee. ## Per-direction walkthroughs [#per-direction-walkthroughs] * [Deposit from Ethereum](/docs/network/bridge/deposit-from-ethereum) * [Withdraw to Ethereum](/docs/network/bridge/withdraw-to-ethereum) # Withdraw to Ethereum (/docs/network/bridge/withdraw-to-ethereum) Withdrawals go from Mandala back up to Ethereum. They take \~7 days because the optimistic-rollup challenge window enforced by the L1 Bridge has to pass before funds can be released. There is no way to skip this on the canonical bridge. The challenge window is enforced by the L1 contracts. Mandala has no fast path. If you need funds on L1 sooner, use a third-party fast bridge that fronts the funds for a fee. See [Faster withdrawals](#faster-withdrawals) below. ## Before you start [#before-you-start] * A wallet on Mandala Chain (Chain ID `20010`) with KPG for gas. * The funds on Mandala that you want to withdraw. * Some ETH on Ethereum L1 to pay for the eventual claim transaction (Step 3 below). ## Steps [#steps] 1. **Initiate on L2** Open the Arbitrum Portal Mandala bridge with the direction reversed: [portal.arbitrum.io/bridge → Mandala to Ethereum](https://portal.arbitrum.io/bridge?destinationChain=ethereum\&sanitized=true\&sourceChain=mandala-chain) Connect your wallet on Mandala. Pick the token (ETH, KPG, ERC-20) and the amount. Confirm in your wallet. This submits an L2-to-L1 message via the `ArbSys` precompile at `0x0000000000000000000000000000000000000064`. 2. **Wait for the challenge window** The Portal will show your withdrawal as pending with a countdown. The window is approximately 7 days. The exact unlock time depends on when the L2 state root containing your withdrawal is asserted on L1. 3. **Claim on L1** Once the window passes, return to the Portal. Connect your wallet on **Ethereum**. Find your pending withdrawal in the history tab and click **Claim**. This triggers an L1 transaction that pulls the funds out of the Outbox at `0x004eF39261cee56409Dbd26040a33Eca8326490C` and delivers them to your address on L1. You pay the L1 gas for the claim. If you do not claim, anyone else can claim on your behalf to your address; the claim is permissionless. ## What lands on Ethereum [#what-lands-on-ethereum] | Token withdrawn | Balance on Ethereum | | :-------------- | :-------------------------------------------------------------------------------------------------------------- | | **ETH** | ETH balance on Ethereum L1. | | **KPG** | The L1 representation of KPG (the same ERC-20 that the bridge uses on the L1 side). | | **ERC-20** | The original L1 token (or, for tokens with custom bridge logic, the canonical L1 form returned by the gateway). | ## Why 7 days [#why-7-days] The 7-day delay is the optimistic-rollup challenge window. It gives validators time to dispute a bad L2 state root before the L1 Outbox releases funds. Mandala does not set this value; it is the standard Arbitrum dispute period. For the full story, see [Trust & Security Model](/docs/learn/trust-and-security-model#withdrawal-challenge-window). ## Faster withdrawals [#faster-withdrawals] Third-party fast bridges sell the wait time for a fee. They monitor your pending L2 withdrawal, front you the equivalent funds on L1 immediately, and collect the canonical withdrawal once the window passes. The trade-offs: * **Pro:** funds in minutes instead of days. * **Con:** you pay a discount fee to the liquidity provider. * **Con:** trust shifts to the fast-bridge operator until the canonical withdrawal lands. These services are not part of Mandala's protocol. They are operated by third parties. Examples (not exhaustive, not endorsements): Across, intent-based bridge aggregators. ## Tracking the withdrawal [#tracking-the-withdrawal] * **L2 side:** [explorer.mandalachain.io](https://explorer.mandalachain.io) shows your initiation transaction, including the call to `ArbSys`. * **L1 side:** during the wait, no L1 activity. After you claim, the claim transaction shows up on Etherscan against the Outbox contract. ## Troubleshooting [#troubleshooting] **The Portal does not show my withdrawal.** Confirm the initiation transaction succeeded on the [Mandala explorer](https://explorer.mandalachain.io). Sometimes the Portal takes a few minutes to index a fresh withdrawal. **Claim transaction failing on L1.** Most common cause: the challenge window has not actually passed. The Portal countdown is approximate; the L1 contract is the source of truth. **Cannot afford the L1 claim gas.** You can wait until L1 gas is cheaper; the withdrawal does not expire. Anyone can claim on your behalf, so a friend with L1 ETH can also do it. # Faucet (/docs/network/testnet/faucet) The [Mandala Chain Faucet](https://faucet.mandalachain.io/) hands out free **KPGT** (Kepeng Test) tokens so you can build on Mandala Testnet. Use them to pay gas while you deploy contracts, send transactions, and test your dApps, all at no cost. Each request sends **10 KPGT** to one address, and each address can claim once per day. Testnet tokens have no monetary value and cannot be exchanged for real assets. They exist only for development and testing. KPGT is the testnet token; the mainnet gas token is KPG. ## Before you start [#before-you-start] You need: * An EVM wallet such as [MetaMask](/docs/network/wallet-setup/metamask) or [Rabby](/docs/network/wallet-setup/rabby), with **Mandala Testnet** added. The connection values are on the [Network Details](/docs/network/testnet/network-details) page. * Your wallet address. It starts with `0x` and is 42 characters long. ## How to get testnet tokens [#how-to-get-testnet-tokens] ### Step 1: Open the faucet [#step-1-open-the-faucet] Go to [faucet.mandalachain.io](https://faucet.mandalachain.io/). The **Testnet Active** badge means the faucet is online and ready to send tokens. Mandala Chain Faucet homepage ### Step 2: Enter your wallet address [#step-2-enter-your-wallet-address] Copy your address from your wallet and paste it into the **Wallet Address** field. * **MetaMask:** click your account name at the top to copy the address. * **Rabby:** click your address at the top to copy it. Wallet address pasted into the faucet Double-check the address before you continue. Tokens are sent to exactly the address you enter, and the transaction cannot be reversed. ### Step 3: Verify and claim [#step-3-verify-and-claim] Tick the **Verify you are human** checkbox, then click **Claim Tokens**. The faucet shows **Processing your request...** while it submits the transaction. Human verification and claim in progress ### Step 4: Confirm the transaction [#step-4-confirm-the-transaction] When the request finishes, the faucet confirms **Successfully sent 10** to your address. Click **View on Explorer** to see the transaction on the [testnet explorer](https://explorer.testnet.mandalachain.io). Successful claim with View on Explorer link ### Step 5: Check your wallet [#step-5-check-your-wallet] Switch your wallet to **Mandala Testnet** and your KPGT balance should update with the 10 tokens. If you do not see them right away, wait a few seconds and refresh; testnet transactions usually confirm within seconds. ## Faucet limits [#faucet-limits] | Limit | Value | | :--------------------- | :----------------------- | | **Amount per request** | 10 KPGT | | **Frequency** | Once per address per day | | **Verification** | Cloudflare human check | If you need more than the daily allowance for integration work, bridge Sepolia ETH into Mandala Testnet through the Arbitrum Portal, or reach out via the channels on the [Getting Help](/docs/support/getting-help) page. ## Troubleshooting [#troubleshooting] **Too many requests.** You have already claimed within the last 24 hours. Wait until the daily window resets, or use a different address. **Invalid address.** The faucet only accepts a valid EVM address: `0x` followed by 40 hexadecimal characters (42 characters total). Re-copy it straight from your wallet. **Tokens not showing.** Confirm your wallet is connected to Mandala Testnet (Chain ID `20011`), then refresh. You can verify the transfer on the [testnet explorer](https://explorer.testnet.mandalachain.io) using the address or transaction hash. **Verification will not complete.** Finish the Cloudflare **Verify you are human** check before clicking Claim Tokens. Aggressive privacy extensions or VPNs can block it; disable them for the faucet site and try again. # Network Details (/docs/network/testnet/network-details) Mandala maintains a testnet for development and integration work. It runs the same Arbitrum Orbit and AnyTrust stack as mainnet, with two differences: the testnet settles to Sepolia instead of Ethereum mainnet, and gas is paid in KPGT (Kepeng Test) rather than KPG. ## Connection details [#connection-details] Use these settings to connect any EVM tool (MetaMask, Rabby, Hardhat, Foundry, ethers, viem) to Mandala Testnet. | Detail | Value | | :------------------- | :----------------------------------------- | | **Network Name** | Mandala Testnet | | **Chain ID** | `20011` | | **RPC URL** | `https://rpc1-testnet.mandalachain.io` | | **WebSocket URL** | `wss://rpc1-testnet.mandalachain.io/ws` | | **Block Explorer** | `https://explorer.testnet.mandalachain.io` | | **Native Currency** | KPGT (Kepeng Test) | | **Decimals** | `18` | | **Settlement chain** | Sepolia | ## Add to your wallet [#add-to-your-wallet] The setup flow is identical to mainnet. Follow the [MetaMask](/docs/network/wallet-setup/metamask) or [Rabby](/docs/network/wallet-setup/rabby) walkthroughs and substitute the testnet values from the table above. ## Get testnet tokens [#get-testnet-tokens] You start with 0 KPGT. To send transactions you need KPGT for gas. Claim free testnet tokens from the [Faucet](/docs/network/testnet/faucet). You can also bridge Sepolia ETH (and supported testnet tokens) into Mandala Testnet through the Arbitrum Portal with the Mandala testnet selected. Sepolia ETH faucets are listed in the [Ethereum docs](https://ethereum.org/developers/docs/networks/#sepolia). ## What testnet is for [#what-testnet-is-for] * Deploying and testing contracts before pushing to mainnet. * Integration work against the real Mandala stack (sequencer, batch poster, AnyTrust DAC, validators). * Local end-to-end runs that need actual L1 settlement, not a forked node. ## What testnet is not for [#what-testnet-is-not-for] * Production traffic. * Anything that depends on KPG balances or KPG-priced fees (testnet uses KPGT). * Stable economic assumptions; testnet parameters may be reset. # MetaMask (/docs/network/wallet-setup/metamask) MetaMask is the most common Ethereum browser-extension wallet. Because Mandala is EVM-equivalent, MetaMask works against it the same way it does against Ethereum mainnet, once you point it at the Mandala RPC. ## Installation [#installation] Skip this section if you already have MetaMask. ### Step 1: Download [#step-1-download] Visit [metamask.io/download](https://metamask.io/download) and select your browser. Verify the URL before clicking; phishing copies of this site exist. MetaMask download page ### Step 2: Add to your browser [#step-2-add-to-your-browser] The download button takes you to the official extension store (Chrome Web Store, Firefox Add-ons, etc.). Click **Add to Chrome** (or your browser's equivalent). MetaMask in the Chrome Web Store ### Step 3: Pin the extension [#step-3-pin-the-extension] Click the puzzle-piece icon in your browser toolbar and pin MetaMask so the fox icon stays visible. ## Creating a wallet [#creating-a-wallet] If you already have a MetaMask wallet, skip to [Adding Mandala Chain](#adding-mandala-chain). ### Step 1: Open MetaMask [#step-1-open-metamask] Click the fox icon in your browser toolbar. ### Step 2: Get started [#step-2-get-started] On the welcome screen, click **Create a new wallet**. To import an existing seed, click **Import an existing wallet** instead. MetaMask welcome screen ### Step 3: Choose creation method [#step-3-choose-creation-method] You can continue with Google, Apple, or use a Secret Recovery Phrase. The Secret Recovery Phrase route is the canonical, self-custodial path. MetaMask creation method ### Step 4: Set a password [#step-4-set-a-password] Pick a strong, unique password. It encrypts your wallet locally on this device. MetaMask password setup ### Step 5: Save your Secret Recovery Phrase [#step-5-save-your-secret-recovery-phrase] MetaMask reveals a 12-word phrase. This phrase, by itself, can recover your wallet on any device. Anyone with the phrase has full control of your funds. MetaMask Secret Recovery Phrase reveal Write the phrase down on paper. Do not screenshot it. Do not paste it into a password manager that syncs to the cloud. Do not photograph it. Anyone with this phrase has full access to your wallet. ### Step 6: Confirm the phrase [#step-6-confirm-the-phrase] MetaMask asks you to re-enter the phrase in order, to confirm you wrote it down correctly. MetaMask seed phrase confirmation ### Step 7: Wallet created [#step-7-wallet-created] You land on the main MetaMask interface with a 0 ETH balance. MetaMask main wallet view ## Adding Mandala Chain [#adding-mandala-chain] By default, MetaMask is connected to Ethereum mainnet. Add Mandala as a custom network. ### Step 1: Open the network dropdown [#step-1-open-the-network-dropdown] Click the network selector at the top of the MetaMask popup (it usually reads "Ethereum Mainnet" or "All popular networks"). Switch to the **Custom** tab and click **Add custom network**. MetaMask network dropdown ### Step 2: Enter the Mandala values [#step-2-enter-the-mandala-values] Fill in the form with the Mandala mainnet values. | Detail | Value | | :--------------------- | :------------------------------------- | | **Network Name** | `Mandala Chain` | | **New RPC URL** | `https://rpc1-mainnet.mandalachain.io` | | **Chain ID** | `20010` | | **Currency Symbol** | `KPG` | | **Block Explorer URL** | `https://explorer.mandalachain.io` | For Mandala Testnet (Chain ID `20011`, KPGT, settles to Sepolia), use the values from the [Testnet Network Details](/docs/network/testnet/network-details) page instead. ### Step 3: Save [#step-3-save] Click **Save**. MetaMask switches to Mandala Chain automatically and shows a 0 KPG balance. ### Step 4: Verify [#step-4-verify] The network selector at the top should now read **Mandala Chain**, and the balance should be denominated in KPG. ## Getting KPG [#getting-kpg] You start with 0 KPG. To send transactions you need KPG for gas. Bridge it from Ethereum via the Arbitrum Portal: see [Deposit from Ethereum](/docs/network/bridge/deposit-from-ethereum). ## Switching networks [#switching-networks] To move between networks, click the network selector and pick the network you want. MetaMask retains every custom network you have added. ## Troubleshooting [#troubleshooting] **Cannot connect to Mandala.** Confirm the RPC URL is exactly `https://rpc1-mainnet.mandalachain.io` and the Chain ID is `20010`. A wrong chain ID is the most common cause of failed connections. **Forgot your password.** Click **Forgot password?** on the login screen and reset using your Secret Recovery Phrase. **Need a fresh address.** Click your account icon and select **Add account**. Each new account is a fresh address derived from the same Secret Recovery Phrase. # Rabby (/docs/network/wallet-setup/rabby) Rabby is a multi-chain EVM wallet with stronger transaction previews and automatic network detection. It works with Mandala the same way it works with any EVM chain, once Mandala is added as a custom network. ## Installation [#installation] Skip this section if you already have Rabby. ### Step 1: Download [#step-1-download] Visit [rabby.io](https://rabby.io/) and click **Download**, or install directly from your browser's extension store. Rabby download page Make sure you are on `rabby.io` or the official Chrome Web Store listing. Phishing copies of Rabby exist. ### Step 2: Add to your browser [#step-2-add-to-your-browser] Click **Add to Chrome** (or your browser's equivalent). Rabby add-to-browser confirmation ## Creating a wallet [#creating-a-wallet] If you already have a Rabby wallet, skip to [Adding Mandala Chain](#adding-mandala-chain). ### Step 1: Open Rabby [#step-1-open-rabby] Click the Rabby icon in your browser toolbar. ### Step 2: Choose create [#step-2-choose-create] Select **Create a new address**. To import an existing seed, choose **I already have an address** instead. Rabby welcome screen ### Step 3: Save your seed phrase [#step-3-save-your-seed-phrase] Rabby reveals a 12-word phrase. The phrase alone can recover your wallet on any device. Rabby seed phrase reveal Write the phrase down on paper. Do not screenshot it. Do not paste it into cloud-synced storage. Anyone with this phrase has full access to your wallet. Click **I've Saved the Phrase** when you have stored it safely. ### Step 4: Set a password [#step-4-set-a-password] Pick a strong password. It encrypts your wallet locally. Rabby password setup ### Step 5: Wallet created [#step-5-wallet-created] Rabby opens its dashboard with your new account. Rabby get-started screen Rabby dashboard ## Adding Mandala Chain [#adding-mandala-chain] Rabby auto-detects networks when a dApp asks to connect, but you can also add Mandala manually. ### Step 1: Open settings [#step-1-open-settings] Click the settings icon in the top right of Rabby and select **Add Custom Network**. Rabby settings menu ### Step 2: Click Add Custom Network [#step-2-click-add-custom-network] Rabby custom networks list ### Step 3: Enter the Mandala values [#step-3-enter-the-mandala-values] | Detail | Value | | :--------------------- | :------------------------------------- | | **Network Name** | `Mandala Chain` | | **RPC URL** | `https://rpc1-mainnet.mandalachain.io` | | **Chain ID** | `20010` | | **Currency Symbol** | `KPG` | | **Block Explorer URL** | `https://explorer.mandalachain.io` | For Mandala Testnet (Chain ID `20011`, KPGT, settles to Sepolia), use the values from the [Testnet Network Details](/docs/network/testnet/network-details) page. ### Step 4: Confirm [#step-4-confirm] Click **Confirm**. Mandala Chain is now in your custom networks list, and Rabby will switch to it whenever a dApp requests Chain ID `20010`. ## Auto-detection [#auto-detection] Rabby's signature feature is automatic network switching. When a dApp asks to connect on Chain ID `20010`, Rabby switches to Mandala without prompting. This makes development noticeably smoother than wallets that require manual switching. ## Getting KPG [#getting-kpg] You start with 0 KPG. Bridge KPG or ETH from Ethereum via the Arbitrum Portal: see [Deposit from Ethereum](/docs/network/bridge/deposit-from-ethereum). ## Troubleshooting [#troubleshooting] **Rabby will not connect to Mandala.** Confirm the Chain ID is exactly `20010`. Rabby is strict about chain ID matching for security. **The dApp does not switch automatically.** Make sure the dApp's frontend is configured to request Chain ID `20010`, not a different number. **Need multiple accounts.** Click your account name at the top and select **Add New Address** to derive additional addresses from the same seed phrase.