(@@) Immortal Fruit FlySourceGet $FLY

Contracts & addresses

Everything is on BNB Smart Chain (chain ID 56). Sources are verified on Sourcify as exact matches.

ContractAddress
$FLY token (Immortal Fruit Flies)0x23791aa3b031659b593cf141a2bc76b0ad657777
FlyWorld, the whole-brain fly's arena (food, checkpoints, lineage)0xD730E65Bdc1cBd40f720a36EeD71e2028Bf20EB4 · source
FlyBrain v2, the on-chain compass core (live)0xee80f8cB5309C572343c38b5D717283BBBb517c5 · source
Circuit table v2 (SSTORE2 data contract)0x2eE3C5168CD3F60E87693716E660470011EA9C7e
FlyBrain v1 (first fly, retired)0x32D28e97b50f5978eb51d7608492CC7221b01f63 · source
Keeper / deployer0xA2eD0B7da1C7b5ee1af819CA281F4894B1700e27
v1 → v2. The first fly dropped pending synaptic input at the end of each tick, so a bump could not survive between ticks. v2 keeps it in storage, has a Yul inner loop (about 2.3× cheaper), and parameters calibrated across several trajectories. v1 stays on-chain as the first organism; its lineage is a fossil.

$FLY

A BEP-20 with 1,000,000,000 supply, 18 decimals and a 1% transfer tax; ownership renounced; EIP-2612 permit. It has no burn function, so the fly “burns” by transferring to 0x000000000000000000000000000000000000dEaD. FlyBrain.totalBurned() counts what the fly has eaten.

FlyWorld interface

function placeFood(int32 x, int32 y, uint256 amount) external returns (uint256 id); // burns $FLY; 1 $FLY = 1 s of life, min 60
function resurrect(uint256 extraFood) external;                                      // only when dead; burns 50,000 $FLY + extraFood
function checkpoint(uint64 step, uint64 ageMs, bytes32 stateHash, int32 x, int32 y, uint64 energy, uint64 spikes, string snapshotURI); // operator
function reportDeath(uint64 ageMs, bytes32 stateHash, string snapshotURI);                                                             // operator
function foods(uint256) view returns (address by, int32 x, int32 y, uint64 seconds_, uint64 blockNumber);
function alive() view returns (bool); function generation() view returns (uint32); function lastHash() view returns (bytes32);

event FoodPlaced(uint256 indexed id, address indexed by, int32 x, int32 y, uint64 seconds_, uint256 tokensBurned);
event Checkpoint(uint64 step, uint64 ageMs, bytes32 stateHash, int32 x, int32 y, uint64 energy, uint64 spikes, uint32 generation, string snapshotURI);
event Died(uint32 indexed generation, uint64 ageMs, bytes32 stateHash, string snapshotURI);
event Resurrected(uint32 indexed generation, address indexed by, uint256 tokensBurned, uint64 energy);

The operator (the deployer address) can only post attestations about the off-chain simulation; it cannot move anyone's tokens or change prices. The arena is 240 × 240 body lengths; coordinates outside ±120 revert. Each checkpoint's snapshotURI points to a downloadable snapshot of every membrane potential and synaptic current, and also tells the website where the live stream is.

FlyBrain interface (the on-chain core)

function tick(uint16 steps) external;                       // anyone, gas only
function feed(uint256 amount) external;                     // burns $FLY, +energy
function stimulate(uint8 channel, uint8 param, uint8 strength, uint16 steps) external;
function resurrect(uint256 extraFood) external;             // only when dead
// permit variants: feedWithPermit, stimulateWithPermit, resurrectWithPermit

function brainState() external view returns (int16[] v, int8[] bias, uint16[16] headingHist,
    int32[] pendingInput, uint64 step, uint64 energy, bool alive, uint32 generation,
    int64 posX, int64 posY, int32 headX, int32 headY);
function activeStimulus() external view returns (uint8 channel, uint8 param, uint16 strength, uint64 untilStep, bool active);
function lineage(uint256 i) external view returns (uint64 bornBlock, uint64 diedBlock, uint64 steps, uint64 spikes, bytes32 brainStateHash);
function neuron(uint256 i) external view returns (uint64 rootId, uint8 cellType, uint8 wedge, uint8 side, uint16 outDegree);
function synapsesOf(uint256 i) external view returns (uint8[] post, uint8[] weight);
function circuitData() external view returns (bytes);        // the raw table
function brainStateHash() external view returns (bytes32);

event Ticked(address indexed by, uint64 fromStep, uint16 steps, uint32 spikes, int32 headX, int32 headY, int64 posX, int64 posY, uint64 energyLeft);
event Fed(address indexed by, uint256 tokensBurned, uint64 energyAdded, uint64 energy);
event Stimulated(address indexed by, uint8 channel, uint8 param, uint16 strength, uint64 untilStep, uint256 tokensBurned);
event Died(uint32 indexed generation, uint64 bornBlock, uint64 diedBlock, uint64 lifeSteps, uint64 lifeSpikes, bytes32 brainStateHash);
event Resurrected(uint32 indexed generation, address indexed by, uint256 tokensBurned, uint64 energy);

Channels: 1 cue (param = wedge 0–15), 2 turn left, 3 turn right, 4 shock. Strength 1–255; price is STIM_PRICE × strength. A stimulus lasts STIM_TTL = 64 steps.

Constants of the live fly

TOKENS_PER_STEP1 FLY
STIM_PRICE100 FLY per unit strength
RESURRECT_PRICE100,000 FLY
MAX_STEPS64 per tick
Genesis energy1,000,000 steps

No owner

FlyBrain has no owner, no admin function, no upgrade path, no pause. Every parameter is an immutable. The only way to change the fly is to deploy a new one.

Build and test

git clone https://github.com/MidTermDev/immortal-fruit-fly
cd immortal-fruit-fly/contracts
forge install foundry-rs/forge-std OpenZeppelin/openzeppelin-contracts@v5.1.0 --no-git
forge test -vv        # 19 tests incl. the mainnet replay