PETRODAO.SOL

// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/utils/math/Math.sol"; interface IERC1363Receiver { function onTokenTransfer(address from, uint256 amount, bytes calldata data) external returns (bool); } interface IERC1363Spender { function onApprovalReceived(address owner, uint256 amount, bytes calldata data) external returns (bool); } // 接收方回调接口 interface ITokenReceiver { function tokenReceived(address from, uint256 amount) external returns (bool); } // ---------- Custom Errors (reduce runtime bytecode size) ---------- error TransfersDisabled(); error SenderRestricted(); error AddressBlocked(); error AmountZero(); error InsufficientUnlocked(); error InsufficientBalance(); error TimeNotInFuture(); error BadAddress(); error LengthMismatch(); error EmptyArray(); error Overflow(); error BadIndex(); error LockAlreadyRemoved(); error NoLocks(); error NoNative(); error NativeTokenTransferFailed(); error CannotRecoverSelf(); error MintExceedsMaxSupply(); error BurnExceedsSupply(); error RateTooHigh(); error NotExists(); error Expired(); error LocksMax(); error TransferCallbackFailed(); error ApprovalCallbackFailed(); error BadMax(); contract PetroDAO is ERC20, Ownable, ReentrancyGuard { uint256 public constant MAX_TOTAL_SUPPLY = 3000000000000 * (10 ** 18); // 30000亿代币 uint256 public maxSupply; bool public transfersEnabled = true; // 全局转账开关 mapping(address => bool) public transferDisabled; // 记录被禁止转账的账户 mapping(address => bool) public transferBlocked; // 记录无法发送 & 接收的账户 // 记录哪些地址启用了自动回调 mapping(address => bool) public transferOnCallEnabled; // 手续费配置(PPQ:千千万亿分比,分母 1e15)与白名单 // FEE_DENOMINATOR = 1,000,000,000,000,000 (1e15) uint256 public constant FEE_DENOMINATOR = 1000000000000000; // 费率: feePpq / FEE_DENOMINATOR(不是百分比) // Normal: 0.000001% -> 10,000,000 PPQ,最小: 0.001 代币 uint256 public normalFeePpq = 10000000; uint256 public normalMinFee = 1000000000000000; // Whitelist: 0.0000001% -> 1,000,000 PPQ,最小: 0.0001 代币 uint256 public whitelistFeePpq = 1000000; uint256 public whitelistMinFee = 100000000000000; // SuperWhitelist: 0.00000001% -> 100,000 PPQ,最小: 0.00001 代币 uint256 public superWhitelistFeePpq = 100000; uint256 public superWhitelistMinFee = 10000000000000; // VIP: 0.000000001% -> 10,000 PPQ,最小: 0.000001 代币 uint256 public vipFeePpq = 10000; uint256 public vipMinFee = 1000000000000; // VVIP: 0.0000000001% -> 1,000 PPQ,最小: 0.0000001 代币 uint256 public vvipFeePpq = 1000; uint256 public vvipMinFee = 100000000000; // VVVIP: 0.000000000001% -> 10 PPQ,最小: 0.000000001 代币 uint256 public vvvipFeePpq = 10; uint256 public vvvipMinFee = 1000000000; mapping(address => bool) public whitelist; mapping(address => bool) public superWhitelist; mapping(address => bool) public vip; mapping(address => bool) public vvip; mapping(address => bool) public vvvip; // 自动白名单阈值(基于持仓,用户可自助升级;仅上调,不会自动降级) uint256 public autoWhitelistThreshold; // 例如 10 * 1e18 uint256 public autoSuperWhitelistThreshold; // 例如 100000 * 1e18 uint256 public autoVipThreshold; // 例如 1000000 * 1e18 // 手续费豁免 mapping(address => bool) public feeExemptSender; // 作为发送方豁免 mapping(address => bool) public feeExemptReceiver; // 作为接收方豁免 uint256 public maxLocksPerAddress = 16; address public recoverWallet; // 误转代币接收地址(默认 Owner) address public feeRecipient; // 手续费接收地址(为 0 时烧毁) // 折扣配置:持有指定代币达到阈值享 50% 折扣(可叠加) address public discountToken; // 可配置的ERC20代币地址 uint256 public senderDiscountThreshold; // 发送方阈值,例如 1000 * 10^18 uint256 public receiverDiscountThreshold; // 接收方阈值,例如 10 * 10^18 // 特定合约地址的额外手续费 mapping(address => uint256) public contractExtraFee; // 记录每个合约地址的额外手续费 // 付费VIP1结构(最优先,覆盖所有其他手续费功能) struct PaidVip1Info { uint256 feePpq; // 手续费率(PPQ:分母 1e15) uint256 minFee; // 最小手续费(wei) uint256 expireTime; // 过期时间戳 } mapping(address => PaidVip1Info) public paidVip1Status; // 付费VIP1状态 // 锁仓结构 struct LockedBalance { uint256 amount; uint256 unlockTime; } // 增强的锁仓结构,支持按索引查询 struct LockInfo { uint256 amount; uint256 releaseTime; } mapping(address => LockedBalance) public lockedBalances; // 按索引存储的锁仓记录 mapping(address => LockInfo[]) public locks; mapping(address => uint256) public totalLocked; uint256 public totalHold; // 全局锁仓总量 event Minted(address indexed to, uint256 amount); event TransferDisabled(address indexed account); event TransferEnabled(address indexed account); event BurnMaxSupply(uint256 amount); event TransferBlocked(address indexed account); event TransferUnblocked(address indexed account); event TokensLocked(address indexed account, uint256 amount, uint256 unlockTime); event TokensUnlocked(address indexed account, uint256 amount); event RecoverWalletUpdated(address indexed newWallet); event ApprovalAndCall(address indexed owner, address indexed spender, uint256 amount); event NativeTokenRecovered(address indexed to, uint256 amount); event Burned(address indexed burner, uint256 amount); event ApprovalIncreased(address indexed owner, address indexed spender, uint256 addedValue); event ApprovalDecreased(address indexed owner, address indexed spender, uint256 subtractedValue); event LockAdded(address indexed to, uint256 amount, uint256 releaseTime); event LockRemoved(address indexed from, uint256 amount); event TransferOnCallEnabled(address indexed account); event TransferOnCallDisabled(address indexed account); event TransferOnCallExecuted(address indexed from, address indexed to, uint256 amount, bool success); event TransferWithCallExecuted(address indexed from, address indexed to, uint256 amount, bool success); // 新增:手续费与白名单相关事件 event FeeConfigUpdated( uint256 normalFeePpq, uint256 normalMinFee, uint256 whitelistFeePpq, uint256 whitelistMinFee, uint256 superWhitelistFeePpq, uint256 superWhitelistMinFee ); event WhitelistUpdated(address indexed account, bool enabled); event SuperWhitelistUpdated(address indexed account, bool enabled); event VipUpdated(address indexed account, bool enabled); event VvipUpdated(address indexed account, bool enabled); event VvvipUpdated(address indexed account, bool enabled); event TransferFeeBurned(address indexed from, uint256 fee); event ExpiredLocksPruned(address indexed account, uint256 processed, uint256 totalAmount); event MaxLocksPerAddressUpdated(uint256 newMax); event FeeExemptSenderUpdated(address indexed account, bool enabled); event FeeExemptReceiverUpdated(address indexed account, bool enabled); event FeeRecipientUpdated(address indexed newRecipient); event DiscountConfigUpdated(address indexed token, uint256 senderThreshold, uint256 receiverThreshold); event ContractExtraFeeUpdated(address indexed contractAddr, uint256 extraFee); event PaidVip1Set(address indexed account, uint256 feePpq, uint256 minFee, uint256 expireTime); event PaidVip1Removed(address indexed account); event AutoWhitelistConfigUpdated(uint256 whitelistThreshold, uint256 superWhitelistThreshold); event AutoWhitelistApplied(address indexed account, bool whitelistUpgraded, bool superWhitelistUpgraded); event AutoVipConfigUpdated(uint256 vipThreshold); event AutoVipApplied(address indexed account, bool vipUpgraded); constructor() ERC20("PetroCash DAO", "PetroDAO") Ownable(msg.sender) { // 设置最大供应量,但初始不铸造任何代币 maxSupply = MAX_TOTAL_SUPPLY; recoverWallet = msg.sender; // 默认合约 owner 作为发送方免手续费(批量发送/运营用途) feeExemptSender[msg.sender] = true; feeRecipient = address(0); // 默认烧毁 // 默认自动白名单阈值(可后续由 onlyOwner 修改) autoWhitelistThreshold = 10 * (10 ** 18); autoSuperWhitelistThreshold = 100000 * (10 ** 18); autoVipThreshold = 1000000 * (10 ** 18); } // 内部函数:检查地址是否为合约 function _isContract(address addr) internal view returns (bool) { uint256 size; assembly { size := extcodesize(addr) } return size > 0; } // 设置手续费接收地址(设为 0 表示烧毁) function setFeeRecipient(address newRecipient) external onlyOwner { // 允许设为 0 以恢复烧毁 feeRecipient = newRecipient; emit FeeRecipientUpdated(newRecipient); } // 设置折扣代币与阈值 function setDiscountConfig(address token, uint256 senderThreshold, uint256 receiverThreshold) external onlyOwner { discountToken = token; // 允许为0表示不启用折扣 senderDiscountThreshold = senderThreshold; receiverDiscountThreshold = receiverThreshold; emit DiscountConfigUpdated(token, senderThreshold, receiverThreshold); } // 设置特定合约地址的额外手续费 function setContractExtraFee(address contractAddr, uint256 extraFee) external onlyOwner { contractExtraFee[contractAddr] = extraFee; emit ContractExtraFeeUpdated(contractAddr, extraFee); } // 移除特定合约地址的额外手续费 function removeContractExtraFee(address contractAddr) external onlyOwner { contractExtraFee[contractAddr] = 0; emit ContractExtraFeeUpdated(contractAddr, 0); } // 查询地址是否设置了额外手续费 function hasContractExtraFee(address contractAddr) external view returns (bool) { return contractExtraFee[contractAddr] > 0; } // 设置付费VIP1(覆盖所有其他手续费功能,最优先) // feePpq: 手续费率(PPQ,分母 1e15) // minFee: 最小手续费(wei),例如 0.000000001 PETRO = 1000000000 wei // expireTime: 过期时间戳(uint256),必须大于当前时间戳 function setPaidVip1(address account, uint256 feePpq, uint256 minFee, uint256 expireTime) external onlyOwner { if (feePpq > FEE_DENOMINATOR) revert RateTooHigh(); if (expireTime <= block.timestamp) revert TimeNotInFuture(); if (account == address(0)) revert BadAddress(); paidVip1Status[account] = PaidVip1Info({ feePpq: feePpq, minFee: minFee, expireTime: expireTime }); emit PaidVip1Set(account, feePpq, minFee, expireTime); } // 更新付费VIP1的最小手续费(不改变其他设置) function setPaidVip1MinFee(address account, uint256 minFee) external onlyOwner { PaidVip1Info storage vip1 = paidVip1Status[account]; if (vip1.expireTime == 0) revert NotExists(); if (block.timestamp >= vip1.expireTime) revert Expired(); vip1.minFee = minFee; emit PaidVip1Set(account, vip1.feePpq, minFee, vip1.expireTime); } // 移除付费VIP1 function removePaidVip1(address account) external onlyOwner { delete paidVip1Status[account]; emit PaidVip1Removed(account); } // 查询付费VIP1状态 function getPaidVip1Status(address account) external view returns (bool isActive, uint256 feePpq, uint256 minFee, uint256 expireTime, uint256 remainingTime) { PaidVip1Info memory vip1 = paidVip1Status[account]; if (vip1.expireTime == 0) { return (false, 0, 0, 0, 0); } bool active = block.timestamp < vip1.expireTime; uint256 remaining = active ? (vip1.expireTime - block.timestamp) : 0; return (active, vip1.feePpq, vip1.minFee, vip1.expireTime, remaining); } // **Mint(增发代币)** function mint(address _to, uint256 _amount) external onlyOwner { if (totalSupply() + _amount > maxSupply) revert MintExceedsMaxSupply(); _mint(_to, _amount); emit Minted(_to, _amount); } // **增加 maxSupply(允许未来增发)** function increaseMaxSupply(uint256 amount) external onlyOwner { if (amount == 0) revert AmountZero(); maxSupply += amount; } // 关闭/开启全局转账 function setTransfersEnabled(bool _enabled) external onlyOwner { transfersEnabled = _enabled; } // 禁止某个地址转账 function disableTransfer(address account) external onlyOwner { transferDisabled[account] = true; emit TransferDisabled(account); } // 允许某个地址恢复转账 function enableTransfer(address account) external onlyOwner { transferDisabled[account] = false; emit TransferEnabled(account); } // 冻结某个地址(无法发送 & 接收) function blockTransfer(address account) external onlyOwner { transferBlocked[account] = true; emit TransferBlocked(account); } // 解除冻结 function unblockTransfer(address account) external onlyOwner { transferBlocked[account] = false; emit TransferUnblocked(account); } // 新增:手续费配置与白名单管理(PPQ:分母 1e15) function setFeeConfig( uint256 _normalFeePpq, uint256 _normalMinFee, uint256 _whitelistFeePpq, uint256 _whitelistMinFee, uint256 _superWhitelistFeePpq, uint256 _superWhitelistMinFee, uint256 _vipFeePpq, uint256 _vipMinFee, uint256 _vvipFeePpq, uint256 _vvipMinFee, uint256 _vvvipFeePpq, uint256 _vvvipMinFee ) external onlyOwner { if (!(_normalFeePpq <= FEE_DENOMINATOR && _whitelistFeePpq <= FEE_DENOMINATOR && _superWhitelistFeePpq <= FEE_DENOMINATOR)) revert RateTooHigh(); if (!(_vipFeePpq <= FEE_DENOMINATOR && _vvipFeePpq <= FEE_DENOMINATOR && _vvvipFeePpq <= FEE_DENOMINATOR)) revert RateTooHigh(); normalFeePpq = _normalFeePpq; normalMinFee = _normalMinFee; whitelistFeePpq = _whitelistFeePpq; whitelistMinFee = _whitelistMinFee; superWhitelistFeePpq = _superWhitelistFeePpq; superWhitelistMinFee = _superWhitelistMinFee; vipFeePpq = _vipFeePpq; vipMinFee = _vipMinFee; vvipFeePpq = _vvipFeePpq; vvipMinFee = _vvipMinFee; vvvipFeePpq = _vvvipFeePpq; vvvipMinFee = _vvvipMinFee; emit FeeConfigUpdated(normalFeePpq, normalMinFee, whitelistFeePpq, whitelistMinFee, superWhitelistFeePpq, superWhitelistMinFee); } function setWhitelist(address account, bool enabled) external onlyOwner { whitelist[account] = enabled; emit WhitelistUpdated(account, enabled); } function setSuperWhitelist(address account, bool enabled) external onlyOwner { superWhitelist[account] = enabled; emit SuperWhitelistUpdated(account, enabled); } function setVip(address account, bool enabled) external onlyOwner { vip[account] = enabled; emit VipUpdated(account, enabled); } function setVvip(address account, bool enabled) external onlyOwner { vvip[account] = enabled; emit VvipUpdated(account, enabled); } function setVvvip(address account, bool enabled) external onlyOwner { vvvip[account] = enabled; emit VvvipUpdated(account, enabled); } function setWhitelistBatch(address[] calldata accounts, bool enabled) external onlyOwner { for (uint256 i = 0; i < accounts.length; i++) { whitelist[accounts[i]] = enabled; emit WhitelistUpdated(accounts[i], enabled); } } function setSuperWhitelistBatch(address[] calldata accounts, bool enabled) external onlyOwner { for (uint256 i = 0; i < accounts.length; i++) { superWhitelist[accounts[i]] = enabled; emit SuperWhitelistUpdated(accounts[i], enabled); } } function setVipBatch(address[] calldata accounts, bool enabled) external onlyOwner { for (uint256 i = 0; i < accounts.length; i++) { vip[accounts[i]] = enabled; emit VipUpdated(accounts[i], enabled); } } function setVvipBatch(address[] calldata accounts, bool enabled) external onlyOwner { for (uint256 i = 0; i < accounts.length; i++) { vvip[accounts[i]] = enabled; emit VvipUpdated(accounts[i], enabled); } } function setVvvipBatch(address[] calldata accounts, bool enabled) external onlyOwner { for (uint256 i = 0; i < accounts.length; i++) { vvvip[accounts[i]] = enabled; emit VvvipUpdated(accounts[i], enabled); } } // 配置基于持仓的自动白名单阈值(仅 Owner) function setAutoWhitelistThresholds(uint256 whitelistThreshold, uint256 superWhitelistThreshold) external onlyOwner { autoWhitelistThreshold = whitelistThreshold; autoSuperWhitelistThreshold = superWhitelistThreshold; emit AutoWhitelistConfigUpdated(whitelistThreshold, superWhitelistThreshold); } // 配置基于持仓的自动 VIP 阈值(仅 Owner) function setAutoVipThreshold(uint256 vipThreshold) external onlyOwner { autoVipThreshold = vipThreshold; emit AutoVipConfigUpdated(vipThreshold); } // 用户自助申请基于当前持仓的白名单升级(只会上调,不会下调) // 返回值为是否被升级到 whitelist / superWhitelist function applyWhitelistUpgrade() external returns (bool whitelistUpgraded, bool superWhitelistUpgraded) { uint256 bal = balanceOf(msg.sender); if (autoSuperWhitelistThreshold > 0 && bal >= autoSuperWhitelistThreshold && !superWhitelist[msg.sender]) { superWhitelist[msg.sender] = true; superWhitelistUpgraded = true; emit SuperWhitelistUpdated(msg.sender, true); } if (autoWhitelistThreshold > 0 && bal >= autoWhitelistThreshold && !whitelist[msg.sender]) { whitelist[msg.sender] = true; whitelistUpgraded = true; emit WhitelistUpdated(msg.sender, true); } if (whitelistUpgraded || superWhitelistUpgraded) { emit AutoWhitelistApplied(msg.sender, whitelistUpgraded, superWhitelistUpgraded); } } // 用户自助申请基于当前持仓的 VIP 升级(只会上调,不会下调) function applyVipUpgrade() external returns (bool vipUpgraded) { uint256 bal = balanceOf(msg.sender); if (autoVipThreshold > 0 && bal >= autoVipThreshold && !vip[msg.sender]) { vip[msg.sender] = true; vipUpgraded = true; emit VipUpdated(msg.sender, true); emit AutoVipApplied(msg.sender, true); } } function setMaxLocksPerAddress(uint256 newMax) external onlyOwner { if (newMax < 1 || newMax > 64) revert BadMax(); maxLocksPerAddress = newMax; emit MaxLocksPerAddressUpdated(newMax); } // 手续费豁免管理 function setFeeExemptSender(address account, bool enabled) external onlyOwner { feeExemptSender[account] = enabled; emit FeeExemptSenderUpdated(account, enabled); } function setFeeExemptSenderBatch(address[] calldata accounts, bool enabled) external onlyOwner { for (uint256 i = 0; i < accounts.length; i++) { feeExemptSender[accounts[i]] = enabled; emit FeeExemptSenderUpdated(accounts[i], enabled); } } function setFeeExemptReceiver(address account, bool enabled) external onlyOwner { feeExemptReceiver[account] = enabled; emit FeeExemptReceiverUpdated(account, enabled); } function setFeeExemptReceiverBatch(address[] calldata accounts, bool enabled) external onlyOwner { for (uint256 i = 0; i < accounts.length; i++) { feeExemptReceiver[accounts[i]] = enabled; emit FeeExemptReceiverUpdated(accounts[i], enabled); } } // 变更所有权时,切换豁免到新 owner function transferOwnership(address newOwner) public override onlyOwner { address oldOwner = owner(); super.transferOwnership(newOwner); feeExemptSender[oldOwner] = false; feeExemptSender[newOwner] = true; } // 检查地址是否可以转账 function canBeTransfered(address _addr, uint256 value) public view returns (bool) { if (!transfersEnabled) return false; if (transferDisabled[_addr]) return false; if (transferBlocked[_addr]) return false; if (_getUnlockedBalance(_addr) < value) return false; return true; } // 启用 TransferOnCall 功能 function enableTransferOnCall() external { transferOnCallEnabled[msg.sender] = true; emit TransferOnCallEnabled(msg.sender); } // 禁用 TransferOnCall 功能 function disableTransferOnCall() external { transferOnCallEnabled[msg.sender] = false; emit TransferOnCallDisabled(msg.sender); } // 重写 _update 函数以支持 TransferOnCall 和收取手续费(加法模式:收款方收到全额,发送方额外支付手续费) function _update(address from, address to, uint256 amount) internal override { // 铸造或销毁不收取手续费 if (from == address(0) || to == address(0)) { super._update(from, to, amount); return; } // 统一的限制检查(涵盖 multiSend 等所有路径) if (!transfersEnabled) revert TransfersDisabled(); if (transferDisabled[from]) revert SenderRestricted(); if (transferBlocked[from] || transferBlocked[to]) revert AddressBlocked(); if (amount == 0) revert AmountZero(); // 计算手续费(与金额独立转移) uint256 feeAmount = _calculateFee(from, to, amount); // 发送方需要有 amount + fee 的未锁定余额 uint256 required = amount + feeAmount; if (_getUnlockedBalance(from) < required) revert InsufficientUnlocked(); // 先扣手续费 if (feeAmount > 0) { address recipient = feeRecipient; if (recipient == address(0)) { super._update(from, address(0), feeAmount); emit TransferFeeBurned(from, feeAmount); } else { super._update(from, recipient, feeAmount); } } // 再转全额给接收方 super._update(from, to, amount); // TransferOnCall(传递全额 amount) if (_isContract(to) && transferOnCallEnabled[to]) { bool success = _executeTransferOnCall(from, to, amount); emit TransferOnCallExecuted(from, to, amount, success); } } // 执行 TransferOnCall 回调 - 优化版本 function _executeTransferOnCall(address from, address to, uint256 amount) internal returns (bool) { try ITokenReceiver(to).tokenReceived(from, amount) returns (bool success) { return success; } catch { // 接收方回调失败不影响转账,只是返回失败状态 return false; } } // 计算可用余额(避免下溢) function _getUnlockedBalance(address account) internal view returns (uint256) { uint256 bal = balanceOf(account); uint256 locked = getLockedBalance(account); return bal > locked ? bal - locked : 0; } // 获取手续费参数(付费VIP1最优先,覆盖所有其他手续费功能) function _getFeeParams(address from) internal view returns (uint256 ppq, uint256 minFee) { // 最优先检查付费VIP1,如果有效则覆盖所有其他手续费功能 PaidVip1Info memory vip1 = paidVip1Status[from]; if (vip1.expireTime > 0 && block.timestamp < vip1.expireTime) { // 付费VIP1使用自定义的ppq和minFee return (vip1.feePpq, vip1.minFee); } // 如果没有付费VIP1,则按原有逻辑 if (vvvip[from]) { return (vvvipFeePpq, vvvipMinFee); } if (vvip[from]) { return (vvipFeePpq, vvipMinFee); } if (vip[from]) { return (vipFeePpq, vipMinFee); } if (superWhitelist[from]) { return (superWhitelistFeePpq, superWhitelistMinFee); } if (whitelist[from]) { return (whitelistFeePpq, whitelistMinFee); } return (normalFeePpq, normalMinFee); } // 查询某地址费率层级与参数(付费VIP1优先) function getFeeTier(address account) external view returns (string memory tier, uint256 ppq, uint256 minFee) { if (feeExemptSender[account] || feeExemptReceiver[account]) { return ("exempt", 0, 0); } // 最优先检查付费VIP1,如果有效则覆盖所有其他手续费功能 PaidVip1Info memory vip1 = paidVip1Status[account]; if (vip1.expireTime > 0 && block.timestamp < vip1.expireTime) { return ("paidvip1", vip1.feePpq, vip1.minFee); } if (vvvip[account]) { return ("vvvip", vvvipFeePpq, vvvipMinFee); } if (vvip[account]) { return ("vvip", vvipFeePpq, vvipMinFee); } if (vip[account]) { return ("vip", vipFeePpq, vipMinFee); } if (superWhitelist[account]) { return ("super", superWhitelistFeePpq, superWhitelistMinFee); } if (whitelist[account]) { return ("whitelist", whitelistFeePpq, whitelistMinFee); } return ("normal", normalFeePpq, normalMinFee); } // 预估手续费(加法模式):若在豁免名单则为 0;否则按层级费率和最小费取较大值 function estimateFee(address from, address to, uint256 amount) external view returns (uint256) { if (amount == 0) revert AmountZero(); return _calculateFee(from, to, amount); } function _findLockIndex(address _addr, uint256 releaseTime) internal view returns (bool found, uint256 index) { for (uint256 i = 0; i < locks[_addr].length; i++) { if (locks[_addr][i].releaseTime == releaseTime) { return (true, i); } } return (false, 0); } function _isFeeExempt(address from, address to) internal view returns (bool) { if (feeExemptSender[from]) return true; if (feeExemptReceiver[to]) return true; return false; } // 内部函数:应用折扣到手续费 function _applyDiscount(address from, address to, uint256 amount, uint256 fee) internal view returns (uint256) { if (discountToken == address(0) || fee == 0) return fee; uint256 discountedFee = fee; // 发送方折扣 if (senderDiscountThreshold > 0) { if (IERC20(discountToken).balanceOf(from) >= senderDiscountThreshold && balanceOf(from) >= amount + senderDiscountThreshold) { discountedFee = discountedFee / 2; } } // 接收方折扣 if (receiverDiscountThreshold > 0) { if (IERC20(discountToken).balanceOf(to) >= receiverDiscountThreshold) { discountedFee = discountedFee / 2; } } return discountedFee; } // 计算手续费:若豁免则 0;否则 max(mulDiv(amount, ppq, FEE_DENOMINATOR), minFee) + 合约额外手续费(也会受折扣影响) function _calculateFee(address from, address to, uint256 amount) internal view returns (uint256) { if (_isFeeExempt(from, to)) return 0; (uint256 ppq, uint256 minFee) = _getFeeParams(from); uint256 percentFee = Math.mulDiv(amount, ppq, FEE_DENOMINATOR); uint256 fee = percentFee > minFee ? percentFee : minFee; // 添加合约额外手续费 uint256 extraFee = contractExtraFee[to]; if (extraFee > 0) { fee += extraFee; } // 应用折扣 return _applyDiscount(from, to, amount, fee); } // **自定义 Transfer**(收款方收全额,发送方额外支付手续费) function transfer(address to, uint256 amount) public override nonReentrant returns (bool) { if (!transfersEnabled) revert TransfersDisabled(); if (transferDisabled[msg.sender]) revert SenderRestricted(); if (transferBlocked[msg.sender] || transferBlocked[to]) revert AddressBlocked(); uint256 feeAmount = _calculateFee(msg.sender, to, amount); if (amount == 0) revert AmountZero(); if (_getUnlockedBalance(msg.sender) < amount + feeAmount) revert InsufficientUnlocked(); _transfer(msg.sender, to, amount); // 回调传递全额 amount _callOnTokenTransfer(msg.sender, to, amount, ""); return true; } function transferFrom(address from, address to, uint256 amount) public override nonReentrant returns (bool) { if (!transfersEnabled) revert TransfersDisabled(); if (transferDisabled[from]) revert SenderRestricted(); if (transferBlocked[from] || transferBlocked[to]) revert AddressBlocked(); uint256 feeAmount = _calculateFee(from, to, amount); if (amount == 0) revert AmountZero(); if (_getUnlockedBalance(from) < amount + feeAmount) revert InsufficientUnlocked(); _spendAllowance(from, msg.sender, amount); _transfer(from, to, amount); // 回调传递全额 amount _callOnTokenTransfer(from, to, amount, ""); return true; } // 支持 转账 + 回调 - 优化版本(收款方收全额,发送方额外支付手续费) function transferWithCall(address to, uint256 amount, bytes calldata data) public nonReentrant returns (bool) { if (!transfersEnabled) revert TransfersDisabled(); if (transferDisabled[msg.sender]) revert SenderRestricted(); if (transferBlocked[msg.sender] || transferBlocked[to]) revert AddressBlocked(); uint256 feeAmount = _calculateFee(msg.sender, to, amount); if (amount == 0) revert AmountZero(); if (_getUnlockedBalance(msg.sender) < amount + feeAmount) revert InsufficientUnlocked(); _transfer(msg.sender, to, amount); bool success = _callOnTokenTransfer(msg.sender, to, amount, data); emit TransferWithCallExecuted(msg.sender, to, amount, success); if (!success) revert TransferCallbackFailed(); return true; } // 支持 批准 + 回调 function approveAndCall(address spender, uint256 amount, bytes calldata data) public nonReentrant returns (bool) { if (transferDisabled[msg.sender]) revert SenderRestricted(); if (transferBlocked[msg.sender] || transferBlocked[spender]) revert AddressBlocked(); _approve(msg.sender, spender, amount); bool success = true; // 默认成功,如果spender不是合约则直接成功 if (_isContract(spender)) { try IERC1363Spender(spender).onApprovalReceived(msg.sender, amount, data) returns (bool callSuccess) { success = callSuccess; } catch { revert ApprovalCallbackFailed(); } } if (!success) revert ApprovalCallbackFailed(); emit ApprovalAndCall(msg.sender, spender, amount); return true; } // 增加授权额度 function increaseApproval(address _spender, uint256 _addedValue) public returns (bool) { uint256 currentAllowance = allowance(msg.sender, _spender); _approve(msg.sender, _spender, currentAllowance + _addedValue); emit ApprovalIncreased(msg.sender, _spender, _addedValue); return true; } // 减少授权额度 function decreaseApproval(address _spender, uint256 _subtractedValue) public returns (bool) { uint256 currentAllowance = allowance(msg.sender, _spender); uint256 newAllowance = currentAllowance > _subtractedValue ? currentAllowance - _subtractedValue : 0; _approve(msg.sender, _spender, newAllowance); emit ApprovalDecreased(msg.sender, _spender, _subtractedValue); return true; } // 改进回调函数,确保调用失败时回滚 function _callOnTokenTransfer(address from, address to, uint256 amount, bytes memory data) internal returns (bool) { if (_isContract(to)) { try IERC1363Receiver(to).onTokenTransfer(from, amount, data) returns (bool success) { return success; } catch { return false; } } return true; } // **锁仓** function lockTokens(address account, uint256 amount, uint256 unlockTime) external onlyOwner { if (balanceOf(account) < amount) revert InsufficientBalance(); if (unlockTime <= block.timestamp) revert TimeNotInFuture(); lockedBalances[account].amount += amount; lockedBalances[account].unlockTime = unlockTime; emit TokensLocked(account, amount, unlockTime); } // 新增锁仓函数,支持按索引存储 function lock(address _to, uint256 releaseTime, uint256 lockamount) external onlyOwner { if (balanceOf(_to) < lockamount) revert InsufficientBalance(); if (releaseTime <= block.timestamp) revert TimeNotInFuture(); if (lockamount == 0) revert AmountZero(); // 添加溢出检查 if (totalLocked[_to] + lockamount < totalLocked[_to]) revert Overflow(); (bool found, uint256 idx) = _findLockIndex(_to, releaseTime); if (found) { locks[_to][idx].amount += lockamount; } else { if (locks[_to].length >= maxLocksPerAddress) revert LocksMax(); locks[_to].push(LockInfo({ amount: lockamount, releaseTime: releaseTime })); } totalLocked[_to] += lockamount; totalHold += lockamount; emit LockAdded(_to, lockamount, releaseTime); } // 移除指定地址的所有锁仓 function removeHoldByAddress(address _address) external onlyOwner { uint256 totalAmount = totalLocked[_address]; if (totalAmount == 0) revert NoLocks(); delete locks[_address]; totalHold -= totalAmount; // 使用保存的totalAmount而不是totalLocked[_address] totalLocked[_address] = 0; emit LockRemoved(_address, totalAmount); } // 移除指定地址的指定索引锁仓 function removeHoldByAddressIndex(address _address, uint256 _index) external onlyOwner { if (_index >= locks[_address].length) revert BadIndex(); uint256 amount = locks[_address][_index].amount; if (amount == 0) revert LockAlreadyRemoved(); totalHold -= amount; totalLocked[_address] -= amount; // 移除指定索引的锁仓记录 if (_index < locks[_address].length - 1) { locks[_address][_index] = locks[_address][locks[_address].length - 1]; } locks[_address].pop(); emit LockRemoved(_address, amount); } // 清理已到期的锁仓,避免累积 O(n) 遍历 function pruneExpiredLocks(address _address, uint256 maxToProcess) external returns (uint256 processed, uint256 totalReleased) { uint256 i = 0; while (i < locks[_address].length && processed < maxToProcess) { if (locks[_address][i].releaseTime <= block.timestamp) { uint256 amount = locks[_address][i].amount; totalHold -= amount; totalLocked[_address] -= amount; if (i < locks[_address].length - 1) { locks[_address][i] = locks[_address][locks[_address].length - 1]; } locks[_address].pop(); processed += 1; totalReleased += amount; } else { i += 1; } } if (processed > 0) { emit ExpiredLocksPruned(_address, processed, totalReleased); } } // 获取指定地址的锁仓记录数量 function getlockslen(address _address) public view returns (uint256) { return locks[_address].length; } // 获取指定地址的指定索引锁仓记录 function getlocksbyindex(address _address, uint256 _index) public view returns (uint256 amount, uint256 releaseTime) { if (_index >= locks[_address].length) revert BadIndex(); LockInfo memory lockData = locks[_address][_index]; return (lockData.amount, lockData.releaseTime); } // 获取全局锁仓总量 function gettotalHold() public view returns (uint256) { return totalHold; } // **解锁** function unlockTokens(address account) external onlyOwner { uint256 amount = lockedBalances[account].amount; if (amount == 0) revert NoLocks(); lockedBalances[account].amount = 0; lockedBalances[account].unlockTime = 0; emit TokensUnlocked(account, amount); } function getLockedBalance(address account) public view returns (uint256) { uint256 lockedAmount = 0; // 检查旧的锁仓机制 if (block.timestamp < lockedBalances[account].unlockTime) { lockedAmount += lockedBalances[account].amount; } // 检查新的锁仓机制 for (uint256 i = 0; i < locks[account].length; i++) { if (block.timestamp < locks[account][i].releaseTime) { lockedAmount += locks[account][i].amount; } } return lockedAmount; } function getAccountBalance(address account) public view returns (uint256 available, uint256 locked) { uint256 lockedAmount = getLockedBalance(account); uint256 bal = balanceOf(account); uint256 avail = bal > lockedAmount ? bal - lockedAmount : 0; return (avail, lockedAmount); } // **销毁代币,并减少 maxSupply** function burnMaxSupply(uint256 amount) external onlyOwner { if (amount == 0) revert AmountZero(); if (amount > totalSupply()) revert BurnExceedsSupply(); _burn(msg.sender, amount); maxSupply -= amount; emit BurnMaxSupply(amount); } // 普通销毁 function burn(uint256 amount) public { if (amount == 0) revert AmountZero(); if (_getUnlockedBalance(msg.sender) < amount) revert InsufficientUnlocked(); _burn(msg.sender, amount); emit Burned(msg.sender, amount); } // **允许 onlyOwner 销毁** function burnFrom(address account, uint256 amount) public onlyOwner { _burn(account, amount); emit Burned(account, amount); } // **误转代币找回 - ERC20代币** function recoverTokens(address token, uint256 amount) external onlyOwner { if (token == address(this)) revert CannotRecoverSelf(); IERC20(token).transfer(recoverWallet, amount); } // **误转代币找回 - 批量ERC20代币** function recoverAllTokens(address[] calldata tokens) external onlyOwner { for (uint256 i = 0; i < tokens.length; i++) { if (tokens[i] != address(this)) { uint256 balance = IERC20(tokens[i]).balanceOf(address(this)); if (balance > 0) { IERC20(tokens[i]).transfer(recoverWallet, balance); } } } } // **误转原生代币找回** function recoverNativeToken() external onlyOwner { uint256 balance = address(this).balance; if (balance == 0) revert NoNative(); (bool success, ) = recoverWallet.call{value: balance}(""); if (!success) revert NativeTokenTransferFailed(); emit NativeTokenRecovered(recoverWallet, balance); } // **设置误转代币接收地址** function setNewRecoverWallet(address newWallet) external onlyOwner { if (newWallet == address(0)) revert BadAddress(); recoverWallet = newWallet; emit RecoverWalletUpdated(newWallet); } // **批量发送代币** - 优化版本(收款方收全额,发送方额外支付手续费) function multiSend(address[] calldata _recipients, uint256[] calldata _amounts) external onlyOwner nonReentrant returns (bool) { if (_recipients.length != _amounts.length) revert LengthMismatch(); if (_recipients.length == 0) revert EmptyArray(); uint256 totalAmount = 0; uint256 totalFee = 0; for (uint256 i = 0; i < _recipients.length; i++) { if (_recipients[i] == address(0)) revert BadAddress(); totalAmount += _amounts[i]; if (totalAmount < _amounts[i]) revert Overflow(); uint256 fee = _calculateFee(msg.sender, _recipients[i], _amounts[i]); totalFee += fee; if (totalFee < fee) revert Overflow(); } if (!transfersEnabled) revert TransfersDisabled(); if (transferDisabled[msg.sender]) revert SenderRestricted(); if (transferBlocked[msg.sender]) revert AddressBlocked(); if (_getUnlockedBalance(msg.sender) < totalAmount + totalFee) revert InsufficientUnlocked(); for (uint256 i = 0; i < _recipients.length; i++) { if (transferBlocked[_recipients[i]]) revert AddressBlocked(); _transfer(msg.sender, _recipients[i], _amounts[i]); } return true; } // 批量增发代币(按地址-金额) function multiMint(address[] calldata _recipients, uint256[] calldata _amounts) external onlyOwner returns (bool) { if (_recipients.length != _amounts.length) revert LengthMismatch(); if (_recipients.length == 0) revert EmptyArray(); uint256 totalMint = 0; for (uint256 i = 0; i < _recipients.length; i++) { if (_recipients[i] == address(0)) revert BadAddress(); if (transferBlocked[_recipients[i]]) revert AddressBlocked(); uint256 amount = _amounts[i]; if (amount == 0) revert AmountZero(); totalMint += amount; if (totalMint < amount) revert Overflow(); } if (totalSupply() + totalMint > maxSupply) revert MintExceedsMaxSupply(); for (uint256 i = 0; i < _recipients.length; i++) { _mint(_recipients[i], _amounts[i]); emit Minted(_recipients[i], _amounts[i]); } return true; } // 接收原生代币 receive() external payable {} // ========== 诊断和检查函数 ========== // 获取账户完整状态信息(用于诊断) function getAccountStatus(address account) external view returns ( uint256 balance, uint256 unlockedBalance, uint256 lockedBalance, bool isTransferDisabled, bool isTransferBlocked, bool isWhitelist, bool isSuperWhitelist, bool isVip, bool isVvip, bool isVvvip, bool isFeeExemptSender, bool isFeeExemptReceiver, bool hasPaidVip1, bool paidVip1Active, uint256 lockCount ) { balance = balanceOf(account); unlockedBalance = _getUnlockedBalance(account); lockedBalance = getLockedBalance(account); isTransferDisabled = transferDisabled[account]; isTransferBlocked = transferBlocked[account]; isWhitelist = whitelist[account]; isSuperWhitelist = superWhitelist[account]; isVip = vip[account]; isVvip = vvip[account]; isVvvip = vvvip[account]; isFeeExemptSender = feeExemptSender[account]; isFeeExemptReceiver = feeExemptReceiver[account]; PaidVip1Info memory vip1 = paidVip1Status[account]; hasPaidVip1 = vip1.expireTime > 0; paidVip1Active = hasPaidVip1 && block.timestamp < vip1.expireTime; lockCount = locks[account].length; } // 获取手续费计算明细(用于调试) function getFeeBreakdown(address from, address to, uint256 amount) external view returns ( bool isExempt, string memory tier, uint256 feePpq, uint256 minFee, uint256 percentFee, uint256 baseFee, uint256 extraFeeAmount, uint256 feeBeforeDiscount, bool hasSenderDiscount, bool hasReceiverDiscount, uint256 finalFee ) { // 检查豁免 if (_isFeeExempt(from, to)) { return (true, "exempt", 0, 0, 0, 0, 0, 0, false, false, 0); } // 获取费率层级 (tier, feePpq, minFee) = this.getFeeTier(from); // 计算基础手续费 percentFee = Math.mulDiv(amount, feePpq, FEE_DENOMINATOR); baseFee = percentFee > minFee ? percentFee : minFee; // 添加合约额外手续费 extraFeeAmount = contractExtraFee[to]; feeBeforeDiscount = baseFee + extraFeeAmount; // 检查折扣条件 if (discountToken != address(0) && feeBeforeDiscount > 0) { if (senderDiscountThreshold > 0) { hasSenderDiscount = IERC20(discountToken).balanceOf(from) >= senderDiscountThreshold && balanceOf(from) >= amount + senderDiscountThreshold; } if (receiverDiscountThreshold > 0) { hasReceiverDiscount = IERC20(discountToken).balanceOf(to) >= receiverDiscountThreshold; } } // 应用折扣计算最终手续费 finalFee = feeBeforeDiscount; if (hasSenderDiscount) { finalFee = finalFee / 2; } if (hasReceiverDiscount) { finalFee = finalFee / 2; } return (false, tier, feePpq, minFee, percentFee, baseFee, extraFeeAmount, feeBeforeDiscount, hasSenderDiscount, hasReceiverDiscount, finalFee); } // 检查转账可行性(完整检查) function checkTransferFeasibility(address from, address to, uint256 amount) external view returns ( bool feasible, string memory reason, uint256 requiredBalance, uint256 availableBalance, uint256 feeAmount, bool transfersEnabledStatus, bool senderNotDisabled, bool senderNotBlocked, bool receiverNotBlocked, bool hasEnoughBalance ) { transfersEnabledStatus = transfersEnabled; senderNotDisabled = !transferDisabled[from]; senderNotBlocked = !transferBlocked[from]; receiverNotBlocked = !transferBlocked[to]; if (!transfersEnabledStatus) { return (false, "Transfers disabled", 0, 0, 0, false, senderNotDisabled, senderNotBlocked, receiverNotBlocked, false); } if (!senderNotDisabled) { return (false, "Sender restricted", 0, 0, 0, true, false, senderNotBlocked, receiverNotBlocked, false); } if (!senderNotBlocked || !receiverNotBlocked) { return (false, "Address blocked", 0, 0, 0, true, true, senderNotBlocked, receiverNotBlocked, false); } if (amount == 0) { return (false, "Amount zero", 0, 0, 0, true, true, true, true, false); } feeAmount = _calculateFee(from, to, amount); requiredBalance = amount + feeAmount; availableBalance = _getUnlockedBalance(from); hasEnoughBalance = availableBalance >= requiredBalance; if (!hasEnoughBalance) { return (false, "Insufficient balance", requiredBalance, availableBalance, feeAmount, true, true, true, true, false); } return (true, "Feasible", requiredBalance, availableBalance, feeAmount, true, true, true, true, true); } // 获取所有手续费配置(用于检查) function getAllFeeConfigs() external view returns ( uint256 normalPpq, uint256 normalMin, uint256 whitelistPpq, uint256 whitelistMin, uint256 superWhitelistPpq, uint256 superWhitelistMin, uint256 vipPpq, uint256 vipMin, uint256 vvipPpq, uint256 vvipMin, uint256 vvvipPpq, uint256 vvvipMin ) { return ( normalFeePpq, normalMinFee, whitelistFeePpq, whitelistMinFee, superWhitelistFeePpq, superWhitelistMinFee, vipFeePpq, vipMinFee, vvipFeePpq, vvipMinFee, vvvipFeePpq, vvvipMinFee ); } // 获取折扣配置(用于检查) function getDiscountConfig() external view returns ( address token, uint256 senderThreshold, uint256 receiverThreshold, bool isEnabled ) { return (discountToken, senderDiscountThreshold, receiverDiscountThreshold, discountToken != address(0)); } // 获取折扣状态(用于检查) function getDiscountStatus(address account, uint256 amount) external view returns ( bool senderEligible, bool receiverEligible, uint256 senderBalance, uint256 receiverBalance, uint256 petroBalance ) { if (discountToken == address(0)) { return (false, false, 0, 0, 0); } senderBalance = IERC20(discountToken).balanceOf(account); receiverBalance = senderBalance; // 接收方和发送方是同一个地址 petroBalance = balanceOf(account); senderEligible = senderDiscountThreshold > 0 && senderBalance >= senderDiscountThreshold && petroBalance >= amount + senderDiscountThreshold; receiverEligible = receiverDiscountThreshold > 0 && receiverBalance >= receiverDiscountThreshold; return (senderEligible, receiverEligible, senderBalance, receiverBalance, petroBalance); } // 获取锁仓详情(用于检查) function getLockDetails(address account) external view returns ( uint256 totalLockedAmount, uint256 activeLockCount, uint256[] memory lockAmounts, uint256[] memory releaseTimes, bool[] memory isExpired ) { totalLockedAmount = totalLocked[account]; uint256 lockCount = locks[account].length; activeLockCount = 0; lockAmounts = new uint256[](lockCount); releaseTimes = new uint256[](lockCount); isExpired = new bool[](lockCount); for (uint256 i = 0; i < lockCount; i++) { LockInfo memory lockInfo = locks[account][i]; lockAmounts[i] = lockInfo.amount; releaseTimes[i] = lockInfo.releaseTime; bool expired = block.timestamp >= lockInfo.releaseTime; isExpired[i] = expired; if (!expired) { activeLockCount++; } } } // 获取合约状态(用于检查) function getContractStatus() external view returns ( uint256 totalSupplyValue, uint256 maxSupplyValue, uint256 totalHoldValue, bool transfersEnabledStatus, address feeRecipientAddress, address recoverWalletAddress, uint256 maxLocksPerAddressValue ) { return ( totalSupply(), maxSupply, totalHold, transfersEnabled, feeRecipient, recoverWallet, maxLocksPerAddress ); } // 检查地址的所有白名单状态 function getAllWhitelistStatus(address account) external view returns ( bool whitelistStatus, bool superWhitelistStatus, bool vipStatus, bool vvipStatus, bool vvvipStatus, bool paidVip1StatusActive, bool feeExemptSenderStatus, bool feeExemptReceiverStatus ) { whitelistStatus = whitelist[account]; superWhitelistStatus = superWhitelist[account]; vipStatus = vip[account]; vvipStatus = vvip[account]; vvvipStatus = vvvip[account]; PaidVip1Info memory vip1 = paidVip1Status[account]; paidVip1StatusActive = vip1.expireTime > 0 && block.timestamp < vip1.expireTime; feeExemptSenderStatus = feeExemptSender[account]; feeExemptReceiverStatus = feeExemptReceiver[account]; } // 模拟转账(用于测试,不实际执行) function simulateTransfer(address from, address to, uint256 amount) external view returns ( bool success, string memory message, uint256 feeAmount, uint256 fromBalanceBefore, uint256 fromBalanceAfter, uint256 toBalanceBefore, uint256 toBalanceAfter, uint256 fromUnlockedBefore, uint256 fromUnlockedAfter ) { // 获取余额 fromBalanceBefore = balanceOf(from); toBalanceBefore = balanceOf(to); fromUnlockedBefore = _getUnlockedBalance(from); // 快速检查基本条件并提前返回 if (!transfersEnabled) { return (false, "Transfers disabled", 0, fromBalanceBefore, fromBalanceBefore, toBalanceBefore, toBalanceBefore, fromUnlockedBefore, fromUnlockedBefore); } if (transferDisabled[from]) { return (false, "Sender restricted", 0, fromBalanceBefore, fromBalanceBefore, toBalanceBefore, toBalanceBefore, fromUnlockedBefore, fromUnlockedBefore); } if (transferBlocked[from] || transferBlocked[to]) { return (false, "Address blocked", 0, fromBalanceBefore, fromBalanceBefore, toBalanceBefore, toBalanceBefore, fromUnlockedBefore, fromUnlockedBefore); } if (amount == 0) { return (false, "Amount zero", 0, fromBalanceBefore, fromBalanceBefore, toBalanceBefore, toBalanceBefore, fromUnlockedBefore, fromUnlockedBefore); } // 计算手续费 feeAmount = _calculateFee(from, to, amount); // 检查余额 if (fromUnlockedBefore < amount + feeAmount) { return (false, "Insufficient balance", feeAmount, fromBalanceBefore, fromBalanceBefore, toBalanceBefore, toBalanceBefore, fromUnlockedBefore, fromUnlockedBefore); } // 计算转账后的余额 fromBalanceAfter = fromBalanceBefore - amount - feeAmount; toBalanceAfter = toBalanceBefore + amount; fromUnlockedAfter = fromUnlockedBefore - amount - feeAmount; return (true, "Success", feeAmount, fromBalanceBefore, fromBalanceAfter, toBalanceBefore, toBalanceAfter, fromUnlockedBefore, fromUnlockedAfter); } }