Comparing coingecko with monad

coingecko

View full →

Author

@0xinit

Stars

53

Repository

0xinit/cryptoskills

skills/coingecko/SKILL.md

CoinGecko Solana API Development Guide

A comprehensive guide for integrating CoinGecko's on-chain API for Solana. Access real-time token prices, DEX pool data, OHLCV charts, trade history, and market analytics across 1,700+ decentralized exchanges.

Overview

CoinGecko's Solana API provides:

  • Token Prices: Real-time prices by contract address (single or batch)
  • Pool Data: Liquidity pool information, trending pools, top pools
  • OHLCV Charts: Candlestick data for technical analysis
  • Trade History: Recent trades for any pool
  • DEX Discovery: List all DEXes operating on Solana
  • Search: Find pools by token name, symbol, or address
  • Megafilter: Advanced filtering across pools, tokens, and DEXes

Key Features

FeatureDescription
250+ NetworksMulti-chain support including Solana
1,700+ DEXesRaydium, Orca, Jupiter, Meteora, Pump.fun, etc.
15M+ TokensComprehensive token coverage
Real-time DataUpdates every 10-30 seconds
Historical DataOHLCV charts and trade history

Quick Start

Get Your API Key

  1. Demo API (Free): Visit coingecko.com/en/api
  2. Pro API (Paid): Visit coingecko.com/en/api/pricing

Environment Setup

# .env file
COINGECKO_API_KEY=your_api_key_here
COINGECKO_API_TYPE=demo  # or 'pro'

API Configuration

// Configuration for both Demo and Pro APIs
const CONFIG = {
  demo: {
    baseUrl: 'https://api.coingecko.com/api/v3/onchain',
    headerKey: 'x-cg-demo-api-key',
    rateLimit: 30, // calls per minute
  },
  pro: {
    baseUrl: 'https://pro-api.coingecko.com/api/v3/onchain',
    headerKey: 'x-cg-pro-api-key',
    rateLimit: 500, // calls per minute (varies by plan)
  },
};

const apiType = process.env.COINGECKO_API_TYPE || 'demo';
const apiKey = process.env.COINGECKO_API_KEY;

const BASE_URL = CONFIG[apiType].baseUrl;
const HEADER_KEY = CONFIG[apiType].headerKey;

// Solana network identifier
const NETWORK = 'solana';

Basic Token Price Fetch

async function getTokenPrice(tokenAddress: string): Promise<number | null> {
  const url = `${BASE_URL}/simple/networks/${NETWORK}/token_price/${tokenAddress}`;

  const response = await fetch(url, {
    headers: {
      [HEADER_KEY]: apiKey,
      'Accept': 'application/json',
    },
  });

  if (!response.ok) {
    throw new Error(`API error: ${response.status}`);
  }

  const data = await response.json();
  return data.data?.attributes?.token_prices?.[tokenAddress] ?? null;
}

// Usage
const USDC = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';
const price = await getTokenPrice(USDC);
console.log(`USDC Price: $${price}`);

API Endpoints Reference

Simple Token Price

Get token prices by contract address.

Endpoint: GET /simple/networks/{network}/token_price/{addresses}

Parameters:

ParameterTypeRequiredDescription
networkstringYesNetwork ID (solana)
addressesstringYesComma-separated token addresses (max 30 Demo, 100 Pro)
include_market_capbooleanNoInclude market cap data
include_24hr_volbooleanNoInclude 24h volume
include_24hr_price_changebooleanNoInclude 24h price change %
async function getTokenPrices(addresses: string[]): Promise<Record<string, TokenPriceData>> {
  const addressList = addresses.join(',');
  const url = `${BASE_URL}/simple/networks/${NETWORK}/token_price/${addressList}`;

  const params = new URLSearchParams({
    include_market_cap: 'true',
    include_24hr_vol: 'true',
    include_24hr_price_change: 'true',
  });

  const response = await fetch(`${url}?${params}`, {
    headers: { [HEADER_KEY]: apiKey },
  });

  const data = await response.json();
  return data.data?.attributes || {};
}

Token Data by Address

Get detailed token information.

Endpoint: GET /networks/{network}/tokens/{address}

Parameters:

