文件 1 的 1:DAOTOKEN.sol
pragma solidity ^0.8.12;
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);
}
library Address {
error AddressInsufficientBalance(address account);
error AddressEmptyCode(address target);
error FailedInnerCall();
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
function _revert(bytes memory returndata) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}
library SafeERC20 {
using Address for address;
error SafeERC20FailedOperation(address token);
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
}
library MerkleProof {
error MerkleProofInvalidMultiproof();
function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
return processProof(proof, leaf) == root;
}
function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
return processProofCalldata(proof, leaf) == root;
}
function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
function multiProofVerify(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProof(proof, proofFlags, leaves) == root;
}
function multiProofVerifyCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProofCalldata(proof, proofFlags, leaves) == root;
}
function processMultiProof(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
uint256 leavesLen = leaves.length;
uint256 proofLen = proof.length;
uint256 totalHashes = proofFlags.length;
if (leavesLen + proofLen != totalHashes + 1) {
revert MerkleProofInvalidMultiproof();
}
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i]
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
: proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
if (proofPos != proofLen) {
revert MerkleProofInvalidMultiproof();
}
unchecked {
return hashes[totalHashes - 1];
}
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function processMultiProofCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
uint256 leavesLen = leaves.length;
uint256 proofLen = proof.length;
uint256 totalHashes = proofFlags.length;
if (leavesLen + proofLen != totalHashes + 1) {
revert MerkleProofInvalidMultiproof();
}
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i]
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
: proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
if (proofPos != proofLen) {
revert MerkleProofInvalidMultiproof();
}
unchecked {
return hashes[totalHashes - 1];
}
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
}
function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
assembly {
mstore(0x00, a)
mstore(0x20, b)
value := keccak256(0x00, 0x40)
}
}
}
interface IUniswapV2Factory {
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint) external view returns (address pair);
function allPairsLength() external view returns (uint);
function createPair(address tokenA, address tokenB) external returns (address pair);
function setFeeTo(address) external;
function setFeeToSetter(address) external;
}
interface IUniswapV2Router01 {
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 removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountA, uint amountB);
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountToken, uint amountETH);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}
interface IUniswapV2Router02 is IUniswapV2Router01 {
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountETH);
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;
}
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;
error OwnableUnauthorizedAccount(address account);
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
contract DAOTOKEN is Ownable, IERC20 {
using SafeERC20 for IERC20;
event ChangeBuyTax(uint256 prevTax, uint256 newTax);
event ChangeSellTax(uint256 prevTax, uint256 newTax);
bool private _swap;
uint8 private constant _decimals = 18;
uint16 public buyTax = 500;
uint16 public sellTax = 500;
uint16 public constant denominator = 10_000;
uint256 public constant maxSupply = 100_000_000 ether;
uint256 private _totalSupply = 61_000_000 ether;
uint256 public threshold = 0.25 ether;
uint256 public swapPct = 10_000;
uint256 public immutable genesis;
uint256 public startLiquidity;
uint256 public constant firstDate2024 = 1704067200;
address payable private _multiSig;
address public immutable pair;
bytes32 public OGRoot;
bytes32 public annualRoot;
string private constant _name = "DAOGAME";
string private constant _symbol = "DAOG";
IUniswapV2Router02 immutable private uniV2Router;
uint256[] public remainingCommunity = [1_000_000 ether, 1_000_000 ether];
uint256[] public remainingTeam = [2_500_000 ether, 2_500_000 ether];
uint256[] public remainingRewards = [12_000_000 ether, 10_000_000 ether, 10_000_000 ether];
mapping(address => bool) private _isPool;
mapping(address => uint256) private _balances;
mapping(address => mapping (address => uint256)) private _allowances;
mapping(address => bool) public exempted;
mapping(address => bytes32[]) public proofs;
constructor(address multiSig_, address router_) Ownable(msg.sender){
require(
multiSig_ != address(0) &&
router_ != address(0),
"zero address"
);
genesis = block.timestamp;
exempted[_msgSender()] = true;
exempted[multiSig_] = true;
exempted[address(this)] = true;
_balances[multiSig_] = 1_000_000 ether;
_balances[_msgSender()] = 60_000_000 ether;
uniV2Router = IUniswapV2Router02(router_);
_multiSig = payable(multiSig_);
pair = IUniswapV2Factory(uniV2Router.factory()).createPair(uniV2Router.WETH(), address(this));
_isPool[pair] = true;
}
modifier lockSwap {
_swap = true;
_;
_swap = false;
}
receive() external payable {}
function name() external pure returns (string memory) {
return _name;
}
function symbol() external pure returns (string memory) {
return _symbol;
}
function decimals() external pure returns (uint8) {
return _decimals;
}
function totalSupply() external view override returns(uint256) {
return _totalSupply;
}
function balanceOf(address account) external view override returns (uint256) {
return _balances[account];
}
function allowance(address owner, address spender) external view override returns (uint256) {
return _allowances[owner][spender];
}
function isPool(address addr) external view returns (bool){
return _isPool[addr];
}
function approve(address spender, uint256 amount) external override returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
function transfer(address recipient, uint256 amount) external override returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
function transferFrom(address sender, address recipient, uint256 amount) external override returns (bool) {
require (_allowances[sender][_msgSender()] >= amount, "ERC20: transfer amount exceeds allowance");
_transfer(sender, recipient, amount);
_approve(sender, _msgSender(), _allowances[sender][_msgSender()] - amount);
return true;
}
function setProof(bytes32[] memory _proof) external {
proofs[_msgSender()] = _proof;
}
function setBuyTax(uint16 newTax) external onlyOwner {
require (newTax <= 500, "tax cannot exceed 5%");
emit ChangeBuyTax(buyTax, newTax);
buyTax = newTax;
}
function setSellTax(uint16 newTax) external onlyOwner {
require (newTax <= 500, "tax cannot exceed 5%");
emit ChangeSellTax(sellTax, newTax);
sellTax = newTax;
}
function setExempted(address _address, bool exempt_) external onlyOwner {
exempted[_address] = exempt_;
}
function setPool(address addr, bool isPool_) external onlyOwner {
require(addr != address(0), "zero address cannot be pool");
_isPool[addr] = isPool_;
}
function safeTokenSwap(uint256 amount) external onlyOwner {
_tokensToETH(amount);
}
function safeETHtransfer() external onlyOwner {
(bool success,) = _multiSig.call{value: address(this).balance}("");
require(success, "Failed to send Ether");
}
function setOGRoot(bytes32 _OGRoot) external onlyOwner {
OGRoot = _OGRoot;
}
function setAnnualRoot(bytes32 _annualRoot) external onlyOwner {
annualRoot = _annualRoot;
}
function setStartLiquidity() external onlyOwner {
require(startLiquidity == 0, "already set");
startLiquidity = block.timestamp;
}
function setThreshold(uint256 _threshold) external onlyOwner {
threshold = _threshold;
}
function setSwapPct(uint256 _swapPct) external onlyOwner {
require(_swapPct <= denominator, "wrong pct");
swapPct = _swapPct;
}
function mintCommunity() external onlyOwner {
_mint(remainingCommunity);
}
function mintTeam() external onlyOwner {
_mint(remainingTeam);
}
function mintRewards() external onlyOwner {
uint256 available;
if(block.timestamp >= firstDate2024 + 2 * (365.25 * 1 days)) {
available += remainingRewards[2];
delete remainingRewards[2];
}
if(block.timestamp >= firstDate2024 + (365.25 * 1 days)) {
available += remainingRewards[1];
delete remainingRewards[1];
}
if(block.timestamp >= firstDate2024) {
available += remainingRewards[0];
delete remainingRewards[0];
}
_mintAvailable(available);
}
function setMultiSig(address payable multiSig_) external onlyOwner {
_multiSig = multiSig_;
}
function withdrawLiquidity() external onlyOwner {
require(
startLiquidity != 0 &&
block.timestamp >= startLiquidity + (365.25 * 1 days),
"not yet"
);
uint256 lpBalance = IERC20(pair).balanceOf(address(this));
require(lpBalance != 0, "zero lp balance");
IERC20(pair).safeTransfer(_multiSig, lpBalance);
}
function _approve(address owner, address spender, uint256 amount) private {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _transfer(address sender, address recipient, uint256 amount) private {
require(amount != 0, "cannot transfer zero");
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
require(_balances[sender] >= amount, "ERC20: transfer exceeds balance");
require(!(_isPool[sender] && _isPool[recipient]), "cannot transfer pool to pool");
require(
startLiquidity != 0
|| exempted[sender]
|| exempted[recipient],
"unauthorized transfer"
);
uint256 taxedAmount = amount;
if(startLiquidity != 0){
uint256 tax;
bool buy;
bool sell;
if(_isPool[sender]) {
buy = true;
} else if(_isPool[recipient]) {
sell = true;
}
if(buy && !exempted[recipient]) {
if(block.timestamp <= startLiquidity + 1 hours / 2) {
_verify(recipient, OGRoot);
} else if(block.timestamp <= startLiquidity + 1 hours) {
_verify(recipient, annualRoot);
}
tax = amount * buyTax / denominator;
} else if(sell && !exempted[sender]) {
tax = amount * sellTax / denominator;
}
if(tax != 0){
unchecked {
taxedAmount -= tax;
_balances[address(this)] += tax;
}
emit Transfer(sender, address(this), tax);
}
if(sell && _balances[address(this)] != 0) {
address[] memory path = _getPath();
uint256 amountOut = uniV2Router.getAmountsOut(_balances[address(this)], path)[1];
if (amountOut >= threshold && !_swap && swapPct != 0) {
_tokensToETH(_balances[address(this)] * swapPct / denominator);
}
}
}
if(block.timestamp <= startLiquidity + 1 days ){
_checkLimits(
recipient,
taxedAmount,
50
);
} else if(block.timestamp <= startLiquidity + 4 days) {
_checkLimits(
recipient,
taxedAmount,
100
);
}
unchecked{
_balances[recipient] += taxedAmount;
_balances[sender] -= amount;
}
emit Transfer(sender, recipient, taxedAmount);
}
function _mint(uint256[] storage remaining) private {
uint256 available;
if(block.timestamp >= genesis + (365.25 * 2 days) ) {
available += remaining[1];
delete remaining[1];
}
if(block.timestamp >= genesis + (365.25 * 1 days)) {
available += remaining[0];
delete remaining[0];
}
_mintAvailable(available);
}
function _checkLimits(
address recipient,
uint256 taxedAmount,
uint8 pct
) private view {
uint256 limit = maxSupply * pct / denominator;
string memory pctStr = pct == 50 ? "0.5% supply": "1% supply";
if(!exempted[recipient] && !_isPool[recipient]) {
require(
_balances[recipient] + taxedAmount <= limit,
string.concat("recipient balance ", pctStr)
);
}
}
function _verify(address _whitelisted, bytes32 _root) private view {
string memory group = _root == OGRoot ? "OG" : "Annual";
require(
MerkleProof.verify(
proofs[_whitelisted],
_root,
keccak256(abi.encodePacked(_whitelisted))
),
string.concat("not whitelisted ", group)
);
}
function _getPath() private view returns(address[] memory) {
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = uniV2Router.WETH();
return path;
}
function _tokensToETH(uint256 amount) private lockSwap {
if(_multiSig != address(0)){
address[] memory path = _getPath();
_approve(address(this), address(uniV2Router), amount);
uniV2Router
.swapExactTokensForETHSupportingFeeOnTransferTokens(
amount,
0,
path,
_multiSig,
block.timestamp
);
}
}
function _mintAvailable(uint256 available) private {
require(available != 0, "nothing to withdraw");
unchecked {
_balances[_multiSig] += available;
_totalSupply += available;
}
require(_totalSupply <= maxSupply, "wrong supply");
emit Transfer(address(0), _multiSig, available);
}
}