Game Logic
How Adrift uses onchain check-ins and randomness for a last-player-standing survival game.
Adrift is an onchain survival game where players must regularly check in to avoid disqualification. All game logic and randomness are enforced by smart contracts, with parameters like intervals, grace period, and outcome odds configurable by the admin. This ensures fairness, transparency, and an engaging experience. The last player remaining wins.
Players experience the game as follows:
- Register before the game starts.
- Check in regularly to stay in the game.
- Each check-in (handled by the Adrift and CheckInOutcomes contracts) has a random outcome: buff, debuff, or disqualification.
- Miss a check-in or get disqualified, and you’re out.
- The last player remaining wins.
Registration
- Before the game starts (before
gameStartTime
). - Players register by calling the
register
function in the Adrift contract. - The player's next check-in time is initialized.
- The player count increases.
- If the contract has enough balance, the player receives a registration gas reward (1 token by default), paid in the appchain's custom gas token. Custom gas tokens make subsidies simple and low cost.
- An event is emitted with registration details.
Game Start
- The game starts at a predefined
gameStartTime
(set by the admin). - No check-ins are allowed before this time.
Check-In
- During the game, players must call
checkIn
before theirnextCheckInTime
lapses. - The outcome of each check-in is determined by the CheckInOutcomes contract and can be a buff, debuff, or disqualification.
- If disqualified, the player is removed from the game.
- The next check-in time is updated based on the outcome.
- An event is emitted with the check-in result.
Disqualification
- If a player misses their check-in window, anyone can call
disqualifyInactivePlayer
in the Adrift contract to remove them. - Disqualification can also occur randomly during check-in.
- The player's status is updated to disqualified and they are excluded from the game.
- An event is emitted for disqualification.
We run a simple cron job that periodically calls a heartbeat endpoint to automatically disqualify inactive players and finalize the game when a single active player remains.
Outcomes & Randomness
Check-in outcomes are determined by the CheckInOutcomes
contract, which uses fresh sequencer-injected randomness via the Random
contract for every block. When a player checks in:
- The contract combines the latest random value, the player's address, and a nonce to generate a unique random number.
- There is a configurable chance (default: 2%) that the player is immediately disqualified.
- Otherwise, a random outcome (buff or debuff) is generated within a set range (default: 1–24), and its sign (positive/negative) is chosen randomly.
- The
Random
contract's value is set by the sequencer, ensuring unpredictability and auditability.
This system ensures that every check-in is unpredictable, fair, and verifiable onchain.
Winning & Game End
- The last remaining active player is declared the winner.
- If all players are disqualified, there is no winner.
- The game end time and winner are recorded and emitted as an event.