Skip to main content

Security

The Reborn contracts are Solidity 0.8.24 with via_ir, native overflow checks, and OpenZeppelin 5.x. The original Fantums was Solidity 0.6.2 with manual SafeMath. The list below is the audit-grade diff.

Risks closed vs the original

Risk in originalClosed in Reborn
No reentrancy guard on mintFantum (sends FTM → calls Sushi for buyback → then mutates state)Every payable function uses nonReentrant
Approve-then-transferFrom self-pattern in withdrawOtherToken (weird semantics, breaks on tokens that block self-approval)SafeERC20.safeTransfer used directly
Hardcoded burn address 0xf000000000000000000000000000000000000000 (non-standard)0x000000000000000000000000000000000000dEaD for visible burns
No pause mechanism for emergenciesEvery Reborn contract inherits Pausable
Mutable _owners array of addresses with no time-lockOwnable with TokenTimelock for the team's sFUM allocation
No EIP-2981 royalty standardEIP-2981 from day 1
Centralised metadata APIOn-chain SVG renderer — see On-chain rendering
Client-side PoW mint puzzleDeterministic shuffle with public seed commitment

OpenZeppelin 5.x stack

LibraryUsage
PausableEmergency pause on all stateful contracts
ReentrancyGuardEvery payable and external state-mutating function on Duel / MintDrop / Marketplace / Graveyard
SafeERC20All ERC-20 transfers
OwnableAdmin functions, with intent to migrate to a TokenTimelock and eventually a multisig
Base64On-chain SVG encoding
ERC721 + ERC721EnumerableCore NFT
EIP-2981Royalty standard

Hard caps everywhere

The original had unbounded price functions (priceOf could climb absurdly), unbounded name-change costs (2^count * 10 FTM becomes impossible after a few changes), and an unbounded _owners array.

Reborn's hard caps:

ContractCapValue
MintDropMAX_ETH_PRICE1 ether per mint
MintDropMAX_STABLE_PRICE$10,000 in USDC/USDT
MintDropMAX_AIRDROP_PER_MINT1,000 sFUM per mint
MintDropMAX_BATCH20 mints per transaction
DuelMAX_FIGHT_COST_SFUMS10,000 sFUM per fight
GraveyardPer-tier cost capOwner-tunable up to a hard ceiling per tier
MarketplacefeeBps ceilingOwner-tunable up to 10% (cannot exceed)
MarketplaceogFeeBps <= feeBpsInvariant enforced both ways

These caps mean the owner cannot tune values into a state that grief-traps the protocol.

Time-locked team allocation

The team's 20,000 sFUM allocation is timelocked in SFUMSTimelock.sol:

PropertyValue
Allocation20,000 sFUM (20% of total supply)
Cliff12 months
Linear vest after cliff24 months
Total lock period36 months from deployment
Early releaseNot possible. Period.

The timelock is a one-way deposit. Once the team's allocation is deposited, the only way out is the schedule.

EIP-712 signing for duel results

The duel keeper signs results with EIP-712 typed data:

struct DuelResult {
uint256 tokenA;
uint256 tokenB;
uint256 winnerId;
uint8 rounds;
bytes32 seed;
int32 newEloA;
int32 newEloB;
uint256 nonce;
uint64 expiry;
}

The on-chain contract:

  1. Recovers the signer via ECDSA.recover
  2. Checks the signer is the trusted keeper
  3. Re-runs the duel computation on-chain from seed + the two stat blocks
  4. Reverts if the computed winner doesn't match the signed winnerId
  5. Checks expiry > block.timestamp
  6. Checks the nonce hasn't been used

The keeper EOA can be replaced by the contract owner. It can later be replaced by a multisig, or eventually a fully on-chain matchmaking contract.

Supply chain audit

A full supply-chain audit of npm dependencies was performed on 2026-05-20 against the known compromises from April-May 2026:

CheckOutcome
npm audit on root0 vulnerabilities
42 compromised @tanstack/* names (May 11 attack)0 present
node-ipc (May 14 attack)0 present
14 compromised @antv/* + adjacent names (May 19 wave)0 present
Shai-Hulud worm IOCs (strings, binaries, exfil patterns)0 present
Suspicious install scripts in node_modules0 found

Full audit report lives in docs/SECURITY-AUDIT-2026-05-20.md. Verdict: clean.

Ongoing security posture

PracticeStatus
Direct deps pinned to exact versions (no ^)Planned for pre-mainnet
npm provenance verification on installPlanned
GitHub Actions: pull_request only, never pull_request_target with fork checkoutPlanned (no CI exists yet)
External smart-contract auditPlanned pre-mainnet
Bug bounty programPlanned post-launch

What we do NOT defend against

Be honest about scope:

  • Sonic chain-level failures. If Sonic mainnet itself has a consensus bug or a hostile validator majority, our contracts cannot defend against that. This is true of every dApp.
  • Founder wallet compromise. If the founder wallet's seed is leaked, the attacker can call pause(). They cannot mint more sFUM (fixed supply), cannot release timelocked tokens (timelock contract), cannot break the mint cap (hard cap). The blast radius is "the protocol gets paused" and "the dev's 1-of-1 Monarch moves".
  • External marketplace exploits. If a third-party marketplace listing our tokens has a bug, that's their bug. Our marketplace contract is audit-targeted.
  • Frontend phishing. A clone of our frontend can capture user signatures. Always verify the URL.

See also


Last updated: 2026-05-21