FloorGameV2

0x89d40f5e4d260577691d05e681d47519eb44f113

Verification
Verified
v0.8.34+commit.80d5c536
Type
Contract
15,019 bytes
ABI entries
104
39 read · 21 write
License
mit

Contract information

Address
0x89d40f5e4d260577691d05e681d47519eb44f113
Chain
Robinhood Chain (4663)
Compiler
v0.8.34+commit.80d5c536
Optimization
Enabled
Creation tx
0xcd6e6c08bf…bad01236f0

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (39)

EMISSIONS_POOL()uint256
EPOCH_LENGTH()uint256
INITIAL_RATE()uint256
MAX_TOTAL_BOOST_BPS()uint256
STARTER_FEE()uint256
accFloorPerAlpha()uint256
boostSource()address
currentEpoch()uint256
deskLevelCount()uint8
emissionRate()uint256
emissionsStart()uint64
emissionsStarted()bool
floorToken()address
getDesk(address)uint8, string, uint16, uint32, uint16, uint32, uint256, uint16
getDeskLevel(uint8)string, uint16, uint32, uint16, uint256
getOperatorType(uint8)string, uint8, uint32, uint32, uint256, bool
getSeatedOperators(address)uint256[]
globalAlphaPower()uint256
hasDesk(address)bool
lastRewardTime()uint256
maxSeededPending()uint256
migrationSealed()bool
nextHalvingTime()uint256
operatorNFT()address
operatorTypeCount()uint8
owner()address
paused()bool
pendingBoostBps(address)uint256
pendingPnL(address)uint256
referralEarned(address)uint256
referrerOf(address)address
seededPendingOf(address)uint256
seededPendingTotal()uint256
starterClaimed(address)bool
totalEmitted()uint256
totalFloorBurned()uint256
treasury()address
userAlphaPower(address)uint256
userBoostBps(address)uint256

Events (18)

