> For the complete documentation index, see [llms.txt](https://docs.bitbadges.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.bitbadges.io/token-standard/evm_integration/setup-and-configuration.md).

# Setup and Configuration

This guide covers everything you need to set up your development environment for building dApps on BitBadges Chain with EVM compatibility.

## Chain Configuration

### Chain ID

The BitBadges Chain EVM uses a custom Chain ID for EVM compatibility:

* **Local Development**: `90123`
* **Testnet**: `50025` (claimed in ethereum-lists/chains registry)
* **Mainnet**: `50024` (claimed in ethereum-lists/chains registry)

The Chain ID is configured in `app/params/constants.go`:

```go
// EVMChainIDMainnet is the EVM chain ID for BitBadges mainnet
// Chain ID: 50024 (claimed in ethereum-lists/chains registry)
// This should match the chain_id in genesis under app_state.evm.params.chain_config.chain_id
EVMChainIDMainnet = "50024"

// EVMChainIDTestnet is the EVM chain ID for BitBadges testnet
// Chain ID: 50025 (claimed in ethereum-lists/chains registry)
// This should match the chain_id in genesis under app_state.evm.params.chain_config.chain_id
EVMChainIDTestnet = "50025"

EVMChainID = "90123" // Default for local development/testing
```

**Important**: The Chain ID in your genesis file (`app_state.evm.params.chain_config.chain_id`) must match this value.

### RPC Endpoints

BitBadges Chain provides two RPC interfaces:

1. **Tendermint RPC** (Port 26657)
   * Used for Cosmos SDK queries and transactions
   * Endpoint: `http://localhost:26657`
   * Supports standard Cosmos SDK operations
2. **EVM JSON-RPC** (Port 8545)
   * Used for Ethereum-compatible operations
   * Endpoint: `http://localhost:8545`
   * Supports standard Ethereum JSON-RPC methods
   * Required for MetaMask, ethers.js, web3.js, etc.

### Starting the Chain with EVM

To start the chain with EVM support, use the `--json-rpc.enable` flag:

```bash
# From the bitbadgeschain repository root
bitbadgeschaind start --json-rpc.enable --json-rpc.address 0.0.0.0:8545
```

Or use the provided startup script:

```bash
# From the bitbadgeschain repository root
./start-chain.sh start
```

The startup script automatically enables EVM JSON-RPC on port 8545.

**Note**: The EVM module is always enabled in the chain binary. You only need to enable the JSON-RPC server to interact with it via Ethereum-compatible tools (MetaMask, ethers.js, etc.).

## MetaMask Configuration

To connect MetaMask to your local BitBadges chain:

1. Open MetaMask
2. Go to **Settings > Networks > Add Network**
3. Add the following network configuration:

**For Local Development:**

* **Network Name**: BitBadges Local
* **RPC URL**: `http://localhost:8545` (EVM JSON-RPC)
* **Chain ID**: `90123`
* **Currency Symbol**: `BADGE`
* **Block Explorer**: (Optional, leave blank for local)

**For Testnet:**

* **Network Name**: BitBadges Testnet
* **RPC URL**: `https://evm-rpc-testnet.bitbadges.io`
* **Chain ID**: `50025`
* **Currency Symbol**: `BADGE`
* **Block Explorer**: (Testnet block explorer URL)

**For Mainnet:**

* **Network Name**: BitBadges Mainnet
* **RPC URL**: `https://evm-rpc.bitbadges.io`
* **Chain ID**: `50024`
* **Currency Symbol**: `BADGE`
* **Block Explorer**: `https://explorer.bitbadges.io`

**Note**: Use port 8545 (EVM JSON-RPC), not 26657 (Tendermint RPC).

### Getting Test Tokens

After starting your local chain, fund your MetaMask account:

```bash
# Get your MetaMask address (0x... format)
# Then fund it using the chain's genesis or by transferring from a validator

# Option 1: Transfer from a validator account
bitbadgeschaind tx bank send \
  $(bitbadgeschaind keys show alice -a --keyring-backend test) \
  <your-metamask-address> \
  1000000000ubadge \
  --chain-id bitbadges \
  --keyring-backend test \
  --yes

# Option 2: Use the chain's genesis accounts if configured
```

## Simple dApp Setup

### Project Structure

A typical dApp project structure:

```
my-dapp/
├── contracts/              # Solidity contracts
│   ├── MyContract.sol
│   └── interfaces/
│       └── ITokenizationPrecompile.sol
├── scripts/               # Deployment scripts
│   └── deploy.ts
├── app/                   # Frontend (Next.js, React, etc.)
│   └── page.tsx
└── package.json
```

### Basic Contract Template

Here's a minimal contract that uses the tokenization precompile:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./interfaces/ITokenizationPrecompile.sol";
import "./types/TokenizationTypes.sol";

contract MyTokenContract {
    // Precompile address
    ITokenizationPrecompile constant precompile = 
        ITokenizationPrecompile(0x0000000000000000000000000000000000001001);
    
    uint256 public collectionId;
    
    constructor(uint256 _collectionId) {
        collectionId = _collectionId;
    }
    
    function transfer(
        address to,
        uint256 amount,
        uint256 tokenId
    ) external returns (bool) {
        address[] memory recipients = new address[](1);
        recipients[0] = to;
        
        TokenizationTypes.UintRange[] memory tokenIds = new TokenizationTypes.UintRange[](1);
        tokenIds[0] = TokenizationTypes.UintRange({
            start: tokenId,
            end: tokenId
        });
        
        TokenizationTypes.UintRange[] memory ownershipTimes = new TokenizationTypes.UintRange[](1);
        ownershipTimes[0] = TokenizationTypes.UintRange({
            start: 1,
            end: type(uint256).max
        });
        
        return precompile.transferTokens(
            collectionId,
            recipients,
            amount,
            tokenIds,
            ownershipTimes
        );
    }
    
    function getBalance(address user) external view returns (uint256) {
        TokenizationTypes.UintRange[] memory tokenIds = new TokenizationTypes.UintRange[](1);
        tokenIds[0] = TokenizationTypes.UintRange({
            start: 1,
            end: type(uint256).max
        });
        
        TokenizationTypes.UintRange[] memory ownershipTimes = new TokenizationTypes.UintRange[](1);
        ownershipTimes[0] = TokenizationTypes.UintRange({
            start: 1,
            end: type(uint256).max
        });
        
        return precompile.getBalanceAmount(collectionId, user, tokenIds, ownershipTimes);
    }
}
```

### Deployment Script (TypeScript/ethers.js)

```typescript
import { ethers } from "ethers";
import * as fs from "fs";

async function deploy() {
  // Connect to EVM JSON-RPC
  const provider = new ethers.JsonRpcProvider("http://localhost:8545");
  
  // Get deployer wallet
  const privateKey = process.env.PRIVATE_KEY || "";
  if (!privateKey) {
    throw new Error("PRIVATE_KEY environment variable required");
  }
  
  const wallet = new ethers.Wallet(privateKey, provider);
  console.log("Deployer address:", wallet.address);
  
  // Check balance
  const balance = await provider.getBalance(wallet.address);
  console.log("Balance:", ethers.formatEther(balance), "BADGE");
  
  // Deploy contract
  const contractFactory = new ethers.ContractFactory(
    CONTRACT_ABI,
    CONTRACT_BYTECODE,
    wallet
  );
  
  const contract = await contractFactory.deploy(collectionId);
  await contract.waitForDeployment();
  
  const address = await contract.getAddress();
  console.log("Contract deployed at:", address);
  
  // Save deployment info
  fs.writeFileSync(
    "deployed.json",
    JSON.stringify({ address, abi: CONTRACT_ABI }, null, 2)
  );
}

deploy().catch(console.error);
```

### Frontend Integration (React/ethers.js)

```typescript
import { ethers } from "ethers";
import { useState, useEffect } from "react";

export function useContract() {
  const [contract, setContract] = useState<ethers.Contract | null>(null);
  const [provider, setProvider] = useState<ethers.BrowserProvider | null>(null);
  
  useEffect(() => {
    if (typeof window.ethereum !== "undefined") {
      const provider = new ethers.BrowserProvider(window.ethereum);
      setProvider(provider);
      
      // Load deployed contract
      const contractAddress = "0x..."; // Your deployed contract address
      const contract = new ethers.Contract(
        contractAddress,
        CONTRACT_ABI,
        await provider.getSigner()
      );
      setContract(contract);
    }
  }, []);
  
  const transfer = async (to: string, amount: bigint, tokenId: bigint) => {
    if (!contract) throw new Error("Contract not loaded");
    const tx = await contract.transfer(to, amount, tokenId);
    await tx.wait();
  };
  
  return { contract, provider, transfer };
}
```

## Contract Snippets

### Helper Library

The repository includes a comprehensive helper library at `contracts/libraries/TokenizationHelpers.sol` that provides utility functions for:

* Creating `UintRange` structs (single values, sequences, full ranges)
* Creating `Balance`, `CollectionMetadata`, `TokenMetadata` structs
* Creating empty permission structures
* Validating ranges and balances
* Common patterns for ownership times and token IDs

**Import and use the helper library:**

```solidity
import "./libraries/TokenizationHelpers.sol";

contract MyContract {
    function example() external {
        // Create a single token ID range
        TokenizationTypes.UintRange memory tokenId = 
            TokenizationHelpers.createSingleTokenIdRange(123);
        
        // Create a full ownership time range (1 to max uint256)
        TokenizationTypes.UintRange memory fullTime = 
            TokenizationHelpers.createFullOwnershipTimeRange();
        
        // Create a token ID sequence (range from start to end)
        TokenizationTypes.UintRange memory sequence = 
            TokenizationHelpers.createTokenIdSequence(1, 100);
        
        // Create a UintRange array from arrays
        uint256[] memory starts = new uint256[](2);
        uint256[] memory ends = new uint256[](2);
        starts[0] = 1; ends[0] = 10;
        starts[1] = 20; ends[1] = 30;
        TokenizationTypes.UintRange[] memory ranges = 
            TokenizationHelpers.createUintRangeArray(starts, ends);
    }
}
```

See the [TokenizationHelpers.sol](https://github.com/BitBadges/bitbadgeschain/tree/evm-poc/contracts/libraries/TokenizationHelpers.sol) file for all available helper functions.

### Common Patterns

#### Pattern 1: Simple Token Transfer

```solidity
ITokenizationPrecompile constant precompile = 
    ITokenizationPrecompile(0x0000000000000000000000000000000000001001);

function simpleTransfer(
    uint256 collectionId,
    address to,
    uint256 amount,
    uint256 tokenId
) external returns (bool) {
    address[] memory recipients = new address[](1);
    recipients[0] = to;
    
    TokenizationTypes.UintRange[] memory tokenIds = new TokenizationTypes.UintRange[](1);
    tokenIds[0] = TokenizationHelpers.createSingleTokenIdRange(tokenId);
    
    TokenizationTypes.UintRange[] memory ownershipTimes = new TokenizationTypes.UintRange[](1);
    ownershipTimes[0] = TokenizationHelpers.createFullOwnershipTimeRange();
    
    return precompile.transferTokens(
        collectionId,
        recipients,
        amount,
        tokenIds,
        ownershipTimes
    );
}
```

#### Pattern 2: Batch Transfer

```solidity
ITokenizationPrecompile constant precompile = 
    ITokenizationPrecompile(0x0000000000000000000000000000000000001001);

function batchTransfer(
    uint256 collectionId,
    address[] calldata recipients,
    uint256[] calldata amounts,
    uint256 tokenId
) external returns (bool) {
    require(recipients.length == amounts.length, "Arrays length mismatch");
    
    // Transfer to each recipient
    for (uint256 i = 0; i < recipients.length; i++) {
        address[] memory singleRecipient = new address[](1);
        singleRecipient[0] = recipients[i];
        
        TokenizationTypes.UintRange[] memory tokenIds = new TokenizationTypes.UintRange[](1);
        tokenIds[0] = TokenizationHelpers.createSingleTokenIdRange(tokenId);
        
        TokenizationTypes.UintRange[] memory ownershipTimes = new TokenizationTypes.UintRange[](1);
        ownershipTimes[0] = TokenizationHelpers.createFullOwnershipTimeRange();
        
        precompile.transferTokens(
            collectionId,
            singleRecipient,
            amounts[i],
            tokenIds,
            ownershipTimes
        );
    }
    
    return true;
}
```

#### Pattern 3: Time-Limited Transfer

```solidity
ITokenizationPrecompile constant precompile = 
    ITokenizationPrecompile(0x0000000000000000000000000000000000001001);

function transferWithExpiration(
    uint256 collectionId,
    address to,
    uint256 amount,
    uint256 tokenId,
    uint256 expirationTime
) external returns (bool) {
    address[] memory recipients = new address[](1);
    recipients[0] = to;
    
    TokenizationTypes.UintRange[] memory ownershipTimes = new TokenizationTypes.UintRange[](1);
    ownershipTimes[0] = TokenizationTypes.UintRange({
        start: block.timestamp,
        end: expirationTime
    });
    
    TokenizationTypes.UintRange[] memory tokenIds = new TokenizationTypes.UintRange[](1);
    tokenIds[0] = TokenizationHelpers.createSingleTokenIdRange(tokenId);
    
    return precompile.transferTokens(
        collectionId,
        recipients,
        amount,
        tokenIds,
        ownershipTimes
    );
}
```

#### Pattern 4: Using Helper Library

```solidity
import "./libraries/TokenizationHelpers.sol";

contract HelperExample {
    ITokenizationPrecompile constant precompile = 
        ITokenizationPrecompile(0x0000000000000000000000000000000000001001);
    
    function transferWithHelpers(
        uint256 collectionId,
        address to,
        uint256 amount,
        uint256 tokenId
    ) external returns (bool) {
        address[] memory recipients = new address[](1);
        recipients[0] = to;
        
        // Use helper library for cleaner code
        TokenizationTypes.UintRange[] memory tokenIds = new TokenizationTypes.UintRange[](1);
        tokenIds[0] = TokenizationHelpers.createSingleTokenIdRange(tokenId);
        
        TokenizationTypes.UintRange[] memory ownershipTimes = new TokenizationTypes.UintRange[](1);
        ownershipTimes[0] = TokenizationHelpers.createFullOwnershipTimeRange();
        
        return precompile.transferTokens(
            collectionId,
            recipients,
            amount,
            tokenIds,
            ownershipTimes
        );
    }
}
```

#### Pattern 5: Dynamic Store for Compliance

```solidity
contract ComplianceToken {
    ITokenizationPrecompile constant precompile = 
        ITokenizationPrecompile(0x0000000000000000000000000000000000001001);
    
    uint256 public kycRegistryId;
    uint256 public collectionId;
    
    function initialize(uint256 _collectionId) external {
        collectionId = _collectionId;
        
        // Create KYC registry (default: false = not KYC'd)
        kycRegistryId = precompile.createDynamicStore(
            false,
            "ipfs://...", // URI
            "" // customData
        );
    }
    
    function setKYC(address user, bool isKYCd) external {
        precompile.setDynamicStoreValue(kycRegistryId, user, isKYCd);
    }
    
    function isKYCd(address user) public view returns (bool) {
        string memory getValueJson = TokenizationJSONHelpers.getDynamicStoreValueJSON(
            kycRegistryId,
            user
        );
        DynamicStoreValueResult memory result = precompile.getDynamicStoreValue(getValueJson);
        // Use the field that matches your store's value type (e.g. result.verified for a boolean store)
        return result.verified;
    }
    
    function transfer(address to, uint256 amount, uint256 tokenId) external {
        require(isKYCd(msg.sender), "Sender not KYC'd");
        require(isKYCd(to), "Recipient not KYC'd");
        
        // Proceed with transfer...
    }
}
```

## Complete Examples

### Counter dApp

For a complete end-to-end example, see the [counter-dapp](https://github.com/BitBadges/bitbadgeschain/tree/evm-poc/counter-dapp) in the repository. It includes:

* Simple Solidity contract (Counter.sol)
* Deployment script (TypeScript)
* Next.js frontend with MetaMask integration
* Complete setup instructions

### ERC-3643 Example Contracts

The [contracts/examples](https://github.com/BitBadges/bitbadgeschain/tree/evm-poc/contracts/examples) directory contains production-ready examples:

1. **TwoFactorSecurityToken.sol** - Security token with 2FA authentication
2. **RealEstateSecurityToken.sol** - Tokenized real estate with KYC/AML
3. **CarbonCreditToken.sol** - Carbon credits with vintage tracking
4. **PrivateEquityToken.sol** - Private equity fund tokens with lock-ups

Each example demonstrates:

* Dynamic Stores for compliance registries
* Time-bound ownership for lock-ups and expirations
* Complex approval systems
* Real-world use cases

See the [examples README](https://github.com/BitBadges/bitbadgeschain/tree/evm-poc/contracts/examples/README.md) for detailed explanations of each contract.

## Troubleshooting

### RPC Connection Issues

**Problem**: Can't connect to RPC endpoint

**Solutions**:

* Ensure the chain is running: `bitbadgeschaind start --json-rpc.enable --json-rpc.address 0.0.0.0:8545`
* Check if EVM JSON-RPC is enabled in `app.toml`
* Try both ports: `http://localhost:8545` (EVM) and `http://localhost:26657` (Tendermint)
* Verify the chain is fully synced

### MetaMask Connection Issues

**Problem**: MetaMask can't connect to the network

**Solutions**:

* Use the correct Chain ID:
  * `90123` for local development
  * `50025` for testnet
  * `50024` for mainnet
* Use EVM JSON-RPC port: `http://localhost:8545` (not 26657) for local development
* Ensure your local chain is running (for local development)
* Check MetaMask console for detailed error messages

### Transaction Failures

**Problem**: Transactions fail with "insufficient funds" or revert

**Solutions**:

* Fund your account with BADGE tokens:

  ```bash
  bitbadgeschaind tx bank send <validator> <your-address> 1000000000ubadge --keyring-backend test
  ```
* Check gas prices (may need to adjust in MetaMask)
* Verify approvals are set correctly for token transfers
* Check contract logs for specific error messages

### Contract Deployment Issues

**Problem**: Contract deployment fails

**Solutions**:

* Ensure you have sufficient balance for deployment gas
* Check that the EVM module is enabled
* Verify your Solidity version matches the chain's supported version
* Check deployment script logs for specific errors

## Next Steps

* Review the [Developer Guide](/token-standard/evm_integration/developer-guide.md) for essential information
* Explore [Contract Examples](https://github.com/BitBadges/bitbadgeschain/tree/evm-poc/contracts/examples) for real-world patterns
* Check the [Precompile API Reference](/token-standard/evm_integration/tokenization-precompile/api.md) for all available methods
* See the [Counter dApp](https://github.com/BitBadges/bitbadgeschain/tree/evm-poc/counter-dapp) for a complete working example


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.bitbadges.io/token-standard/evm_integration/setup-and-configuration.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
