No Polymarket market. No external data feed. We deployed a contract on Base, pointed Quicknode Streams at it, and this scoreboard reads the chain directly — 81ms, no middlemen.
| Team | F1 | F2 | F3 | F4 | B1 | B2 | B3 | B4 | Singles | Pts |
|---|---|---|---|---|---|---|---|---|---|---|
| 🇺🇸 USA | – | – | – | – | – | – | – | – | – | 0 |
| 🌍 International | – | – | – | – | – | – | – | – | – | 0 |
A single-function Solidity contract accepts session results from one owner wallet. No funds held. The moment a session is official, one transaction writes it permanently onchain.
A JS filter function in the Streams dashboard decodes every ResultLogged event on Base. Fires the moment the block lands — no polling, no missed events.
This scoreboard calls eth_getLogs on the contract every 20 seconds. 81ms average on Base. Every cell is a live chain read — no database behind this page.
// PresidentsCupResults.sol — single-purpose, no funds pragma solidity ^0.8.20; contract PresidentsCupResults { address public owner; mapping(uint256 => bool) public sessionLocked; event ResultLogged( uint256 indexed sessionId, uint8 indexed team, // 0 = USA, 1 = Intl uint256 points ); constructor() { owner = msg.sender; } function logResult(uint256 sessionId, uint8 team, uint256 points) external { require(msg.sender == owner, "not owner"); require(!sessionLocked[sessionId], "locked"); sessionLocked[sessionId] = true; emit ResultLogged(sessionId, team, points); } }
// Quicknode Streams — filter function // Paste into the Streams dashboard under "Filter Function" function main(data) { const CONTRACT = process.env.CONTRACT_ADDRESS.toLowerCase(); const TOPIC = process.env.EVENT_TOPIC; // keccak256("ResultLogged(...)") return data.logs .filter(log => log.address.toLowerCase() === CONTRACT && log.topics[0] === TOPIC ) .map(log => ({ sessionId: parseInt(log.topics[1], 16), team: parseInt(log.topics[2], 16) === 0 ? "usa" : "intl", points: parseInt(log.data, 16), txHash: log.transactionHash, block: parseInt(log.blockNumber, 16), })); }
// Pages Function — /functions/api/standings.js // Calls Base Mainnet RPC, keeps endpoint URL server-side const res = await fetch(env.QUICKNODE_BASE_ENDPOINT, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_getLogs", params: [{ fromBlock: "0x0", toBlock: "latest", address: env.PRESIDENTS_CUP_CONTRACT, topics: [env.PRESIDENTS_CUP_TOPIC], }], }), signal: AbortSignal.timeout(4000), }); const { result: logs } = await res.json(); // decode topics → sessionId, team, points → return standings JSON
One filter function in the Streams dashboard watches every Base block. Fires on every ResultLogged event — no missed blocks, no polling.
Streams delivers the decoded JSON payload within seconds of the block landing. Point it at Slack, a database, or a custom endpoint — same config.
Configure destinations →Every scoreboard cell is a direct chain read via eth_getLogs. 99.99% uptime. No third-party data feed. The contract is the source of truth.
If a Presidents Cup outcome market lists on a supported chain, one SQL query pulls live odds from the indexed tables.
SQL Explorer →The contract is 30 lines. The Streams filter is 15. The scoreboard reads directly from the chain. Start free — no credit card.