// accx-blockchain-explorer
// Routes: api.africacryptochainx.com/*

const CORS_HEADERS = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
"Content-Type": "application/json"
};

// Blockchain API endpoints
const PROVIDERS = {
ethereum: "https://eth-mainnet.g.alchemy.com/v2/demo",
bsc: "https://bsc-dataseed.binance.org",
polygon: "https://polygon-rpc.com",
bitcoin: "https://blockchain.info"
};

export default {
async fetch(request, env, ctx) {
if (request.method === "OPTIONS") {
return new Response(null, { status: 204, headers: CORS_HEADERS });
}

const url = new URL(request.url);
const path = url.pathname;

try {
  // Health check
  if (path === "/" || path === "/health") {
    return jsonResponse({ status: "ok", service: "ACCX Blockchain Explorer", timestamp: new Date().toISOString() });
  }

  // === ETHEREUM ===
  if (path === "/eth/balance") {
    const address = url.searchParams.get("address");
    if (!address) return errorResponse("address required");
    const res = await fetch(PROVIDERS.ethereum, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_getBalance", params: [address, "latest"] })
    });
    const data = await res.json();
    return jsonResponse({ address, balanceWei: data.result, balanceEth: parseInt(data.result, 16) / 1e18 });
  }

  if (path === "/eth/gas") {
    const res = await fetch(PROVIDERS.ethereum, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_gasPrice", params: [] })
    });
    const data = await res.json();
    return jsonResponse({ gasPriceWei: data.result, gasPriceGwei: parseInt(data.result, 16) / 1e9 });
  }

  if (path === "/eth/block") {
    const res = await fetch(PROVIDERS.ethereum, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_blockNumber", params: [] })
    });
    const data = await res.json();
    return jsonResponse({ blockHeight: parseInt(data.result, 16) });
  }

  // === BSC ===
  if (path === "/bsc/balance") {
    const address = url.searchParams.get("address");
    if (!address) return errorResponse("address required");
    const res = await fetch(PROVIDERS.bsc, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_getBalance", params: [address, "latest"] })
    });
    const data = await res.json();
    return jsonResponse({ address, balanceWei: data.result, balanceBnb: parseInt(data.result, 16) / 1e18 });
  }

  if (path === "/bsc/gas") {
    const res = await fetch(PROVIDERS.bsc, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_gasPrice", params: [] })
    });
    const data = await res.json();
    return jsonResponse({ gasPriceWei: data.result, gasPriceGwei: parseInt(data.result, 16) / 1e9 });
  }

  // === POLYGON ===
  if (path === "/polygon/balance") {
    const address = url.searchParams.get("address");
    if (!address) return errorResponse("address required");
    const res = await fetch(PROVIDERS.polygon, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_getBalance", params: [address, "latest"] })
    });
    const data = await res.json();
    return jsonResponse({ address, balanceWei: data.result, balanceMatic: parseInt(data.result, 16) / 1e18 });
  }

  // === BITCOIN ===
  if (path === "/btc/balance") {
    const address = url.searchParams.get("address");
    if (!address) return errorResponse("address required");
    const res = await fetch(`${PROVIDERS.bitcoin}/rawaddr/${address}`);
    const data = await res.json();
    return jsonResponse({ address, balanceSatoshi: data.final_balance, balanceBtc: data.final_balance / 1e8, txs: data.n_tx });
  }

  if (path === "/btc/block") {
    const res = await fetch(`${PROVIDERS.bitcoin}/latestblock`);
    const data = await res.json();
    return jsonResponse({ blockHeight: data.height, hash: data.hash, time: data.time });
  }

  // === CRYPTO PRICES ===
  if (path === "/prices") {
    const symbols = url.searchParams.get("symbols") || "bitcoin,ethereum,binancecoin,polygon";
    const currency = url.searchParams.get("currency") || "usd";
    const res = await fetch(`https://api.coingecko.com/api/v3/simple/price?ids=${symbols}&vs_currencies=${currency},eur,ngn`);
    const data = await res.json();
    return jsonResponse(data);
  }

  // 404
  return errorResponse("Endpoint not found. Try: /eth/balance?address=0x..., /eth/gas, /eth/block, /bsc/balance, /bsc/gas, /polygon/balance, /btc/balance, /btc/block, /prices", 404);

} catch (err) {
  return errorResponse(err.message, 500);
}

}
};

function jsonResponse(data) {
return new Response(JSON.stringify(data, null, 2), { status: 200, headers: CORS_HEADERS });
}

function errorResponse(message, status = 400) {
return new Response(JSON.stringify({ error: message }, null, 2), { status, headers: CORS_HEADERS });
}

// ============================================================
// ACCX Blockchain Explorer Worker
// AfricaCryptoChainx (ACCX) Ecosystem
// Routes: api.africacryptochainx.com/*
// Network: BSC Mainnet (Chain 56)
// Token: 0xae6C2FEA44a07022177B3481B45412A2800487b5
// ============================================================

// CORS headers for cross-origin requests from dashboard
const CORS_HEADERS = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
  "Access-Control-Allow-Headers": "Content-Type, Authorization",
  "Content-Type": "application/json"
};

// Blockchain RPC endpoints and API providers
const PROVIDERS = {
  ethereum: "https://eth-mainnet.g.alchemy.com/v2/demo",  // Replace with actual API key
  bsc: "https://bsc-dataseed.binance.org",               // BNB Smart Chain
  polygon: "https://polygon-rpc.com",                     // Polygon (Matic)
  bitcoin: "https://blockchain.info"                      // Bitcoin explorer
};

