FireToken

0x43eea882b845a8493152ebc55cf30ae9281b02d5

Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
11,328 bytes
ABI entries
81
43 read · 20 write
License
none

Contract information

Address
0x43eea882b845a8493152ebc55cf30ae9281b02d5
Chain
Robinhood Chain (4663)
Compiler
v0.8.26+commit.8a97fa7a
Optimization
Enabled
Creation tx
0x47ebd39881…3777e90d4d

Token

Name
FIRE
Symbol
FIRE
Decimals
18
Holders
2,101

Read contract (43)

BUCKET()uint256
DAY()uint256
DEAD()address
REPAIR_WINDOW()uint256
TOTAL_SUPPLY()uint256
allowance(address, address)uint256
attributionQueueLength()uint256
balanceOf(address)uint256
decimals()uint8
dividendScore(address)uint256
feeDecayPeriod()uint256
holderCount()uint256
holderList(uint256)address
holderStatus(address)tuple
hook()address
isAMM(address)bool
isExempt(address)bool
isMigrated(address)bool
isTrackedHolder(address)bool
jackpotWeight(address)uint256
launchTime()uint256
name()string
owner()address
peakBalance(address)uint256
prestige1Days()uint256
prestige2Days()uint256
prestigeBump()uint256
previewSellFeeBps(address, uint256)uint256
sellFeeMaxBps()uint256
sellFeeMinBps()uint256
streakDays(address)uint256
streakStart(address)uint64
symbol()string
tierBaseMult()uint256
tierHardCap()uint256
tierMaxBase()uint256
tierMultiplier(address)uint256
tierRampPeriod()uint256
totalSupply()uint256
tradingOpen()bool
trancheAt(address, uint256)uint64, uint192
trancheCount(address)uint256
v1SnapshotTime()uint256

Events (7)

ApprovalOwnershipTransferredSellAttributedStreakAdminSetStreakBrokenTradingOpenedTransfer

ABI

