What is InferStake?
InferStake is an AI-powered native token staking protocol deployed on Ritual Chain (Chain ID 1979). Users stake native RITUAL tokens directly from their wallet and earn yield at a configurable APY — currently 15% annualised.
What makes InferStake unique is its integration with Ritual Infernet — an on-chain AI inference layer. Using the 0x080C precompile address, the protocol can submit staking data to off-chain AI nodes and receive cryptographically verifiable advisory results without leaving the chain.
InferStake uses native RITUAL — no ERC-20 approval step needed. Just send RITUAL with your transaction and you're staked.
The contract is immutable (no proxy pattern), open-source, and all reward calculations are executed deterministically on-chain — every number you see in the dashboard is computed directly from contract state.
Quick Start
How Yield Works
InferStake uses a simple, transparent, time-weighted reward formula. There are no lock-up periods, no vesting schedules, and no compounding complexity — rewards accrue every second and can be claimed at any time.
Reward Formula
Example Calculation
Staking 100 RITUAL for 30 days at 15% APY:
staked = 100 RITUAL
APY = 15% → 1500 basis points
timeElapsed = 30 days → 2,592,000 seconds
reward = (100 × 1500 × 2,592,000) / (10,000 × 31,536,000)
= 388,800,000,000 / 315,360,000,000
≈ 1.2328 RITUALReward Accrual
Rewards accrue continuously and are snapshotted into accruedRewards whenever you stake more or unstake. This prevents reward dilution — your earned yield is never lost when changing your position.
Reward Reserve
The contract owner pre-funds a native RITUAL reserve via fundRewardReserve(). When you claim, rewards come from this reserve. If the reserve is insufficient, claims will revert — check rewardReserve() on the contract before claiming.
The owner can update the APY via setAPY(newApyBps). APY changes affect future accrual only — already-accrued rewards are always preserved in accruedRewards.
AI Advisor
InferStake integrates with Ritual's Infernet network — a decentralised AI inference layer built into Ritual Chain. The 0x080C precompile address exposes a requestCompute() function that submits AI jobs to off-chain Infernet nodes.
How it works
Infernet payload structure
bytes memory payload = abi.encode(
msg.sender, // address: user
info.stakedAmount, // uint256: wei staked
info.accruedRewards + pendingRewards, // uint256: total claimable wei
apyBasisPoints, // uint256: e.g. 1500 = 15%
block.timestamp - info.stakeTimestamp // uint256: seconds staked
);
IInfernetCoordinator(0x000...080C).requestCompute(
"inferstake-advisor-v1", // model ID
payload,
200_000 // callback gas limit
);Every Infernet result is tied to a unique requestId emitted in the AIAdvisoryRequested event. You can verify the computation on Ritual's Infernet explorer using this ID.
Contract Reference
Contract Address
Functions
Full ABI
[
{
"name": "stake",
"type": "function",
"stateMutability": "payable",
"inputs": [],
"outputs": []
},
{
"name": "unstake",
"type": "function",
"stateMutability": "nonpayable",
"inputs": [
{
"name": "amount",
"type": "uint256"
}
],
"outputs": []
},
{
"name": "claimRewards",
"type": "function",
"stateMutability": "nonpayable",
"inputs": [],
"outputs": []
},
{
"name": "requestAIAdvisory",
"type": "function",
"stateMutability": "nonpayable",
"inputs": [],
"outputs": [
{
"name": "requestId",
"type": "uint256"
}
]
},
{
"name": "getStakedBalance",
"type": "function",
"stateMutability": "view",
"inputs": [
{
"name": "user",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256"
}
]
},
{
"name": "getRewards",
"type": "function",
"stateMutability": "view",
"inputs": [
{
"name": "user",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256"
}
]
},
{
"name": "getUserDashboard",
"type": "function",
"stateMutability": "view",
"inputs": [
{
"name": "user",
"type": "address"
}
],
"outputs": [
{
"name": "stakedAmount",
"type": "uint256"
},
{
"name": "totalRewards",
"type": "uint256"
},
{
"name": "apyBps",
"type": "uint256"
},
{
"name": "timeStakedSeconds",
"type": "uint256"
},
{
"name": "lastAiRequestId",
"type": "uint256"
}
]
},
{
"name": "getProtocolStats",
"type": "function",
"stateMutability": "view",
"inputs": [],
"outputs": [
{
"name": "_totalStaked",
"type": "uint256"
},
{
"name": "_totalStakers",
"type": "uint256"
},
{
"name": "_totalAiQueries",
"type": "uint256"
},
{
"name": "_apyBasisPoints",
"type": "uint256"
}
]
},
{
"name": "contractBalance",
"type": "function",
"stateMutability": "view",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256"
}
]
},
{
"name": "fundRewardReserve",
"type": "function",
"stateMutability": "payable",
"inputs": [],
"outputs": []
},
{
"name": "setAPY",
"type": "function",
"stateMutability": "nonpayable",
"inputs": [
{
"name": "newApyBps",
"type": "uint256"
}
],
"outputs": []
},
{
"name": "apyBasisPoints",
"type": "function",
"stateMutability": "view",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256"
}
]
},
{
"name": "totalStaked",
"type": "function",
"stateMutability": "view",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256"
}
]
},
{
"name": "owner",
"type": "function",
"stateMutability": "view",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"name": "rewardReserve",
"type": "function",
"stateMutability": "view",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256"
}
]
},
{
"name": "Staked",
"type": "event",
"inputs": [
{
"indexed": true,
"name": "user",
"type": "address"
},
{
"name": "amount",
"type": "uint256"
},
{
"name": "timestamp",
"type": "uint256"
}
]
},
{
"name": "Unstaked",
"type": "event",
"inputs": [
{
"indexed": true,
"name": "user",
"type": "address"
},
{
"name": "amount",
"type": "uint256"
},
{
"name": "timestamp",
"type": "uint256"
}
]
},
{
"name": "RewardsClaimed",
"type": "event",
"inputs": [
{
"indexed": true,
"name": "user",
"type": "address"
},
{
"name": "amount",
"type": "uint256"
},
{
"name": "timestamp",
"type": "uint256"
}
]
},
{
"name": "AIAdvisoryRequested",
"type": "event",
"inputs": [
{
"indexed": true,
"name": "user",
"type": "address"
},
{
"name": "requestId",
"type": "uint256"
}
]
}
]ethers.js Integration
import { ethers } from "ethers";
const CONTRACT = "0x6e4463b62a2e332b007573dbe7f0Bf3B784B4838";
const ABI = [
"function stake() external payable",
"function unstake(uint256 amount) external",
"function claimRewards() external",
"function getUserDashboard(address user) view returns (uint256,uint256,uint256,uint256,uint256)",
"function getProtocolStats() view returns (uint256,uint256,uint256,uint256)",
];
// Connect
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const contract = new ethers.Contract(CONTRACT, ABI, signer);
// Stake 10 RITUAL (native token — no approve needed)
const tx = await contract.stake({ value: ethers.parseEther("10") });
await tx.wait();
// Read dashboard
const [staked, rewards, apyBps, timeSecs] = await contract.getUserDashboard(userAddress);
console.log("Staked:", ethers.formatEther(staked), "RITUAL");
console.log("Rewards:", ethers.formatEther(rewards), "RITUAL");
console.log("APY:", Number(apyBps) / 100, "%");
// Unstake
await contract.unstake(ethers.parseEther("5"));
// Claim
await contract.claimRewards();Network & RPC
| Parameter | Value |
|---|---|
| Network Name | Ritual Chain |
| Chain ID | 1979 |
| Currency | RITUAL (18 decimals) |
| Block Time | ~350ms |
| RPC (HTTP) | https://rpc.ritualfoundation.org |
| RPC (WebSocket) | wss://rpc.ritualfoundation.org/ws |
| Explorer | https://explorer.ritualfoundation.org |
| Contract | 0x6e4463b62a2e332b007573dbe7f0Bf3B784B4838 |
| Infernet Coord. | 0x000000000000000000000000000000000000080C |
MetaMask — Add Ritual Chain
await window.ethereum.request({
method: "wallet_addEthereumChain",
params: [{
chainId: "0x7BB", // 1979 in hex
chainName: "Ritual Chain",
nativeCurrency: {
name: "RITUAL", symbol: "RITUAL", decimals: 18
},
rpcUrls: ["https://rpc.ritualfoundation.org"],
blockExplorerUrls: ["https://explorer.ritualfoundation.org"],
}],
});