export default {
  async fetch(request, env, ctx) {
    // Handle CORS preflight requests
    if (request.method === "OPTIONS") {
      return new Response(null, { status: 204, headers: CORS_HEADERS });
    }

    const url = new URL(request.url);
    const path = url.pathname;

    try {
      // Health check endpoint
      if (path === "/" || path === "/health") {
        return jsonResponse({ 
          status: "ok", 
          service: "ACCX Blockchain Explorer", 
          network: "BSC Mainnet (56)",
          token: "0xae6C2FEA44a07022177B3481B45412A2800487b5",
          timestamp: new Date().toISOString() 
        });
      }

      // ==================== ETHEREUM ====================
      
      // GET /eth/balance?address=0x...
      if (path === "/eth/balance") {
        const address = url.searchParams.get("address");
        if (!address) return errorResponse("address parameter required");
        const res = await fetch(PROVIDERS.ethereum, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_getBalance", params: [address, "latest"] })
        });
        const data = await res.json();
        return jsonResponse({ 
          address, 
          balanceWei: data.result, 
          balanceEth: parseInt(data.result, 16) / 1e18 
        });
      }

      // GET /eth/gas - Current gas price
      if (path === "/eth/gas") {
        const res = await fetch(PROVIDERS.ethereum, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_gasPrice", params: [] })
        });
        const data = await res.json();
        return jsonResponse({ 
          gasPriceWei: data.result, 
          gasPriceGwei: parseInt(data.result, 16) / 1e9 
        });
      }

      // GET /eth/block - Current block number
      if (path === "/eth/block") {
        const res = await fetch(PROVIDERS.ethereum, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_blockNumber", params: [] })
        });
        const data = await res.json();
        return jsonResponse({ blockHeight: parseInt(data.result, 16) });
      }

      // ==================== BSC (BNB Smart Chain) ====================
      
      // GET /bsc/balance?address=0x...
      if (path === "/bsc/balance") {
        const address = url.searchParams.get("address");
        if (!address) return errorResponse("address parameter required");
        const res = await fetch(PROVIDERS.bsc, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_getBalance", params: [address, "latest"] })
        });
        const data = await res.json();
        return jsonResponse({ 
          address, 
          balanceWei: data.result, 
          balanceBnb: parseInt(data.result, 16) / 1e18 
        });
      }

      // GET /bsc/gas - BSC gas price
      if (path === "/bsc/gas") {
        const res = await fetch(PROVIDERS.bsc, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_gasPrice", params: [] })
        });
        const data = await res.json();
        return jsonResponse({ 
          gasPriceWei: data.result, 
          gasPriceGwei: parseInt(data.result, 16) / 1e9 
        });
      }

      // ==================== POLYGON ====================
      
      // GET /polygon/balance?address=0x...
      if (path === "/polygon/balance") {
        const address = url.searchParams.get("address");
        if (!address) return errorResponse("address parameter required");
        const res = await fetch(PROVIDERS.polygon, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_getBalance", params: [address, "latest"] })
        });
        const data = await res.json();
        return jsonResponse({ 
          address, 
          balanceWei: data.result, 
          balanceMatic: parseInt(data.result, 16) / 1e18 
        });
      }

      // ==================== BITCOIN ====================
      
      // GET /btc/balance?address=...
      if (path === "/btc/balance") {
        const address = url.searchParams.get("address");
        if (!address) return errorResponse("address parameter required");
        const res = await fetch(`${PROVIDERS.bitcoin}/rawaddr/${address}`);
        const data = await res.json();
        return jsonResponse({ 
          address, 
          balanceSatoshi: data.final_balance, 
          balanceBtc: data.final_balance / 1e8, 
          transactions: data.n_tx 
        });
      }

      // GET /btc/block - Latest Bitcoin block
      if (path === "/btc/block") {
        const res = await fetch(`${PROVIDERS.bitcoin}/latestblock`);
        const data = await res.json();
        return jsonResponse({ 
          blockHeight: data.height, 
          hash: data.hash, 
          time: data.time 
        });
      }

      // ==================== CRYPTO PRICES ====================
      
      // GET /prices?symbols=bitcoin,binancecoin&currency=usd
      // Supports NGN (Nigerian Naira) for local pricing
      if (path === "/prices") {
        const symbols = url.searchParams.get("symbols") || "bitcoin,ethereum,binancecoin,polygon";
        const currency = url.searchParams.get("currency") || "usd";
        const res = await fetch(`https://api.coingecko.com/api/v3/simple/price?ids=${symbols}&vs_currencies=${currency},eur,ngn`);
        const data = await res.json();
        return jsonResponse(data);
      }

      // 404 - Endpoint not found
      return errorResponse(
        "Endpoint not found. Available endpoints: /health, /eth/balance, /eth/gas, /eth/block, /bsc/balance, /bsc/gas, /polygon/balance, /btc/balance, /btc/block, /prices", 
        404
      );

    } catch (err) {
      return errorResponse(err.message, 500);
    }
  }
};

function jsonResponse(data) {
  return new Response(JSON.stringify(data, null, 2), { status: 200, headers: CORS_HEADERS });
}

function errorResponse(message, status = 400) {
  return new Response(JSON.stringify({ error: message }, null, 2), { status, headers: CORS_HEADERS });
}
AfricaCryptoChainx changed pull request status to closed

Sign up or log in to comment