[
  {
    "inputs": [],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "allowance",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "needed",
        "type": "uint256"
      }
    ],
    "name": "ERC20InsufficientAllowance",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "balance",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "needed",
        "type": "uint256"
      }
    ],
    "name": "ERC20InsufficientBalance",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "approver",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidApprover",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "receiver",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidReceiver",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidSender",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidSpender",
    "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": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "name": "SafeERC20FailedOperation",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "owner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Approval",
    "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": true,
        "internalType": "address",
        "name": "seller",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "weightedBps",
        "type": "uint256"
      }
    ],
    "name": "SellAttributed",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "holder",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint64",
        "name": "start",
        "type": "uint64"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "migrated",
        "type": "bool"
      }
    ],
    "name": "StreakAdminSet",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "holder",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "newBalance",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "oldPeak",
        "type": "uint256"
      }
    ],
    "name": "StreakBroken",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [],
    "name": "TradingOpened",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Transfer",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "BUCKET",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "DAY",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "DEAD",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "REPAIR_WINDOW",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "TOTAL_SUPPLY",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "h",
        "type": "address"
      }
    ],
    "name": "adminClearStreak",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "h",
        "type": "address"
      },
      {
        "internalType": "uint64",
        "name": "start",
        "type": "uint64"
      },
      {
        "internalType": "bool",
        "name": "migrated",
        "type": "bool"
      }
    ],
    "name": "adminSetStreak",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address[]",
        "name": "hs",
        "type": "address[]"
      },
      {
        "internalType": "uint64[]",
        "name": "starts",
        "type": "uint64[]"
      },
      {
        "internalType": "bool[]",
        "name": "migrated",
        "type": "bool[]"
      }
    ],
    "name": "adminSetStreakBatch",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      }
    ],
    "name": "allowance",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "approve",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "attributionQueueLength",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "balanceOf",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address[]",
        "name": "to",
        "type": "address[]"
      },
      {
        "internalType": "uint256[]",
        "name": "amounts",
        "type": "uint256[]"
      }
    ],
    "name": "batchAirdrop",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "decimals",
    "outputs": [
      {
        "internalType": "uint8",
        "name": "",
        "type": "uint8"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "h",
        "type": "address"
      }
    ],
    "name": "dividendScore",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "feeDecayPeriod",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "holderCount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "holderList",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "h",
        "type": "address"
      }
    ],
    "name": "holderStatus",
    "outputs": [
      {
        "components": [
          {
            "internalType": "uint256",
            "name": "balance",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "streakDays_",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "tierMultX100",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "peak",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "breakBelowBalance",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "tranches_",
            "type": "uint256"
          },
          {
            "internalType": "bool",
            "name": "migrated",
            "type": "bool"
          }
        ],
        "internalType": "struct FireToken.HolderStatus",
        "name": "s",
        "type": "tuple"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "hook",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "isAMM",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "isExempt",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "isMigrated",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "isTrackedHolder",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "h",
        "type": "address"
      }
    ],
    "name": "jackpotWeight",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "launchTime",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "name",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "openTrading",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "peakBalance",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "prestige1Days",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "prestige2Days",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "prestigeBump",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "h",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "previewSellFeeBps",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "weightedBps",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "fireAmount",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "nonce",
        "type": "uint256"
      }
    ],
    "name": "pullAttribution",
    "outputs": [
      {
        "internalType": "bool",
        "name": "found",
        "type": "bool"
      },
      {
        "internalType": "address",
        "name": "seller",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "weightedBps",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "renounceOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "rescueETH",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token_",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "rescueTokens",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "sellFeeMaxBps",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "sellFeeMinBps",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "venue",
        "type": "address"
      },
      {
        "internalType": "bool",
        "name": "v",
        "type": "bool"
      }
    ],
    "name": "setAMM",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "a",
        "type": "address"
      },
      {
        "internalType": "bool",
        "name": "v",
        "type": "bool"
      }
    ],
    "name": "setExempt",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "h",
        "type": "address"
      }
    ],
    "name": "setHook",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "maxBps",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "minBps",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "decaySeconds",
        "type": "uint256"
      }
    ],
    "name": "setSellFeeCurve",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address[]",
        "name": "hs",
        "type": "address[]"
      },
      {
        "internalType": "uint64[]",
        "name": "starts",
        "type": "uint64[]"
      },
      {
        "internalType": "bool[]",
        "name": "migrated",
        "type": "bool[]"
      }
    ],
    "name": "setStreakBatch",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "ramp",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "maxBase",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "p1Days",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "p2Days",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "bump",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "cap",
        "type": "uint256"
      }
    ],
    "name": "setTierConfig",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "t",
        "type": "uint256"
      }
    ],
    "name": "setV1SnapshotTime",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "h",
        "type": "address"
      }
    ],
    "name": "streakDays",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "streakStart",
    "outputs": [
      {
        "internalType": "uint64",
        "name": "",
        "type": "uint64"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "symbol",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "tierBaseMult",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "tierHardCap",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "tierMaxBase",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "h",
        "type": "address"
      }
    ],
    "name": "tierMultiplier",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "tierRampPeriod",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalSupply",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "tradingOpen",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "h",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "i",
        "type": "uint256"
      }
    ],
    "name": "trancheAt",
    "outputs": [
      {
        "internalType": "uint64",
        "name": "start",
        "type": "uint64"
      },
      {
        "internalType": "uint192",
        "name": "amount",
        "type": "uint192"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "h",
        "type": "address"
      }
    ],
    "name": "trancheCount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "transfer",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "transferFrom",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "v1SnapshotTime",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "stateMutability": "payable",
    "type": "receive"
  }
]

Source code

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

import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

interface IFireHook {
    function attributeSell(address seller, uint256 fireAmount, uint256 weightedBps, uint256 swapNonce) external;
    function swapNonce() external view returns (uint256);
}

