Security
Audits
LiquidLottery has undergone two independent security audits by Hashlock.
Audit 1 — Initial Review
Findings summary:
High
1
Mitigated
Medium
3
Fixed
Low
3
Fixed / Acknowledged
Gas
1
Fixed
Key findings and resolutions:
[High] Centralized admin control — mitigated by adding 48-hour and 72-hour timelocks on all critical admin actions (router changes, upgrades, etc.), reducing the impact of a compromised admin key.
[Medium] VRF request ID collision — addressed by validating the round ID in
fulfillRandomWordsand trackingpendingRoundId.[Medium] Gas DoS in settlement — resolved by implementing batch settlement (
settleRoundBatch) so large rounds can be settled in chunks of configurable size.[Medium] Missing VRF coordinator validation — addressed with contract-existence checks on address setters.
[Low] Precision loss in prize distribution — dust from integer division carries over to the next round.
[Low] Deterministic RNG derivation — accepted; the VRF seed itself is unpredictable, and the derivation is deterministic by design.
[Low] Reentrancy in prize claiming — the contract uses OpenZeppelin
ReentrancyGuardand checks-effects-interactions where possible.
Full report: HASHLOCK_AUDIT.md
Audit 2 — Follow-Up Review
Findings summary:
Medium
2
Fixed / Acknowledged
Low
3
Fixed / Acknowledged
Gas
1
Fixed
Informational
1
Acknowledged
Key findings and resolutions:
[Medium]
tx.origininnoContractmodifier — acknowledged; the modifier exists to prevent contract-based griefing and is paired withmsg.senderchecks for access control.[Medium] Gas DoS in single settlement — already addressed with
settleRoundBatchin the first audit cycle.[Low] Open settlement functions — settlement is permissionless by design (anyone can call it), with a 1 % fee-pool reward incentivizing timely settlement.
[Low] Precision loss — same as Audit 1, with dust rollover to next round.
[Low] Timestamp dependence — acknowledged; miner manipulation is bounded to ~15 seconds and does not materially affect fairness.
Full report: HASHLOCK_AUDIT_2.md
Randomness — Chainlink VRF v2.5
Winning numbers are generated using Chainlink VRF (Verifiable Random Function) v2.5 on the Base network.
How It Works
The lottery contract on Hyperliquid sends a draw request via CCIP to
LotteryVRFRequesteron Base.LotteryVRFRequestercalls the Chainlink VRF Coordinator requesting 1 random word.Chainlink's decentralized oracle network generates the random word with a cryptographic proof.
The VRF Coordinator calls
fulfillRandomWords()onLotteryVRFRequester.The random word is sent back to Hyperliquid via CCIP.
The lottery contract deterministically derives all drawn numbers from the single random word.
Why This Matters
Tamper-proof — neither the contract owner, the miners, nor the VRF node operators can predict or influence the outcome.
Verifiable — anyone can verify the VRF proof on-chain and confirm the drawn numbers are correct.
Decentralized — Chainlink VRF is operated by a decentralized network of independent node operators.
Non-Custodial Design
The smart contract is fully non-custodial:
Prize pools are held in the contract, not in any external wallet.
No human can move prize funds — pools can only be distributed through the settlement logic.
Owner fees are accumulated separately and can only be withdrawn from the fee pool (
withdrawFees).Prizes never expire — players can claim at any time.
Pending payouts — if an ETH transfer fails, funds are escrowed in
pendingPayoutsand can be withdrawn by the player at any time.
Admin Safeguards
All sensitive admin operations are protected by timelocks:
Change CCIP router
48 hours
proposeSetCCIPRouter → executeSetCCIPRouter
Change VRF requester
48 hours
proposeSetVRFRequester → executeSetVRFRequester
Change source chain
48 hours
proposeSetSourceChainSelector → executeSetSourceChainSelector
Change upkeep interval
24 hours
proposeSetUpkeepInterval → executeSetUpkeepInterval
Upgrade contract
72 hours + 1 h window
proposeUpgrade → upgradeToAndCall
Any pending action can be cancelled by the owner with cancelAdminAction(hash).
During the upgrade execution window, ticket purchases are blocked to prevent state corruption.
Emergency Mechanisms
Admin Emergency Cancel
If a draw is stuck (CCIP message lost, VRF failure), the owner can cancel after a 5-minute grace period:
Public Emergency Cancel
If the owner is unresponsive, anyone can cancel a stuck draw after 24 hours:
This ensures the lottery can never be permanently stuck, even without owner intervention.
Access Control
Owner (admin)
Deployer
Admin functions, fee withdrawal, emergency cancel
CCIP Router
Chainlink
Deliver cross-chain messages to ccipReceive
VRF Requester
LotteryVRFRequester on Base
Send draw results back via CCIP
Players
Any EOA
Buy tickets, claim prizes, trigger public draw, trigger settlement
The noContract modifier on buyTickets requires tx.origin == msg.sender, preventing contracts from purchasing tickets directly.
Additional Protections
ReentrancyGuard — all state-changing functions that transfer ETH are protected.
ERC-165
supportsInterface— bothHyperLotteryV1andLotteryVRFRequestercorrectly respond to CCIP interface queries.CCIP sender validation —
ccipReceiveverifies the source chain selector and sender address.Upgrade window purchase block —
buyTicketsreverts during the 1-hour upgrade execution window.Contract-existence checks — all address setters verify the target has deployed bytecode.
Last updated
Was this helpful?