ParameterTypeRequiredDescription
networkstringYesNetwork ID
addressstringYesToken contract address
includestringNoInclude top_pools for liquidity data
interface TokenData {
  address: string;
  name: string;
  symbol: string;
  decimals: number;
  image_url: string;
  price_usd: string;
  fdv_usd: string;
  market_cap_usd: string;
  total_supply: string;
  volume_usd: {
    h24: string;
  };
  price_change_percentage: {
    h24: string;
  };
}

async function getTokenData(address: string): Promise<TokenData> {
  const url = `${BASE_URL}/networks/${NETWORK}/tokens/${address}?include=top_pools`;

  const response = await fetch(url, {
    headers: { [HEADER_KEY]: apiKey },
  });

  const data = await response.json();
  return data.data?.attributes;
}

Multi-Token Data

Batch fetch multiple tokens.

Endpoint: GET /networks/{network}/tokens/multi/{addresses}

async function getMultipleTokens(addresses: string[]): Promise<TokenData[]> {
  const addressList = addresses.join(',');
  const url = `${BASE_URL}/networks/${NETWORK}/tokens/multi/${addressList}`;

  const response = await fetch(url, {
    headers: { [HEADER_KEY]: apiKey },
  });

  const data = await response.json();
  return data.data?.map((item: any) => item.attributes) || [];
}

Pool Data by Address

Get detailed pool information.

Endpoint: GET /networks/{network}/pools/{address}

Parameters:

ParameterTypeRequiredDescription
includestringNobase_token, quote_token, dex
include_volume_breakdownbooleanNoVolume breakdown by timeframe
interface PoolData {
  address: string;
  name: string;
  pool_created_at: string;
  base_token_price_usd: string;
  quote_token_price_usd: string;
  base_token_price_native_currency: string;
  fdv_usd: string;
  market_cap_usd: string;
  reserve_in_usd: string;
  price_change_percentage: {
    m5: string;
    h1: string;
    h6: string;
    h24: string;
  };
  transactions: {
    m5: { buys: number; sells: number };
    h1: { buys: number; sells: number };
    h24: { buys: number; sells: number };
  };
  volume_usd: {
    m5: string;
    h1: string;
    h6: string;
    h24: string;
  };
}

async function getPoolData(poolAddress: string): Promise<PoolData> {
  const url = `${BASE_URL}/networks/${NETWORK}/pools/${poolAddress}`;

  const params = new URLSearchParams({
    include: 'base_token,quote_token,dex',
  });

  const response = await fetch(`${url}?${params}`, {
    headers: { [HEADER_KEY]: apiKey },
  });

  const data = await response.json();
  return data.data?.attributes;
}

Trending Pools

Get trending pools across all networks or filtered by network.

Endpoint: GET /networks/trending_pools

Parameters:

ParameterTypeDefaultDescription
includestringbase_tokenAttributes to include
pageinteger1Page number
durationstring24h5m, 1h, 6h, 24h
async function getTrendingPools(duration: '5m' | '1h' | '6h' | '24h' = '24h'): Promise<PoolData[]> {
  const url = `${BASE_URL}/networks/trending_pools`;

  const params = new URLSearchParams({
    include: 'base_token,quote_token,dex,network',
    duration,
    page: '1',
  });

  const response = await fetch(`${url}?${params}`, {
    headers: { [HEADER_KEY]: apiKey },
  });

  const data = await response.json();
  return data.data?.map((item: any) => item.attributes) || [];
}

// Filter for Solana pools
async function getSolanaTrendingPools(): Promise<PoolData[]> {
  const allPools = await getTrendingPools();
  return allPools.filter(pool => pool.network === 'solana');
}

Top Pools on Network

Get top pools by volume on Solana.

Endpoint: GET /networks/{network}/pools

async function getTopPools(page: number = 1): Promise<PoolData[]> {
  const url = `${BASE_URL}/networks/${NETWORK}/pools`;

  const params = new URLSearchParams({
    include: 'base_token,quote_token,dex',
    page: page.toString(),
  });

  const response = await fetch(`${url}?${params}`, {
    headers: { [HEADER_KEY]: apiKey },
  });

  const data = await response.json();
  return data.data?.map((item: any) => item.attributes) || [];
}

Search Pools

Search for pools by token name, symbol, or address.

Endpoint: GET /search/pools

Parameters:

ParameterTypeDescription
querystringSearch term (name, symbol, address)
networkstringFilter by network
pageintegerPage number
async function searchPools(query: string): Promise<PoolData[]> {
  const url = `${BASE_URL}/search/pools`;

  const params = new URLSearchParams({
    query,
    network: NETWORK,
    include: 'base_token,quote_token,dex',
  });

  const response = await fetch(`${url}?${params}`, {
    headers: { [HEADER_KEY]: apiKey },
  });

  const data = await response.json();
  return data.data?.map((item: any) => item.attributes) || [];
}

// Search for SOL pools
const solPools = await searchPools('SOL');

Pool OHLCV Chart

Get candlestick data for technical analysis.

Endpoint: GET /networks/{network}/pools/{pool_address}/ohlcv/{timeframe}

Timeframes: day, hour, minute

Parameters:

ParameterTypeDescription
aggregateintegerCandle aggregation (1, 5, 15 for minute; 1, 4, 12 for hour)
before_timestampintegerUnix timestamp for pagination
limitintegerNumber of candles (max 1000)
currencystringusd or token
interface OHLCVData {
  timestamp: number;
  open: number;
  high: number;
  low: number;
  close: number;
  volume: number;
}

async function getPoolOHLCV(
  poolAddress: string,
  timeframe: 'day' | 'hour' | 'minute' = 'hour',
  aggregate: number = 1,
  limit: number = 100
): Promise<OHLCVData[]> {
  const url = `${BASE_URL}/networks/${NETWORK}/pools/${poolAddress}/ohlcv/${timeframe}`;

  const params = new URLSearchParams({
    aggregate: aggregate.toString(),
    limit: limit.toString(),
    currency: 'usd',
  });

  const response = await fetch(`${url}?${params}`, {
    headers: { [HEADER_KEY]: apiKey },
  });

  const data = await response.json();

  return data.data?.attributes?.ohlcv_list?.map((candle: number[]) => ({
    timestamp: candle[0],
    open: candle[1],
    high: candle[2],
    low: candle[3],
    close: candle[4],
    volume: candle[5],
  })) || [];
}

// Get hourly candles
const hourlyCandles = await getPoolOHLCV(poolAddress, 'hour', 1, 24);

// Get 5-minute candles
const fiveMinCandles = await getPoolOHLCV(poolAddress, 'minute', 5, 100);

Recent Trades

Get recent trades for a pool.

Endpoint: GET /networks/{network}/pools/{pool_address}/trades

interface TradeData {
  block_number: number;
  block_timestamp: string;
  tx_hash: string;
  tx_from_address: string;
  from_token_amount: string;
  to_token_amount: string;
  price_from_in_currency_token: string;
  price_to_in_currency_token: string;
  price_from_in_usd: string;
  price_to_in_usd: string;
  kind: 'buy' | 'sell';
  volume_in_usd: string;
}

async function getRecentTrades(poolAddress: string): Promise<TradeData[]> {
  const url = `${BASE_URL}/networks/${NETWORK}/pools/${poolAddress}/trades`;

  const response = await fetch(url, {
    headers: { [HEADER_KEY]: apiKey },
  });

  const data = await response.json();
  return data.data?.map((item: any) => item.attributes) || [];
}

List DEXes on Solana

Get all decentralized exchanges on Solana.

Endpoint: GET /networks/{network}/dexes

interface DexData {
  id: string;
  name: string;
}

async function getSolanaDexes(): Promise<DexData[]> {
  const url = `${BASE_URL}/networks/${NETWORK}/dexes`;

  const response = await fetch(url, {
    headers: { [HEADER_KEY]: apiKey },
  });

  const data = await response.json();
  return data.data?.map((item: any) => ({
    id: item.id,
    name: item.attributes.name,
  })) || [];
}

Megafilter (Advanced)

Advanced filtering for pools across networks, DEXes, and tokens.

Endpoint: GET /pools/megafilter

Parameters:

