Quick Start
Get verifiable randomness in your smart contract in 3 steps.
Get an API Key
Visit chainvrf.com, connect your MetaMask wallet, and subscribe to a plan. Free plan gives you 100 requests/month.
Implement the Consumer Interface
Your contract must implement IRandomnessConsumer and the receiveRandomness callback.
Request Randomness
Call requestRandomness() on the oracle contract. Pay the request fee in MATIC. Receive your randomness in the callback.
How It Works
requestRandomness() on the RandomnessOracle, paying a small MATIC fee.
RandomnessRequested event with a unique requestId.
receiveRandomness(requestId, randomness) callback.
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
}
}
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
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
Creates a new subscription. Returns API key and payment info for paid plans.
Request Body
| Field | Type | Description |
|---|---|---|
plan | string | Plan ID: free, starter, pro, business |
walletAddress | string | Your 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
Checks if your USDT payment has been received and activates your subscription.
Request Body
| Field | Type | Description |
|---|---|---|
apiKey | string | Your API key from the subscribe step |
Response
// Payment confirmed
{ "status": "active", "plan": { ... }, "txHash": "0x..." }
// Payment pending
{ "status": "pending_payment", "plan": { ... } }
Verify API Key
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
Increments the request counter after a successful randomness request.
// Success
{ "ok": true }
// Invalid key
{ "error": "Invalid" }
Subscription Info
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
{ "status": "ok", "oracle": "0x7493604e02bb9dA1be2AC820167B0dA5B31704a2", "network": "polygon" }
USDT Payment
Paid plans are activated by sending USDT on Polygon. No credit card needed.
Payment Flow
Payment Details
| Token | USDT (PoS) on Polygon |
|---|---|
| Token Address | 0xc2132D05D31c914a87C6611C10748AEb04B58e8F |
| Network | Polygon (Chain ID: 137) |
| Payment Wallet | 0x8af85C78260DC147E9f6Ed85F58C2DAef707087C |
- 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
| Plan | Price | Requests/month | Cost per request |
|---|---|---|---|
| Free | $0 | 100 | $0.00 |
| Starter | $5 | 5,000 | $0.001 |
| Pro | $25 | 50,000 | $0.0005 |
| Business | $100 | 500,000 | $0.0002 |
Contract Addresses
All contracts are deployed on Polygon Mainnet (Chain ID: 137).
| Contract | Address |
|---|---|
| RandomnessOracle | 0x7493604e02bb9dA1be2AC820167B0dA5B31704a2 |
| USDT (PoS) | 0xc2132D05D31c914a87C6611C10748AEb04B58e8F |
| Payment Wallet | 0x8af85C78260DC147E9f6Ed85F58C2DAef707087C |
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)