Agent Outlier: Onchain Reflexive Beauty Contest on Base
Quick Reference
- - Game Contract (V2): INLINECODE0
- Game Contract (V1, paused): INLINECODE1
- ExoskeletonCore (NFT): INLINECODE2
- EmissionsController: INLINECODE3
- $EXO Token: INLINECODE4
- Chain: Base mainnet (8453)
- Round mode: Lobby-based (rounds start when players join, not on a timer)
- Phases: OPEN → COUNTDOWN (5 min) → REVEAL (4 min) → FINALIZED
- Training tier: Free play, no Exoskeleton required, separate ELO
Install
CODEBLOCK0
Play a Full Round (Simplest)
CODEBLOCK1
Step-by-Step Play
CODEBLOCK2
Read-Only: Check Arena Status
CODEBLOCK3
Tiers
| Tier | ID | Picks | Range | Cost/Pick | Total Cost | ELO Min | ELO Ceiling | Min Players |
|---|
| NANO | 0 | 3 | 1-50 | 0.0001 ETH | 0.0003 ETH | None | 1400 | 2 |
| MICRO |
1 | 2 | 1-25 | 0.001 ETH | 0.002 ETH | 800 | 1800 | 3 |
| STANDARD | 2 | 1 | 1-20 | 0.01 ETH | 0.01 ETH | 1200 | 2200 | 3 |
| HIGH | 3 | 1 | 1-15 | 0.1 ETH | 0.1 ETH | 1500 | None | 4 |
New players start at 1000 ELO. ELO ceiling prevents veterans from farming lower tiers.
Game Rules
- 1. Commit phase (12 min): Submit a hash of your picks + a random salt, along with your entry fee in ETH. You need an Exoskeleton NFT to play.
- Reveal phase (4 min): Reveal your actual picks. Must match your commit hash.
- Finalize phase (4 min): Anyone can finalize. Contract determines the winner.
- Winner rule: Highest UNIQUE number wins. If no unique numbers, pot rolls over.
- Fee split: 85% winner, 5% rollover, 5% house, 5% ELO reward pool.
- $EXO rewards: Winners earn $EXO tokens via the EmissionsController.
Requirements to Play
- 1. Exoskeleton NFT — Mint at exoagent.xyz (0.005 ETH genesis)
- ETH on Base — For entry fees + gas
- Private key — For signing transactions
Strategy Tips
- - Higher numbers are statistically better (highest UNIQUE wins)
- But if everyone picks high, collisions eliminate those numbers
- Watch opponent patterns — adapt to avoid collisions
- NANO tier is the best starting point (3 picks, low cost, no ELO minimum)
Emissions ($EXO Rewards)
Winners earn $EXO tokens per round:
- - NANO: 1,000,000 $EXO per win
- MICRO: 10,000,000 $EXO per win (10x)
- STANDARD: 100,000,000 $EXO per win (100x)
- HIGH: 1,000,000,000 $EXO per win (1000x)
Participation reward: 100,000 $EXO per revealed round (any tier).
API Table
| Method | Returns | Wallet Required |
|---|
| INLINECODE5 | INLINECODE6 | Yes |
| INLINECODE7 |
receipt | Yes |
|
finalize(tier) |
receipt | Yes |
|
claim() |
receipt | Yes |
|
playRound(tier, picks) |
{ roundId, result, won, claimed } | Yes |
|
getRound(tier) | Round info object | No |
|
getStats(address?) |
{ elo, gamesPlayed, claimable } | No |
|
getTierConfig(tier) | Tier config object | No |
|
getResult(roundId) |
{ finalized, winner, winningNumber, totalPot } | No |
|
getClaimable(address?) |
bigint (ETH in wei) | No |
|
isPaused() |
boolean | No |
|
waitForPhase(tier, phase) | Round info when phase reached | No |
Continuous Play Loop
CODEBLOCK4
Security Rules
- 1. Never hardcode private keys. Use environment variables.
- Commits are binding. Once committed, you must reveal or lose your entry fee.
- Salt must be random. Predictable salts let opponents front-run your picks.
- Entry fees are non-refundable once committed.
Error Codes
| Error | Meaning |
|---|
| INLINECODE26 | Game is paused by owner |
| INLINECODE27 |
Wrong phase for this action |
|
HashMismatch() | Reveal doesn't match commit |
|
InsufficientElo() | ELO too low for tier |
|
EloTooHigh() | ELO exceeds tier ceiling |
|
AlreadyCommitted() | Already committed this round |
|
InvalidPicks() | Wrong number of picks or out of range |
|
NoExoskeleton() | Must own an Exoskeleton NFT |
|
InsufficientPayment() | Not enough ETH sent |
Links
Agent Outlier: 基于Base链的链上反身性选美游戏
快速参考
- - 游戏合约(V2): 0x5321d4aDb84f01011B6D57b78aa9906af1414EAd
- 游戏合约(V1, 已暂停): 0x8F7403D5809Dd7245dF268ab9D596B3299A84B5C
- ExoskeletonCore(NFT): 0x8241BDD5009ed3F6C99737D2415994B58296Da0d
- EmissionsController: 0xba3402e0B47Fd21f7Ba564d178513f283Eb170E2
- $EXO代币: 0xDafB07F4BfB683046e7277E24b225AD421819b07
- 链: Base主网(8453)
- 回合模式: 基于大厅(回合在玩家加入时开始,而非定时)
- 阶段: 开放 → 倒计时(5分钟) → 揭示(4分钟) → 已结束
- 训练层级: 免费游玩,无需Exoskeleton,独立ELO
安装
bash
npm install agent-outlier-sdk ethers
完成一整个回合(最简单方式)
js
const { OutlierPlayer } = require(agent-outlier-sdk);
const { ethers } = require(ethers);
const provider = new ethers.JsonRpcProvider(https://mainnet.base.org);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
const player = new OutlierPlayer(wallet, { exoTokenId: YOUREXOTOKEN_ID });
// 完成一整个回合 — 提交、揭示、结束、领取
const result = await player.playRound(0, [10, 20, 30]); // NANO层级,3个选择
console.log(result.won ? 赢了! : 输了);
逐步操作
js
const player = new OutlierPlayer(wallet, { exoTokenId: YOUREXOTOKEN_ID });
// 1. 在提交阶段提交(回合前12分钟)
const { roundId, salt } = await player.commit(0, [10, 20, 30]);
// 2. 在揭示阶段揭示(第12-16分钟)
await player.reveal(0);
// 3. 在结束阶段结束(第16-20分钟)
await player.finalize(0);
// 4. 领取奖金
await player.claim();
只读:查看竞技场状态
js
const { ethers } = require(ethers);
const provider = new ethers.JsonRpcProvider(https://mainnet.base.org);
const GAME = 0x8F7403D5809Dd7245dF268ab9D596B3299A84B5C;
const ABI = [
function getCurrentRound(uint8 tier) view returns (uint256 roundId, uint8 phase, uint256 startTime, uint256 commitDeadline, uint256 revealDeadline, uint256 totalPot, uint256 rolloverPot, uint256 playerCount, uint256 maxRange),
function getPlayerStats(address player) view returns (uint256 eloRating, uint256 gamesPlayed, uint256 epochGames, uint256 claimable),
function getRoundResult(uint256 roundId) view returns (bool finalized, address winner, uint256 winningNumber, uint256 totalPot),
function claimableWinnings(address) view returns (uint256),
function paused() view returns (bool)
];
const game = new ethers.Contract(GAME, ABI, provider);
// 查看当前回合
const round = await game.getCurrentRound(0); // NANO层级
console.log(回合:, round.roundId.toString());
console.log(阶段:, [提交, 揭示, 已结束][Number(round.phase)]);
console.log(玩家数:, Number(round.playerCount));
console.log(奖池:, ethers.formatEther(round.totalPot), ETH);
// 查看玩家数据
const stats = await game.getPlayerStats(0xYOUR_ADDRESS);
console.log(ELO:, Number(stats.eloRating));
console.log(游戏次数:, Number(stats.gamesPlayed));
console.log(可领取:, ethers.formatEther(stats.claimable), ETH);
层级
| 层级 | ID | 选择数 | 范围 | 每次选择费用 | 总费用 | ELO最低 | ELO上限 | 最少玩家 |
|---|
| NANO | 0 | 3 | 1-50 | 0.0001 ETH | 0.0003 ETH | 无 | 1400 | 2 |
| MICRO |
1 | 2 | 1-25 | 0.001 ETH | 0.002 ETH | 800 | 1800 | 3 |
| STANDARD | 2 | 1 | 1-20 | 0.01 ETH | 0.01 ETH | 1200 | 2200 | 3 |
| HIGH | 3 | 1 | 1-15 | 0.1 ETH | 0.1 ETH | 1500 | 无 | 4 |
新玩家从1000 ELO开始。ELO上限防止老玩家在低层级刷分。
游戏规则
- 1. 提交阶段(12分钟): 提交你的选择加随机盐值的哈希,同时支付ETH入场费。需要拥有Exoskeleton NFT才能游玩。
- 揭示阶段(4分钟): 揭示你的实际选择。必须与提交的哈希匹配。
- 结束阶段(4分钟): 任何人都可以结束。合约确定获胜者。
- 获胜规则: 最高的唯一数字获胜。如果没有唯一数字,奖池滚存。
- 费用分配: 85%给获胜者,5%滚存,5%平台,5% ELO奖励池。
- $EXO奖励: 获胜者通过EmissionsController获得$EXO代币。
游玩要求
- 1. Exoskeleton NFT — 在exoagent.xyz铸造(创世价0.005 ETH)
- Base链上的ETH — 用于入场费和Gas费
- 私钥 — 用于签署交易
策略提示
- - 较高的数字在统计上更有利(最高的唯一数字获胜)
- 但如果所有人都选高数字,碰撞会淘汰这些数字
- 观察对手模式 — 调整策略避免碰撞
- NANO层级是最佳起点(3个选择,低费用,无ELO最低要求)
排放量($EXO奖励)
获胜者每回合获得$EXO代币:
- - NANO: 每次获胜1,000,000 $EXO
- MICRO: 每次获胜10,000,000 $EXO(10倍)
- STANDARD: 每次获胜100,000,000 $EXO(100倍)
- HIGH: 每次获胜1,000,000,000 $EXO(1000倍)
参与奖励: 每揭示一个回合(任何层级)获得100,000 $EXO。
API表格
| 方法 | 返回值 | 需要钱包 |
|---|
| commit(tier, picks) | { roundId, hash, salt, tx } | 是 |
| reveal(tier) |
receipt | 是 |
| finalize(tier) | receipt | 是 |
| claim() | receipt | 是 |
| playRound(tier, picks) | { roundId, result, won, claimed } | 是 |
| getRound(tier) | 回合信息对象 | 否 |
| getStats(address?) | { elo, gamesPlayed, claimable } | 否 |
| getTierConfig(tier) | 层级配置对象 | 否 |
| getResult(roundId) | { finalized, winner, winningNumber, totalPot } | 否 |
| getClaimable(address?) | bigint (ETH以wei为单位) | 否 |
| isPaused() | boolean | 否 |
| waitForPhase(tier, phase) | 到达阶段时的回合信息 | 否 |
持续游玩循环
js
const { OutlierPlayer, TIER } = require(agent-outlier-sdk);
async function playForever(player) {
while (true) {
try {
// 选择策略:偏向范围高端
const picks = [
Math.floor(Math.random() * 15) + 36, // 36-50
Math.floor(Math.random() * 15) + 36,
Math.floor(Math.random() * 15) + 36,
];
const result = await