BankrollToken

0x1c5be03b4475fbdd678aa2c19904a03c957cb244

Verification
Verified
v0.8.35+commit.47b9dedd
Type
Contract
12,258 bytes
ABI entries
103
34 read · 19 write
License
none

Contract information

Address
0x1c5be03b4475fbdd678aa2c19904a03c957cb244
Chain
Robinhood Chain (4663)
Compiler
v0.8.35+commit.47b9dedd
Optimization
Enabled
Creation tx
0x7460586baf…4238758a0d

Token

Name
BANKROLL
Symbol
BANKROLL
Decimals
18
Holders
170

Read contract (34)

BPS_DENOMINATOR()uint16
DOMAIN_SEPARATOR()bytes32
MAX_TAX_BPS()uint16
POOL_TOKEN_AMOUNT()uint256
TAX_SWITCHOVER_BLOCKS()uint32
UNISWAP_V2_ROUTER()address
allowance(address, address)uint256
automatedMarketMakerPairs(address)bool
balanceOf(address)uint256
decimals()uint8
eip712Domain()bytes1, string, string, uint256, address, bytes32, uint256[]
finalBuyTaxBps()uint16
finalSellTaxBps()uint16
initialBuyTaxBps()uint16
initialLiquidityAdded()bool
initialSellTaxBps()uint16
isExcludedFromFees(address)bool
lastSwapBlock()uint32
launchTaxesFinalized()bool
limitsEnabled()bool
maxSwapAmount()uint256
maxWalletAmount()uint256
minBlocksBetweenSwaps()uint32
name()string
nonces(address)uint256
owner()address
swapEnabled()bool
symbol()string
taxWallet()address
taxesAndLimitsRemoved()bool
totalSupply()uint256
tradingActive()bool
tradingActiveBlock()uint32
uniswapV2Pair()address

Events (15)

ApprovalEIP712DomainChangedExcludedFromFeesSetInitialLiquidityAddedLimitsRemovedOwnershipTransferredPairCreatedPublicTradingOpenedRecoveredERC20SwapEnabledSetTaxTokensSwappedTaxWalletUpdatedTaxesAndLimitsRemovedTaxesUpdatedTransfer

ABI

