Polygon Mainnet

Documentation

Everything you need to integrate ChainVRF randomness into your smart contracts.

Quick Start

Get verifiable randomness in your smart contract in 3 steps.

1

Get an API Key

Visit chainvrf.com, connect your MetaMask wallet, and subscribe to a plan. Free plan gives you 100 requests/month.

2

Implement the Consumer Interface

Your contract must implement IRandomnessConsumer and the receiveRandomness callback.

3

Request Randomness

Call requestRandomness() on the oracle contract. Pay the request fee in MATIC. Receive your randomness in the callback.

That's it! From request to on-chain fulfillment in ~15-30 seconds. No off-chain infrastructure needed.

How It Works

1
Your contract calls requestRandomness() on the RandomnessOracle, paying a small MATIC fee.
2
The oracle emits a RandomnessRequested event with a unique requestId.
3
Oracle nodes detect the request, generate randomness using cryptographic primitives, and submit responses on-chain.
4
Once enough responses are collected, the oracle combines them via XOR and calls your contract's receiveRandomness(requestId, randomness) callback.
5
Your contract uses the verified randomness. Anyone can verify the entire process on-chain.
Security model: Randomness is generated by staked oracle operators. The XOR combination of multiple independent responses ensures no single operator can predict or manipulate the result. All data is recorded on-chain for full transparency.

Solidity Integration

Consumer Interface

Your contract must implement this interface:

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

interface IRandomnessConsumer {
    /// @notice Called by the oracle with verified randomness
    /// @param requestId The unique request identifier
    /// @param randomness The verified random bytes32 value
    function receiveRandomness(uint256 requestId, bytes32 randomness) external;
}

Full Example

Here's a complete example — a lottery contract that uses ChainVRF:

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

// Import the interface
interface IRandomnessOracle {
    function requestRandomness() external payable returns (uint256);
    function requestFee() external view returns (uint256);
}

interface IRandomnessConsumer {
    function receiveRandomness(uint256 requestId, bytes32 randomness) external;
}

contract MyLottery is IRandomnessConsumer {
    IRandomnessOracle public oracle;
    uint256 public latestRequestId;
    bytes32 public latestRandomness;
    bool public pending;

    constructor(address _oracle) {
        oracle = IRandomnessOracle(_oracle);
    }

    /// @notice Request new randomness. Send enough MATIC for the fee.
    function roll() external payable {
        uint256 fee = oracle.requestFee();
        require(msg.value >= fee, "Insufficient fee");

        latestRequestId = oracle.requestRandomness{value: fee}();
        pending = true;
    }

    /// @notice Callback from the oracle — this is where you use the randomness
    function receiveRandomness(uint256 requestId, bytes32 randomness) external override {
        require(msg.sender == address(oracle), "Only oracle");
        require(requestId == latestRequestId, "Wrong request");

        latestRandomness = randomness;
        pending = false;

        // Use the randomness!
        // Example: pick a winner from 1-100
        uint256 winner = (uint256(randomness) % 100) + 1;

        // ... your logic here
    }
}
Important: Always check msg.sender == address(oracle) in your callback to prevent anyone from sending fake randomness.

REST API Reference

Base URL: https://chainvrf.com/api

Get Plans

GET /api/plans

Returns all available pricing plans.

// Response
[
  { "id": "free",     "name": "Free",     "requests": 100,    "price": 0 },
  { "id": "starter",  "name": "Starter",  "requests": 5000,   "price": 5 },
  { "id": "pro",      "name": "Pro",      "requests": 50000,  "price": 25 },
  { "id": "business", "name": "Business", "requests": 500000, "price": 100 }
]

Subscribe

POST /api/subscribe

Creates a new subscription. Returns API key and payment info for paid plans.

Request Body

FieldTypeDescription
planstringPlan ID: free, starter, pro, business
walletAddressstringYour Polygon wallet address

Free Plan Response

{
  "apiKey": "cvrf_a1b2c3d4...",
  "plan": { "id": "free", "name": "Free", "requests": 100, "price": 0 },
  "status": "active",
  "paymentRequired": false
}

Paid Plan Response

{
  "apiKey": "cvrf_e5f6g7h8...",
  "plan": { "id": "pro", "name": "Pro", "requests": 50000, "price": 25 },
  "status": "pending_payment",
  "paymentRequired": true,
  "paymentInfo": {
    "token": "USDT",
    "network": "Polygon",
    "amount": 25,
    "to": "0x8af85C78260DC147E9f6Ed85F58C2DAef707087C",
    "tokenAddress": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F"
  }
}

Check Payment

POST /api/check-payment

Checks if your USDT payment has been received and activates your subscription.

Request Body

FieldTypeDescription
apiKeystringYour API key from the subscribe step

Response

// Payment confirmed
{ "status": "active", "plan": { ... }, "txHash": "0x..." }

