RobinhoodReflectionToken
0xe88f76a87c3ad4072bd72fd728f3b378fdde871e
Verification
Verified
0.8.10+commit.fc410830
Type
Contract
8,802 bytes
ABI entries
54
36 read · 9 write
License
none
Contract information
- Address
- 0xe88f76a87c3ad4072bd72fd728f3b378fdde871e
- Chain
- Robinhood Chain (4663)
- Compiler
- 0.8.10+commit.fc410830
- Optimization
- Enabled
- Creator
- 0x730BA590BD…b6c411183C
- Creation tx
- 0x524c9cd1e5…214f08f07d
Token
- Name
- Mini Cash Cat
- Symbol
- MINICAT
- Decimals
- 9
- Holders
- 1,110
- Market
- View token page →
Read contract (36)
CONTRACT_FEE_BPS() → uint16
FEE_DENOMINATOR() → uint16
LIQUIDITY_FEE_BPS() → uint16
MARKETING_FEE_BPS() → uint16
REFLECTION_FEE_BPS() → uint16
TOTAL_FEE_BPS() → uint16
allowance(address, address) → uint256
balanceOf(address) → uint256
buyFee() → uint16
decimals() → uint8
feeBreakdown() → uint16, uint16, uint16, uint16
feeForTransfer(address, address) → uint16
isReflectionExcluded(address) → bool
isTradeAmountAllowed(uint256) → bool
marketingWallet() → address
maximumTradeTokens() → uint256
minimumTradeTokens() → uint256
name() → string
pendingFeeTokens() → uint256
processingFees() → bool
sellFee() → uint16
swapThreshold() → uint256
symbol() → string
totalLiquidityEthAdded() → uint256
totalLiquidityFeesCollected() → uint256
totalLiquidityTokensAdded() → uint256
totalMarketingEthSent() → uint256
totalMarketingFeesCollected() → uint256
totalReflectionFees() → uint256
totalSupply() → uint256
totalTokensProcessed() → uint256
tradeLimitController() → address
tradeLimitsEnabled() → bool
transferFee() → uint16
uniswapV2Pair() → address
uniswapV2Router() → address
Events (7)
ApprovalFeesProcessedForeignTokenRecoveredNativeRecoveredSwapThresholdUpdatedTradeLimitsUpdatedTransfer
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "routerAddress",
"type": "address"
},
{
"internalType": "address",
"name": "marketingWalletAddress",
"type": "address"
},
{
"internalType": "uint256",
"name": "initialSwapThreshold",
"type": "uint256"
},
{
"internalType": "string",
"name": "tokenName",
"type": "string"
},
{
"internalType": "string",
"name": "tokenSymbol",
"type": "string"
},
{
"internalType": "uint8",
"name": "tokenDecimals",
"type": "uint8"
},
{
"internalType": "uint256",
"name": "initialSupply",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"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": false,
"internalType": "uint256",
"name": "tokensProcessed",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "tokensSwapped",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "nativeReceived",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "liquidityTokensAdded",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "liquidityNativeAdded",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "marketingNativeSent",
"type": "uint256"
}
],
"name": "FeesProcessed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "ForeignTokenRecovered",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "NativeRecovered",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "previousThreshold",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "newThreshold",
"type": "uint256"
}
],
"name": "SwapThresholdUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "minimumNetTokens",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "maximumNetTokens",
"type": "uint256"
},
{
"indexed": false,
"internalType": "bool",
"name": "enabled",
"type": "bool"
}
],
"name": "TradeLimitsUpdated",
"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": "CONTRACT_FEE_BPS",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "FEE_DENOMINATOR",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "LIQUIDITY_FEE_BPS",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MARKETING_FEE_BPS",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "REFLECTION_FEE_BPS",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "TOTAL_FEE_BPS",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"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": "amount",
"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": "buyFee",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [],
"name": "decimals",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"internalType": "uint256",
"name": "subtractedValue",
"type": "uint256"
}
],
"name": "decreaseAllowance",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "feeBreakdown",
"outputs": [
{
"internalType": "uint16",
"name": "reflectionBps",
"type": "uint16"
},
{
"internalType": "uint16",
"name": "liquidityBps",
"type": "uint16"
},
{
"internalType": "uint16",
"name": "marketingBps",
"type": "uint16"
},
{
"internalType": "uint16",
"name": "totalBps",
"type": "uint16"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
}
],
"name": "feeForTransfer",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"internalType": "uint256",
"name": "addedValue",
"type": "uint256"
}
],
"name": "increaseAllowance",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "isReflectionExcluded",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "netTokenAmount",
"type": "uint256"
}
],
"name": "isTradeAmountAllowed",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "marketingWallet",
"outputs": [
{
"internalType": "address payable",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "maximumTradeTokens",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "minimumTradeTokens",
"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": "pendingFeeTokens",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "processingFees",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "recoverForeignToken",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "recoverNative",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "sellFee",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "newThreshold",
"type": "uint256"
}
],
"name": "setSwapThreshold",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "minimumNetTokens",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maximumNetTokens",
"type": "uint256"
}
],
"name": "setTradeLimits",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "swapThreshold",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "symbol",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalLiquidityEthAdded",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalLiquidityFeesCollected",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalLiquidityTokensAdded",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalMarketingEthSent",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalMarketingFeesCollected",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalReflectionFees",
"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": "totalTokensProcessed",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "tradeLimitController",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "tradeLimitsEnabled",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "transferFee",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "sender",
"type": "address"
},
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "uniswapV2Pair",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "uniswapV2Router",
"outputs": [
{
"internalType": "contract IUniswapV2Router02",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"stateMutability": "payable",
"type": "receive"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
interface IUniswapV2Factory {
function createPair(address tokenA, address tokenB) external returns (address pair);
}
interface IUniswapV2Pair {
function getReserves()
external
view
returns (
uint112 reserve0,
uint112 reserve1,
uint32 blockTimestampLast
);
}
interface IUniswapV2Router02 {
function factory() external view returns (address);
function WETH() external view returns (address);
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external;
function addLiquidityETH(
address token,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external payable returns (
uint256 amountToken,
uint256 amountETH,
uint256 liquidity
);
}
/// @title RobinhoodReflectionToken
/// @notice Fixed-supply ERC-20 with permanently untaxed buys and wallet
/// transfers. Transfers into the immutable V2 pair pay a permanent
/// 3.33% reflection, 3.33% liquidity, and 3.33% marketing fee.
/// @dev The sell-side transfer fee is hard-coded at 9.99%. There is no owner,
/// user whitelist, blacklist, mutable fee configuration, launch fee
/// transition, or upgrade path. The deployer can only configure an
/// optional trade token range, update the fee-processing threshold, and
/// recover accidentally sent native ETH or unrelated ERC-20s. The token's
/// own fee balance and immutable-pair LP tokens cannot be recovered. The
/// immutable V2 pair is excluded from reflection rewards.
contract RobinhoodReflectionToken is IERC20 {
uint16 public constant FEE_DENOMINATOR = 10_000;
uint16 public constant REFLECTION_FEE_BPS = 333;
uint16 public constant LIQUIDITY_FEE_BPS = 333;
uint16 public constant MARKETING_FEE_BPS = 333;
uint16 public constant CONTRACT_FEE_BPS =
LIQUIDITY_FEE_BPS + MARKETING_FEE_BPS;
uint16 public constant TOTAL_FEE_BPS =
REFLECTION_FEE_BPS + CONTRACT_FEE_BPS;
uint256 private constant MAX = type(uint256).max;
uint256 private constant MIN_REFLECTION_MULTIPLIER = 1e36;
string private _name;
string private _symbol;
uint8 private immutable _decimals;
uint256 private immutable _totalSupply;
uint256 private _reflectionSupply;
uint256 private _pairTokenBalance;
bool private _processingFees;
uint256 public totalReflectionFees;
uint256 public totalLiquidityFeesCollected;
uint256 public totalMarketingFeesCollected;
uint256 public totalTokensProcessed;
uint256 public totalLiquidityTokensAdded;
uint256 public totalLiquidityEthAdded;
uint256 public totalMarketingEthSent;
mapping(address => uint256) private _reflectionBalances;
mapping(address => mapping(address => uint256)) private _allowances;
IUniswapV2Router02 public immutable uniswapV2Router;
address public immutable uniswapV2Pair;
address payable public immutable marketingWallet;
uint256 public swapThreshold;
address public immutable tradeLimitController;
uint256 public minimumTradeTokens;
uint256 public maximumTradeTokens;
event FeesProcessed(
uint256 tokensProcessed,
uint256 tokensSwapped,
uint256 nativeReceived,
uint256 liquidityTokensAdded,
uint256 liquidityNativeAdded,
uint256 marketingNativeSent
);
event TradeLimitsUpdated(
uint256 minimumNetTokens,
uint256 maximumNetTokens,
bool enabled
);
event SwapThresholdUpdated(
uint256 previousThreshold,
uint256 newThreshold
);
event NativeRecovered(uint256 amount);
event ForeignTokenRecovered(address indexed token, uint256 amount);
constructor(
address routerAddress,
address marketingWalletAddress,
uint256 initialSwapThreshold,
string memory tokenName,
string memory tokenSymbol,
uint8 tokenDecimals,
uint256 initialSupply
) {
require(routerAddress != address(0), "Router cannot be zero");
require(marketingWalletAddress != address(0), "Marketing cannot be zero");
require(marketingWalletAddress != address(this), "Marketing cannot be token");
require(bytes(tokenName).length != 0, "Name cannot be empty");
require(bytes(tokenSymbol).length != 0, "Symbol cannot be empty");
require(initialSupply != 0, "Supply cannot be zero");
require(
initialSupply <= MAX / MIN_REFLECTION_MULTIPLIER,
"Supply is too large"
);
require(
initialSwapThreshold >= 4 && initialSwapThreshold <= initialSupply,
"Invalid swap threshold"
);
IUniswapV2Router02 router = IUniswapV2Router02(routerAddress);
address factoryAddress = router.factory();
address wrappedNative = router.WETH();
require(factoryAddress != address(0), "Factory cannot be zero");
require(wrappedNative != address(0), "WETH cannot be zero");
_name = tokenName;
_symbol = tokenSymbol;
_decimals = tokenDecimals;
_totalSupply = initialSupply;
_reflectionSupply = MAX - (MAX % initialSupply);
_reflectionBalances[msg.sender] = _reflectionSupply;
uniswapV2Router = router;
marketingWallet = payable(marketingWalletAddress);
swapThreshold = initialSwapThreshold;
tradeLimitController = msg.sender;
uniswapV2Pair = IUniswapV2Factory(factoryAddress).createPair(
address(this),
wrappedNative
);
emit Transfer(address(0), msg.sender, initialSupply);
}
receive() external payable {}
function name() external view returns (string memory) {
return _name;
}
function symbol() external view returns (string memory) {
return _symbol;
}
function decimals() external view returns (uint8) {
return _decimals;
}
function totalSupply() external view override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view override returns (uint256) {
if (account == uniswapV2Pair) {
return _pairTokenBalance;
}
return _reflectionBalances[account] / _currentRate();
}
/// @notice The immutable V2 pair is the only address excluded from rewards.
/// @dev This is fixed at construction and is not a mutable exemption list.
function isReflectionExcluded(address account) external view returns (bool) {
return account == uniswapV2Pair;
}
function allowance(address owner, address spender)
external
view
override
returns (uint256)
{
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount)
external
override
returns (bool)
{
_approve(msg.sender, spender, amount);
return true;
}
function increaseAllowance(address spender, uint256 addedValue)
external
returns (bool)
{
_approve(msg.sender, spender, _allowances[msg.sender][spender] + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue)
external
returns (bool)
{
uint256 currentAllowance = _allowances[msg.sender][spender];
require(currentAllowance >= subtractedValue, "Allowance below zero");
unchecked {
_approve(msg.sender, spender, currentAllowance - subtractedValue);
}
return true;
}
function transfer(address recipient, uint256 amount)
external
override
returns (bool)
{
_transfer(msg.sender, recipient, amount);
return true;
}
function transferFrom(
address sender,
address recipient,
uint256 amount
) external override returns (bool) {
_spendAllowance(sender, msg.sender, amount);
_transfer(sender, recipient, amount);
return true;
}
/// @notice Permanent total buy fee in basis points (zero).
function buyFee() external pure returns (uint16) {
return 0;
}
/// @notice Permanent total sell fee in basis points (999 = 9.99%).
function sellFee() external pure returns (uint16) {
return TOTAL_FEE_BPS;
}
/// @notice Permanent wallet transfer fee in basis points (zero).
function transferFee() external pure returns (uint16) {
return 0;
}
function feeBreakdown()
external
pure
returns (
uint16 reflectionBps,
uint16 liquidityBps,
uint16 marketingBps,
uint16 totalBps
)
{
return (
REFLECTION_FEE_BPS,
LIQUIDITY_FEE_BPS,
MARKETING_FEE_BPS,
TOTAL_FEE_BPS
);
}
/// @notice Returns the immutable fee for the supplied route.
/// @dev A normal transfer into the pair is the sell-side route. Transfers
/// from the pair and wallet-to-wallet transfers are untaxed.
function feeForTransfer(address from, address to)
external
view
returns (uint16)
{
return
to == uniswapV2Pair && from != address(this)
? TOTAL_FEE_BPS
: 0;
}
function pendingFeeTokens() external view returns (uint256) {
return balanceOf(address(this));
}
function processingFees() external view returns (bool) {
return _processingFees;
}
/// @notice Enables or disables the net-token range for every buy or sell
/// through the immutable V2 pair.
/// @dev Both values at zero disable the gate. When enabled, the accepted
/// amount is strictly greater than minimumNetTokens and strictly less
/// than maximumNetTokens.
function setTradeLimits(
uint256 minimumNetTokens,
uint256 maximumNetTokens
) external {
require(msg.sender == tradeLimitController, "Only limit controller");
require(
(minimumNetTokens == 0 && maximumNetTokens == 0) ||
(minimumNetTokens < maximumNetTokens &&
maximumNetTokens <= _totalSupply),
"Invalid trade limits"
);
minimumTradeTokens = minimumNetTokens;
maximumTradeTokens = maximumNetTokens;
emit TradeLimitsUpdated(
minimumNetTokens,
maximumNetTokens,
maximumNetTokens != 0
);
}
function tradeLimitsEnabled() public view returns (bool) {
return maximumTradeTokens != 0;
}
/// @notice Updates the token balance that triggers one automatic fee batch.
/// @dev Only the immutable deployment controller can update the threshold.
/// This does not change any fee rate or move accumulated fee tokens.
function setSwapThreshold(uint256 newThreshold) external {
require(msg.sender == tradeLimitController, "Only limit controller");
require(
newThreshold >= 4 && newThreshold <= _totalSupply,
"Invalid swap threshold"
);
uint256 previousThreshold = swapThreshold;
swapThreshold = newThreshold;
emit SwapThresholdUpdated(previousThreshold, newThreshold);
}
/// @notice Recovers native ETH accidentally left in the token contract.
/// @dev The destination is always the immutable deployment controller.
function recoverNative(uint256 amount) external {
require(msg.sender == tradeLimitController, "Only limit controller");
require(amount != 0 && amount <= address(this).balance, "Invalid recovery amount");
(bool success, ) = payable(tradeLimitController).call{value: amount}("");
require(success, "Native recovery failed");
emit NativeRecovered(amount);
}
/// @notice Recovers an unrelated ERC-20 accidentally sent to this contract.
/// @dev The native token's fee inventory and the pair's permanently held
/// automatic LP tokens are intentionally not recoverable.
function recoverForeignToken(address token, uint256 amount) external {
require(msg.sender == tradeLimitController, "Only limit controller");
require(token != address(0) && token.code.length != 0, "Invalid recovery token");
require(token != address(this), "Cannot recover fee tokens");
require(token != uniswapV2Pair, "Cannot recover automatic LP");
require(amount != 0, "Invalid recovery amount");
(bool success, bytes memory result) = token.call(
abi.encodeWithSelector(IERC20.transfer.selector, tradeLimitController, amount)
);
require(
success && (result.length == 0 || abi.decode(result, (bool))),
"Token recovery failed"
);
emit ForeignTokenRecovered(token, amount);
}
/// @notice Returns whether a proposed net token amount would pass the
/// current trade limits.
function isTradeAmountAllowed(uint256 netTokenAmount)
external
view
returns (bool)
{
if (!tradeLimitsEnabled()) {
return true;
}
return
netTokenAmount > minimumTradeTokens &&
netTokenAmount < maximumTradeTokens;
}
function _approve(
address owner,
address spender,
uint256 amount
) private {
require(owner != address(0), "Approve from zero");
require(spender != address(0), "Approve to zero");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _spendAllowance(
address owner,
address spender,
uint256 amount
) private {
uint256 currentAllowance = _allowances[owner][spender];
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "Insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
function _transfer(
address from,
address to,
uint256 amount
) private {
require(from != address(0), "Transfer from zero");
require(to != address(0), "Transfer to zero");
bool pairHasLiquidity =
(from == uniswapV2Pair || to == uniswapV2Pair) &&
_pairHasLiquidity();
if (
amount != 0 &&
!_processingFees &&
to == uniswapV2Pair &&
from != address(this) &&
pairHasLiquidity
) {
uint256 contractBalance = balanceOf(address(this));
if (contractBalance >= swapThreshold) {
_processFees(swapThreshold);
}
}
bool takeFee =
to == uniswapV2Pair &&
!(_processingFees && from == address(this));
uint256 rate = _currentRate();
uint256 reflectedAmount = amount * rate;
uint256 reflectionFeeAmount;
uint256 liquidityFeeAmount;
uint256 marketingFeeAmount;
if (takeFee) {
reflectionFeeAmount = (amount * REFLECTION_FEE_BPS) / FEE_DENOMINATOR;
liquidityFeeAmount = (amount * LIQUIDITY_FEE_BPS) / FEE_DENOMINATOR;
marketingFeeAmount = (amount * MARKETING_FEE_BPS) / FEE_DENOMINATOR;
}
uint256 contractFeeAmount = liquidityFeeAmount + marketingFeeAmount;
uint256 receivedAmount = amount - reflectionFeeAmount - contractFeeAmount;
_enforceTradeLimits(
from,
to,
receivedAmount,
pairHasLiquidity
);
_reflectionBalances[from] -= reflectedAmount;
_reflectionBalances[to] += receivedAmount * rate;
if (from == uniswapV2Pair) {
_pairTokenBalance -= amount;
}
if (to == uniswapV2Pair) {
_pairTokenBalance += receivedAmount;
}
if (contractFeeAmount != 0) {
_reflectionBalances[address(this)] += contractFeeAmount * rate;
totalLiquidityFeesCollected += liquidityFeeAmount;
totalMarketingFeesCollected += marketingFeeAmount;
emit Transfer(from, address(this), contractFeeAmount);
}
if (reflectionFeeAmount != 0) {
_reflectionSupply -= reflectionFeeAmount * rate;
totalReflectionFees += reflectionFeeAmount;
}
emit Transfer(from, to, receivedAmount);
}
function _enforceTradeLimits(
address from,
address to,
uint256 netTokenAmount,
bool pairHasLiquidity
) private view {
if (
_processingFees ||
!pairHasLiquidity ||
!tradeLimitsEnabled()
) {
return;
}
bool isPrimaryPairTrade =
(from == uniswapV2Pair && to != address(uniswapV2Router)) ||
(to == uniswapV2Pair && from != address(this));
if (!isPrimaryPairTrade) {
return;
}
require(
netTokenAmount > minimumTradeTokens,
"Trade below minimum"
);
require(
netTokenAmount < maximumTradeTokens,
"Trade above maximum"
);
}
function _processFees(uint256 tokenAmount) private {
_processingFees = true;
uint256 liquidityAllocation =
(tokenAmount * LIQUIDITY_FEE_BPS) /
CONTRACT_FEE_BPS;
uint256 tokensForLiquidity = liquidityAllocation / 2;
uint256 tokensToSwap = tokenAmount - tokensForLiquidity;
uint256 initialNativeBalance = address(this).balance;
_swapTokensForEth(tokensToSwap);
uint256 nativeReceived = address(this).balance - initialNativeBalance;
uint256 swappedLiquidityTokens = liquidityAllocation - tokensForLiquidity;
uint256 nativeForLiquidity =
(nativeReceived * swappedLiquidityTokens) /
tokensToSwap;
uint256 liquidityTokensUsed;
uint256 liquidityNativeUsed;
if (tokensForLiquidity != 0 && nativeForLiquidity != 0) {
(liquidityTokensUsed, liquidityNativeUsed, ) = _addLiquidity(
tokensForLiquidity,
nativeForLiquidity
);
}
uint256 nativeForMarketing = nativeReceived - liquidityNativeUsed;
if (nativeForMarketing != 0) {
(bool success, ) = marketingWallet.call{value: nativeForMarketing}("");
require(success, "Marketing ETH transfer failed");
}
totalTokensProcessed += tokenAmount;
totalLiquidityTokensAdded += liquidityTokensUsed;
totalLiquidityEthAdded += liquidityNativeUsed;
totalMarketingEthSent += nativeForMarketing;
emit FeesProcessed(
tokenAmount,
tokensToSwap,
nativeReceived,
liquidityTokensUsed,
liquidityNativeUsed,
nativeForMarketing
);
_processingFees = false;
}
function _swapTokensForEth(uint256 tokenAmount) private {
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = uniswapV2Router.WETH();
_approve(address(this), address(uniswapV2Router), tokenAmount);
uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens(
tokenAmount,
0,
path,
address(this),
block.timestamp
);
}
function _addLiquidity(uint256 tokenAmount, uint256 nativeAmount)
private
returns (uint256 tokenUsed, uint256 nativeUsed, uint256 liquidity)
{
_approve(address(this), address(uniswapV2Router), tokenAmount);
return
uniswapV2Router.addLiquidityETH{value: nativeAmount}(
address(this),
tokenAmount,
0,
0,
address(this),
block.timestamp
);
}
function _pairHasLiquidity() private view returns (bool) {
(uint112 reserve0, uint112 reserve1, ) = IUniswapV2Pair(uniswapV2Pair)
.getReserves();
return reserve0 != 0 && reserve1 != 0;
}
function _currentRate() private view returns (uint256) {
uint256 pairReflections = _reflectionBalances[uniswapV2Pair];
uint256 pairTokens = _pairTokenBalance;
uint256 defaultRate = _reflectionSupply / _totalSupply;
if (
pairReflections > _reflectionSupply ||
pairTokens >= _totalSupply
) {
return defaultRate;
}
uint256 eligibleReflections = _reflectionSupply - pairReflections;
uint256 eligibleTokens = _totalSupply - pairTokens;
if (eligibleReflections < defaultRate || eligibleTokens == 0) {
return defaultRate;
}
return eligibleReflections / eligibleTokens;
}
}
Chain explorer6495msChain node79ms