BoostSourceSetBoostSyncedDeskCreatedDeskSeededDeskUpgradedEmissionsStartedFloorBurnedMigrationSealedOperatorRecruitedOperatorRemovedOperatorSeatedOwnershipTransferredPausedPnLCollectedReferralPaidStarterFeePaidTreasurySetUnpaused

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "floorToken_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "operatorNFT_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "treasury_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "v1Game_",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "maxSeededPending_",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "DeskAlreadyExists",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "EmissionsAlreadyStarted",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "EnforcedPause",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ExpectedPause",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InsufficientStarterFee",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidConfigId",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "LengthMismatch",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "MaxDeskLevel",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NoDesk",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NoSeatsAvailable",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NotEnoughBandwidth",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "NotSeatedByUser",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "NotTokenOwner",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "uint8",
        "name": "operatorType",
        "type": "uint8"
      }
    ],
    "name": "OperatorTypeDisabled",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      }
    ],
    "name": "OwnableInvalidOwner",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "OwnableUnauthorizedAccount",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ReentrancyGuardReentrantCall",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "SeedCapExceeded",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "SeedingClosed",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "SelfReferral",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "StarterAlreadyClaimed",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "StarterFeeTransferFailed",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "uint8",
        "name": "level",
        "type": "uint8"
      }
    ],
    "name": "UnknownDeskLevel",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "uint8",
        "name": "operatorType",
        "type": "uint8"
      }
    ],
    "name": "UnknownOperatorType",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ZeroAddress",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "source",
        "type": "address"
      }
    ],
    "name": "BoostSourceSet",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "user",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "effectiveAlpha",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "boostBps",
        "type": "uint256"
      }
    ],
    "name": "BoostSynced",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "user",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "referrer",
        "type": "address"
      }
    ],
    "name": "DeskCreated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "user",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint8",
        "name": "level",
        "type": "uint8"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "starterClaimed",
        "type": "bool"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "pending",
        "type": "uint256"
      }
    ],
    "name": "DeskSeeded",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "user",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint8",
        "name": "newLevel",
        "type": "uint8"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "cost",
        "type": "uint256"
      }
    ],
    "name": "DeskUpgraded",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint64",
        "name": "startTime",
        "type": "uint64"
      }
    ],
    "name": "EmissionsStarted",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "FloorBurned",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [],
    "name": "MigrationSealed",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "user",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint8",
        "name": "operatorType",
        "type": "uint8"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "costPaid",
        "type": "uint256"
      }
    ],
    "name": "OperatorRecruited",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "user",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "OperatorRemoved",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "user",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "OperatorSeated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "previousOwner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "OwnershipTransferred",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "Paused",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "user",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "PnLCollected",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "referrer",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "user",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "ReferralPaid",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "user",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "StarterFeePaid",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "treasury",
        "type": "address"
      }
    ],
    "name": "TreasurySet",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "Unpaused",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "EMISSIONS_POOL",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "EPOCH_LENGTH",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "INITIAL_RATE",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAX_TOTAL_BOOST_BPS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "STARTER_FEE",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "accFloorPerAlpha",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "boostSource",
    "outputs": [
      {
        "internalType": "contract IBoostSource",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "collectPnL",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "referrer",
        "type": "address"
      }
    ],
    "name": "createDesk",
    "outputs": [],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "currentEpoch",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "deskLevelCount",
    "outputs": [
      {
        "internalType": "uint8",
        "name": "",
        "type": "uint8"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "emissionRate",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "emissionsStart",
    "outputs": [
      {
        "internalType": "uint64",
        "name": "",
        "type": "uint64"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "emissionsStarted",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "floorToken",
    "outputs": [
      {
        "internalType": "contract IFloorToken",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "user",
        "type": "address"
      }
    ],
    "name": "getDesk",
    "outputs": [
      {
        "internalType": "uint8",
        "name": "level",
        "type": "uint8"
      },
      {
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "internalType": "uint16",
        "name": "seats",
        "type": "uint16"
      },
      {
        "internalType": "uint32",
        "name": "bandwidth",
        "type": "uint32"
      },
      {
        "internalType": "uint16",
        "name": "seatsUsed",
        "type": "uint16"
      },
      {
        "internalType": "uint32",
        "name": "bandwidthUsed",
        "type": "uint32"
      },
      {
        "internalType": "uint256",
        "name": "alphaPower",
        "type": "uint256"
      },
      {
        "internalType": "uint16",
        "name": "prestigeBps",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint8",
        "name": "level",
        "type": "uint8"
      }
    ],
    "name": "getDeskLevel",
    "outputs": [
      {
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "internalType": "uint16",
        "name": "seats",
        "type": "uint16"
      },
      {
        "internalType": "uint32",
        "name": "bandwidth",
        "type": "uint32"
      },
      {
        "internalType": "uint16",
        "name": "prestigeBps",
        "type": "uint16"
      },
      {
        "internalType": "uint256",
        "name": "upgradeCost",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint8",
        "name": "id",
        "type": "uint8"
      }
    ],
    "name": "getOperatorType",
    "outputs": [
      {
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "internalType": "uint8",
        "name": "rarity",
        "type": "uint8"
      },
      {
        "internalType": "uint32",
        "name": "alphaPower",
        "type": "uint32"
      },
      {
        "internalType": "uint32",
        "name": "bandwidthCost",
        "type": "uint32"
      },
      {
        "internalType": "uint256",
        "name": "costFloor",
        "type": "uint256"
      },
      {
        "internalType": "bool",
        "name": "enabled",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "user",
        "type": "address"
      }
    ],
    "name": "getSeatedOperators",
    "outputs": [
      {
        "internalType": "uint256[]",
        "name": "",
        "type": "uint256[]"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "globalAlphaPower",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "user",
        "type": "address"
      }
    ],
    "name": "hasDesk",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "lastRewardTime",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "maxSeededPending",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "migrationSealed",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "nextHalvingTime",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "operatorNFT",
    "outputs": [
      {
        "internalType": "contract IOperatorNFT",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "operatorTypeCount",
    "outputs": [
      {
        "internalType": "uint8",
        "name": "",
        "type": "uint8"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "pause",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "paused",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "user",
        "type": "address"
      }
    ],
    "name": "pendingBoostBps",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "user",
        "type": "address"
      }
    ],
    "name": "pendingPnL",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint8",
        "name": "operatorType",
        "type": "uint8"
      }
    ],
    "name": "recruitOperator",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "recruitStarter",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "referralEarned",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "referrerOf",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "renounceOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "sealMigration",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "seatOperator",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "user",
        "type": "address"
      },
      {
        "internalType": "uint8",
        "name": "level",
        "type": "uint8"
      },
      {
        "internalType": "bool",
        "name": "starterClaimed_",
        "type": "bool"
      },
      {
        "internalType": "uint256",
        "name": "pending",
        "type": "uint256"
      }
    ],
    "name": "seedDesk",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address[]",
        "name": "users",
        "type": "address[]"
      },
      {
        "internalType": "uint8[]",
        "name": "levels",
        "type": "uint8[]"
      },
      {
        "internalType": "bool[]",
        "name": "starterClaimeds",
        "type": "bool[]"
      },
      {
        "internalType": "uint256[]",
        "name": "pendings",
        "type": "uint256[]"
      }
    ],
    "name": "seedDeskBatch",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "seededPendingOf",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "seededPendingTotal",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "source",
        "type": "address"
      }
    ],
    "name": "setBoostSource",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint8",
        "name": "level",
        "type": "uint8"
      },
      {
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "internalType": "uint16",
        "name": "seats",
        "type": "uint16"
      },
      {
        "internalType": "uint32",
        "name": "bandwidth",
        "type": "uint32"
      },
      {
        "internalType": "uint16",
        "name": "prestigeBps",
        "type": "uint16"
      },
      {
        "internalType": "uint256",
        "name": "upgradeCost",
        "type": "uint256"
      }
    ],
    "name": "setDeskLevel",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint8",
        "name": "id",
        "type": "uint8"
      },
      {
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "internalType": "uint8",
        "name": "rarity",
        "type": "uint8"
      },
      {
        "internalType": "uint32",
        "name": "alphaPower",
        "type": "uint32"
      },
      {
        "internalType": "uint32",
        "name": "bandwidthCost",
        "type": "uint32"
      },
      {
        "internalType": "uint256",
        "name": "costFloor",
        "type": "uint256"
      },
      {
        "internalType": "bool",
        "name": "enabled",
        "type": "bool"
      }
    ],
    "name": "setOperatorType",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "t",
        "type": "address"
      }
    ],
    "name": "setTreasury",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "startEmissions",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "user",
        "type": "address"
      }
    ],
    "name": "starterClaimed",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "user",
        "type": "address"
      }
    ],
    "name": "syncBoost",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address[]",
        "name": "users",
        "type": "address[]"
      }
    ],
    "name": "syncBoostBatch",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalEmitted",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalFloorBurned",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "treasury",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "unpause",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "unseatOperator",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "upgradeDesk",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "user",
        "type": "address"
      }
    ],
    "name": "userAlphaPower",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "user",
        "type": "address"
      }
    ],
    "name": "userBoostBps",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  }
]