[
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "string",
            "name": "name",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "symbol",
            "type": "string"
          },
          {
            "internalType": "uint8",
            "name": "decimals_",
            "type": "uint8"
          },
          {
            "internalType": "uint256",
            "name": "totalSupply",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "poolTokenAmount",
            "type": "uint256"
          },
          {
            "internalType": "address",
            "name": "taxWallet",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "uniswapV2Router",
            "type": "address"
          },
          {
            "components": [
              {
                "internalType": "uint16",
                "name": "initialBuyTaxBps",
                "type": "uint16"
              },
              {
                "internalType": "uint16",
                "name": "finalBuyTaxBps",
                "type": "uint16"
              },
              {
                "internalType": "uint16",
                "name": "initialSellTaxBps",
                "type": "uint16"
              },
              {
                "internalType": "uint16",
                "name": "finalSellTaxBps",
                "type": "uint16"
              },
              {
                "internalType": "uint32",
                "name": "taxSwitchoverBlocks",
                "type": "uint32"
              },
              {
                "internalType": "uint16",
                "name": "maxTaxBps",
                "type": "uint16"
              }
            ],
            "internalType": "struct BankrollToken.TaxConfig",
            "name": "tax",
            "type": "tuple"
          },
          {
            "components": [
              {
                "internalType": "bool",
                "name": "limitsEnabled",
                "type": "bool"
              },
              {
                "internalType": "uint256",
                "name": "maxWalletAmount",
                "type": "uint256"
              }
            ],
            "internalType": "struct BankrollToken.LimitConfig",
            "name": "limits",
            "type": "tuple"
          },
          {
            "components": [
              {
                "internalType": "bool",
                "name": "autoSwapEnabled",
                "type": "bool"
              },
              {
                "internalType": "uint256",
                "name": "maxSwapAmount",
                "type": "uint256"
              },
              {
                "internalType": "uint32",
                "name": "minBlocksBetweenSwaps",
                "type": "uint32"
              }
            ],
            "internalType": "struct BankrollToken.ClogConfig",
            "name": "clog",
            "type": "tuple"
          }
        ],
        "internalType": "struct BankrollToken.LaunchTokenConfig",
        "name": "config",
        "type": "tuple"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "AlreadySet",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ECDSAInvalidSignature",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "length",
        "type": "uint256"
      }
    ],
    "name": "ECDSAInvalidSignatureLength",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "bytes32",
        "name": "s",
        "type": "bytes32"
      }
    ],
    "name": "ECDSAInvalidSignatureS",
    "type": "error"
  },
  {
    "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": "uint256",
        "name": "deadline",
        "type": "uint256"
      }
    ],
    "name": "ERC2612ExpiredSignature",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "signer",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      }
    ],
    "name": "ERC2612InvalidSigner",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InitialLiquidityAlreadyAdded",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InitialLiquidityNotAdded",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "currentNonce",
        "type": "uint256"
      }
    ],
    "name": "InvalidAccountNonce",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidAmount",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidRecipient",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidShortString",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidTax",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "LimitsAlreadyRemoved",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NotOwnerOrTaxWallet",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NotTaxWallet",
    "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": "PairNotCreated",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ProtectedExclusion",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "name": "SafeERC20FailedOperation",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "string",
        "name": "str",
        "type": "string"
      }
    ],
    "name": "StringTooLong",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "SwapInProgress",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TaxesAndLimitsAlreadyRemoved",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TradingAlreadyActive",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TradingNotActive",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TradingNotOpen",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "UnauthorizedTransferBeforeTrading",
    "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": [],
    "name": "EIP712DomainChanged",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "account",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "excluded",
        "type": "bool"
      }
    ],
    "name": "ExcludedFromFeesSet",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "pair",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "tokenAmount",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "ethAmount",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "liquidity",
        "type": "uint256"
      }
    ],
    "name": "InitialLiquidityAdded",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [],
    "name": "LimitsRemoved",
    "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": "pair",
        "type": "address"
      }
    ],
    "name": "PairCreated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint32",
        "name": "tradingActiveBlock",
        "type": "uint32"
      }
    ],
    "name": "PublicTradingOpened",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "RecoveredERC20",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "bool",
        "name": "enabled",
        "type": "bool"
      }
    ],
    "name": "SwapEnabledSet",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "tokensSold",
        "type": "uint256"
      }
    ],
    "name": "TaxTokensSwapped",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "taxWallet",
        "type": "address"
      }
    ],
    "name": "TaxWalletUpdated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [],
    "name": "TaxesAndLimitsRemoved",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint16",
        "name": "initialBuyTaxBps",
        "type": "uint16"
      },
      {
        "indexed": false,
        "internalType": "uint16",
        "name": "finalBuyTaxBps",
        "type": "uint16"
      },
      {
        "indexed": false,
        "internalType": "uint16",
        "name": "initialSellTaxBps",
        "type": "uint16"
      },
      {
        "indexed": false,
        "internalType": "uint16",
        "name": "finalSellTaxBps",
        "type": "uint16"
      }
    ],
    "name": "TaxesUpdated",
    "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": "BPS_DENOMINATOR",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "DOMAIN_SEPARATOR",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAX_TAX_BPS",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "POOL_TOKEN_AMOUNT",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "TAX_SWITCHOVER_BLOCKS",
    "outputs": [
      {
        "internalType": "uint32",
        "name": "",
        "type": "uint32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "UNISWAP_V2_ROUTER",
    "outputs": [
      {
        "internalType": "contract IUniswapV2Router02",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "tokenAmount",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "amountTokenMin",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "amountEthMin",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "lpRecipient",
        "type": "address"
      }
    ],
    "name": "addInitialLiquidity",
    "outputs": [],
    "stateMutability": "payable",
    "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": [
      {
        "internalType": "address",
        "name": "pair",
        "type": "address"
      }
    ],
    "name": "automatedMarketMakerPairs",
    "outputs": [
      {
        "internalType": "bool",
        "name": "enabled",
        "type": "bool"
      }
    ],
    "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": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "burn",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "burnFrom",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "createPair",
    "outputs": [
      {
        "internalType": "address",
        "name": "pair",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "decimals",
    "outputs": [
      {
        "internalType": "uint8",
        "name": "",
        "type": "uint8"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "eip712Domain",
    "outputs": [
      {
        "internalType": "bytes1",
        "name": "fields",
        "type": "bytes1"
      },
      {
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "version",
        "type": "string"
      },
      {
        "internalType": "uint256",
        "name": "chainId",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "verifyingContract",
        "type": "address"
      },
      {
        "internalType": "bytes32",
        "name": "salt",
        "type": "bytes32"
      },
      {
        "internalType": "uint256[]",
        "name": "extensions",
        "type": "uint256[]"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "finalBuyTaxBps",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "finalSellTaxBps",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "initialBuyTaxBps",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "initialLiquidityAdded",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "initialSellTaxBps",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "isExcludedFromFees",
    "outputs": [
      {
        "internalType": "bool",
        "name": "excluded",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "lastSwapBlock",
    "outputs": [
      {
        "internalType": "uint32",
        "name": "",
        "type": "uint32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "launchTaxesFinalized",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "limitsEnabled",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "tokenAmount",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "minOut",
        "type": "uint256"
      }
    ],
    "name": "manualSwap",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "maxSwapAmount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "maxWalletAmount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "minBlocksBetweenSwaps",
    "outputs": [
      {
        "internalType": "uint32",
        "name": "",
        "type": "uint32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "name",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      }
    ],
    "name": "nonces",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "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": "owner",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "deadline",
        "type": "uint256"
      },
      {
        "internalType": "uint8",
        "name": "v",
        "type": "uint8"
      },
      {
        "internalType": "bytes32",
        "name": "r",
        "type": "bytes32"
      },
      {
        "internalType": "bytes32",
        "name": "s",
        "type": "bytes32"
      }
    ],
    "name": "permit",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      }
    ],
    "name": "recoverERC20",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "removeLimits",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "removeTaxesAndLimits",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "renounceOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address[]",
        "name": "accounts",
        "type": "address[]"
      },
      {
        "internalType": "bool",
        "name": "excluded",
        "type": "bool"
      }
    ],
    "name": "setExcludedFromFees",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "bool",
        "name": "enabled",
        "type": "bool"
      }
    ],
    "name": "setSwapEnabled",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "newTaxWallet",
        "type": "address"
      }
    ],
    "name": "setTaxWallet",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint16",
        "name": "newInitialBuyTaxBps",
        "type": "uint16"
      },
      {
        "internalType": "uint16",
        "name": "newFinalBuyTaxBps",
        "type": "uint16"
      },
      {
        "internalType": "uint16",
        "name": "newInitialSellTaxBps",
        "type": "uint16"
      },
      {
        "internalType": "uint16",
        "name": "newFinalSellTaxBps",
        "type": "uint16"
      }
    ],
    "name": "setTaxes",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "swapEnabled",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "symbol",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "taxWallet",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "taxesAndLimitsRemoved",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalSupply",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "tradingActive",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "tradingActiveBlock",
    "outputs": [
      {
        "internalType": "uint32",
        "name": "",
        "type": "uint32"
      }
    ],
    "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": "uniswapV2Pair",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  }
]