/**
 * FIRE v2 — clean ERC-20 (Robinhood Chain)
 * ─────────────────────────────────────────
 * NO transfer taxes. All fees live in the v4 hook, in ETH.
 * The token keeps only the state machines that need balance-change
 * visibility:
 *
 *   TRANCHES  — LIFO, 30-day buckets, dust-merge, inbound transfers
 *               open day-0 tranches (no age import). Consumed newest-
 *               first on any balance decrease. On sells (transfer →
 *               PoolManager) the amount-weighted fee bps (300→100 over
 *               90d per tranche) is computed and reported to the hook,
 *               which credits the seller's ETH fee rebate.
 *
 *   STREAK    — uncapped day counter. Breaks only if balance drops
 *               below 50% of peak. Pride metric + jackpot weight.
 *
 *   TIER      — 1x→5x linear over 90d, +0.25x at 180d, +0.25x at 365d,
 *               cap 5.5x. Migrated wallets floor at 5x (cleared if the
 *               streak breaks). Earnings weight = balance × tier.
 */
contract FireToken is ERC20, Ownable {
    using SafeERC20 for IERC20;

    uint256 public constant TOTAL_SUPPLY = 1_000_000_000 * 1e18;
    uint256 public constant BUCKET = 30 days;
    uint256 public constant DAY    = 86400;
    address public constant DEAD   = 0x000000000000000000000000000000000000dEaD;

    mapping(address => bool) public isAMM;      // v4 PoolManager
    address public hook;
    bool    public tradingOpen;
    uint256 public launchTime;                    // set once by openTrading()
    uint256 public v1SnapshotTime;                // Base snapshot timestamp — repair floor
    uint256 public constant REPAIR_WINDOW = 14 days;
    mapping(address => bool) public isExempt;   // deployer, hook, this, distributor

    struct Tranche { uint64 start; uint192 amount; }
    mapping(address => Tranche[]) private _tranches;

    mapping(address => uint64)  public streakStart;
    mapping(address => uint256) public peakBalance;
    mapping(address => bool)    public isMigrated;

    // sell-fee curve (bps) — used for ATTRIBUTION only; ETH is taken by the hook
    uint256 public sellFeeMaxBps  = 300;
    uint256 public sellFeeMinBps  = 100;
    uint256 public feeDecayPeriod = 90 days;

    // tier config
    uint256 public tierRampPeriod = 90 days;
    uint256 public tierBaseMult   = 100;
    uint256 public tierMaxBase    = 500;
    uint256 public prestige1Days  = 180;
    uint256 public prestige2Days  = 365;
    uint256 public prestigeBump   = 25;
    uint256 public tierHardCap    = 550;

    address[] public holderList;
    mapping(address => bool) public isTrackedHolder;

    // sell-attribution queue — two-sided handshake with the hook.
    // Whichever contract acts second (token _update vs hook afterSwap)
    // completes the match, so BOTH settle-before-swap and settle-after-swap
    // router orderings are covered. Stale entries (older block) are dropped.
    struct Attribution { address seller; uint128 amount; uint64 blockNo; uint32 bps; uint256 nonce; }
    Attribution[] private _attributions;

    event StreakBroken(address indexed holder, uint256 newBalance, uint256 oldPeak);
    event StreakAdminSet(address indexed holder, uint64 start, bool migrated);
    event SellAttributed(address indexed seller, uint256 amount, uint256 weightedBps);
    event TradingOpened();

    constructor() ERC20("FIRE", "FIRE") Ownable(msg.sender) {
        isExempt[msg.sender]    = true;
        isExempt[address(this)] = true;
        _mint(msg.sender, TOTAL_SUPPLY);
    }

    // ═════════════════ ADMIN ═════════════════

    function setAMM(address venue, bool v) external onlyOwner { isAMM[venue] = v; }
    function setHook(address h) external onlyOwner { hook = h; isExempt[h] = true; }
    function setExempt(address a, bool v) external onlyOwner { isExempt[a] = v; }

    function setSellFeeCurve(uint256 maxBps, uint256 minBps, uint256 decaySeconds) external onlyOwner {
        require(maxBps <= 1000 && minBps <= maxBps && decaySeconds >= 1 days, "range");
        sellFeeMaxBps = maxBps; sellFeeMinBps = minBps; feeDecayPeriod = decaySeconds;
    }

    function setTierConfig(uint256 ramp, uint256 maxBase, uint256 p1Days, uint256 p2Days, uint256 bump, uint256 cap)
        external onlyOwner
    {
        require(ramp >= 1 days && maxBase >= 100 && cap >= maxBase, "range");
        tierRampPeriod = ramp; tierMaxBase = maxBase;
        prestige1Days = p1Days; prestige2Days = p2Days;
        prestigeBump = bump; tierHardCap = cap;
    }

    /// Migration (pre-launch): carry v1 streaks; migrated wallets get the 5x floor.
    function setStreakBatch(address[] calldata hs, uint64[] calldata starts, bool[] calldata migrated)
        external onlyOwner
    {
        require(!tradingOpen, "locked");
        require(hs.length == starts.length && hs.length == migrated.length, "len");
        for (uint256 i; i < hs.length; i++) {
            require(starts[i] < block.timestamp, "future");
            streakStart[hs[i]] = starts[i];
            isMigrated[hs[i]]  = migrated[i];
            peakBalance[hs[i]] = balanceOf(hs[i]);
        }
    }

    /// Migration repair tool — BOUNDED (provable-fairness fix):
    ///   1. dies REPAIR_WINDOW (14 days) after launch — after that no owner
    ///      path to grant streaks/tiers exists, so jackpot fairness is provable
    ///   2. can never set a streak older than the v1 snapshot itself
    /// Effective immediately within the window. peakBalance resets to current
    /// balance so the restored streak can't instantly re-break.
    function adminSetStreak(address h, uint64 start, bool migrated) public onlyOwner {
        require(tradingOpen && block.timestamp < launchTime + REPAIR_WINDOW, "repair window closed");
        require(v1SnapshotTime == 0 || start >= v1SnapshotTime, "predates v1 snapshot");
        require(start < block.timestamp, "future");
        require(h != address(0) && !isAMM[h], "bad addr");
        streakStart[h] = start;
        isMigrated[h]  = migrated;
        peakBalance[h] = balanceOf(h);
        if (!isTrackedHolder[h]) { isTrackedHolder[h] = true; holderList.push(h); }
        emit StreakAdminSet(h, start, migrated);
    }

    function adminSetStreakBatch(address[] calldata hs, uint64[] calldata starts, bool[] calldata migrated)
        external onlyOwner
    {
        require(hs.length == starts.length && hs.length == migrated.length, "len");
        for (uint256 i; i < hs.length; i++) adminSetStreak(hs[i], starts[i], migrated[i]);
    }

    /// Wipe a holder's streak entirely (tier back to 1x).
    function adminClearStreak(address h) external onlyOwner {
        streakStart[h] = 0;
        isMigrated[h]  = false;
        peakBalance[h] = balanceOf(h);
        emit StreakAdminSet(h, 0, false);
    }

    function batchAirdrop(address[] calldata to, uint256[] calldata amounts) external onlyOwner {
        require(to.length == amounts.length && to.length <= 500, "len");
        for (uint256 i; i < to.length; i++) {
            address r = to[i];
            if (r == address(0) || r == address(this) || r == DEAD || isAMM[r]) continue;
            _update(msg.sender, r, amounts[i]);
        }
    }

    function openTrading() external onlyOwner {
        require(!tradingOpen, "open");
        tradingOpen = true;
        launchTime = block.timestamp;
        emit TradingOpened();
    }

    /// The Base v1 snapshot timestamp — repairs can never fabricate a streak
    /// older than v1 itself. Settable pre-launch only.
    function setV1SnapshotTime(uint256 t) external onlyOwner {
        require(!tradingOpen, "locked");
        require(t < block.timestamp, "future");
        v1SnapshotTime = t;
    }

    // ═════════════════ TRANSFER ENGINE ═════════════════

    function _update(address from, address to, uint256 amount) internal override {
        bool fromAMM = isAMM[from];
        bool toAMM   = isAMM[to];

        // launch gate: only exempt (deployer/hook/distributor) move pre-open.
        // covers mint (from=0 → deployer is exempt) and blocks pool snipes.
        require(tradingOpen || isExempt[from] || isExempt[to], "trading closed");

        super._update(from, to, amount);

        // sender: consume tranches LIFO; attribute sells to the hook for rebates
        if (from != address(0) && !isExempt[from] && !fromAMM && amount > 0) {
            uint256 weightedBps = _consumeTranches(from, amount, toAMM);
            if (toAMM && hook != address(0)) {
                emit SellAttributed(from, amount, weightedBps);
                // nonce ties this transfer to the hook's current swap session,
                // so two identical-size sells in one block can never cross-match
                uint256 nonce = 0;
                try IFireHook(hook).swapNonce() returns (uint256 n) { nonce = n; } catch {}
                // 1) record durably so the hook can pull it in afterSwap
                //    (covers settle-BEFORE-swap ordering)
                _attributions.push(Attribution(from, uint128(amount), uint64(block.number), uint32(weightedBps), nonce));
                // 2) best-effort push for settle-AFTER-swap ordering — a hook
                //    revert must never block the transfer
                try IFireHook(hook).attributeSell(from, amount, weightedBps, nonce) {} catch {}
            }
            _checkStreakBreak(from);
        }

        // receiver: day-0 tranche, streak start, peak, holder list
        if (to != address(0) && to != DEAD && to != address(this) && !isExempt[to] && !toAMM && amount > 0) {
            _addTranche(to, amount);
            if (streakStart[to] == 0) streakStart[to] = uint64(block.timestamp);
            uint256 bal = balanceOf(to);
            if (bal > peakBalance[to]) peakBalance[to] = bal;
            if (!isTrackedHolder[to]) { isTrackedHolder[to] = true; holderList.push(to); }
        }
    }

    function _addTranche(address h, uint256 amount) internal {
        uint64 bucketStart = uint64((block.timestamp / BUCKET) * BUCKET);
        Tranche[] storage ts = _tranches[h];
        if (ts.length > 0 && ts[ts.length - 1].start == bucketStart) {
            ts[ts.length - 1].amount += uint192(amount);
        } else {
            ts.push(Tranche(bucketStart, uint192(amount)));
        }
    }

    function _consumeTranches(address h, uint256 amount, bool computeFee) internal returns (uint256 weightedBps) {
        Tranche[] storage ts = _tranches[h];
        uint256 remaining = amount;
        uint256 feeWeighted;
        while (remaining > 0 && ts.length > 0) {
            Tranche storage top = ts[ts.length - 1];
            uint256 take = remaining < top.amount ? remaining : top.amount;
            if (computeFee) feeWeighted += take * _trancheFeeBps(top.start);
            if (take == top.amount) ts.pop();
            else top.amount -= uint192(take);
            remaining -= take;
        }
        if (computeFee) {
            if (remaining > 0) feeWeighted += remaining * sellFeeMinBps; // pre-tracking flows = aged
            weightedBps = feeWeighted / amount;
        }
    }

    function _trancheFeeBps(uint64 start) internal view returns (uint256) {
        uint256 age = block.timestamp - start;
        if (age >= feeDecayPeriod) return sellFeeMinBps;
        return sellFeeMaxBps - (sellFeeMaxBps - sellFeeMinBps) * age / feeDecayPeriod;
    }

    function _checkStreakBreak(address h) internal {
        uint256 bal  = balanceOf(h);
        uint256 peak = peakBalance[h];
        if (peak > 0 && bal < peak / 2) {
            emit StreakBroken(h, bal, peak);
            streakStart[h] = bal > 0 ? uint64(block.timestamp) : 0;
            peakBalance[h] = bal;
            isMigrated[h]  = false;
        }
    }

    /// Hook-only: pull the pending attribution matching (fireAmount, swapNonce).
    /// The nonce requirement makes cross-matching between identical-size sells
    /// impossible — each record only pairs with its own swap session. Stale
    /// entries from earlier blocks are dropped as the scan passes them.
    function pullAttribution(uint256 fireAmount, uint256 nonce) external returns (bool found, address seller, uint256 weightedBps) {
        require(msg.sender == hook, "not hook");
        uint256 i = 0;
        while (i < _attributions.length) {
            Attribution memory a = _attributions[i];
            if (a.blockNo < block.number) { _removeAttribution(i); continue; } // stale
            if (a.amount == uint128(fireAmount) && a.nonce == nonce) {
                _removeAttribution(i);
                return (true, a.seller, a.bps);
            }
            i++;
        }
        return (false, address(0), 0);
    }

    function _removeAttribution(uint256 i) internal {
        uint256 last = _attributions.length - 1;
        if (i != last) _attributions[i] = _attributions[last];
        _attributions.pop();
    }

    function attributionQueueLength() external view returns (uint256) { return _attributions.length; }

    // ═════════════════ VIEWS ═════════════════

    function streakDays(address h) public view returns (uint256) {
        uint64 s = streakStart[h];
        return s == 0 ? 0 : (block.timestamp - s) / DAY;
    }

    function tierMultiplier(address h) public view returns (uint256) {
        uint64 s = streakStart[h];
        if (s == 0) return tierBaseMult;
        uint256 elapsed = block.timestamp - s;
        uint256 base = elapsed >= tierRampPeriod
            ? tierMaxBase
            : tierBaseMult + (tierMaxBase - tierBaseMult) * elapsed / tierRampPeriod;
        if (isMigrated[h] && base < tierMaxBase) base = tierMaxBase;
        uint256 d = elapsed / DAY;
        if (d >= prestige1Days) base += prestigeBump;
        if (d >= prestige2Days) base += prestigeBump;
        return base > tierHardCap ? tierHardCap : base;
    }

    /// Dividend weight = bag × tier. The Friday snapshot reads this.
    function dividendScore(address h) external view returns (uint256) {
        if (isAMM[h] || isExempt[h] || h == DEAD) return 0;
        return balanceOf(h) * tierMultiplier(h) / 100;
    }

    /// Jackpot weight = streakDays × bag (min-streak gate enforced by the Distributor).
    function jackpotWeight(address h) external view returns (uint256) {
        if (isAMM[h] || isExempt[h] || h == DEAD) return 0;
        return streakDays(h) * balanceOf(h);
    }

    function previewSellFeeBps(address h, uint256 amount) external view returns (uint256 weightedBps) {
        Tranche[] storage ts = _tranches[h];
        uint256 remaining = amount;
        uint256 feeWeighted;
        for (uint256 i = ts.length; i > 0 && remaining > 0; i--) {
            uint256 take = remaining < ts[i-1].amount ? remaining : ts[i-1].amount;
            feeWeighted += take * _trancheFeeBps(ts[i-1].start);
            remaining   -= take;
        }
        if (remaining > 0) feeWeighted += remaining * sellFeeMinBps;
        weightedBps = amount > 0 ? feeWeighted / amount : 0;
    }

    function trancheCount(address h) external view returns (uint256) { return _tranches[h].length; }
    function trancheAt(address h, uint256 i) external view returns (uint64 start, uint192 amount) {
        Tranche storage t = _tranches[h][i];
        return (t.start, t.amount);
    }
    function holderCount() external view returns (uint256) { return holderList.length; }

    struct HolderStatus {
        uint256 balance;
        uint256 streakDays_;
        uint256 tierMultX100;
        uint256 peak;
        uint256 breakBelowBalance;
        uint256 tranches_;
        bool    migrated;
    }

    function holderStatus(address h) external view returns (HolderStatus memory s) {
        s.balance      = balanceOf(h);
        s.streakDays_  = streakDays(h);
        s.tierMultX100 = tierMultiplier(h);
        s.peak         = peakBalance[h];
        s.breakBelowBalance = peakBalance[h] / 2;
        s.tranches_    = _tranches[h].length;
        s.migrated     = isMigrated[h];
    }

    // ═════════════════ RESCUE ═════════════════

    function rescueTokens(address token_, uint256 amount) external onlyOwner {
        if (token_ == address(this)) super._update(address(this), msg.sender, amount);
        else IERC20(token_).safeTransfer(msg.sender, amount);
    }

    function rescueETH(uint256 amount) external onlyOwner {
        (bool ok,) = msg.sender.call{value: amount}("");
        require(ok, "eth");
    }

    receive() external payable {}
}
Chain explorer1866msChain node83ms