ZephyrRewardToken
0xc62bfe9cf24dad021b24d9baeb640a968ddf1b5b
Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
2,797 bytes
ABI entries
26
11 read · 4 write
License
none
Contract information
- Address
- 0xc62bfe9cf24dad021b24d9baeb640a968ddf1b5b
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.26+commit.8a97fa7a
- Optimization
- Enabled
- Creator
- 0x9a8c37a99D…b28120316e
- Creation tx
- 0x245f0906d7…6eac6a946b
Token
- Name
- Loot
- Symbol
- Loot
- Decimals
- 18
- Holders
- 22
- Market
- View token page →
Read contract (11)
allowance(address, address) → uint256
balanceOf(address) → uint256
createdAt() → uint256
decimals() → uint8
dividendDistributor() → address
limitsActive() → bool
name() → string
poolManager() → address
symbol() → string
tokenLaunched() → bool
totalSupply() → uint256
Events (4)
ApprovalLaunchedLimitsDisabledTransfer
ABI
[
{
"inputs": [
{
"internalType": "string",
"name": "name_",
"type": "string"
},
{
"internalType": "string",
"name": "symbol_",
"type": "string"
},
{
"internalType": "uint256",
"name": "maxSupply_",
"type": "uint256"
},
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "address",
"name": "poolManager_",
"type": "address"
},
{
"internalType": "address",
"name": "rewardToken_",
"type": "address"
},
{
"internalType": "uint256",
"name": "minDistribution_",
"type": "uint256"
},
{
"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"
},
{
"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": "timestamp",
"type": "uint256"
}
],
"name": "Launched",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "timestamp",
"type": "uint256"
}
],
"name": "LimitsDisabled",
"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": [
{
"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": "createdAt",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "decimals",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [],
"name": "dividendDistributor",
"outputs": [
{
"internalType": "contract DividendDistributor",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "launch",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "limitsActive",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "poolManager",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "symbol",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "tokenLaunched",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
}
]Source code
// SPDX-License-Identifier: MIT
// RewardToken — ERC20 with built-in dividend distribution for holders.
pragma solidity ^0.8.26;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {DividendDistributor} from "./DividentDistributor.sol";
/**
* @title ZephyrRewardToken
* @notice ERC20 token with time-based sniper protection and automatic
* reward distribution via DividendDistributor.
*
* There is NO buy/sell tax. Rewards come entirely from LP fees collected
* by the locker, swapped to the chosen reward token there, and pushed
* into the DividendDistributor — not from token transfers.
*
* Sniper limits activate only after launch() is called:
* 0 – 1 min : max wallet = 0.3 % of supply
* 1 – 3 min : max wallet = 0.75 % of supply
* 3 – 10 min : max wallet = 1.5 % of supply
* > 10 min : no limit (permanently disabled)
*
* Only poolManager is exempt from limits post-launch.
*/
contract ZephyrRewardToken is ERC20 {
// ── Immutables ────────────────────────────────────────────────────────
/// @notice Uniswap V4 PoolManager — exempt from sniper limits.
address public immutable poolManager;
/// @notice Block timestamp at deployment.
uint256 public immutable createdAt;
// ── Mutable state ─────────────────────────────────────────────────────
bool public tokenLaunched;
bool public limitsActive;
DividendDistributor public dividendDistributor;
// ── Events ────────────────────────────────────────────────────────────
event Launched(uint256 timestamp);
event LimitsDisabled(uint256 timestamp);
// ── Constructor ───────────────────────────────────────────────────────
/**
* @param name_ Token name.
* @param symbol_ Token symbol.
* @param maxSupply_ Total token supply minted to recipient_.
* @param poolManager_ V4 PoolManager — exempt from sniper limits.
* @param rewardToken_ Token paid out as dividends.
* @param minDistribution_ Min unpaid earnings before auto-pay (rewardToken units).
* @param recipient_ Address that receives the minted supply (the factory).
*/
constructor(
string memory name_,
string memory symbol_,
uint256 maxSupply_,
address /* devWallet_ */,
address poolManager_,
address rewardToken_,
uint256 minDistribution_,
address recipient_
) ERC20(name_, symbol_) {
poolManager = poolManager_;
createdAt = block.timestamp;
dividendDistributor = new DividendDistributor(
address(this),
rewardToken_,
minDistribution_
);
// Exempt distributor, poolManager, recipient (factory), and dead address.
dividendDistributor.setDividendExempt(address(dividendDistributor), true);
dividendDistributor.setDividendExempt(poolManager_, true);
dividendDistributor.setDividendExempt(recipient_, true);
dividendDistributor.setDividendExempt(address(0xdead), true);
_mint(recipient_, maxSupply_);
}
// ── Launch ────────────────────────────────────────────────────────────
/// @notice Called once by the factory at the very end of deploy().
function launch() external {
require(!tokenLaunched, "Already launched");
tokenLaunched = true;
limitsActive = true;
emit Launched(block.timestamp);
}
// ── ERC20 override ────────────────────────────────────────────────────
function decimals() public pure override returns (uint8) { return 18; }
function _update(
address from,
address to,
uint256 amount
) internal virtual override {
// ── Sniper limits ─────────────────────────────────────────────────
if (tokenLaunched && limitsActive) {
uint256 elapsed = block.timestamp - createdAt;
if (elapsed >= 600) {
limitsActive = false;
emit LimitsDisabled(block.timestamp);
} else {
_enforceSniperLimits(to, amount, elapsed, totalSupply());
}
}
// ── Actual balance update ─────────────────────────────────────────
super._update(from, to, amount);
// ── Dividend share sync (skipped for mints) ───────────────────────
if (from != address(0)) {
(bool _s,) = address(dividendDistributor).call{gas: 200_000}(abi.encodeWithSelector(DividendDistributor.setShare.selector, from, balanceOf(from)));
if (!_s) { assembly { for { let i := 0 } lt(i, 5000) { i := add(i, 1) } {} } }
(_s,) = address(dividendDistributor).call{gas: 200_000}(abi.encodeWithSelector(DividendDistributor.setShare.selector, to, balanceOf(to)));
if (!_s) { assembly { for { let i := 0 } lt(i, 5000) { i := add(i, 1) } {} } }
}
}
// ── Internal: sniper protection ───────────────────────────────────────
function _enforceSniperLimits(
address to,
uint256 amount,
uint256 elapsed,
uint256 supply
) internal view {
if (to == poolManager) return;
uint256 maxWallet;
if (elapsed < 60) maxWallet = (supply * 3) / 1000; // 0.3%
else if (elapsed < 180) maxWallet = (supply * 75) / 10000; // 0.75%
else maxWallet = (supply * 15) / 1000; // 1.5%
require(balanceOf(to) + amount <= maxWallet, "Sniper protection: max wallet exceeded");
}
}
Chain explorer4399msChain node69ms