Source code

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

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

import { IUniswapV2Factory } from "../interfaces/IUniswapV2Factory.sol";
import { IUniswapV2Pair } from "../interfaces/IUniswapV2Pair.sol";
import { IUniswapV2Router02 } from "../interfaces/IUniswapV2Router02.sol";

contract BankrollToken is ERC20, ERC20Burnable, ERC20Permit, Ownable {
    using SafeERC20 for IERC20;

    uint16 public constant BPS_DENOMINATOR = 10_000;

    struct TaxConfig {
        uint16 initialBuyTaxBps;
        uint16 finalBuyTaxBps;
        uint16 initialSellTaxBps;
        uint16 finalSellTaxBps;
        uint32 taxSwitchoverBlocks;
        uint16 maxTaxBps;
    }

    struct LimitConfig {
        bool limitsEnabled;
        uint256 maxWalletAmount;
    }

    struct ClogConfig {
        bool autoSwapEnabled;
        uint256 maxSwapAmount;
        uint32 minBlocksBetweenSwaps;
    }

    struct LaunchTokenConfig {
        string name;
        string symbol;
        uint8 decimals_;
        uint256 totalSupply;
        uint256 poolTokenAmount;
        address taxWallet;
        address uniswapV2Router;
        TaxConfig tax;
        LimitConfig limits;
        ClogConfig clog;
    }

    IUniswapV2Router02 public immutable UNISWAP_V2_ROUTER;
    uint8 private immutable TOKEN_DECIMALS;
    uint16 public immutable MAX_TAX_BPS;
    uint32 public immutable TAX_SWITCHOVER_BLOCKS;
    uint256 public immutable POOL_TOKEN_AMOUNT;

    address public uniswapV2Pair;
    address public taxWallet;

    uint16 public initialBuyTaxBps;
    uint16 public finalBuyTaxBps;
    uint16 public initialSellTaxBps;
    uint16 public finalSellTaxBps;

    bool public tradingActive;
    bool public initialLiquidityAdded;
    bool public launchTaxesFinalized;
    bool public limitsEnabled;
    bool public swapEnabled;
    bool public taxesAndLimitsRemoved;
    bool private swapping;

    uint32 public tradingActiveBlock;
    uint32 public minBlocksBetweenSwaps;
    uint32 public lastSwapBlock;

    uint256 public maxWalletAmount;
    uint256 public maxSwapAmount;

    mapping(address account => bool excluded) public isExcludedFromFees;
    mapping(address pair => bool enabled) public automatedMarketMakerPairs;

    event PairCreated(address indexed pair);
    event InitialLiquidityAdded(
        address indexed pair, uint256 tokenAmount, uint256 ethAmount, uint256 liquidity
    );
    event PublicTradingOpened(uint32 tradingActiveBlock);
    event ExcludedFromFeesSet(address indexed account, bool excluded);
    event TaxesUpdated(
        uint16 initialBuyTaxBps,
        uint16 finalBuyTaxBps,
        uint16 initialSellTaxBps,
        uint16 finalSellTaxBps
    );
    event LimitsRemoved();
    event TaxesAndLimitsRemoved();
    event SwapEnabledSet(bool enabled);
    event TaxWalletUpdated(address indexed taxWallet);
    event TaxTokensSwapped(uint256 tokensSold);
    event RecoveredERC20(address indexed token, address indexed to, uint256 amount);

    error AlreadySet();
    error InvalidAmount();
    error InvalidRecipient();
    error InvalidTax();
    error LimitsAlreadyRemoved();
    error NotTaxWallet();
    error NotOwnerOrTaxWallet();
    error PairNotCreated();
    error InitialLiquidityAlreadyAdded();
    error InitialLiquidityNotAdded();
    error ProtectedExclusion();
    error SwapInProgress();
    error TaxesAndLimitsAlreadyRemoved();
    error TradingAlreadyActive();
    error TradingNotActive();
    error TradingNotOpen();
    error UnauthorizedTransferBeforeTrading();

    /**
     * @notice Deploys a configured Base Uniswap v2 launch token.
     * @param config Token metadata, launch allocation, authorities, tax, limits, and clog settings.
     */
    constructor(LaunchTokenConfig memory config)
        ERC20(config.name, config.symbol)
        ERC20Permit(config.name)
        Ownable(msg.sender)
    {
        TOKEN_DECIMALS = config.decimals_;
        POOL_TOKEN_AMOUNT = config.poolTokenAmount;
        taxWallet = config.taxWallet;
        UNISWAP_V2_ROUTER = IUniswapV2Router02(config.uniswapV2Router);

        initialBuyTaxBps = config.tax.initialBuyTaxBps;
        finalBuyTaxBps = config.tax.finalBuyTaxBps;
        initialSellTaxBps = config.tax.initialSellTaxBps;
        finalSellTaxBps = config.tax.finalSellTaxBps;
        MAX_TAX_BPS = config.tax.maxTaxBps;
        TAX_SWITCHOVER_BLOCKS = config.tax.taxSwitchoverBlocks;

        limitsEnabled = config.limits.limitsEnabled;
        maxWalletAmount = config.limits.maxWalletAmount;

        swapEnabled = config.clog.autoSwapEnabled;
        maxSwapAmount = config.clog.maxSwapAmount;
        minBlocksBetweenSwaps = config.clog.minBlocksBetweenSwaps;
        launchTaxesFinalized = true;

        _setFeeExcluded(msg.sender, true);
        _setFeeExcluded(address(this), true);
        _setFeeExcluded(config.taxWallet, true);
        _setFeeExcluded(config.uniswapV2Router, true);
        _setFeeExcluded(address(0xdead), true);

        _mint(address(this), config.poolTokenAmount);
        uint256 retainedSupply = config.totalSupply - config.poolTokenAmount;
        if (retainedSupply != 0) {
            _mint(msg.sender, retainedSupply);
        }
    }

    /**
     * @notice Returns the configured display decimals for the token.
     * @return Token decimals.
     */
    function decimals() public view override returns (uint8) {
        return TOKEN_DECIMALS;
    }

    /**
     * @notice Creates the Uniswap v2 WETH pair before Base launch construction.
     * @return pair The created pair address.
     */
    function createPair() external onlyOwner returns (address pair) {
        if (tradingActive) revert TradingAlreadyActive();

        IUniswapV2Factory factory = IUniswapV2Factory(UNISWAP_V2_ROUTER.factory());
        address weth = UNISWAP_V2_ROUTER.WETH();
        pair = factory.createPair(address(this), weth);

        uniswapV2Pair = pair;
        automatedMarketMakerPairs[pair] = true;

        emit PairCreated(pair);
    }

    /**
     * @notice Adds initial Uniswap v2 liquidity while public trading remains closed.
     * @param tokenAmount Amount of this token to pair with the supplied ETH.
     * @param amountTokenMin Minimum token amount accepted by the router.
     * @param amountEthMin Minimum ETH amount accepted by the router.
     * @param lpRecipient Recipient of the minted LP tokens.
     */
    function addInitialLiquidity(
        uint256 tokenAmount,
        uint256 amountTokenMin,
        uint256 amountEthMin,
        address lpRecipient
    ) external payable onlyOwner {
        address pair = uniswapV2Pair;
        if (pair == address(0)) revert PairNotCreated();
        if (tradingActive) revert TradingAlreadyActive();
        if (initialLiquidityAdded) revert InitialLiquidityAlreadyAdded();

        IUniswapV2Pair(pair).skim(taxWallet);
        _approve(address(this), address(UNISWAP_V2_ROUTER), type(uint256).max);

        (uint256 amountToken, uint256 amountEth, uint256 liquidity) = UNISWAP_V2_ROUTER.addLiquidityETH{
            value: msg.value
        }(
            address(this), tokenAmount, amountTokenMin, amountEthMin, lpRecipient, block.timestamp
        );

        initialLiquidityAdded = true;

        emit InitialLiquidityAdded(pair, amountToken, amountEth, liquidity);
    }

    /**
     * @notice Opens public trading after liquidity and exempt launch-wallet buys are complete.
     */
    function openTrading() external onlyOwner {
        if (uniswapV2Pair == address(0)) revert PairNotCreated();
        if (!initialLiquidityAdded) revert InitialLiquidityNotAdded();
        if (tradingActive) revert TradingAlreadyActive();

        tradingActive = true;
        tradingActiveBlock = uint32(block.number);

        emit PublicTradingOpened(tradingActiveBlock);
    }

    /**
     * @notice Adds or removes permanent fee, limit, and pre-trading exemptions.
     * @dev Excluded accounts can trade before public open and remain fee/max-wallet exempt after open.
     * @param accounts Accounts to update.
     * @param excluded Whether each account should be excluded.
     */
    function setExcludedFromFees(address[] calldata accounts, bool excluded)
        external
        onlyOwnerOrTaxWallet
    {
        for (uint256 i = 0; i < accounts.length; i++) {
            address account = accounts[i];
            if (account == address(0)) revert InvalidRecipient();
            if (automatedMarketMakerPairs[account]) revert ProtectedExclusion();
            if (!excluded && _isProtectedExclusion(account)) revert ProtectedExclusion();

            _setFeeExcluded(account, excluded);

            emit ExcludedFromFeesSet(account, excluded);
        }
    }

    /**
     * @notice Updates tax values after launch finalization.
     * @dev All provided values must be less than or equal to `MAX_TAX_BPS`.
     * @param newInitialBuyTaxBps New initial buy tax in basis points.
     * @param newFinalBuyTaxBps New final buy tax in basis points.
     * @param newInitialSellTaxBps New initial sell tax in basis points.
     * @param newFinalSellTaxBps New final sell tax in basis points.
     */
    function setTaxes(
        uint16 newInitialBuyTaxBps,
        uint16 newFinalBuyTaxBps,
        uint16 newInitialSellTaxBps,
        uint16 newFinalSellTaxBps
    ) external onlyTaxWallet {
        if (taxesAndLimitsRemoved) revert TaxesAndLimitsAlreadyRemoved();
        if (!launchTaxesFinalized) revert TradingNotOpen();
        if (
            newInitialBuyTaxBps > MAX_TAX_BPS || newFinalBuyTaxBps > MAX_TAX_BPS
                || newInitialSellTaxBps > MAX_TAX_BPS || newFinalSellTaxBps > MAX_TAX_BPS
        ) {
            revert InvalidTax();
        }

        initialBuyTaxBps = newInitialBuyTaxBps;
        finalBuyTaxBps = newFinalBuyTaxBps;
        initialSellTaxBps = newInitialSellTaxBps;
        finalSellTaxBps = newFinalSellTaxBps;

        emit TaxesUpdated(
            newInitialBuyTaxBps, newFinalBuyTaxBps, newInitialSellTaxBps, newFinalSellTaxBps
        );
    }

    /**
     * @notice Updates the tax wallet in one step.
     * @param newTaxWallet New tax wallet address.
     */
    function setTaxWallet(address newTaxWallet) external onlyTaxWallet {
        if (newTaxWallet == address(0)) revert InvalidRecipient();
        address oldTaxWallet = taxWallet;
        taxWallet = newTaxWallet;
        _clearRoleExclusionIfUnused(oldTaxWallet);
        _setFeeExcluded(taxWallet, true);
        emit TaxWalletUpdated(taxWallet);
    }

    /**
     * @notice Permanently removes max wallet, max buy, and max sell checks.
     */
    function removeLimits() external onlyTaxWallet {
        if (!limitsEnabled) revert LimitsAlreadyRemoved();
        limitsEnabled = false;
        emit LimitsRemoved();
    }

    /**
     * @notice Permanently removes all taxes, limits, and automatic tax-token swaps.
     */
    function removeTaxesAndLimits() external onlyTaxWallet {
        taxesAndLimitsRemoved = true;
        limitsEnabled = false;
        swapEnabled = false;
        initialBuyTaxBps = 0;
        finalBuyTaxBps = 0;
        initialSellTaxBps = 0;
        finalSellTaxBps = 0;
        emit TaxesAndLimitsRemoved();
    }

    /**
     * @notice Enables or disables automatic tax-token swaps.
     * @param enabled Whether auto-swap should be enabled.
     */
    function setSwapEnabled(bool enabled) external onlyTaxWallet {
        if (taxesAndLimitsRemoved) revert TaxesAndLimitsAlreadyRemoved();
        swapEnabled = enabled;
        emit SwapEnabledSet(enabled);
    }

    /**
     * @notice Privately swaps accumulated tax tokens for ETH sent directly to the tax wallet.
     * @param tokenAmount Amount of accumulated tax tokens to sell.
     * @param minOut Minimum ETH output accepted by the router.
     */
    function manualSwap(uint256 tokenAmount, uint256 minOut) external onlyTaxWallet {
        _swapTaxTokens(tokenAmount, minOut);
    }

    /**
     * @notice Recovers ERC-20 tokens sent to this contract.
     * @param token ERC-20 token to recover.
     * @param amount Amount to recover.
     * @param to Recipient. Own-token recovery must go to `taxWallet`.
     */
    function recoverERC20(address token, uint256 amount, address to) external onlyTaxWallet {
        if (token == address(0) || to == address(0) || amount == 0) revert InvalidAmount();
        if (token == address(this) && to != taxWallet) revert InvalidRecipient();

        IERC20(token).safeTransfer(to, amount);
        emit RecoveredERC20(token, to, amount);
    }

    modifier onlyTaxWallet() {
        _checkTaxWallet();
        _;
    }

    modifier onlyOwnerOrTaxWallet() {
        _checkOwnerOrTaxWallet();
        _;
    }

    function _checkTaxWallet() private view {
        if (msg.sender != taxWallet) revert NotTaxWallet();
    }

    function _checkOwnerOrTaxWallet() private view {
        if (msg.sender != owner() && msg.sender != taxWallet) revert NotOwnerOrTaxWallet();
    }

    function _update(address from, address to, uint256 amount) internal override {
        if (from == address(0) || to == address(0)) {
            super._update(from, to, amount);
            return;
        }

        if (swapping) {
            super._update(from, to, amount);
            return;
        }

        if (!tradingActive && !isExcludedFromFees[from] && !isExcludedFromFees[to]) {
            revert UnauthorizedTransferBeforeTrading();
        }

        if (taxesAndLimitsRemoved) {
            super._update(from, to, amount);
            return;
        }

        bool isBuy = automatedMarketMakerPairs[from];
        bool isSell = automatedMarketMakerPairs[to];
        bool takeFee = tradingActive && !isExcludedFromFees[from] && !isExcludedFromFees[to];
        uint256 feeAmount = takeFee ? _feeAmount(amount, isBuy, isSell) : 0;
        uint256 transferAmount = amount - feeAmount;

        _enforceLimits(to, transferAmount, isBuy, isSell);

        if (_shouldAutoSwap(from, isSell)) {
            _swapTaxTokens(_min(_min(balanceOf(address(this)), maxSwapAmount), amount), 0);
        }

        if (feeAmount > 0) {
            super._update(from, address(this), feeAmount);
        }
        super._update(from, to, transferAmount);
    }

    function _feeAmount(uint256 amount, bool isBuy, bool isSell) private view returns (uint256) {
        uint16 taxBps;
        if (isBuy) {
            taxBps = _currentBuyTaxBps();
        } else if (isSell) {
            taxBps = _currentSellTaxBps();
        }
        return taxBps == 0 ? 0 : (amount * taxBps) / BPS_DENOMINATOR;
    }

    function _currentBuyTaxBps() private view returns (uint16) {
        return _initialTaxPeriodActive() ? initialBuyTaxBps : finalBuyTaxBps;
    }

    function _currentSellTaxBps() private view returns (uint16) {
        return _initialTaxPeriodActive() ? initialSellTaxBps : finalSellTaxBps;
    }

    function _initialTaxPeriodActive() private view returns (bool) {
        return tradingActive && block.number < uint256(tradingActiveBlock) + TAX_SWITCHOVER_BLOCKS;
    }

    function _enforceLimits(address to, uint256 transferAmount, bool isBuy, bool isSell)
        private
        view
    {
        if (!limitsEnabled) return;

        if (isBuy && !isExcludedFromFees[to]) {
            if (maxWalletAmount != 0 && balanceOf(to) + transferAmount > maxWalletAmount) {
                revert InvalidAmount();
            }
            return;
        }

        if (isSell) return;

        if (!isExcludedFromFees[to]) {
            if (maxWalletAmount != 0 && balanceOf(to) + transferAmount > maxWalletAmount) {
                revert InvalidAmount();
            }
        }
    }

    function _shouldAutoSwap(address from, bool isSell) private view returns (bool) {
        if (!isSell || from == address(this) || isExcludedFromFees[from]) return false;
        if (!swapEnabled || maxSwapAmount == 0) return false;
        if (balanceOf(address(this)) < _swapThresholdAmount()) return false;
        return block.number >= uint256(lastSwapBlock) + minBlocksBetweenSwaps;
    }

    function _swapThresholdAmount() private view returns (uint256) {
        return ((maxSwapAmount - 1) / 20) + 1;
    }

    function _swapTaxTokens(uint256 tokenAmount, uint256 minOut) private {
        if (tokenAmount == 0 || tokenAmount > balanceOf(address(this))) revert InvalidAmount();
        if (swapping) revert SwapInProgress();

        address[] memory path = new address[](2);
        path[0] = address(this);
        path[1] = UNISWAP_V2_ROUTER.WETH();

        swapping = true;
        UNISWAP_V2_ROUTER.swapExactTokensForETHSupportingFeeOnTransferTokens(
            tokenAmount, minOut, path, taxWallet, block.timestamp
        );
        swapping = false;
        lastSwapBlock = uint32(block.number);
        emit TaxTokensSwapped(tokenAmount);
    }

    function _setFeeExcluded(address account, bool excluded) private {
        isExcludedFromFees[account] = excluded;
    }

    function _clearRoleExclusionIfUnused(address account) private {
        if (
            account == owner() || account == address(this) || account == taxWallet
                || account == address(UNISWAP_V2_ROUTER) || account == address(0xdead)
        ) {
            return;
        }
        _setFeeExcluded(account, false);
    }

    function _isProtectedExclusion(address account) private view returns (bool) {
        return account == owner() || account == address(this) || account == taxWallet
            || account == address(UNISWAP_V2_ROUTER) || account == address(0xdead);
    }

    function _min(uint256 a, uint256 b) private pure returns (uint256) {
        return a < b ? a : b;
    }
}
Chain explorer2193msChain node86ms