Beasts is a fully onchain NFT collection featuring 75 unique monster species that integrate with the Loot Survivor game ecosystem on Starknet. Each Beast is dynamically generated with unique attributes, names, and artworkโall stored and rendered directly from the blockchain.
The Beasts are a collection of digital-native creatures, born onchain and built for battle. Across 75 species, each Beast combines naming, visual, and combat attributes to balance abundance and scarcity. Beasts carry two sets of traits: visual and combat.
- Visual traits power collecting: Shiny and Animated forms activate pixel-perfect effects. Non-genesis Beasts receive live ranking within their species based on power and health, and those rankings update as new Beasts are minted.
- Combat traits power play: On mint, a Beast includes level and health. Together with its type and tier, this defines a combat profile compatible with the Loot Survivor system that first brought Beasts into the world.
- Live, credibly neutral traits such as Adventurers slain, last Adventurer who defeated a Beast, and timestamp of that defeat enable long-term growth systems without hardcoding game logic.
- Beasts are earned by worthy Adventurers in the dungeons of Loot Survivor using verifiable randomness. Every step is etched onchain for permanent provenance. For collectors, Beasts offer verifiable scarcity and provenance; for players, they unlock endless onchain fun.
- ๐จ Fully Onchain Artwork: Every Beastโs image data and metadata are generated onchain
- ๐ฎ Born Onchain: Beasts emerge from the dungeons of Loot Survivor
- โ๏ธ Battle-Ready: Each Beast is minted with level and health and is compatible with the Loot Survivor combat system
- ๐๏ธ 75 Unique Species: From mystical Warlocks to fierce Minotaurs, each with distinct visual traits
- ๐ Tiered Rarity System: 5 tiers with visual indicators through border colors and effects
- ๐ Deterministic Token IDs: A Beastโs ERC721 token ID is the packed representation of its species, name parts, combat stats, and visual flags
- Scarb 2.18.0
- Starknet Foundry 0.60.0
- Starkli for deployment
- Cairo Coverage and lcov for local coverage reports
Tool versions used by CI are pinned in .tool-versions.
- Clone the repository:
git clone https://github.com/Provable-Games/beasts.git
cd beasts- Build contracts:
scarb build- Run tests:
snforge testsrc/
โโโ lib.cairo # Entry point; exposes modules and ERC721 contract (beasts_nft)
โโโ beast_definitions.cairo # 75 species definitions and names
โโโ beast_manager.cairo # Validation and uniqueness hashing
โโโ minting_coordinator.cairo # Single and batch mint prep
โโโ beast_ranking.cairo # Per-species live ranking
โโโ pack.cairo # Attribute packing (id, name parts, level, health, shiny, animated)
โโโ metadata_generator.cairo # Onchain JSON metadata generation
โโโ beast_svg.cairo # Dynamic SVG artwork generation
โโโ beast_images.cairo # Shared image helpers
โโโ beast_png_*_data.cairo # PNG image data provider contracts
โโโ beast_gif_*_data.cairo # GIF image data provider contracts
โโโ encoding.cairo # Encoding helpers
โโโ utils.cairo # Shared utilities
โโโ interfaces.cairo # External interfaces (image data providers, systems)
Each Beast is efficiently packed into 53 bits. The packed value is also the ERC721 token_id:
PackableBeast {
id: u8, // 7 bits - species (1โ75)
prefix: u8, // 7 bits - name prefix
suffix: u8, // 5 bits - name suffix
level: u16, // 16 bits - level
health: u16, // 16 bits - health
shiny: u8, // 1 bit - visual trait
animated: u8, // 1 bit - visual trait
}Beasts do not use sequential token IDs. For fresh deployments, every token ID is deterministic:
token_id = encode_token_id(PackableBeast)
The bit layout is:
id
+ prefix * 2^7
+ suffix * 2^14
+ level * 2^19
+ health * 2^35
+ shiny * 2^51
+ animated * 2^52
This keeps every valid Beast token ID below 2^53, so it fits comfortably in u256. The same format is used for genesis and non-genesis Beasts.
Because the token ID is the source of the Beast attributes, contract reads such as get_beast(token_id), token_uri(token_id), and ranking comparisons decode the token ID after verifying ERC721 ownership/existence. There is no separate onchain map from token_id to PackableBeast.
Genesis Beasts are minted in the constructor to the owner with prefix = 0, suffix = 0, level = 1, health = 100, shiny = 1, and animated = 1. Genesis Beasts have rank 0 and are not entered into the non-genesis uniqueness map. Non-genesis Beast uniqueness is tracked by (beast_id, prefix, suffix), while ranking and metadata refresh state continue to index by packed token ID.
total_supply() is a count of minted NFTs, not the largest token ID.
- ๐ฎ Magical: Mystical creatures with arcane powers
- ๐น Hunter: Swift and agile predators
- โ๏ธ Brute: Raw strength and physical dominance
- Tier 1: Orange borders (Legendary) - Most powerful beasts
- Tier 2: Purple borders (Epic)
- Tier 3: Blue borders (Rare)
- Tier 4: Green borders (Uncommon)
- Tier 5: White borders (Common) - Entry level beasts
Run the test suite:
# Default local run
snforge test
# Match the CI test command
snforge test --max-n-steps 4294967295
# Generate local coverage
snforge test --coverage
# Summarize coverage locally
lcov --summary coverage/coverage.lcovFor a longer local pass, use snforge test --fuzzer-runs 500 --coverage. CI currently enforces formatting and tests, but not coverage thresholds; aim for >=80% overall coverage when feasible.
- Configure environment variables:
cp .env.example .env
# Edit .env with your configurationRequired in .env (no defaults are assumed):
STARKNET_ACCOUNT,STARKNET_PRIVATE_KEYRPC_URL(e.g., Sepolia or Mainnet endpoint)NAME,SYMBOLOWNER,ROYALTY_RECEIVER,ROYALTY_FRACTION(u128, denominator 10,000)TERMINAL_TIMESTAMP(u64): UNIX timestamp in seconds after whichtoken_uriis disabled and calls revert. Use0to keeptoken_uriactive indefinitely.
Optional in .env:
DEATH_MOUNTAIN_ADDRESS(ContractAddress, default0): external systems integration address; set to0to disable.
- Deploy to Starknet:
bash scripts/deploy.shNotes:
- The script declares and deploys the four image data provider contracts, then deploys the core NFT with their addresses passed to the constructor.
- The script fails with a descriptive error if any required
.envvalue is missing. - The deploy script reads
TERMINAL_TIMESTAMPandDEATH_MOUNTAIN_ADDRESSand appends them to the constructor. IfTERMINAL_TIMESTAMP > 0, after that time,token_uricalls revert withTerminal: token_uri disabled.
- Run formatter before committing:
scarb fmt
scarb fmt --check --workspaceThe project uses GitHub Actions for:
- Linting (
scarb fmt --check --workspace) - Contract tests (
snforge test --max-n-steps 4294967295) - Caching/installing coverage tools for local parity; coverage thresholds are not currently enforced in CI
- Beast pixels from the legends at 1337 Skulls