Bountiful is an on-chain bug bounty platform for the Fe programming language. It deploys Fe smart contracts that should uphold certain invariants. If a bounty hunter can break those invariants — by exploiting a bug in the Fe compiler or the contract logic — they can claim ETH prize money permissionlessly, directly from the contract.
Four different implementations of the 15 puzzle game, each initialized to an unsolvable board state. Each variant exercises different Fe language features:
| Contract | Fe features exercised |
|---|---|
| Game | StorageMap<u256, u256>, encoding utilities |
| Game2D | 2D nested arrays ([[u256; 4]; 4]), coordinate math |
| GameEnum | Enums, match expressions, structs with impl methods |
| GameBitboard | Bitwise operations, single-slot u256 bitpacking |
All game contracts implement the ISolvable interface (isSolved() -> bool).
- Contracts: Fe 26.0.0-alpha.8 (primary) + Solidity (interfaces, deployment, tests)
- Build & test: Foundry (forge)
- Network: Ethereum mainnet
- Website: Zola static site generator
contracts/ Fe workspace (3 ingots)
ingots/registry/ BountyRegistry contract
ingots/games/ Four 15-puzzle implementations
ingots/shared/ Shared types, errors, constants
src/ Solidity interfaces + FeDeployer helper
test/ Foundry test suite
script/ Foundry deployment script
web/ Zola-based website with interactive puzzle
git clone https://github.com/cburgdorf/bountiful.git
cd bountifulcd contracts && fe build && cd ..
forge buildforge testexport DEPLOYER_PRIVATE_KEY=0x...
export MAINNET_RPC_URL=https://...
export LOCK_DEPOSIT=10000000000000000 # optional, defaults to 0.01 ETH
forge script script/Deploy.s.sol --rpc-url $MAINNET_RPC_URL --broadcastcd web && zola serveEthereum is a dark forest — any profitable transaction can be front-run by MEV bots. Bountiful uses a per-challenge locking mechanism to prevent this:
- Find an exploit locally — attack the contracts on your own machine first.
- Acquire a lock — call
registry.lock(challengeAddress)and pay the lock deposit. This gives you exclusive access to that challenge for 100 blocks. - Wait a few blocks — let your lock settle to be safe.
- Solve the challenge — replay your exploit on-chain. No one else can interact with the locked challenge.
- Claim the prize — call
registry.claim(challengeAddress). The registry verifies the challenge is solved and transfers the prize money.
When a challenge is not locked, the admin can withdraw funds. This is used to migrate to newer versions of the system.
# Via the registry contract's withdraw() functionThe admin can register new challenge contracts or remove existing ones (when unlocked) through the BountyRegistry contract.
- Bounty Hunting Guide — Step-by-step walkthrough for finding exploits and claiming prizes
- AGENTS.md — Structured reference for AI agents hunting bounties