Source code

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

abstract contract Ownable is Context {
    address private _owner;

    error OwnableUnauthorizedAccount(address account);

    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    function owner() public view virtual returns (address) {
        return _owner;
    }

    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

abstract contract Pausable is Context {
    bool private _paused;

    event Paused(address account);

    event Unpaused(address account);

    error EnforcedPause();

    error ExpectedPause();

    constructor() {
        _paused = false;
    }

    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    modifier whenPaused() {
        _requirePaused();
        _;
    }

    function paused() public view virtual returns (bool) {
        return _paused;
    }

    function _requireNotPaused() internal view virtual {
        if (paused()) {
            revert EnforcedPause();
        }
    }

    function _requirePaused() internal view virtual {
        if (!paused()) {
            revert ExpectedPause();
        }
    }

    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

abstract contract ReentrancyGuard {

    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {

        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        _status = ENTERED;
    }

    function _nonReentrantAfter() private {

        _status = NOT_ENTERED;
    }

    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

interface IERC165 {

    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

interface IERC721 is IERC165 {

    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    function balanceOf(address owner) external view returns (uint256 balance);

    function ownerOf(uint256 tokenId) external view returns (address owner);

    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    function transferFrom(address from, address to, uint256 tokenId) external;

    function approve(address to, uint256 tokenId) external;

    function setApprovalForAll(address operator, bool approved) external;

    function getApproved(uint256 tokenId) external view returns (address operator);

    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

interface IBoostSource {

    function boostBps(address user) external view returns (uint256);
}

interface IFloorToken {
    function gameMint(address to, uint256 amount) external;
    function burn(uint256 value) external;
    function transfer(address to, uint256 value) external returns (bool);
    function transferFrom(address from, address to, uint256 value) external returns (bool);
    function cap() external view returns (uint256);
    function totalSupply() external view returns (uint256);
}

interface IOperatorNFT is IERC721 {
    function gameMint(address to, uint8 operatorType) external returns (uint256);
    function getOperator(uint256 tokenId) external view returns (uint8 operatorType, uint8 generation);
}

interface IFloorGameV1 {
    function emissionsStart() external view returns (uint64);
    function totalEmitted() external view returns (uint256);
}

contract FloorGameV2 is Ownable, Pausable, ReentrancyGuard {

    struct OperatorTypeConfig {
        string name;
        uint8 rarity;
        uint32 alphaPower;
        uint32 bandwidthCost;
        uint256 costFloor;
        bool enabled;
    }

    struct DeskLevelConfig {
        string name;
        uint16 seats;
        uint32 bandwidth;
        uint16 prestigeBps;
        uint256 upgradeCost;
    }

    struct Desk {
        bool exists;
        bool starterClaimed;
        uint8 level;
        uint16 seatsUsed;
        uint32 bandwidthUsed;
        uint256 rawAlpha;
        uint256 effectiveAlpha;
        uint256 rewardDebt;
        uint256 pendingStored;
        uint256 boostBps;
    }

    IFloorToken public immutable floorToken;
    IOperatorNFT public immutable operatorNFT;
    address public treasury;

    uint64 public emissionsStart;
    uint256 public totalEmitted;

    mapping(address => address) public referrerOf;
    mapping(address => uint256) public referralEarned;

    uint256 public totalFloorBurned;
    uint256 public globalAlphaPower;
    uint256 public accFloorPerAlpha;
    uint256 public lastRewardTime;

    uint8 public operatorTypeCount;
    uint8 public deskLevelCount;

    IBoostSource public boostSource;

    uint256 public constant MAX_TOTAL_BOOST_BPS = 5_000;

    bool public migrationSealed;

    uint256 public seededPendingTotal;
    uint256 public immutable maxSeededPending;

    mapping(address => uint256) public seededPendingOf;

    uint256 private constant ACC_PRECISION = 1e12;
    uint256 private constant BPS = 10_000;
    uint256 private constant BURN_PERCENT = 75;
    uint256 private constant REFERRAL_PERCENT = 5;

    uint256 public constant INITIAL_RATE = 3.2839e18;
    uint256 public constant EPOCH_LENGTH = 30 days;
    uint256 public constant EMISSIONS_POOL = 17_024_000e18;
    uint256 private constant MAX_EPOCHS = 62;
    uint256 public constant STARTER_FEE = 0.01 ether;

    mapping(uint8 => OperatorTypeConfig) private _operatorTypes;
    mapping(uint8 => DeskLevelConfig) private _deskLevels;
    mapping(address => Desk) private _desks;

    mapping(address => uint256[]) private _seated;
    mapping(uint256 => uint256) private _seatedIndex;
    mapping(uint256 => address) private _seatedBy;

    struct SeatedStats {
        uint32 alphaPower;
        uint32 bandwidthCost;
    }
    mapping(uint256 => SeatedStats) private _seatedStats;

    event DeskCreated(address indexed user, address indexed referrer);
    event StarterFeePaid(address indexed user, uint256 amount);
    event OperatorRecruited(address indexed user, uint256 indexed tokenId, uint8 operatorType, uint256 costPaid);
    event OperatorSeated(address indexed user, uint256 indexed tokenId);
    event OperatorRemoved(address indexed user, uint256 indexed tokenId);
    event PnLCollected(address indexed user, uint256 amount);
    event DeskUpgraded(address indexed user, uint8 newLevel, uint256 cost);
    event FloorBurned(uint256 amount);
    event ReferralPaid(address indexed referrer, address indexed user, uint256 amount);
    event EmissionsStarted(uint64 startTime);
    event TreasurySet(address indexed treasury);

    event BoostSourceSet(address indexed source);
    event BoostSynced(address indexed user, uint256 effectiveAlpha, uint256 boostBps);
    event DeskSeeded(address indexed user, uint8 level, bool starterClaimed, uint256 pending);
    event MigrationSealed();

    error DeskAlreadyExists();
    error NoDesk();
    error StarterAlreadyClaimed();
    error UnknownOperatorType(uint8 operatorType);
    error OperatorTypeDisabled(uint8 operatorType);
    error UnknownDeskLevel(uint8 level);
    error MaxDeskLevel();
    error NotTokenOwner(uint256 tokenId);
    error NotSeatedByUser(uint256 tokenId);
    error NoSeatsAvailable();
    error NotEnoughBandwidth();
    error ZeroAddress();
    error InvalidConfigId();
    error SelfReferral();
    error EmissionsAlreadyStarted();
    error InsufficientStarterFee();
    error StarterFeeTransferFailed();

    error SeedingClosed();
    error SeedCapExceeded();
    error LengthMismatch();

    constructor(
        address floorToken_,
        address operatorNFT_,
        address treasury_,
        address v1Game_,
        uint256 maxSeededPending_
    ) Ownable(msg.sender) {
        if (floorToken_ == address(0) || operatorNFT_ == address(0) || treasury_ == address(0)) {
            revert ZeroAddress();
        }
        floorToken = IFloorToken(floorToken_);
        operatorNFT = IOperatorNFT(operatorNFT_);
        treasury = treasury_;

        uint64 es = 0;
        uint256 te = 0;
        if (v1Game_ != address(0)) {
            es = IFloorGameV1(v1Game_).emissionsStart();
            te = IFloorGameV1(v1Game_).totalEmitted();
        }
        emissionsStart = es;
        totalEmitted = te;
        lastRewardTime = block.timestamp;
        maxSeededPending = maxSeededPending_;
        if (es != 0) emit EmissionsStarted(es);

        _seedOperatorType(0,  "Retail Analyst",    0, 10,   5,   25e18);
        _seedOperatorType(1,  "Junior Broker",     0, 25,   10,  60e18);
        _seedOperatorType(2,  "Chart Intern",      0, 40,   15,  100e18);
        _seedOperatorType(3,  "Cold Caller",       1, 70,   20,  175e18);
        _seedOperatorType(4,  "Options Degen",     1, 120,  30,  300e18);
        _seedOperatorType(5,  "Market Maker",      1, 200,  45,  500e18);
        _seedOperatorType(6,  "ETF Boomer",        2, 320,  60,  800e18);
        _seedOperatorType(7,  "Sell-Side Analyst", 2, 500,  80,  1250e18);
        _seedOperatorType(8,  "Compliance Guy",    2, 750,  100, 1900e18);
        _seedOperatorType(9,  "Quant Goblin",      3, 1100, 130, 2800e18);
        _seedOperatorType(10, "Dark Pool Dealer",  3, 1600, 170, 4200e18);
        _seedOperatorType(11, "Prop Desk Killer",  3, 2400, 220, 6500e18);
        _seedOperatorType(12, "Activist Whale",    4, 3600, 280, 10000e18);
        _seedOperatorType(13, "Terminal Wizard",   4, 5200, 350, 15000e18);
        _seedOperatorType(14, "The Closer",        4, 8000, 450, 25000e18);

        _seedDeskLevel(0,  "Kitchen Table",       2,  20,   10000, 0);
        _seedDeskLevel(1,  "One Laptop Desk",     3,  45,   10250, 100e18);
        _seedDeskLevel(2,  "Retail Desk",         4,  80,   10500, 250e18);
        _seedDeskLevel(3,  "Boiler Room",         6,  150,  11000, 600e18);
        _seedDeskLevel(4,  "Broker Desk",         8,  260,  11500, 1200e18);
        _seedDeskLevel(5,  "Options Desk",        10, 420,  12000, 2500e18);
        _seedDeskLevel(6,  "Prop Desk",           12, 650,  12750, 5000e18);
        _seedDeskLevel(7,  "Quant Floor",         15, 1000, 13500, 9000e18);
        _seedDeskLevel(8,  "Prime Brokerage",     18, 1500, 14500, 16000e18);
        _seedDeskLevel(9,  "The Exchange Floor",  22, 2200, 16000, 30000e18);
        _seedDeskLevel(10, "The Bell Room",       26, 3200, 18000, 60000e18);
    }

    function createDesk(address referrer) external payable whenNotPaused nonReentrant {
        Desk storage d = _desks[msg.sender];
        if (d.exists) revert DeskAlreadyExists();
        if (referrer == msg.sender) revert SelfReferral();
        if (msg.value < STARTER_FEE) revert InsufficientStarterFee();

        d.exists = true;
        d.level = 0;
        if (referrer != address(0)) {
            referrerOf[msg.sender] = referrer;
        }
        emit DeskCreated(msg.sender, referrer);

        emit StarterFeePaid(msg.sender, msg.value);
        (bool ok, ) = payable(treasury).call{value: msg.value}("");
        if (!ok) revert StarterFeeTransferFailed();
    }

    function hasDesk(address user) external view returns (bool) {
        return _desks[user].exists;
    }

    function getDesk(address user)
        external
        view
        returns (
            uint8 level,
            string memory name,
            uint16 seats,
            uint32 bandwidth,
            uint16 seatsUsed,
            uint32 bandwidthUsed,
            uint256 alphaPower,
            uint16 prestigeBps
        )
    {
        Desk storage d = _desks[user];
        if (!d.exists) {
            return (0, "", 0, 0, 0, 0, 0, 0);
        }
        DeskLevelConfig storage lvl = _deskLevels[d.level];
        return (
            d.level,
            lvl.name,
            lvl.seats,
            lvl.bandwidth,
            d.seatsUsed,
            d.bandwidthUsed,
            d.effectiveAlpha,
            lvl.prestigeBps
        );
    }

    function upgradeDesk() external whenNotPaused nonReentrant {
        Desk storage d = _desks[msg.sender];
        if (!d.exists) revert NoDesk();
        uint8 next = d.level + 1;
        if (next >= deskLevelCount) revert MaxDeskLevel();

        uint256 cost = _deskLevels[next].upgradeCost;
        _chargeFloor(msg.sender, cost);

        d.level = next;
        _setUserAlpha(msg.sender, d.rawAlpha);

        emit DeskUpgraded(msg.sender, next, cost);
    }

    function recruitStarter() external whenNotPaused nonReentrant {
        Desk storage d = _desks[msg.sender];
        if (!d.exists) revert NoDesk();
        if (d.starterClaimed) revert StarterAlreadyClaimed();
        d.starterClaimed = true;
        uint256 tokenId = operatorNFT.gameMint(msg.sender, 0);
        emit OperatorRecruited(msg.sender, tokenId, 0, 0);
    }

    function starterClaimed(address user) external view returns (bool) {
        return _desks[user].starterClaimed;
    }

    function recruitOperator(uint8 operatorType) external whenNotPaused nonReentrant {
        if (!_desks[msg.sender].exists) revert NoDesk();
        if (operatorType >= operatorTypeCount) revert UnknownOperatorType(operatorType);
        OperatorTypeConfig storage cfg = _operatorTypes[operatorType];
        if (!cfg.enabled) revert OperatorTypeDisabled(operatorType);

        uint256 cost = cfg.costFloor;
        _chargeFloor(msg.sender, cost);

        uint256 tokenId = operatorNFT.gameMint(msg.sender, operatorType);
        emit OperatorRecruited(msg.sender, tokenId, operatorType, cost);
    }

    function seatOperator(uint256 tokenId) external whenNotPaused nonReentrant {
        Desk storage d = _desks[msg.sender];
        if (!d.exists) revert NoDesk();
        if (operatorNFT.ownerOf(tokenId) != msg.sender) revert NotTokenOwner(tokenId);

        (uint8 opType, ) = operatorNFT.getOperator(tokenId);
        OperatorTypeConfig storage cfg = _operatorTypes[opType];
        DeskLevelConfig storage lvl = _deskLevels[d.level];

        if (d.seatsUsed + 1 > lvl.seats) revert NoSeatsAvailable();
        if (d.bandwidthUsed + cfg.bandwidthCost > lvl.bandwidth) revert NotEnoughBandwidth();

        _seatedBy[tokenId] = msg.sender;
        _seatedIndex[tokenId] = _seated[msg.sender].length;
        _seated[msg.sender].push(tokenId);
        _seatedStats[tokenId] = SeatedStats({
            alphaPower: cfg.alphaPower,
            bandwidthCost: cfg.bandwidthCost
        });
        d.seatsUsed += 1;
        d.bandwidthUsed += cfg.bandwidthCost;
        _setUserAlpha(msg.sender, d.rawAlpha + cfg.alphaPower);

        operatorNFT.transferFrom(msg.sender, address(this), tokenId);

        emit OperatorSeated(msg.sender, tokenId);
    }

    function unseatOperator(uint256 tokenId) external nonReentrant {
        if (_seatedBy[tokenId] != msg.sender) revert NotSeatedByUser(tokenId);
        Desk storage d = _desks[msg.sender];

        SeatedStats memory stats = _seatedStats[tokenId];

        uint256[] storage list = _seated[msg.sender];
        uint256 index = _seatedIndex[tokenId];
        uint256 lastId = list[list.length - 1];
        list[index] = lastId;
        _seatedIndex[lastId] = index;
        list.pop();
        delete _seatedIndex[tokenId];
        delete _seatedBy[tokenId];
        delete _seatedStats[tokenId];

        d.seatsUsed -= 1;
        d.bandwidthUsed -= stats.bandwidthCost;
        _setUserAlpha(msg.sender, d.rawAlpha - stats.alphaPower);

        operatorNFT.transferFrom(address(this), msg.sender, tokenId);

        emit OperatorRemoved(msg.sender, tokenId);
    }

    function getSeatedOperators(address user) external view returns (uint256[] memory) {
        return _seated[user];
    }

    function collectPnL() external whenNotPaused nonReentrant {
        _updatePool();
        Desk storage d = _desks[msg.sender];
        _settle(d);

        uint256 owed = d.pendingStored;
        d.pendingStored = 0;

        uint256 remaining = floorToken.cap() - floorToken.totalSupply();
        uint256 payout = owed > remaining ? remaining : owed;
        if (payout > 0) {
            floorToken.gameMint(msg.sender, payout);
        }
        emit PnLCollected(msg.sender, payout);
    }

    function pendingPnL(address user) external view returns (uint256) {
        Desk storage d = _desks[user];
        uint256 acc = accFloorPerAlpha;
        if (block.timestamp > lastRewardTime && globalAlphaPower > 0) {
            uint256 reward = _emittedBetween(lastRewardTime, block.timestamp);
            uint256 remainingPool = EMISSIONS_POOL - totalEmitted;
            if (reward > remainingPool) reward = remainingPool;
            acc += (reward * ACC_PRECISION) / globalAlphaPower;
        }
        return d.pendingStored + (d.effectiveAlpha * acc) / ACC_PRECISION - d.rewardDebt;
    }

    function userAlphaPower(address user) external view returns (uint256) {
        return _desks[user].effectiveAlpha;
    }

    function userBoostBps(address user) external view returns (uint256) {
        return _desks[user].boostBps;
    }

    function pendingBoostBps(address user) external view returns (uint256) {
        return _boostOf(user);
    }

    function syncBoost(address user) public nonReentrant {
        Desk storage d = _desks[user];
        if (!d.exists) return;
        _setUserAlpha(user, d.rawAlpha);
        emit BoostSynced(user, d.effectiveAlpha, d.boostBps);
    }

    function syncBoostBatch(address[] calldata users) external {
        for (uint256 i = 0; i < users.length; i++) {
            syncBoost(users[i]);
        }
    }

    function emissionRate() external view returns (uint256) {
        if (emissionsStart == 0) return 0;
        if (totalEmitted >= EMISSIONS_POOL) return 0;
        uint256 epoch = (block.timestamp - uint256(emissionsStart)) / EPOCH_LENGTH;
        if (epoch >= MAX_EPOCHS) return 0;
        return INITIAL_RATE >> epoch;
    }

    function emissionsStarted() external view returns (bool) {
        return emissionsStart != 0;
    }

    function currentEpoch() external view returns (uint256) {
        if (emissionsStart == 0) return 0;
        return (block.timestamp - uint256(emissionsStart)) / EPOCH_LENGTH;
    }

    function nextHalvingTime() external view returns (uint256) {
        if (emissionsStart == 0) return 0;
        uint256 epoch = (block.timestamp - uint256(emissionsStart)) / EPOCH_LENGTH;
        return uint256(emissionsStart) + (epoch + 1) * EPOCH_LENGTH;
    }

    function getOperatorType(uint8 id)
        external
        view
        returns (string memory name, uint8 rarity, uint32 alphaPower, uint32 bandwidthCost, uint256 costFloor, bool enabled)
    {
        if (id >= operatorTypeCount) revert UnknownOperatorType(id);
        OperatorTypeConfig storage cfg = _operatorTypes[id];
        return (cfg.name, cfg.rarity, cfg.alphaPower, cfg.bandwidthCost, cfg.costFloor, cfg.enabled);
    }

    function getDeskLevel(uint8 level)
        external
        view
        returns (string memory name, uint16 seats, uint32 bandwidth, uint16 prestigeBps, uint256 upgradeCost)
    {
        if (level >= deskLevelCount) revert UnknownDeskLevel(level);
        DeskLevelConfig storage cfg = _deskLevels[level];
        return (cfg.name, cfg.seats, cfg.bandwidth, cfg.prestigeBps, cfg.upgradeCost);
    }

    function setOperatorType(
        uint8 id,
        string calldata name,
        uint8 rarity,
        uint32 alphaPower,
        uint32 bandwidthCost,
        uint256 costFloor,
        bool enabled
    ) external onlyOwner {
        if (id > operatorTypeCount) revert InvalidConfigId();
        if (id == operatorTypeCount) operatorTypeCount = id + 1;
        _operatorTypes[id] = OperatorTypeConfig(name, rarity, alphaPower, bandwidthCost, costFloor, enabled);
    }

    function setDeskLevel(
        uint8 level,
        string calldata name,
        uint16 seats,
        uint32 bandwidth,
        uint16 prestigeBps,
        uint256 upgradeCost
    ) external onlyOwner {
        if (level > deskLevelCount) revert InvalidConfigId();
        if (level == deskLevelCount) deskLevelCount = level + 1;
        _deskLevels[level] = DeskLevelConfig(name, seats, bandwidth, prestigeBps, upgradeCost);
    }

    function startEmissions() external onlyOwner {
        if (emissionsStart != 0) revert EmissionsAlreadyStarted();
        emissionsStart = uint64(block.timestamp);
        lastRewardTime = block.timestamp;
        emit EmissionsStarted(uint64(block.timestamp));
    }

    function setTreasury(address t) external onlyOwner {
        if (t == address(0)) revert ZeroAddress();
        treasury = t;
        emit TreasurySet(t);
    }

    function setBoostSource(address source) external onlyOwner {
        boostSource = IBoostSource(source);
        emit BoostSourceSet(source);
    }

    function pause() external onlyOwner {
        _pause();
    }

    function unpause() external onlyOwner {
        _unpause();
    }

    function seedDesk(address user, uint8 level, bool starterClaimed_, uint256 pending) public onlyOwner {
        if (migrationSealed) revert SeedingClosed();
        if (user == address(0)) revert ZeroAddress();
        if (level >= deskLevelCount) revert UnknownDeskLevel(level);

        Desk storage d = _desks[user];

        uint256 prevSeed = seededPendingOf[user];
        uint256 newTotal = seededPendingTotal - prevSeed + pending;
        if (newTotal > maxSeededPending) revert SeedCapExceeded();
        seededPendingTotal = newTotal;
        seededPendingOf[user] = pending;

        d.exists = true;
        d.level = level;
        d.starterClaimed = starterClaimed_;

        d.pendingStored = d.pendingStored - prevSeed + pending;

        emit DeskSeeded(user, level, starterClaimed_, pending);
    }

    function seedDeskBatch(
        address[] calldata users,
        uint8[] calldata levels,
        bool[] calldata starterClaimeds,
        uint256[] calldata pendings
    ) external onlyOwner {
        uint256 n = users.length;
        if (levels.length != n || starterClaimeds.length != n || pendings.length != n) {
            revert LengthMismatch();
        }
        for (uint256 i = 0; i < n; i++) {
            seedDesk(users[i], levels[i], starterClaimeds[i], pendings[i]);
        }
    }

    function sealMigration() external onlyOwner {
        migrationSealed = true;
        emit MigrationSealed();
    }

    function _seedOperatorType(
        uint8 id,
        string memory name,
        uint8 rarity,
        uint32 alphaPower,
        uint32 bandwidthCost,
        uint256 costFloor
    ) private {
        _operatorTypes[id] = OperatorTypeConfig(name, rarity, alphaPower, bandwidthCost, costFloor, true);
        operatorTypeCount = id + 1;
    }

    function _seedDeskLevel(
        uint8 level,
        string memory name,
        uint16 seats,
        uint32 bandwidth,
        uint16 prestigeBps,
        uint256 upgradeCost
    ) private {
        _deskLevels[level] = DeskLevelConfig(name, seats, bandwidth, prestigeBps, upgradeCost);
        deskLevelCount = level + 1;
    }

    function _boostOf(address user) internal view returns (uint256) {
        IBoostSource src = boostSource;
        if (address(src) == address(0)) return 0;
        try src.boostBps(user) returns (uint256 b) {
            return b > MAX_TOTAL_BOOST_BPS ? MAX_TOTAL_BOOST_BPS : b;
        } catch {
            return 0;
        }
    }

    function _emittedBetween(uint256 t1, uint256 t2) private view returns (uint256) {
        uint256 start = uint256(emissionsStart);
        if (start == 0 || t2 <= start) return 0;
        if (t1 < start) t1 = start;
        if (t2 <= t1) return 0;

        uint256 total = 0;
        uint256 epoch = (t1 - start) / EPOCH_LENGTH;
        uint256 cursor = t1;
        while (cursor < t2) {
            if (epoch >= MAX_EPOCHS) break;
            uint256 rate = INITIAL_RATE >> epoch;
            if (rate == 0) break;
            uint256 epochEnd = start + (epoch + 1) * EPOCH_LENGTH;
            uint256 sliceEnd = t2 < epochEnd ? t2 : epochEnd;
            total += (sliceEnd - cursor) * rate;
            cursor = sliceEnd;
            unchecked {
                ++epoch;
            }
        }
        return total;
    }

    function _updatePool() private {
        if (block.timestamp <= lastRewardTime) return;
        if (emissionsStart == 0 || globalAlphaPower == 0) {
            lastRewardTime = block.timestamp;
            return;
        }
        uint256 reward = _emittedBetween(lastRewardTime, block.timestamp);
        uint256 remainingPool = EMISSIONS_POOL - totalEmitted;
        if (reward > remainingPool) reward = remainingPool;
        if (reward > 0) {
            totalEmitted += reward;
            accFloorPerAlpha += (reward * ACC_PRECISION) / globalAlphaPower;
        }
        lastRewardTime = block.timestamp;
    }

    function _settle(Desk storage d) private {
        if (d.effectiveAlpha > 0) {
            d.pendingStored += (d.effectiveAlpha * accFloorPerAlpha) / ACC_PRECISION - d.rewardDebt;
        }
        d.rewardDebt = (d.effectiveAlpha * accFloorPerAlpha) / ACC_PRECISION;
    }

    function _setUserAlpha(address user, uint256 newRawAlpha) private {
        _updatePool();
        Desk storage d = _desks[user];
        _settle(d);

        uint256 boost = _boostOf(user);
        d.boostBps = boost;

        globalAlphaPower -= d.effectiveAlpha;
        d.rawAlpha = newRawAlpha;
        d.effectiveAlpha =
            (newRawAlpha * _deskLevels[d.level].prestigeBps * (BPS + boost)) / (BPS * BPS);
        globalAlphaPower += d.effectiveAlpha;

        d.rewardDebt = (d.effectiveAlpha * accFloorPerAlpha) / ACC_PRECISION;
    }

    function _chargeFloor(address payer, uint256 cost) private {
        if (cost == 0) return;
        floorToken.transferFrom(payer, address(this), cost);

        uint256 burnAmount = (cost * BURN_PERCENT) / 100;
        floorToken.burn(burnAmount);
        totalFloorBurned += burnAmount;
        emit FloorBurned(burnAmount);

        uint256 rest = cost - burnAmount;
        address referrer = referrerOf[payer];
        if (referrer != address(0)) {
            uint256 referralAmount = (cost * REFERRAL_PERCENT) / 100;
            if (referralAmount > 0) {
                rest -= referralAmount;
                referralEarned[referrer] += referralAmount;
                floorToken.transfer(referrer, referralAmount);
                emit ReferralPaid(referrer, payer, referralAmount);
            }
        }
        if (rest > 0) {
            floorToken.transfer(treasury, rest);
        }
    }
}
Chain explorer5568msChain node74ms