ParameterTypeDescription
networksstringFilter by network(s)
dexesstringFilter by DEX(es)
sortstringSort order (e.g., pool_created_at_desc)
min_reserve_in_usdnumberMinimum liquidity
min_h24_volume_usdnumberMinimum 24h volume
async function getMegafilterPools(options: {
  dexes?: string[];
  minLiquidity?: number;
  minVolume?: number;
  sort?: string;
}): Promise<PoolData[]> {
  const url = `${BASE_URL}/pools/megafilter`;

  const params = new URLSearchParams({
    networks: NETWORK,
    page: '1',
  });

  if (options.dexes) {
    params.set('dexes', options.dexes.join(','));
  }
  if (options.minLiquidity) {
    params.set('min_reserve_in_usd', options.minLiquidity.toString());
  }
  if (options.minVolume) {
    params.set('min_h24_volume_usd', options.minVolume.toString());
  }
  if (options.sort) {
    params.set('sort', options.sort);
  }

  const response = await fetch(`${url}?${params}`, {
    headers: { [HEADER_KEY]: apiKey },
  });

  const data = await response.json();
  return data.data?.map((item: any) => item.attributes) || [];
}

// Get newest Pump.fun pools
const pumpfunPools = await getMegafilterPools({
  dexes: ['pump-fun'],
  sort: 'pool_created_at_desc',
});

// Get high-volume Raydium pools
const raydiumPools = await getMegafilterPools({
  dexes: ['raydium'],
  minVolume: 100000,
  minLiquidity: 50000,
});

Common Solana DEX Identifiers

DEXIDDescription
RaydiumraydiumLeading AMM on Solana
OrcaorcaUser-friendly DEX
JupiterjupiterAggregator with pools
MeteorameteoraDynamic AMM
Pump.funpump-funMemecoin launchpad
OpenBookopenbookOrder book DEX
LifinitylifinityProactive market maker
PhoenixphoenixOn-chain order book

Common Token Addresses

TokenAddress
USDCEPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
USDTEs9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB
SOL (Wrapped)So11111111111111111111111111111111111111112
JUPJUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN
BONKDezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263
WIFEKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm
PYTHHZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3
RAY4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R
ORCAorcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE

Rate Limits

PlanCalls/MinuteMax Addresses/Request
Demo (Free)3030
Analyst50050
Lite50050
Pro1,000100
EnterpriseCustomCustom

Rate Limit Handling

class RateLimiter {
  private calls: number[] = [];
  private maxCalls: number;
  private windowMs: number = 60000; // 1 minute

  constructor(maxCallsPerMinute: number) {
    this.maxCalls = maxCallsPerMinute;
  }

  async waitForSlot(): Promise<void> {
    const now = Date.now();
    this.calls = this.calls.filter(t => now - t < this.windowMs);

    if (this.calls.length >= this.maxCalls) {
      const oldestCall = this.calls[0];
      const waitTime = this.windowMs - (now - oldestCall);
      await new Promise(resolve => setTimeout(resolve, waitTime));
    }

    this.calls.push(Date.now());
  }
}

// Usage
const rateLimiter = new RateLimiter(30); // Demo API

async function fetchWithRateLimit(url: string): Promise<any> {
  await rateLimiter.waitForSlot();
  const response = await fetch(url, {
    headers: { [HEADER_KEY]: apiKey },
  });
  return response.json();
}

Error Handling

async function safeApiCall<T>(url: string): Promise<T | null> {
  try {
    const response = await fetch(url, {
      headers: { [HEADER_KEY]: apiKey },
    });

    if (response.status === 401) {
      throw new Error('Invalid API key');
    }
    if (response.status === 429) {
      throw new Error('Rate limit exceeded - wait before retrying');
    }
    if (response.status === 404) {
      console.warn('Resource not found');
      return null;
    }
    if (!response.ok) {
      throw new Error(`API error: ${response.status}`);
    }

    return response.json();
  } catch (error) {
    console.error('CoinGecko API error:', error);
    throw error;
  }
}

Common Error Codes

CodeMeaningSolution
401Invalid API keyCheck your API key
429Rate limit exceededWait and retry, or upgrade plan
404Resource not foundCheck address/network ID
500+Server errorRetry with exponential backoff

Best Practices

Security

  • Never commit API keys to git
  • Use environment variables
  • Rotate keys periodically
  • Use separate keys for dev/prod

Performance

  • Batch token requests when possible
  • Cache frequently accessed data
  • Use appropriate timeframes for OHLCV
  • Implement request queuing for rate limits

Data Quality

  • Verify market cap data (may be null if unverified)
  • Check pool liquidity before trusting prices
  • Use multiple timeframes for price analysis
  • Monitor last trade timestamp for activity