// Payment pending
{ "status": "pending_payment", "plan": { ... } }
The backend scans the last ~10,000 blocks (~3 hours) for USDT transfers from your wallet to the payment wallet. After sending USDT on Polygon, confirmation usually takes 5-10 seconds.

Verify API Key

GET /api/verify/:apiKey

Verifies an API key and checks quota. Used by oracle nodes before processing requests.

// Valid
{
  "valid": true,
  "plan": "pro",
  "requestsUsed": 142,
  "requestsLimit": 50000,
  "requestsRemaining": 49858
}

// Invalid or expired
{ "valid": false, "error": "Invalid or inactive API key" }

// Quota exceeded
{ "valid": false, "error": "Quota exceeded", "requestsUsed": 50000, "requestsLimit": 50000 }

Increment Usage

POST /api/increment/:apiKey

Increments the request counter after a successful randomness request.

// Success
{ "ok": true }

// Invalid key
{ "error": "Invalid" }

Subscription Info

GET /api/subscription/:apiKey

Returns full subscription details.

{
  "plan": { "id": "pro", "name": "Pro", "requests": 50000, "price": 25 },
  "status": "active",
  "requestsUsed": 142,
  "requestsLimit": 50000,
  "expiresAt": "2026-07-10 12:00:00",
  "walletAddress": "0x..."
}

Health Check

GET /api/health
{ "status": "ok", "oracle": "0x7493604e02bb9dA1be2AC820167B0dA5B31704a2", "network": "polygon" }

USDT Payment

Paid plans are activated by sending USDT on Polygon. No credit card needed.

Payment Flow

1
Choose a plan on chainvrf.com and click Subscribe.
2
Connect MetaMask — make sure you're on the Polygon network and have enough USDT + a small amount of MATIC for gas.
3
Send USDT — MetaMask will prompt you to transfer the exact amount to our payment wallet. Confirm the transaction.
4
Automatic activation — our backend detects the transfer within seconds and activates your API key.

Payment Details

TokenUSDT (PoS) on Polygon
Token Address0xc2132D05D31c914a87C6611C10748AEb04B58e8F
NetworkPolygon (Chain ID: 137)
Payment Wallet0x8af85C78260DC147E9f6Ed85F58C2DAef707087C
Important:
  • Send USDT only on the Polygon network. Ethereum USDT will not be detected.
  • Send the exact amount for your plan ($5, $25, or $100).
  • Make sure you have a small amount of MATIC for the gas fee (~0.01 MATIC).

Manual Payment

If the website flow doesn't work, you can pay manually:

// Using ethers.js
const usdt = new ethers.Contract(
  "0xc2132D05D31c914a87C6611C10748AEb04B58e8F",
  ["function transfer(address to, uint256 amount) returns (bool)"],
  signer
);

// Example: $25 for Pro plan (USDT has 6 decimals)
const tx = await usdt.transfer(
  "0x8af85C78260DC147E9f6Ed85F58C2DAef707087C",
  ethers.utils.parseUnits("25", 6)
);
await tx.wait(2);

After sending, call POST /api/check-payment with your API key to activate.

Pricing Plans

PlanPriceRequests/monthCost per request
Free$0100$0.00
Starter$55,000$0.001
Pro$2550,000$0.0005
Business$100500,000$0.0002
Comparison: Chainlink VRF charges ~$4-30 per request. ChainVRF Pro plan: $0.0005 per request. That's 8,000-60,000x cheaper.

Contract Addresses

All contracts are deployed on Polygon Mainnet (Chain ID: 137).

ContractAddress
RandomnessOracle0x7493604e02bb9dA1be2AC820167B0dA5B31704a2
USDT (PoS)0xc2132D05D31c914a87C6611C10748AEb04B58e8F
Payment Wallet0x8af85C78260DC147E9f6Ed85F58C2DAef707087C

RandomnessOracle Contract

The core oracle contract that manages randomness requests and responses.

Key Functions

Request Randomness

function requestRandomness() external payable returns (uint256 requestId)

Call this from your contract to request randomness. Send MATIC equal to requestFee().

Get Request Fee

function requestFee() external view returns (uint256)

Returns the current fee in MATIC wei per request. Default: 0.01 MATIC.

Get Request Status

function requests(uint256 requestId) external view returns (
    address consumer,       // Your contract address
    bytes4 callbackSelector, // The callback function
    uint256 callbackGasLimit,
    uint256 seed,           // On-chain seed
    uint256 createdAt,
    uint256 fulfilledAt,
    bool fulfilled,         // Has randomness been delivered?
    uint256 numResponses,   // How many oracle nodes responded
    bytes32 finalRandomness // The final random value
)

Events

// Emitted when randomness is requested
event RandomnessRequested(uint256 indexed requestId, address indexed consumer)

// Emitted when oracle submits a response
event RandomnessSubmitted(uint256 indexed requestId, address indexed oracle, bytes32 response)

// Emitted when randomness is fulfilled and callback is made
event RandomnessFulfilled(uint256 indexed requestId, bytes32 finalRandomness)