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
- Creator
- 0x44D1Bb5f85…EcaB0A33D9
- 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