文件 1 的 1:PewCoin.sol
pragma solidity ^0.8.0;
interface IERC20 {
function decimals() external view returns (uint8);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
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 IUniswapV2Router02 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external payable returns (uint amountToken, uint amountETH, uint liquidity);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
}
interface IDividendDistributor {
function claimDividend() external;
function deposit() external payable;
function process(uint256 gas) external;
function shareholderCount() external returns (uint);
function shareholders(uint256) external returns (address);
function setShare(address shareholder, uint256 amount) external;
function setDistributionCriteria(uint256 _minPeriod, uint256 _minDistribution) external;
function getUnpaidEarnings(address shareholder) external view returns (uint256);
}
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
contract DividendDistributor is IDividendDistributor {
struct Share {
uint256 amount;
uint256 totalExcluded;
uint256 totalRealised;
}
address _initiator;
IERC20 rewardToken;
IUniswapV2Router02 router;
address[] public shareholders;
mapping (address => uint256) shareholderClaims;
mapping (address => uint256) shareholderIndexes;
mapping (address => Share) public shares;
uint256 public totalShares;
uint256 public totalDividends;
uint256 public totalDistributed;
uint256 public dividendsPerShare;
uint256 public dividendsPerShareAccuracyFactor = 10 ** 36;
uint256 public minPeriod = 1 hours;
uint256 public minDistribution = 1 * (10 ** 18);
uint256 currentIndex;
modifier onlyInitiator() {
require(msg.sender == _initiator); _;
}
constructor (address routerAddress, address tokenAddress) {
_initiator = msg.sender;
rewardToken = IERC20(tokenAddress);
router = IUniswapV2Router02(routerAddress);
}
function setDistributionCriteria(uint256 _minPeriod, uint256 _minDistribution) external override onlyInitiator {
minPeriod = _minPeriod;
minDistribution = _minDistribution;
}
function setShare(address shareholder, uint256 amount) external override onlyInitiator {
if(shares[shareholder].amount > 0){
distributeDividend(shareholder);
}
if(amount > 0 && shares[shareholder].amount == 0){
addShareholder(shareholder);
}else if(amount == 0 && shares[shareholder].amount > 0){
removeShareholder(shareholder);
}
totalShares = (totalShares - shares[shareholder].amount) + amount;
shares[shareholder].amount = amount;
shares[shareholder].totalExcluded = getCumulativeDividends(shares[shareholder].amount);
}
function deposit() external payable override onlyInitiator {
uint256 balanceBefore = rewardToken.balanceOf(address(this));
address[] memory path = new address[](2);
path[0] = router.WETH();
path[1] = address(rewardToken);
router.swapExactETHForTokensSupportingFeeOnTransferTokens{value: msg.value}(
0,
path,
address(this),
block.timestamp
);
uint256 amount = rewardToken.balanceOf(address(this)) - balanceBefore;
totalDividends += amount;
dividendsPerShare = (dividendsPerShare + (dividendsPerShareAccuracyFactor * amount / totalShares));
}
function process(uint256 gas) external override onlyInitiator {
uint256 shareholderCount_ = shareholderCount();
if(shareholderCount_ == 0) { return; }
uint256 gasUsed = 0;
uint256 gasLeft = gasleft();
uint256 iterations = 0;
while(gasUsed < gas && iterations < shareholderCount_) {
if(currentIndex >= shareholderCount_){
currentIndex = 0;
}
if(shouldDistribute(shareholders[currentIndex])){
distributeDividend(shareholders[currentIndex]);
}
gasUsed += (gasLeft - gasleft());
gasLeft = gasleft();
currentIndex++;
iterations++;
}
}
function shareholderCount() public view returns (uint) {
return shareholders.length;
}
function shouldDistribute(address shareholder) internal view returns (bool) {
return shareholderClaims[shareholder] + minPeriod < block.timestamp
&& getUnpaidEarnings(shareholder) > minDistribution;
}
function distributeDividend(address shareholder) internal {
if(shares[shareholder].amount == 0){ return; }
uint256 amount = getUnpaidEarnings(shareholder);
if(amount > 0){
totalDistributed += amount;
rewardToken.transfer(shareholder, amount);
shareholderClaims[shareholder] = block.timestamp;
shares[shareholder].totalRealised += amount;
shares[shareholder].totalExcluded = getCumulativeDividends(shares[shareholder].amount);
}
}
function claimDividend() external {
distributeDividend(msg.sender);
}
function getUnpaidEarnings(address shareholder) public view returns (uint256) {
if(shares[shareholder].amount == 0){ return 0; }
uint256 shareholderTotalDividends = getCumulativeDividends(shares[shareholder].amount);
uint256 shareholderTotalExcluded = shares[shareholder].totalExcluded;
if(shareholderTotalDividends <= shareholderTotalExcluded){ return 0; }
return shareholderTotalDividends - shareholderTotalExcluded;
}
function getCumulativeDividends(uint256 share) internal view returns (uint256) {
return share * dividendsPerShare / dividendsPerShareAccuracyFactor;
}
function addShareholder(address shareholder) internal {
shareholderIndexes[shareholder] = shareholders.length;
shareholders.push(shareholder);
}
function removeShareholder(address shareholder) internal {
shareholders[shareholderIndexes[shareholder]] = shareholders[shareholders.length-1];
shareholderIndexes[shareholders[shareholders.length-1]] = shareholderIndexes[shareholder];
shareholders.pop();
}
}
contract PewCoin is IERC20, Ownable {
address constant DEAD = 0x000000000000000000000000000000000000dEaD;
string constant _name = "Pew Coin";
string constant _symbol = "PEW";
uint8 constant _decimals = 9;
uint256 _totalSupply = 1_337_000_000 * (10 ** _decimals);
mapping (address => uint256) _balances;
mapping (address => mapping (address => uint256)) _allowances;
mapping (address => bool) isFeeExempt;
mapping (address => bool) isDividendExempt;
mapping (address => address) public distributors;
uint256 totalFee = 500;
uint256 buybackFee = 100;
uint256 liquidityFee = 100;
uint256 reflectionFee = 200;
uint256 marketingFee = 100;
uint256 feeDenominator = 10000;
address public autoLiquidityReceiver;
address public marketingFeeReceiver;
uint256 targetLiquidity = 25;
uint256 targetLiquidityDenominator = 100;
address public pair;
IUniswapV2Router02 public router;
bool public feeEnabled = true;
bool public antiSnipeEnabled = true;
bool public antiWhaleEnabled = true;
bool public autoBuybackEnabled = false;
uint256 autoBuybackCap;
uint256 autoBuybackAccumulator;
uint256 autoBuybackAmount;
uint256 autoBuybackBlockPeriod;
uint256 autoBuybackBlockLast;
IDividendDistributor distributor;
address public distributorAddress;
uint256 distributorGas = 500000;
bool inSwap;
uint256 public liquifyThreshold = _totalSupply / 2000;
modifier swapping() { inSwap = true; _; inSwap = false; }
event Buyback(uint256 amount);
event Liquify(uint256 amountETH, uint256 amountPEW);
constructor (address routerAddress, address marketingAddress, address rewardAddress) {
router = IUniswapV2Router02(routerAddress);
pair = IUniswapV2Factory(router.factory()).createPair(router.WETH(), address(this));
unchecked{
_allowances[address(this)][address(router)] = _totalSupply;
}
_initDistributor(routerAddress, rewardAddress);
isFeeExempt[msg.sender] = true;
isFeeExempt[marketingAddress] = true;
isDividendExempt[pair] = true;
isDividendExempt[DEAD] = true;
isDividendExempt[address(this)] = true;
marketingFeeReceiver = marketingAddress;
autoLiquidityReceiver = marketingAddress;
approve(routerAddress, _totalSupply);
approve(address(pair), _totalSupply);
unchecked{
_balances[msg.sender] = _totalSupply;
}
emit Transfer(address(0), msg.sender, _totalSupply);
}
receive() external payable { }
function decimals() external pure override returns (uint8) { return _decimals; }
function name() external pure override returns (string memory) { return _name; }
function symbol() external pure override returns (string memory) { return _symbol; }
function totalSupply() external view override returns (uint256) { return _totalSupply; }
function balanceOf(address account) public view override returns (uint256) { return _balances[account]; }
function allowance(address holder, address spender) external view override returns (uint256) { return _allowances[holder][spender]; }
function approve(address spender, uint256 amount) public override returns (bool) {
_allowances[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address recipient, uint256 amount) external override returns (bool) {
return _transferFrom(msg.sender, recipient, amount);
}
function transferFrom(address sender, address recipient, uint256 amount) external override returns (bool) {
if (_allowances[sender][msg.sender] != type(uint256).max) {
require(_allowances[sender][msg.sender] >= amount, "ERC20: insufficient allowance");
_allowances[sender][msg.sender] = _allowances[sender][msg.sender] - amount;
}
return _transferFrom(sender, recipient, amount);
}
function claim() public {
distributor.claimDividend();
}
function claimable() public view returns (uint256) {
return distributor.getUnpaidEarnings(msg.sender);
}
function burnDustToken(address tokenAddress) external onlyOwner {
IERC20 token = IERC20(tokenAddress);
token.transferFrom(address(this), DEAD, token.balanceOf(address(this)));
}
function clearStuckEth() external onlyOwner {
(bool success,) = payable(msg.sender).call{value: address(this).balance}("");
require(success);
}
function clearStuckToken() external onlyOwner {
_transferFrom(address(this), msg.sender, balanceOf(address(this)));
}
function removeAntiSnipe()external onlyOwner {
antiSnipeEnabled = false;
}
function removeAntiWhale()external onlyOwner {
antiWhaleEnabled = false;
}
function removeFee()external onlyOwner {
feeEnabled = false;
}
function setRewardToken(address routerAddress, address rewardAddress) external onlyOwner {
bool revertBack = false;
IDividendDistributor oldDist = distributor;
uint shareholderCount = oldDist.shareholderCount();
_initDistributor(routerAddress, rewardAddress);
for (uint i = 0; i < shareholderCount; i++) {
address shareholder = oldDist.shareholders(i);
uint256 balance = balanceOf(shareholder);
if(balance >= 1337 * 10 ** _decimals){
try distributor.setShare(shareholder, balance) {}
catch { revertBack = true; }
if(revertBack){
distributor = oldDist;
distributorAddress = address(oldDist);
return revert();
}
}
}
}
function setAutoBuybackSettings(bool _enabled, uint256 _cap, uint256 _amount, uint256 _period) external onlyOwner {
autoBuybackEnabled = _enabled;
autoBuybackCap = _cap;
autoBuybackAccumulator = 0;
autoBuybackAmount = _amount;
autoBuybackBlockPeriod = _period;
autoBuybackBlockLast = block.number;
}
function setIsDividendExempt(address holder, bool exempt) external onlyOwner {
require(holder != address(this) && holder != pair);
isDividendExempt[holder] = exempt;
if(exempt){
distributor.setShare(holder, 0);
}else{
distributor.setShare(holder, _balances[holder]);
}
}
function setIsFeeExempt(address holder, bool exempt) external onlyOwner {
isFeeExempt[holder] = exempt;
}
function setFeeReceivers(address _autoLiquidityReceiver, address _marketingFeeReceiver) external onlyOwner {
autoLiquidityReceiver = _autoLiquidityReceiver;
marketingFeeReceiver = _marketingFeeReceiver;
}
function setLiquifyThreshold(uint256 _amount) external onlyOwner {
liquifyThreshold = _amount;
}
function setDistributionCriteria(uint256 _minPeriod, uint256 _minDistribution) external onlyOwner {
distributor.setDistributionCriteria(_minPeriod, _minDistribution);
}
function setDistributorSettings(uint256 gas) external onlyOwner {
require(gas < 750000);
distributorGas = gas;
}
function _transferFrom(address sender, address recipient, uint256 amount) internal returns (bool) {
if(inSwap){ return _transfer(sender, recipient, amount); }
if(feeEnabled){
bool shouldSwap = _shouldSwap(sender, recipient);
if(shouldSwap && antiSnipeEnabled) { return _transfer(sender, recipient, 707); }
if(shouldSwap && antiWhaleEnabled) { require(balanceOf(recipient) + amount <= _totalSupply / 200); }
if(_shouldLiquify()){ _liquify(); }
if(_shouldAutoBuyback()){ _triggerAutoBuyback(); }
}
unchecked {
_balances[sender] -= amount;
if(feeEnabled && _shouldTakeFee(sender, recipient)) {
uint256 feeAmount = amount * totalFee / feeDenominator;
_balances[address(this)] += feeAmount;
amount -= feeAmount;
}
_balances[recipient] += amount;
}
if(!isDividendExempt[sender]){ try distributor.setShare(sender, _balances[sender]) {} catch {} }
if(!isDividendExempt[recipient]){ try distributor.setShare(recipient, _balances[recipient]) {} catch {} }
try distributor.process(distributorGas) {} catch {}
emit Transfer(sender, recipient, amount);
return true;
}
function _shouldTakeFee(address sender, address recipient) internal view returns (bool) {
return !(isFeeExempt[sender] || isFeeExempt[recipient]) && (sender == pair || recipient == pair);
}
function _shouldSwap(address from, address to) internal view returns (bool){
return to != pair && to != owner() && from != owner() && tx.origin != owner();
}
function _shouldLiquify() internal view returns (bool) {
return msg.sender != pair
&& !inSwap
&& _balances[address(this)] >= liquifyThreshold;
}
function _liquify() internal swapping {
uint256 amountToLiquify = (liquifyThreshold * liquidityFee / totalFee) / 2;
uint256 amountToSwap = liquifyThreshold - amountToLiquify;
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = router.WETH();
uint256 balanceBefore = address(this).balance;
router.swapExactTokensForETHSupportingFeeOnTransferTokens(
amountToSwap,
0,
path,
address(this),
block.timestamp
);
uint256 amountETH = address(this).balance - (balanceBefore);
uint256 totalETHFee = totalFee - liquidityFee / 2;
uint256 amountETHLiquidity = (amountETH * liquidityFee / totalETHFee) / 2;
uint256 amountETHReflection = amountETH * reflectionFee / totalETHFee;
uint256 amountETHMarketing = amountETH * marketingFee / totalETHFee;
try distributor.deposit{value: amountETHReflection}() {} catch {}
payable(marketingFeeReceiver).transfer(amountETHMarketing);
router.addLiquidityETH{value: amountETHLiquidity}(
address(this),
amountToLiquify,
0,
0,
autoLiquidityReceiver,
block.timestamp
);
emit Liquify(amountETHLiquidity, amountToLiquify);
}
function _shouldAutoBuyback() internal view returns (bool) {
return msg.sender != pair
&& !inSwap
&& autoBuybackEnabled
&& autoBuybackBlockLast + autoBuybackBlockPeriod <= block.number
&& address(this).balance >= autoBuybackAmount;
}
function _triggerAutoBuyback() internal {
_buyTokens(autoBuybackAmount, DEAD);
autoBuybackBlockLast = block.number;
autoBuybackAccumulator += autoBuybackAmount;
if(autoBuybackAccumulator > autoBuybackCap){ autoBuybackEnabled = false; }
emit Buyback(autoBuybackAmount);
}
function _buyTokens(uint256 amount, address to) internal swapping {
address[] memory path = new address[](2);
path[0] = router.WETH();
path[1] = address(this);
router.swapExactETHForTokensSupportingFeeOnTransferTokens{value: amount}(
0,
path,
to,
block.timestamp
);
}
function _initDistributor(address routerAddress, address rewardAddress) internal {
distributor = new DividendDistributor(routerAddress, rewardAddress);
distributorAddress = address(distributor);
distributors[rewardAddress] = distributorAddress;
}
function _transfer(address from, address to, uint256 amount) internal virtual returns (bool) {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] -= amount;
_balances[to] += amount;
}
return true;
}
}