# FBX Protocol — Full technical documentation > Every FBX Protocol contract on Polygon PoS (chain id 137): what it does, its address, and the functions the app calls against it. This mirrors the human docs at https://firebot.gg/docs. For a short overview see https://firebot.gg/llms.txt; for live metrics see https://firebot.gg/api (JSON). The protocol is a small set of immutable contracts — no upgrade proxy, no admin path to mint FBX. Contracts fall into two groups: tokens (the ERC-20s users hold) and vaults & venues (the yield-bearing destinations). ## Tokens | Symbol | Name | Decimals | Address | | --- | --- | --- | --- | | FBX | FireBot Token | 18 | `0xd125443f38a69d776177c2b9c041f462936f8218` | | EP | Elemental Particles | 18 | `0x60ed6acef3a96f8cdaf0c0d207bbafa66e751af2` | | USDT | Tether USD | 6 | `0xc2132d05d31c914a87c6611c10748aeb04b58e8f` | | DCI | Dynamic Composite Index | 18 | `0xc91953E110EbB0039859304A0d1b64f8450763fC` | | WSTETH | Wrapped Staked ETH | 18 | `0x03b54a6e9a984069379fae1a4fc4dbae93b3bccd` | | WETH | Wrapped Ether | 18 | `0x7ceb23fd6bc0add59e62ac25578270cff1b9f619` | | WBTC | Wrapped Bitcoin | 8 | `0x1bfd67037b42cf73acf2047067bd4f2c47d9bfd6` | | WMATIC | Wrapped Matic / POL | 18 | `0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270` | POL (the native gas token) has no ERC-20 address — balances are read via `eth_getBalance`. ## Vaults & venues ### FireVaultFBXV2 — Auto-FBX vault · fireFBX receipt - Address: `0x960d43BE128585Ca45365CD74a7773B9d814dfBE` Auto-compounding FBX vault. Users deposit FBX and receive fireFBX shares; the vault claims and reinvests rewards on every interaction. The share price (FBX per fireFBX) only moves up. | Function | Type | Signature | Purpose | | --- | --- | --- | --- | | deposit | write | `deposit(uint256 amountFBX) returns (uint256 amountFireFBX)` | Deposit FBX, mint fireFBX shares pro-rata against the current rate. | | withdraw | write | `withdraw(uint256 amountFireFBX) returns (uint256 amountFBX)` | Burn fireFBX shares, return the underlying FBX at the current rate. | | claimRewardsAndBalance | write | `claimRewardsAndBalance()` | Force a compound — anyone can call to refresh the share price. | | withdrawalRate | read | `withdrawalRate() returns (uint256)` | Current FBX-per-share rate, scaled by 1e18. Used to convert shares ↔ FBX. | | totalFBXBalance | read | `totalFBXBalance() returns (uint256)` | Total FBX under management — vault TVL in token units. | > Note: The contract itself is the fireFBX ERC-20: balanceOf(user) returns share balance. ### FireVaultEP — Auto-EP vault · fireEP receipt - Address: `0xA2b205F8C0F0E30b3f73B7716a718C53cB8E5cC3` Auto-compounding EP vault. Same shape as Auto-FBX, but the reward path mints new EP from the EP-staking emissions and reinvests it. | Function | Type | Signature | Purpose | | --- | --- | --- | --- | | deposit | write | `deposit(uint256 amountEP) returns (uint256 amountFireEP)` | Deposit EP, mint fireEP shares at the current rate. | | withdraw | write | `withdraw(uint256 amountFireEP) returns (uint256 amountEP)` | Burn fireEP shares, return the underlying EP. | | claimAndMint | write | `claimAndMint()` | Force a compound — claims pending FBX, mints EP from it, restakes. | | withdrawalRate | read | `withdrawalRate() returns (uint256)` | EP-per-share rate, scaled by 1e18. | | getReserveEP / getReserveFBX | read | `getReserveEP() returns (uint256), getReserveFBX() returns (uint256)` | Vault-side accounting of EP staked and FBX held pre-mint. | ### FirePool — EP+FBX Fire Pool · also the swap router - Address: `0xE20E046B230a5530438d32ABfBCC3E61d7670234` Auto-compounding LP for the EP/FBX pair. The same contract is the protocol AMM — `swapExactEPForFBX` and `swapExactFBXForEP` use the pool reserves with a constant-product quote. | Function | Type | Signature | Purpose | | --- | --- | --- | --- | | addLiquidity | write | `addLiquidity(uint256 amountInEP, uint256 amountInFBX, uint256 minFPT, uint256 deadline)` | Deposit a paired EP + FBX amount, receive FPT LP tokens. minFPT is your slippage floor. | | removeLiquidity | write | `removeLiquidity(uint256 amountInFPT, uint256 minEP, uint256 minFBX, uint256 deadline)` | Burn FPT, withdraw your EP + FBX share of the reserves. | | swapExactEPForFBX | write | `swapExactEPForFBX(uint256 amountInEP, uint256 minAmountOutFBX, uint256 deadline)` | Trade EP for FBX along the pool curve. Reverts if output < minAmountOutFBX. | | swapExactFBXForEP | write | `swapExactFBXForEP(uint256 amountInFBX, uint256 minAmountOutEP, uint256 deadline)` | Trade FBX for EP along the pool curve. Reverts if output < minAmountOutEP. | | claimRewards | write | `claimRewards()` | Force a compound on the LP rewards. | | reserveEP / reserveFBX | read | `reserveEP() returns (uint256), reserveFBX() returns (uint256)` | The pool's tracked EP and FBX reserves — used to quote swaps off-chain. | | poolRate | read | `poolRate() returns (uint256)` | EP-per-FBX (or inverse, depending on orientation), scaled by 1e18. | ### FUSDv2 — USDT → DCI vault · FUSD receipt - Address: `0x3c56f017D9cE85350dF8f4B495033AAA15563A99` Points-based stable-coin vault. Users mint FUSD against USDT 1:1; the contract accrues points over time per FUSD. DCI rewards are distributed pro-rata against totalPoints(). | Function | Type | Signature | Purpose | | --- | --- | --- | --- | | mint | write | `mint(uint256 amountUSDT)` | Deposit USDT, receive an equal amount of FUSD. Starts accruing points immediately. | | redeem | write | `redeem(uint256 amountFUSD)` | Burn FUSD, withdraw the underlying USDT 1:1. | | claim | write | `claim(address account)` | Claim accrued DCI rewards for an account (any caller can trigger). | | claimCompoundRewards | write | `claimCompoundRewards(bool shouldAccrue)` | Bookkeeping helper used by the contract internals when accruing. | | points | read | `points(address account) returns (uint256)` | Accrued points for an account. Drives the DCI claim share. | | totalPoints | read | `totalPoints() returns (uint256)` | Denominator for the pro-rata DCI distribution. | ### ElementalParticles — EP token + EP→FBX staking - Address: `0x60Ed6aCEF3a96F8CDaF0c0D207BbAfA66e751af2` The EP ERC-20 with staking baked into the token contract. Stakers earn FBX from a daily emission set at the protocol level. Accrual caps at 30 days since the last claim — claim within that window to keep earning at the full rate. | Function | Type | Signature | Purpose | | --- | --- | --- | --- | | stakeEP | write | `stakeEP(uint256 amountEP)` | Stake EP from the caller. Reward accrual starts on the next emission tick. | | unstakeEP | write | `unstakeEP(uint256 amountEP)` | Withdraw staked EP. Pending FBX must be claimed separately. | | claimRewards | write | `claimRewards() returns (uint256)` | Sweep accrued FBX rewards to the caller. | | claimableRewards | read | `claimableRewards(address account) returns (uint256, uint256, uint256)` | Currently-claimable FBX for an account + bookkeeping fields. | | userInfos | read | `userInfos(address account) returns (uint256, uint256, uint256)` | Per-user state: tuple[0] = staked EP, then internal accumulators. | > Note: EP is the same token used as the staking surface — the EP balance returned by balanceOf is *unstaked* EP. ### Pyromancy — EP → EMBER + BTC omens - Address: `0xea459C173753dA4126e665530E6c82CCb7BF370A` A standalone game alongside the core vaults. Stake EP to gather $EMBER every second — a decaying emission that halves every two years — and reclaim your EP at any time (the EMBER you gathered is yours to keep). Offer EMBER on whether BTC will rise or fall over a window you choose; read it right and the flames return double. Blaze (redeem) EMBER back into a share of the FBX reserve along a 2× pro-rata curve. Forecasts resolve against the canonical Chainlink BTC/USD round, and the entry price locks to the first round after the cast, so a stale quote cannot be gamed. | Function | Type | Signature | Purpose | | --- | --- | --- | --- | | deposit | write | `deposit(uint256 amountEP)` | Stake EP on the altar; $EMBER starts gathering at the live emission rate. | | withdraw | write | `withdraw(uint256 amountEP)` | Reclaim staked EP at any time. Already-gathered EMBER stays in your balance. | | claim | write | `claim() returns (uint256)` | Realize gathered EMBER (plus the FireBots holder bonus) into your ERC-20 balance — required before it can be offered on a forecast or blazed. | | castForecast | write | `castForecast(uint256 amount, bool forecastRise, uint64 duration) returns (uint256 id)` | Offer EMBER on a BTC rise (true) or fall (false) over `duration` seconds. Blind cast: the entry price locks to the first Chainlink round after the tx. | | finalizeForecast | write | `finalizeForecast(uint256 forecastId, uint80 startRoundId, uint80 startPrevRoundId, uint80 resolveRoundId, uint80 resolvePrevRoundId, uint80 startNextGenesis, uint80 resolveNextGenesis)` | Settle a forecast using the canonical Chainlink rounds bracketing its open and resolve times; a correct call pays the winner 2× their offering. The two genesis args pin the phase across a Chainlink aggregator migration and are passed as 0 for current-phase forecasts. | | redeemEmber | write | `redeemEmber(uint256 amount, uint256 minFbxOut) returns (uint256)` | Blaze EMBER for FBX from the reserve along the 2× pro-rata curve (slips on size). minFbxOut is your slippage floor. | | emberRate | read | `emberRate() returns (uint256)` | Live emission as a WAD fraction of the original 1 EMBER/EP/sec (halves every 2 years). Multiply by an account’s deposited EP for its per-second accrual. | | deposited / totalDeposited | read | `deposited(address account) returns (uint256), totalDeposited() returns (uint256)` | EP staked by an account, and pool-wide. | | pendingEmber / pendingBlessing | read | `pendingEmber(address account) returns (uint256), pendingBlessing(address account) returns (uint256)` | Gathered-but-unclaimed EMBER, and the FireBots bonus a claim would add on top. | | pooledFBX | read | `pooledFBX() returns (uint256)` | FBX backing redemptions — the Pyromancy reserve. | | quoteRedeem | read | `quoteRedeem(uint256 amount) returns (uint256 fbxOut, uint256 toUser)` | Simulate a blaze: gross FBX off the curve and the 95% that reaches the redeemer. | | userStats | read | `userStats(address user) returns (uint256 earned, uint256 pendingEarn, uint256 spent, uint256 won, uint256 emberRedeemed, uint256 blessed, uint256 fbxRedeemed)` | Per-user lifetime totals in one call. Total EMBER claimed = earned + blessed. | | totalForecastSpent / totalForecastWon | read | `totalForecastSpent() returns (uint256), totalForecastWon() returns (uint256)` | Pool-wide EMBER offered into forecasts ("volume played"), and paid out to winners. | | getForecastsOf / forecasts | read | `getForecastsOf(address pyromancer) returns (uint256[]), forecasts(uint256 id) returns (address pyromancer, uint64 castTime, bool forecastRise, uint8 status, uint64 duration, uint256 amount)` | A pyromancer's forecast ids, and the struct for any forecast id. | > Note: The FireBots bonus is minted on every EMBER claim and saturates toward 25% as you hold more FireBots NFTs (blessingBpsOf). Forecast offerings are escrowed (not burned) and the escrow pot decays ~1/365 per day. A winning or draw forecast must be finalized to be paid: the payout is full for 7 days after the resolve deadline (CLAIM_GRACE), then erodes 1%/day to zero ~100 days later (PENALTY_RAMP) — so self-finalize promptly. EMBER is created in vast quantities and is cheap per token, so values are usually quoted per 1M EMBER. This is a standalone game — separate from the core deflationary FBX vaults — and forecasts are not no-loss. ### Firesight — EP → Mana · no-loss prediction pool over Polymarket - Address: `0xC0ff29645F2CF5BC055b47429522dBbb4C80b516` Be wrong, keep the money — a no-loss prediction market over Polymarket's binary conditions. Deposit EP and it stays yours and stays staked, win or lose. It earns Mana instead of yield: the FBX yield the deposit generates is what funds the prize pool, so a player's downside is the yield they forgo and nothing more. What you spend is Mana: a play budget that regenerates from your own deposit, cannot be transferred and cannot be cashed out, capped at 100,000 Mana per EP and refilling from empty in ~27.8 hours no matter how much you hold. Mana buys Yes/No shares on a linear curve that prices the two sides to exactly 1 — 1M Mana moves the price one percentage point at every price level, with no spread and no trading fee. Winning shares become Quarks, which redeem pro-rata against the ownerless EP reservoir at a floating rate. A market can only be opened over a condition Polymarket genuinely listed, proven on-chain against the adapter that prepared it — and only by a wallet the owner has whitelisted, which is the one part of this that is not permissionless. Listing used to be open to anyone and cost 20M Mana; both changed together. Markets opened at an anchor the contract chose (1/2, or 1/n inside a neg-risk event), so the walk from that anchor to the real price was free money, and the listing burn could not gate it because it was refunded 1:1 in Quarks. Creators now state the opening price instead, which removes the gap rather than pricing it — but nothing on-chain can tell a knowingly false price from an honest opinion, so who may list is answered off-chain by the whitelist and a public record of who opened what at what price. Trading, claiming, depositing and withdrawing are all still open to anyone, and the whitelist reaches no deposited EP. | Function | Type | Signature | Purpose | | --- | --- | --- | --- | | deposit | write | `deposit(uint256 amountEP, address referrer)` | Deposit EP and start generating Mana. The EP is staked inside the EP contract and stays withdrawable. The referrer slot is decided by your first self-paid deposit and ignored on every deposit after it. | | withdraw | write | `withdraw(uint256 amountEP)` | Take deposited EP back at any time — no lockup, no penalty. Only EP you have not delegated away is withdrawable (see withdrawableOf). | | delegate | write | `delegate(address to, uint256 amountEP)` | Lend Mana generation to another wallet without moving the EP, which stays yours and stays withdrawable once undelegated. Sets an ABSOLUTE amount rather than adding to one — read delegatedTo(from, to) first or a top-up silently replaces the existing delegation. | | createMarket | write | `createMarket(bytes32 questionId, address oracle, uint256 tokenId, uint256 openPrice) returns (uint256 marketId)` | Open a market over a Polymarket condition, at the probability of YES the creator states. Whitelisted wallets only — canCreate(msg.sender) must be true. It burns no Mana, mints no Quarks and carries no arb leg: a market listed where Polymarket already trades has no opening gap to walk, which is what the burn and the bundled arb existed to protect. openPrice must sit inside [P_MIN, P_MAX]; the contract cannot check it against Polymarket and does not try. | | setCreator | write | `setCreator(address account, bool allowed)` | Grant or revoke market-creation rights. Owner only, and instant in BOTH directions — deliberately unlike the oracle allowlist, which is monotonic and timelocked 48 hours. That one names Polymarket’s own adapters, where a removal would grief every creator; this one names people, and a delay on stopping an abusive creator would be a delay on stopping the abuse. It reaches no deposited EP either way. | | canCreate | read | `canCreate(address account) returns (bool)` | Whether a wallet may open markets. The owner is not implicitly a creator: createMarket checks canCreate[msg.sender] and nothing else, so an owner who never listed themselves cannot create either. There is no enumeration — replay CreatorSet logs for the list. | | multicall | write | `multicall(bytes[] data)` | Run several calls on this contract in one transaction. It delegatecalls the contract from itself, so msg.sender survives — which is why the whitelist can name the person rather than a periphery contract, and why every market is credited to its real creator. Its reason for existing is listing a whole neg-risk event: 49 runners, each at its own price, in one transaction rather than 49. The batch reverts as a unit, so a half-listed event cannot exist. | | buy | write | `buy(uint256 marketId, bool yes, uint256 manaIn, uint256 minSharesOut) returns (uint256 sharesOut)` | Spend Mana on the Yes (true) or No (false) side. minSharesOut is your slippage floor; quote it with quoteBuy, which calls the identical share function so a quote cannot diverge from the fill. | | claim | write | `claim(uint256[] marketIds, uint256 minEpOut) returns (uint256 quarksWon, uint256 epOut)` | The default settle action: finalize the listed markets, redeem exactly what they just won, and deposit the EP back in one call. A Quark balance built separately (via contribute) is deliberately left untouched. | | finalize / finalizeAll | write | `finalize(uint256 marketId) returns (uint256), finalizeAll(uint256[] marketIds) returns (uint256)` | Convert winning shares in a settled market into Quarks without redeeming them. Must happen inside the 45-day claim window (claimDeadline) — after that the winnings are forfeit to the reservoir. | | redeem | write | `redeem(uint256 quarks, uint256 minEpOut) returns (uint256 epOut)` | Burn Quarks for their pro-rata slice of the reservoir, less a 2% fee. Moves no EP: it converts an ownerless claim into an owned (deposited) one in bookkeeping. | | contribute | write | `contribute(uint256 epAmount, uint256 minQuarksOut) returns (uint256 quarksOut)` | Buy Quarks with EP at the live rate — take a position in the reservoir itself rather than in any single market. Rate-neutral for existing holders. | | donating | write | `EP.transfer(firesight, amount)` | There is no donate function — it was removed to reclaim bytecode. A plain EP transfer to the contract does the same thing: ownerlessEP is derived from the balance, so the pot grows the moment it lands, and harvest() sweeps it into staking. Raises redeemRate for every Quark holder. | | takeAuction / harvest | write | `takeAuction(uint256 amountEP, uint256 minFbxOut) returns (uint256), harvest() returns (uint256)` | The yield engine, both permissionless. harvest turns accrued FBX staking rewards into reservoir EP; takeAuction lets anyone buy the contract’s FBX with EP at a flat size (max 10 EP per take). Preview with auctionPreview. | | manaOf / maxManaOf | read | `manaOf(address user) returns (uint256), maxManaOf(address user) returns (uint256)` | Live Mana including unsettled accrual (already clamped to the cap), and the cap itself. maxManaOf / MANA_PER_EP is the per-second regeneration rate, which is what lets a client extrapolate the bar between reads. | | priceYes / quoteBuy | read | `priceYes(uint256 marketId) returns (uint256), quoteBuy(uint256 marketId, bool yes, uint256 manaIn) returns (uint256)` | Probability of YES in WAD — exact, with no overround, so NO is simply 1 − priceYes and the contract does not expose it. quoteBuy returns 0 for anything buy would reject. | | markets / nextMarketId | read | `markets(uint256 marketId) returns (bytes32 conditionId, bytes32 questionId, uint256 price, uint256 num0, uint256 num1, uint256 denom, uint64 resolutionTime, address oracle), nextMarketId() returns (uint256)` | The market struct and the id bound. denom > 0 means settled; a zero conditionId means the id was never issued — the seed field that used to be that sentinel is gone, because listing is free. price is the probability of YES in WAD. | | tradingStatus | read | `tradingStatus(uint256 marketId) returns (bool tradeable, bool resolved, bool pending)` | Why buy would refuse. resolved means the CTF has reported and the market is final; pending means the outcome is decided upstream but not yet written on-chain, which is temporary and permissionless to clear. | | sharesOf / quoteFinalize | read | `sharesOf(uint256 marketId, address user) returns (uint256 y, uint256 n), quoteFinalize(uint256 marketId, address user) returns (uint256)` | A wallet’s Yes/No shares in a market, and the Quarks finalizing it would credit right now. | | redeemRate / quoteRedeem | read | `redeemRate() returns (uint256), quoteRedeem(address user, uint256 quarks) returns (uint256 epOut, uint256 fee)` | EP per Quark in WAD (0 when the reservoir is empty — it never reverts), and what a redeem would actually credit net of both deductions. | | totalEP / ownerlessEP / totalDepositedEP | read | `totalEP() returns (uint256), ownerlessEP() returns (uint256), totalDepositedEP() returns (uint256)` | All EP the contract controls, the prize reservoir (totalEP − totalDepositedEP, derived and never stored), and the players’ withdrawable principal. | | withdrawableOf / manaWeight | read | `withdrawableOf(address user) returns (uint256), manaWeight(address user) returns (uint256)` | Deposited EP not currently delegated away (what withdraw accepts), and the generating weight: own EP, minus what is delegated out, plus what is delegated in. | > Note: Principal is never at risk: there is no liquidation, no margin, no lockup, and no path from a losing position to deposited EP. Losing costs only the yield forgone while the Mana was spent. Winnings must be finalized within 45 days of settlement or they are forfeit to the reservoir. Holding a FireBot adds 1% to Mana generation. No pause and no upgrade path, and no key can reach deposited EP — the one privileged action is that an owner may ADD (never remove) an address to the Polymarket resolver allowlists behind a 48-hour timelock, so that a Polymarket adapter rotation does not permanently brick market creation; renounceOwnership is one-way and ends that power for good. ### FireNFTMarket — FireBots floor market · instant buy/sell in FBX - Address: `0x93B8054F51b749ded58fBEae8b63539D49519DF2` An always-on market maker for the FireBots ERC-721 collection, priced entirely in FBX. The contract is both the bid and the ask, and both quotes are a fraction of its own FBX balance: buying takes 1.00% of the reserve, selling pays 0.99%. That 1 bp spread is the contract's edge — every round trip in either direction leaves it holding more FBX than before, so the floor ratchets up and cannot be arbitraged flat. The instant a bot is sold in, the bid drops to zero and grows back along 1 - 0.01^t (t in days, compounded per second): 90% of the floor after 12 hours, 99% after a day, exactly full after nine. That is the anti-dump valve — a queue of sellers cannot drain the reserve in one block, while a patient seller is quoted essentially the full floor. Buys are never throttled. Ownerless apart from stop(), which winds the market down and returns the reserve and any remaining bots to the deployer. | Function | Type | Signature | Purpose | | --- | --- | --- | --- | | buy | write | `buy(uint256 tokenId, uint256 maxCost) returns (uint256 cost)` | Buy one FireBot from inventory for 1% of the reserve. Requires an FBX approval; maxCost caps the price, which is quoted on the reserve before your payment lands. | | buyAny | write | `buyAny(uint256 maxCost) returns (uint256 tokenId, uint256 cost)` | Same as buy, but takes whichever bot is cheapest to dequeue — they all cost the same. | | sell | write | `sell(uint256 tokenId, uint256 minProceeds) returns (uint256 proceeds)` | Sell one FireBot at the live (decayed) bid and reset it to zero. Requires setApprovalForAll on the collection. minProceeds is your floor — passing 0 accepts any price, including free. | | stop | write | `stop(uint256 maxNFTs)` | Owner only, one-way. Halts both sides, sweeps all FBX to the owner, and withdraws up to maxNFTs bots. Re-callable to drain a large inventory in batches. | | buyPrice | read | `buyPrice() returns (uint256)` | What one bot costs right now — 1% of the reserve, rounded up. Never throttled. | | sellPrice | read | `sellPrice() returns (uint256)` | The live bid: fullSellPrice scaled by sellRecovery. Zero in the block of any sale. | | fullSellPrice | read | `fullSellPrice() returns (uint256)` | The bid ceiling with no decay applied — 0.99% of the reserve. | | sellRecovery | read | `sellRecovery() returns (uint256)` | Share of fullSellPrice currently on offer, in WAD. 0 right after a sale, 0.99e18 a day later, 1e18 once fully recovered. | | reserve | read | `reserve() returns (uint256)` | FBX held by the market. Both prices are a fraction of this, so funding it is a plain ERC-20 transfer in. | | inventory | read | `inventory() returns (uint256[])` | Every token id the market holds and will sell. Also inventoryCount() and isHeld(tokenId). | | lastSaleAt | read | `lastSaleAt() returns (uint256)` | Timestamp of the most recent sale in — the anchor the bid recovers from. | > Note: The market starts with no bots, so the first trade must be a sell. It implements no ERC721Receiver hook: a safeTransferFrom into it reverts, and a bot sent via raw transferFrom is unrecoverable by anyone, including the owner — always use sell(). The collection is FireBots at 0xE9eeE7294dc7c3bb64FD57A514E755022a333295 (10,000 tokens, ids 1-10000). ## Swap & liquidity There is no separate router — the FirePool contract is also the EP/FBX AMM, via `swapExactEPForFBX` and `swapExactFBXForEP`. Quotes are constant-product against `reserveEP()` / `reserveFBX()`. Minting EP burns FBX, so EP/FBX trades push the FBX supply down over time. Both swap functions take a `minAmountOut` slippage floor and a unix-seconds `deadline`; the transaction reverts if either condition fails at execution time. The pool fee is fixed in the contract (no fee-tier parameter). ## Price references Tokens with a Chainlink Data Feed on Polygon (ETH, BTC, MATIC/POL, wstETH) read `latestAnswer()`. FBX and DCI have no Chainlink feed, so they fall back to their Uniswap-V2 pair against USDT. EP has no direct USDT pair — it is priced through the Fire Pool FBX rate (`reserveFBX / reserveEP`) then through the FBX/USDT pair. ### Chainlink Data Feeds | Feed | Address | Notes | | --- | --- | --- | | ETH / USD | `0xF9680D99D6C9589e2a93a78A04A279e509205945` | Chainlink AggregatorV3. latestAnswer() returns ETH/USD scaled by 1e8. | | BTC / USD | `0xc907E116054Ad103354f2D350FD2514433D57F6f` | Chainlink AggregatorV3. latestAnswer() returns BTC/USD scaled by 1e8. | | MATIC / USD (POL) | `0xAB594600376Ec9fD91F8e885dADF0CE036862dE0` | Chainlink AggregatorV3. POL is the rebranded MATIC, same token — this feed prices both. | | wstETH / ETH | `0x10f964234cae09cB6a9854B56FF7D4F38Cda5E6a` | Chainlink ratio feed (1e18-scaled). Multiply by ETH/USD for the wstETH/USD price. | ### Uniswap-V2 fallback pools | Pool | Address | Notes | | --- | --- | --- | | FBX / USDT pool | `0x1000bb854fbc6d98dc9d859d6cb47e22a31eb8f9` | Uniswap-V2 pair. FBX has no Chainlink feed — spot price = reserves(USDT) / reserves(FBX), decimal-adjusted. | | DCI / USDT pool | `0xe7b7cf919e2798defc1f08133312cd151e5a5bed` | Uniswap-V2 pair. DCI has no Chainlink feed — same reserve-ratio formula gives DCI/USDT. | ## Contract ABIs Machine-readable ABIs (JSON) are published under `/abi/`. Start with the manifest at https://firebot.gg/abi/index.json — it maps every deployed address to its ABI file. Raw ABIs: https://firebot.gg/abi/.json (worldCupPool, firePool, epStaking, fbxVault, epVault, fusd, erc20, chainlinkFeed, univ2Pair). These cover the functions the app calls; token contracts also implement the full ERC-20 standard.