Resources


Skill Structure

coingecko/
├── SKILL.md                      # This file
├── resources/
│   ├── api-reference.md          # Complete API endpoint reference
│   ├── network-dex-ids.md        # Solana network and DEX identifiers
│   └── token-addresses.md        # Common Solana token addresses
├── examples/
│   ├── token-prices/
│   │   └── get-token-price.ts    # Token price examples
│   ├── pools/
│   │   └── pool-data.ts          # Pool data examples
│   ├── ohlcv/
│   │   └── ohlcv-charts.ts       # OHLCV chart examples
│   ├── trades/
│   │   └── recent-trades.ts      # Trade history examples
│   └── integration/
│       └── full-client.ts        # Complete client example
├── templates/
│   └── coingecko-client.ts       # Production-ready client template
└── docs/
    └── troubleshooting.md        # Common issues and solutions

Author

@0xinit

Stars

53

Repository

0xinit/cryptoskills

skills/monad/SKILL.md

Monad L1 Development

Chain Configuration

Mainnet

PropertyValue
Chain ID143
CurrencyMON (18 decimals)
EVM VersionPectra fork
Block Time400ms
Finality800ms (2 slots)
Block Gas Limit200M
Tx Gas Limit30M
Gas Throughput500M gas/sec
Min Base Fee100 MON-gwei
Node Versionv0.12.7 / MONAD_EIGHT

RPC Endpoints (Mainnet)

URLProviderRate LimitBatchNotes
https://rpc.monad.xyz / wss://rpc.monad.xyzQuickNode25 rps100Default
https://rpc1.monad.xyz / wss://rpc1.monad.xyzAlchemy15 rps100No debug/trace
https://rpc2.monad.xyz / wss://rpc2.monad.xyzGoldsky Edge300/10s10Historical state
https://rpc3.monad.xyz / wss://rpc3.monad.xyzAnkr300/10s10No debug
https://rpc-mainnet.monadinfra.com / wss://rpc-mainnet.monadinfra.comMF20 rps1Historical state

Block Explorers

ExplorerURL
MonadVisionhttps://monadvision.com
Monadscanhttps://monadscan.com
Socialscanhttps://monad.socialscan.io
Visualizationhttps://gmonads.com
TracesPhalcon Explorer, Tenderly
UserOpsJiffyscan

Testnet

PropertyValue
Chain ID10143
RPChttps://testnet-rpc.monad.xyz
WebSocketwss://testnet-rpc.monad.xyz
Explorerhttps://testnet.monadexplorer.com
Faucethttps://testnet.monad.xyz

Key Differences from Ethereum

FeatureEthereumMonad
Block time12s400ms
Finality~12-18 min800ms (2 slots)
Throughput~10 TPS10,000+ TPS
Gas chargingGas usedGas limit
Max contract size24.5 KB128 KB
Blob txns (EIP-4844)SupportedNot supported
Global mempoolYesNo (leader-based forwarding)
Account cold access2,600 gas10,100 gas
Storage cold access2,100 gas8,100 gas
Reserve balanceNone~10 MON per account
TIMESTAMP granularity1 per block2-3 blocks share same second
Precompile 0x0100N/AEIP-7951 secp256r1 (P256)
EIP-7702 min balanceNone10 MON for delegated EOAs
EIP-7702 CREATE/CREATE2AllowedBanned for delegated EOAs
Tx types supported0,1,2,3,40,1,2,4 (no type 3)

Gas Limit Charging Model

Monad charges gas_limit * price_per_gas, NOT gas_used * price_per_gas. This enables asynchronous execution — execution happens after consensus, so gas used isn't known at inclusion time.

gas_paid = gas_limit * price_per_gas
price_per_gas = min(base_price_per_gas + priority_price_per_gas, max_price_per_gas)

Set gas limits explicitly for fixed-cost operations (e.g., 21000 for transfers) to avoid overpaying.

Reserve Balance

Every account maintains a ~10 MON reserve for gas across the next 3 blocks. Transactions that would reduce balance below this threshold are rejected. This prevents DoS during asynchronous execution.

Block Lifecycle & Finality

Proposed → Voted (speculative finality, T+1) → Finalized (T+2) → Verified/state root (T+5)
PhaseLatencyWhen to Use
Voted400msUI updates, most dApps
Finalized800msConservative apps
Verified~2sExchanges, bridges, stablecoins

Quick Start: viem Chain Definition

import { defineChain } from "viem";

export const monad = defineChain({
  id: 143,
  name: "Monad",
  nativeCurrency: { name: "MON", symbol: "MON", decimals: 18 },
  rpcUrls: {
    default: { http: ["https://rpc.monad.xyz"], webSocket: ["wss://rpc.monad.xyz"] },
  },
  blockExplorers: {
    default: { name: "MonadVision", url: "https://monadvision.com" },
    monadscan: { name: "Monadscan", url: "https://monadscan.com" },
  },
});

export const monadTestnet = defineChain({
  id: 10143,
  name: "Monad Testnet",
  nativeCurrency: { name: "MON", symbol: "MON", decimals: 18 },
  rpcUrls: {
    default: { http: ["https://testnet-rpc.monad.xyz"], webSocket: ["wss://testnet-rpc.monad.xyz"] },
  },
  blockExplorers: {
    default: { name: "Monad Explorer", url: "https://testnet.monadexplorer.com" },
  },
  testnet: true,
});

Quick Start: Foundry Setup

Install Monad Foundry Fork

curl -L https://raw.githubusercontent.com/category-labs/foundry/monad/foundryup/install | bash
foundryup --network monad

Project Init

forge init --template monad-developers/foundry-monad my-project

foundry.toml

[profile.default]
src = "src"
out = "out"
libs = ["lib"]
evm_version = "prague"

[rpc_endpoints]
monad = "https://rpc.monad.xyz"
monad_testnet = "https://testnet-rpc.monad.xyz"

[etherscan]
monad = { key = "${ETHERSCAN_API_KEY}", chain = 143, url = "https://api.etherscan.io/v2/api?chainid=143" }
monad_testnet = { key = "${ETHERSCAN_API_KEY}", chain = 10143, url = "https://api.etherscan.io/v2/api?chainid=10143" }

Quick Start: Hardhat Configuration (v2)

const config: HardhatUserConfig = {
  solidity: {
    version: "0.8.28",
    settings: {
      evmVersion: "prague",
      metadata: { bytecodeHash: "ipfs" },
    },
  },
  networks: {
    monadTestnet: {
      url: "https://testnet-rpc.monad.xyz",
      chainId: 10143,
      accounts: [process.env.PRIVATE_KEY!],
    },
    monadMainnet: {
      url: "https://rpc.monad.xyz",
      chainId: 143,
      accounts: [process.env.PRIVATE_KEY!],
    },
  },
  etherscan: {
    customChains: [{
      network: "monadMainnet",
      chainId: 143,
      urls: {
        apiURL: "https://api.etherscan.io/v2/api?chainid=143",
        browserURL: "https://monadscan.com",
      },
    }],
  },
  sourcify: {
    enabled: true,
    apiUrl: "https://sourcify-api-monad.blockvision.org",
    browserUrl: "https://monadvision.com",
  },
};

Deployment

Foundry Deploy (Keystore)

cast wallet import monad-deployer --private-key $(cast wallet new | grep 'Private key:' | awk '{print $3}')

forge create src/MyContract.sol:MyContract \
  --account monad-deployer \
  --rpc-url https://rpc.monad.xyz \
  --broadcast

forge create src/MyToken.sol:MyToken \
  --account monad-deployer \
  --rpc-url https://rpc.monad.xyz \
  --constructor-args "MyToken" "MTK" 18 \
  --broadcast

Foundry Deploy (Script)

forge script script/Deploy.s.sol \
  --account monad-deployer \
  --rpc-url https://rpc.monad.xyz \
  --broadcast \
  --slow

Hardhat Deploy

npx hardhat ignition deploy ignition/modules/Counter.ts --network monadMainnet
npx hardhat ignition deploy ignition/modules/Counter.ts --network monadMainnet --reset

Verification

MonadVision (Sourcify)

forge verify-contract <address> <ContractName> \
  --chain 143 \
  --verifier sourcify \
  --verifier-url https://sourcify-api-monad.blockvision.org/

Monadscan (Etherscan)

forge verify-contract <address> <ContractName> \
  --chain 143 \
  --verifier etherscan \
  --etherscan-api-key $ETHERSCAN_API_KEY \
  --watch

