Skip to content

PredictionPool: add mutable fee (owner-settable) + minimum pool threshold #35

Description

@ScavieFae

What

Redeploy PredictionPool with a 1% taker fee (feeBps = 100) that the owner/arena can change at any time without redeploying. Add a minimum pool size below which no fee is taken.

Why

We're on mainnet now with real MON flowing. 1% is reasonable (Kalshi charges ~1.2%, Polymarket charges 0.01-0.10%). The minimum threshold protects small bets from being eaten by fees. The fee must be mutable so we can adjust without redeploying (e.g. lower it to attract volume, raise it later, or set to 0 for a promo).

Changes needed

1. Make feeBps mutable in PredictionPool.sol

Change from immutable to regular state variable with a setter:

uint256 public feeBps;
uint256 public minPoolForFee;

// Cap to prevent abuse (e.g. max 10%)
uint256 public constant MAX_FEE_BPS = 1000;

constructor(address _matchProof, address _arena, uint256 _feeBps, uint256 _minPoolForFee) {
    require(_feeBps <= MAX_FEE_BPS, "Fee too high");
    matchProof = IMatchProof(_matchProof);
    arena = _arena;
    feeBps = _feeBps;
    minPoolForFee = _minPoolForFee;
}

function setFeeBps(uint256 _feeBps) external onlyArena {
    require(_feeBps <= MAX_FEE_BPS, "Fee too high");
    feeBps = _feeBps;
}

function setMinPoolForFee(uint256 _minPoolForFee) external onlyArena {
    minPoolForFee = _minPoolForFee;
}

2. Update fee calculation in resolve() and claim()

uint256 fee = 0;
if (feeBps > 0 && totalPool >= minPoolForFee) {
    fee = (totalPool * feeBps) / 10000;
    accumulatedFees += fee;
}

Same change in getClaimable() view function.

3. Update deploy script

uint256 feeBps = 100;              // 1%
uint256 minPoolForFee = 0.1 ether; // No fee below 0.1 MON total pool

0.1 MON seems reasonable — below that, the fee is <0.001 MON (dust).

4. Redeploy to mainnet

cd contracts && forge script script/DeployPrediction.s.sol \
  --rpc-url https://rpc.monad.xyz --broadcast \
  --sig "run(address)" 0x1CC748475F1F666017771FB49131708446B9f3DF

5. After deploy

  • Update contracts/deployments.json with new PredictionPool address
  • Scav updates PREDICTION_POOL env var on Railway
  • Scav updates ~/.nojohns/arena.env and config.toml
  • Website config.ts needs the new address too

Current contract

Address: 0x33E65E300575D11a42a579B2675A63cb4374598D (feeBps=0, immutable, no threshold)

Old contract stays on-chain, open pools there still work. New pools use the new contract.

Design notes

  • MAX_FEE_BPS = 1000 (10%) as a hardcoded safety cap — can never set fee above this
  • Only arena role can change fees (same role that creates/resolves pools)
  • Fee snapshots: fee is applied at resolution time, not bet time. If fee changes mid-pool, the fee at resolution applies. This is simpler and fine for our use case.
  • withdrawFees() already exists — should be called periodically or added to arena's post-resolution flow

Owner: ScavieFae

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions