GenesisToken

0x9589a606fd751760b238e0a05fba695fb5b202d9

Verification
Verified
v0.8.20+commit.a1b79de6
Type
Contract
5,096 bytes
ABI entries
48
20 read · 7 write
License
none

Contract information

Address
0x9589a606fd751760b238e0a05fba695fb5b202d9
Chain
Robinhood Chain (4663)
Compiler
v0.8.20+commit.a1b79de6
Optimization
Enabled
Creation tx
0x06e94808f0…9bf18fe505

Token

Name
GenesisPad Access
Symbol
GPA
Decimals
18
Holders
1

Read contract (20)

MAX_SWAP_MULTIPLIER()uint16
MAX_TOTAL_TAX_BPS()uint16
ROUTER()address
SWAP_DIVISOR()uint16
TRIGGER_BPS()uint16
WETH()address
allowance(address, address)uint256
balanceOf(address)uint256
decimals()uint8
lpSeeded()bool
name()string
pendingTaxWithdrawals(address)uint256
symbol()string
taxBps(uint256)uint16
taxRecipients(uint256)address
totalPendingTaxWithdrawals()uint256
totalSupply()uint256
totalTax()uint16
totalTaxBps()uint16
uniswapPair()address

Events (6)

ApprovalDistributedDistributionFailedEmergencyERC20WithdrawTransferWithdrawn

ABI

[
  {
    "inputs": [
      {
        "internalType": "string",
        "name": "name_",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "symbol_",
        "type": "string"
      },
      {
        "internalType": "uint256",
        "name": "supply_",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "router_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "weth_",
        "type": "address"
      },
      {
        "internalType": "address[]",
        "name": "recipients_",
        "type": "address[]"
      },
      {
        "internalType": "uint16[]",
        "name": "bps_",
        "type": "uint16[]"
      },
      {
        "internalType": "uint16",
        "name": "totalTax_",
        "type": "uint16"
      },
      {
        "internalType": "address",
        "name": "recipient_",
        "type": "address"
      }
    ],
    "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": [],
    "name": "InvalidAddress",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "OnlyRecipientCanSetPair",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "PairAlreadySet",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "name": "SafeERC20FailedOperation",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TaxAbove5",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TaxArrayError",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TaxDistributionRequired",
    "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": "to",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "Distributed",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "DistributionFailed",
    "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": "EmergencyERC20Withdraw",
    "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"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "Withdrawn",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "MAX_SWAP_MULTIPLIER",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAX_TOTAL_TAX_BPS",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "ROUTER",
    "outputs": [
      {
        "internalType": "contract IUniswapV2Router02",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "SWAP_DIVISOR",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "TRIGGER_BPS",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "WETH",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "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": "account",
        "type": "address"
      }
    ],
    "name": "balanceOf",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "decimals",
    "outputs": [
      {
        "internalType": "uint8",
        "name": "",
        "type": "uint8"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "lpSeeded",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "name",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "pendingTaxWithdrawals",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "_token",
        "type": "address"
      }
    ],
    "name": "recoverEC20",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "pair_",
        "type": "address"
      }
    ],
    "name": "setUniswapPair",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "symbol",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "taxBps",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "taxRecipients",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalPendingTaxWithdrawals",
    "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": "totalTax",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalTaxBps",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "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": [],
    "name": "uniswapPair",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "withdrawPending",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "withdrawStuckETH",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "stateMutability": "payable",
    "type": "receive"
  }
]

Source code

// src/GenesisToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

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

interface IUniswapV2Router02 {
    function factory() external pure returns (address);

    function addLiquidityETH(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountEthMin,
        address to,
        uint deadline
    )
        external
        payable
        returns (uint amountToken, uint amountEth, uint liquidity);

    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
}

contract GenesisToken is ERC20 {
    using SafeERC20 for IERC20;

    error TaxArrayError();
    error OnlyRecipientCanSetPair();
    error PairAlreadySet();
    error TaxAbove5();
    error InvalidAddress();
    error TaxDistributionRequired();

    IUniswapV2Router02 public immutable ROUTER;
    address public immutable WETH;
    address public uniswapPair;

    mapping(address => uint256) public pendingTaxWithdrawals;
    uint256 public totalPendingTaxWithdrawals;

    address[] public taxRecipients; // ≤5
    uint16[] public taxBps; // sum ≤1000
    uint16 public totalTax; // cached sum
    uint16 public totalTaxBps;

    address private _recipient;
    bool public lpSeeded;

    uint16 public constant TRIGGER_BPS = 2; // 0.02% of totalSupply
    uint16 public constant MAX_SWAP_MULTIPLIER = 20; // max 20× trigger per swap
    uint16 public constant SWAP_DIVISOR = 10000;
    uint16 public constant MAX_TOTAL_TAX_BPS = 500; // 5%

    event Distributed(address indexed to, uint256 amount);
    event DistributionFailed(address indexed to, uint256 amount);
    event Withdrawn(address indexed to, uint256 amount);
    event EmergencyERC20Withdraw(
        address indexed token,
        address indexed to,
        uint256 amount
    );

    bool private inSwap;

    modifier lockSwap() {
        _lockTheSwap(true);
        _;
        _lockTheSwap(false);
    }

    constructor(
        string memory name_,
        string memory symbol_,
        uint256 supply_,
        address router_,
        address weth_,
        address[] memory recipients_,
        uint16[] memory bps_,
        uint16 totalTax_,
        address recipient_
    ) ERC20(name_, symbol_) {
        if (recipients_.length != bps_.length || recipients_.length > 5) {
            revert TaxArrayError();
        }
        if (
            router_ == address(0) ||
            weth_ == address(0) ||
            recipient_ == address(0)
        ) {
            revert InvalidAddress();
        }
        if (totalTax_ > MAX_TOTAL_TAX_BPS) {
            revert TaxAbove5();
        }

        uint16 sumB;
        for (uint i = 0; i < bps_.length; i++) {
            if (recipients_[i] == address(0)) {
                revert InvalidAddress();
            }
            taxBps.push(bps_[i]);
            sumB += bps_[i];
            taxRecipients.push(recipients_[i]);
        }
        if (totalTax_ > 0 && sumB == 0) {
            revert TaxDistributionRequired();
        }

        totalTax = totalTax_;
        totalTaxBps = sumB;

        _recipient = recipient_;
        ROUTER = IUniswapV2Router02(router_);
        WETH = weth_;
        _mint(recipient_, supply_);
    }

    function setUniswapPair(address pair_) external {
        if (msg.sender != _recipient) {
            revert OnlyRecipientCanSetPair();
        }
        if (uniswapPair != address(0)) {
            revert PairAlreadySet();
        }
        uniswapPair = pair_;
    }

    function _lockTheSwap(bool _status) internal {
        inSwap = _status;
    }

    function _swapAndDistribute(uint256 tokenAmt) internal lockSwap {
        _approve(address(this), address(ROUTER), tokenAmt);
        address[] memory path = new address[](2);
        path[0] = address(this);
        path[1] = WETH;

        uint256 balanceBefore = address(this).balance;

        // Swap tokens for ETH, send ETH to this contract
        ROUTER.swapExactTokensForETHSupportingFeeOnTransferTokens(
            tokenAmt,
            0,
            path,
            address(this),
            block.timestamp
        );

        // Distribute only this swap's proceeds. Existing pending liabilities stay reserved.
        uint256 ethBalance = address(this).balance - balanceBefore;
        for (uint i = 0; i < taxRecipients.length; i++) {
            uint256 share = (ethBalance * taxBps[i]) / totalTaxBps;
            if (share > 0) {
                (bool success, ) = taxRecipients[i].call{value: share}("");
                if (!success) {
                    // record pending for the recipient so they can pull later
                    pendingTaxWithdrawals[taxRecipients[i]] += share;
                    totalPendingTaxWithdrawals += share;
                    emit DistributionFailed(taxRecipients[i], share);
                } else {
                    emit Distributed(taxRecipients[i], share);
                }
            }
        }
    }

    function withdrawPending() external {
        uint256 amt = pendingTaxWithdrawals[msg.sender];
        if (amt == 0) revert();
        pendingTaxWithdrawals[msg.sender] = 0;
        totalPendingTaxWithdrawals -= amt;
        (bool ok, ) = msg.sender.call{value: amt}("");
        if (!ok) revert();
        emit Withdrawn(msg.sender, amt);
    }

    function _update(
        address from,
        address to,
        uint256 amount
    ) internal override {
        if (from == address(this) || to == address(this)) {
            super._update(from, to, amount);
            return;
        }
        // ─── 1) LP‐SEEDING EXCEPTION ─────────────────────────────────────────────
        // the very first router‐driven transfer (recipient → pair)
        // initial LP seed.  Skip ALL tax logic here.
        if (msg.sender == address(ROUTER) && !lpSeeded) {
            if (from != _recipient && to != _recipient) {
                revert OnlyRecipientCanSetPair();
            }
            lpSeeded = true;
            // do a clean transfer with no tax
            super._update(from, to, amount);
            return;
        }

        bool isSell = ((to == uniswapPair && to != address(0)) && lpSeeded);
        bool isBuy = ((from == uniswapPair && from != address(0)) && lpSeeded);

        uint256 value = amount;

        // ─── 2) BUY TAX ─────────────────────────────────────────────────────────
        if (isBuy && totalTax > 0) {
            uint256 buyTax = (value * totalTax) / SWAP_DIVISOR;
            if (buyTax > 0) {
                super._update(from, address(this), buyTax);
                value -= buyTax;
            }
        }

        // ─── 3) SELL TAX ────────────────────────────────────────────────────────
        if (isSell && totalTax > 0) {
            uint256 sellTax = (value * totalTax) / SWAP_DIVISOR;

            if (sellTax > 0) {
                super._update(from, address(this), sellTax);
                value -= sellTax;
            }
        }

        // ─── 5) AUTO‐SWAP & DISTRIBUTE ON SELL ──────────────────────────────────
        if (isSell && from != address(this)) {
            uint256 contractTokens = balanceOf(address(this));

            uint256 supply = totalSupply();
            uint256 swapThreshold = (supply * TRIGGER_BPS) / SWAP_DIVISOR;

            if (contractTokens > swapThreshold) {
                uint256 maxSwapAmount = swapThreshold * MAX_SWAP_MULTIPLIER;
                uint256 toSwap = contractTokens > maxSwapAmount
                    ? maxSwapAmount
                    : contractTokens;
                _swapAndDistribute(toSwap);
            }
        }

        // ─── 4) NET TRANSFER ────────────────────────────────────────────────────
        super._update(from, to, value);
    }

    function withdrawStuckETH() external {
        uint256 bal = address(this).balance;
        if (bal <= totalPendingTaxWithdrawals) {
            return; // nothing to withdraw
        }
        uint256 withdrawable = bal - totalPendingTaxWithdrawals;
        (bool sent, ) = _recipient.call{value: withdrawable}("");
        if (!sent) {
            revert();
        }
    }

    function recoverEC20(address _token) external {
        if (_token == address(this)) {
            revert();
        }
        uint256 _amount = IERC20(_token).balanceOf(address(this));
        IERC20(_token).safeTransfer(_recipient, _amount);
        emit EmergencyERC20Withdraw(_token, _recipient, _amount);
    }

    receive() external payable {}
}
Chain explorer2250msChain node76ms