Socialscan

forge verify-contract <address> <ContractName> \
  --chain 143 \
  --verifier etherscan \
  --etherscan-api-key $SOCIALSCAN_API_KEY \
  --verifier-url https://api.socialscan.io/monad-mainnet/v1/explorer/command_api/contract \
  --watch

Hardhat Verify

npx hardhat verify <address> --network monadMainnet

For testnet verification, replace --chain 143 with --chain 10143 and use testnet RPC/explorer URLs.

Opcode Repricing Summary

Cold state access is ~4x more expensive on Monad than Ethereum. Warm access is identical.

Access TypeEthereumMonad
Account (cold)2,60010,100
Storage slot (cold)2,1008,100
Account (warm)100100
Storage slot (warm)100100

Selected precompile repricing:

PrecompileEthereumMonadMultiplier
ecRecover (0x01)3,0006,0002x
ecMul (0x07)6,00030,0005x
ecPairing (0x08)45,000225,0005x
point evaluation (0x0a)50,000200,0004x

Monad-specific precompile: secp256r1 (P256) at 0x0100 for WebAuthn/passkey signature verification (EIP-7951).

EIP-1559 Parameters

ParameterValue
Block gas limit200M
Block gas target160M (80% of limit)
Per-transaction gas limit30M
Min base fee100 MON-gwei
Base fee max step size1/28
Base fee decay factor0.96

The base fee controller increases slower and decreases faster than Ethereum's to prevent blockspace underutilization on a high-throughput chain.

Gas Optimization Tips

  1. Warm your storage — cold reads are 4x more expensive; use access lists (type 1/2 txns) for known slots
  2. Set explicit gas limits — you're charged for the limit, not usage
  3. Batch operations — high throughput means batching is less critical, but still saves gas limit overhead
  4. Avoid unnecessary cold precompile calls — ecPairing is 5x more expensive than Ethereum
  5. Design for parallel execution — per-user mappings over global counters where possible
  6. No blob transactions — use calldata for data availability

Parallel Execution

Monad executes transactions concurrently with optimistic conflict detection. No Solidity changes needed.

  1. Multiple virtual executors process transactions simultaneously
  2. Each generates "pending results" (inputs: SLOADs, outputs: SSTOREs)
  3. Serial commitment validates each result's inputs remain valid
  4. Conflict detected -> re-execute the affected transaction
  5. Results committed in original transaction order

Every transaction executes at most twice. Most transactions don't conflict, achieving near-linear speedup.

Parallel-Friendly Contract Design

PatternParallelizes WellWhy
Per-user mappingsYesIndependent state per user
ERC-20 transfers between different pairsYesDifferent storage slots
Global counter incrementNoAll txns write same slot
AMM swaps on same poolNoSame reserves storage
Independent NFT mints (incremental ID)PartiallytokenId counter serializes

Staking Precompile

Address: 0x0000000000000000000000000000000000001000

Only standard CALL is allowed. STATICCALL, DELEGATECALL, and CALLCODE are not permitted.

Core Functions

FunctionSelectorGas Cost
delegate(uint64)0x84994fec260,850
undelegate(uint64,uint256,uint8)0x5cf41514147,750
compound(uint64)0xb34fea67285,050
claimRewards(uint64)0xa76e2ca5155,375
withdraw(uint64,uint8)0xaed2ee7368,675

Delegate (Solidity)

address constant STAKING = 0x0000000000000000000000000000000000001000;

function delegateToValidator(uint64 validatorId) external payable {
    (bool success,) = STAKING.call{value: msg.value}(
        abi.encodeWithSelector(0x84994fec, validatorId)
    );
    require(success, "Delegation failed");
}

Delegate (viem)

import { encodeFunctionData } from "viem";

const STAKING_ADDRESS = "0x0000000000000000000000000000000000001000";

const hash = await walletClient.sendTransaction({
  to: STAKING_ADDRESS,
  value: parseEther("100"),
  data: encodeFunctionData({
    abi: [{ name: "delegate", type: "function", inputs: [{ name: "validatorId", type: "uint64" }], outputs: [] }],
    functionName: "delegate",
    args: [1n],
  }),
});

EIP-7702 on Monad

