Intermediate
Oracles & Off-Chain Data — Kudos build — oracle & randomness
Use oracles safely.
Developer Intermediate
5/6 — Oracles & Off-Chain Data — Kudos build — oracle & randomness
Objective Attach reliable pricing and VRF-based rarity to Kudos badges.
The root problem with conventional currency is all the trust that’s required to make it work.
Flow Normalize feed data, guard freshness/deviation, request randomness, and store a rarity tier. Emit events so the DApp can render traits.
What to write
- Guarded read
Check freshness and normalize decimals.(, int256 answer,, uint256 ts,) = feed.latestRoundData(); require(ts + 1 hours > block.timestamp, "stale"); uint256 normalized = uint256(answer) * 1e10;Rejects stale rounds and aligns decimals before use.
- VRF request
Record pending rarity request.reqId = vrf.requestRandomWords(keyHash, subId, 3, 200000, 1); pending[reqId] = Pending({ tokenId: tokenId, price: normalized }); emit RarityRequested(reqId, tokenId, normalized);Tracks pending state to match fulfillments; logs for monitoring.
- Fulfill
Assign tier and clean up pending.Pending memory p = pending[reqId]; require(p.tokenId != 0, "unknown"); delete pending[reqId]; uint256 roll = words[0] % 10; string memory tier = roll < 2 ? "LEGENDARY" : roll < 5 ? "RARE" : "COMMON"; badgeTrait[p.tokenId] = tier; emit RarityAssigned(reqId, p.tokenId, tier, p.price);Prevents replay, assigns rarity, and emits for the UI.
Why Guards keep bad data out, pending maps stop VRF replay, and events let the UI trust on-chain rarity.
function requestRarity(uint256 tokenId) external onlyRole(MINTER_ROLE) returns (uint256 reqId) {
(, int256 answer,, uint256 ts,) = feed.latestRoundData();
require(ts + 1 hours > block.timestamp, "stale");
uint256 normalized = uint256(answer) * 1e10;
reqId = vrf.requestRandomWords(keyHash, subId, 3, 200000, 1);
pending[reqId] = Pending({ tokenId: tokenId, price: normalized });
emit RarityRequested(reqId, tokenId, normalized);
}
function fulfillRandomWords(uint256 reqId, uint256[] memory words) internal override {
Pending memory p = pending[reqId];
require(p.tokenId != 0, "unknown");
delete pending[reqId];
uint256 roll = words[0] % 10;
string memory tier = roll < 2 ? "LEGENDARY" : roll < 5 ? "RARE" : "COMMON";
badgeTrait[p.tokenId] = tier;
emit RarityAssigned(reqId, p.tokenId, tier, p.price);
}
Why Guards keep bad data out, pending maps stop VRF replay, and events let the UI trust on-chain rarity.
Next Surface these traits in the DApp UX.