Allows EOAs to gain smart contract capabilities via code delegation.

RestrictionDetail
Minimum balanceDelegated EOAs cannot drop below 10 MON
CREATE/CREATE2Banned when delegated EOAs execute as smart contracts
Clearing delegationSend type 0x04 pointing to address(0)
import { walletClient } from "./client";

const authorization = await walletClient.signAuthorization({
  account,
  contractAddress: "0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2",
});

const hash = await walletClient.sendTransaction({
  authorizationList: [authorization],
  data: "0xdeadbeef",
  to: walletClient.account.address,
});

WebSocket Subscriptions

Standard eth_subscribe plus Monad-specific extensions:

newHeads        — standard new block headers
logs            — standard log filtering
monadNewHeads   — Monad-specific block headers with extra fields
monadLogs       — Monad-specific log events

Execution Events (Advanced)

For ultra-low-latency data consumption, Monad exposes execution events via shared-memory ring buffers. Consumer runs on same host as node. ~1 microsecond latency. Supported in C, C++, and Rust only.

Use execution events when JSON-RPC can't keep up with 10,000 TPS throughput. For most dApps, standard WebSocket subscriptions are sufficient.

Canonical Contracts

ContractAddress
Wrapped MON (WMON)0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A
Staking Precompile0x0000000000000000000000000000000000001000
Multicall30xcA11bde05977b3631167028862bE2a173976CA11
USDC0x754704Bc059F8C67012fEd69BC8A327a5aafb603
USDT00xe7cd86e13AC4309349F30B3435a9d337750fC82D
WETH0xEE8c0E9f1BFFb4Eb878d8f15f368A02a35481242
WBTC0x0555E30da8f98308EdB960aa94C0Db47230d2B9c
ERC-4337 EntryPoint v0.70x0000000071727De22E5E9d8BAf0edAc6f37da032
Safe0x69f4D1788e39c87893C980c06EdF4b7f686e2938

Supported Transaction Types

TypeNameSupportedNotes
0LegacyYesPre-EIP-155 allowed but discouraged
1EIP-2930 (access list)Yes
2EIP-1559 (dynamic fee)YesRecommended
3EIP-4844 (blob)NoNot supported on Monad
4EIP-7702 (delegation)YesWith Monad-specific restrictions

Smart Contract Tips

  • Gas optimization still matters — even with cheap gas, optimize for users
  • Same security model — all Solidity best practices (CEI, reentrancy guards) apply
  • Parallel-friendly design — contracts with per-user mappings parallelize better than global counters
  • 128 KB contract limit — larger contracts are possible but still optimize for gas
  • No code changes needed for parallelism — it's at the runtime level
  • block.timestamp — 2-3 blocks may share the same second; don't rely on sub-second granularity
  • No blob transactions — EIP-4844 type 3 txns are not supported

Required Tooling Versions

ToolMinimum Version
FoundryMonad fork (foundryup --network monad)
viem2.40.0+
alloy-chains0.2.20+
Hardhat SolidityevmVersion: "prague"

Pre-Deployment Checklist

  • Using Monad Foundry fork or Hardhat with evmVersion: "prague"
  • Correct chain ID (143 mainnet / 10143 testnet)
  • Account funded with MON (remember ~10 MON reserve)
  • Gas limit set explicitly for predictable cost (gas limit is charged, not gas used)
  • Private key in env var, not hardcoded
  • Contract size under 128 KB
  • No EIP-4844 blob transactions (type 3 not supported)
  • Verified on at least one explorer after deploy

Additional Reference

FileContents
docs/architecture.mdMonadBFT consensus, parallel execution, deferred execution, MonadDb, JIT, RaptorCast
docs/deployment.mdFoundry + Hardhat deploy/verify step-by-step guides
docs/gas-and-opcodes.mdGas pricing model, opcode repricing tables, precompile costs
docs/staking.mdStaking precompile ABI, functions, events, epoch mechanics
docs/ecosystem.mdToken addresses, bridges, oracles, indexers, canonical contracts
docs/troubleshooting.mdCommon issues and fixes for Monad development
resources/contract-addresses.mdKey Monad contract addresses
templates/deploy-monad.shShell script for deploying to Monad

AI Skill Finder

Ask me what skills you need

What are you building?

Tell me what you're working on and I'll find the best agent skills for you.