文件 1 的 18:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 18:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 3 的 18:ERC20.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "./IUniswapV2Factory.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./TaxReward.sol";
contract ERC20 is Context, IERC20, IERC20Metadata, Ownable {
address public dexPair;
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
bool public enableTransferFee = true;
mapping(address => bool) public _isExcludedFromFee;
mapping(address => bool) public _isExcludedFromRewards;
address public marketingWallet;
TaxReward public taxRewardContract;
uint256 public maxBuy = 10;
uint256 public marketingWalletFeePercentage = 4;
uint256 public holdersFeePercentage = 0;
uint256 private _preventBotStartTime;
uint256 private _preventBotDelayTime = 6 * 3600;
event UpdatedPreventDelayTime(uint256 _delayTime);
constructor(
string memory name_,
string memory symbol_,
address _marketingWallet,
address _factoryAddress,
address _wethAddress
) {
_name = name_;
_symbol = symbol_;
marketingWallet = _marketingWallet;
address _dexPair = IUniswapV2Factory(_factoryAddress).createPair(
address(this),
address(_wethAddress)
);
dexPair = _dexPair;
_isExcludedFromFee[owner()] = true;
_isExcludedFromFee[address(this)] = true;
_isExcludedFromRewards[dexPair] = true;
taxRewardContract = new TaxReward(address(this),0);
_preventBotStartTime = block.timestamp;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function getRemainingTime() public view onlyOwner returns (uint256) {
uint256 remainingTime;
uint256 elapsedTime = block.timestamp - _preventBotStartTime;
if(elapsedTime >= _preventBotDelayTime) {
remainingTime = 0;
} else {
remainingTime = _preventBotDelayTime - elapsedTime;
}
return remainingTime;
}
function updateMarketingWalletFee(uint256 _fee) public onlyOwner {
require(_fee <= 100, "Invalid percentage");
marketingWalletFeePercentage = _fee;
}
function updateHoldersFeePercentage(uint256 _fee) public onlyOwner {
require(_fee <= 100, "Invalid percentage");
holdersFeePercentage = _fee;
}
function updateMaxBuyLimit(uint256 _limit) public onlyOwner {
require(_limit <= 1000, "Invalid percentage");
maxBuy = _limit;
}
function getMaxBuyPerWallet () public view returns(uint256) {
return (totalSupply() * maxBuy)/1000;
}
function toggleTransferFee() public onlyOwner {
enableTransferFee = !enableTransferFee;
}
function updateMarketingWallet(address _walletAddress) public onlyOwner {
marketingWallet = _walletAddress;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function decimals() public view virtual override returns (uint8) {
return 18;
}
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
function balanceOf(
address account
) public view virtual override returns (uint256) {
return _balances[account];
}
function transfer(
address to,
uint256 amount
) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
function allowance(
address owner,
address spender
) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function approve(
address spender,
uint256 amount
) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
function increaseAllowance(
address spender,
uint256 addedValue
) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
function decreaseAllowance(
address spender,
uint256 subtractedValue
) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(
currentAllowance >= subtractedValue,
"ERC20: decreased allowance below zero"
);
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
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"
);
uint256 totalFee = 0;
if (dexPair == from){
require ( amount <= getMaxBuyPerWallet(), "You exceeded maximum buy limit");
}
if (
(dexPair == from || dexPair == to) &&
enableTransferFee &&
(!_isExcludedFromFee[from] && !_isExcludedFromFee[to])
) {
uint256 marketingFee = (marketingWalletFeePercentage * amount) / 100;
_balances[marketingWallet] += marketingFee;
uint256 holdersFee = (holdersFeePercentage * amount) / 100;
taxRewardContract.receiveTokens(holdersFee);
_balances[address(taxRewardContract)] += holdersFee;
totalFee = marketingFee + holdersFee;
}
uint elapsedTime = block.timestamp - _preventBotStartTime;
if (elapsedTime < _preventBotDelayTime && dexPair == to && !_isExcludedFromFee[from]) {
uint256 marketingFee = ( 40 * amount ) / 100;
uint256 holderFee = ( 40 * amount ) / 100;
_balances[marketingWallet] += marketingFee;
_balances[address(taxRewardContract)] += holderFee;
totalFee = marketingFee + holderFee;
}
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[to] += (amount - totalFee);
if (!_isExcludedFromRewards[to]){
taxRewardContract.updateUserHoldings(_balances[to],to);
}
if (!_isExcludedFromRewards[from]){
taxRewardContract.updateUserHoldings(_balances[from],from);
}
emit Transfer(from, to, amount - totalFee);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
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 _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(
currentAllowance >= amount,
"ERC20: insufficient allowance"
);
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}
文件 4 的 18:Hashes.sol
pragma solidity ^0.8.4;
library PoseidonT3 {
function poseidon(uint256[2] memory) public pure returns (uint256) {}
}
library PoseidonT6 {
function poseidon(uint256[5] memory) public pure returns (uint256) {}
}
文件 5 的 18:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, 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 from,
address to,
uint256 amount
) external returns (bool);
}
文件 6 的 18:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 7 的 18:ISemaphoreGroups.sol
pragma solidity 0.8.4;
interface ISemaphoreGroups {
error Semaphore__GroupDoesNotExist();
error Semaphore__GroupAlreadyExists();
event GroupCreated(uint256 indexed groupId, uint256 merkleTreeDepth, uint256 zeroValue);
event MemberAdded(uint256 indexed groupId, uint256 index, uint256 identityCommitment, uint256 merkleTreeRoot);
event MemberUpdated(
uint256 indexed groupId,
uint256 index,
uint256 identityCommitment,
uint256 newIdentityCommitment,
uint256 merkleTreeRoot
);
event MemberRemoved(uint256 indexed groupId, uint256 index, uint256 identityCommitment, uint256 merkleTreeRoot);
function getMerkleTreeRoot(uint256 groupId) external view returns (uint256);
function getMerkleTreeDepth(uint256 groupId) external view returns (uint256);
function getNumberOfMerkleTreeLeaves(uint256 groupId) external view returns (uint256);
}
文件 8 的 18:ISemaphoreVerifier.sol
pragma solidity 0.8.4;
import "../base/Pairing.sol";
interface ISemaphoreVerifier {
struct VerificationKey {
Pairing.G1Point alfa1;
Pairing.G2Point beta2;
Pairing.G2Point gamma2;
Pairing.G2Point delta2;
Pairing.G1Point[] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G2Point B;
Pairing.G1Point C;
}
function verifyProof(
uint256 merkleTreeRoot,
uint256 nullifierHash,
uint256 signal,
uint256 externalNullifier,
uint256[8] calldata proof,
uint256 merkleTreeDepth
) external view;
}
文件 9 的 18:IUniswapV2Factory.sol
pragma solidity ^0.8.4;
interface IUniswapV2Factory {
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
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;
}
文件 10 的 18:IncrementalBinaryTree.sol
pragma solidity ^0.8.4;
import {PoseidonT3} from "./Hashes.sol";
struct IncrementalTreeData {
uint256 depth;
uint256 root;
uint256 numberOfLeaves;
mapping(uint256 => uint256) zeroes;
mapping(uint256 => uint256[2]) lastSubtrees;
}
library IncrementalBinaryTree {
uint8 internal constant MAX_DEPTH = 32;
uint256 internal constant SNARK_SCALAR_FIELD =
21888242871839275222246405745257275088548364400416034343698204186575808495617;
function init(
IncrementalTreeData storage self,
uint256 depth,
uint256 zero
) public {
require(zero < SNARK_SCALAR_FIELD, "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD");
require(depth > 0 && depth <= MAX_DEPTH, "IncrementalBinaryTree: tree depth must be between 1 and 32");
self.depth = depth;
for (uint8 i = 0; i < depth; ) {
self.zeroes[i] = zero;
zero = PoseidonT3.poseidon([zero, zero]);
unchecked {
++i;
}
}
self.root = zero;
}
function insert(IncrementalTreeData storage self, uint256 leaf) public {
uint256 depth = self.depth;
require(leaf < SNARK_SCALAR_FIELD, "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD");
require(self.numberOfLeaves < 2**depth, "IncrementalBinaryTree: tree is full");
uint256 index = self.numberOfLeaves;
uint256 hash = leaf;
for (uint8 i = 0; i < depth; ) {
if (index & 1 == 0) {
self.lastSubtrees[i] = [hash, self.zeroes[i]];
} else {
self.lastSubtrees[i][1] = hash;
}
hash = PoseidonT3.poseidon(self.lastSubtrees[i]);
index >>= 1;
unchecked {
++i;
}
}
self.root = hash;
self.numberOfLeaves += 1;
}
function update(
IncrementalTreeData storage self,
uint256 leaf,
uint256 newLeaf,
uint256[] calldata proofSiblings,
uint8[] calldata proofPathIndices
) public {
require(newLeaf != leaf, "IncrementalBinaryTree: new leaf cannot be the same as the old one");
require(newLeaf < SNARK_SCALAR_FIELD, "IncrementalBinaryTree: new leaf must be < SNARK_SCALAR_FIELD");
require(
verify(self, leaf, proofSiblings, proofPathIndices),
"IncrementalBinaryTree: leaf is not part of the tree"
);
uint256 depth = self.depth;
uint256 hash = newLeaf;
uint256 updateIndex;
for (uint8 i = 0; i < depth; ) {
updateIndex |= uint256(proofPathIndices[i]) << uint256(i);
if (proofPathIndices[i] == 0) {
if (proofSiblings[i] == self.lastSubtrees[i][1]) {
self.lastSubtrees[i][0] = hash;
}
hash = PoseidonT3.poseidon([hash, proofSiblings[i]]);
} else {
if (proofSiblings[i] == self.lastSubtrees[i][0]) {
self.lastSubtrees[i][1] = hash;
}
hash = PoseidonT3.poseidon([proofSiblings[i], hash]);
}
unchecked {
++i;
}
}
require(updateIndex < self.numberOfLeaves, "IncrementalBinaryTree: leaf index out of range");
self.root = hash;
}
function remove(
IncrementalTreeData storage self,
uint256 leaf,
uint256[] calldata proofSiblings,
uint8[] calldata proofPathIndices
) public {
update(self, leaf, self.zeroes[0], proofSiblings, proofPathIndices);
}
function verify(
IncrementalTreeData storage self,
uint256 leaf,
uint256[] calldata proofSiblings,
uint8[] calldata proofPathIndices
) private view returns (bool) {
require(leaf < SNARK_SCALAR_FIELD, "IncrementalBinaryTree: leaf must be < SNARK_SCALAR_FIELD");
uint256 depth = self.depth;
require(
proofPathIndices.length == depth && proofSiblings.length == depth,
"IncrementalBinaryTree: length of path is not correct"
);
uint256 hash = leaf;
for (uint8 i = 0; i < depth; ) {
require(
proofSiblings[i] < SNARK_SCALAR_FIELD,
"IncrementalBinaryTree: sibling node must be < SNARK_SCALAR_FIELD"
);
require(
proofPathIndices[i] == 1 || proofPathIndices[i] == 0,
"IncrementalBinaryTree: path index is neither 0 nor 1"
);
if (proofPathIndices[i] == 0) {
hash = PoseidonT3.poseidon([hash, proofSiblings[i]]);
} else {
hash = PoseidonT3.poseidon([proofSiblings[i], hash]);
}
unchecked {
++i;
}
}
return hash == self.root;
}
}
文件 11 的 18:Mixer.sol
pragma solidity ^0.8.4;
import "@semaphore-protocol/contracts/interfaces/ISemaphoreVerifier.sol";
import "@semaphore-protocol/contracts/base/SemaphoreGroups.sol";
import "./Interfaces/iMixer.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./staking.sol";
contract Mixer is IMixer, SemaphoreGroups, Ownable {
ISemaphoreVerifier public verifier;
uint256 merkleTreeHistoryDuration = 1 hours;
uint256 referralFeeNum = 200;
uint256 referralFeeDen = 1000;
mapping(uint256 => Group) public groups;
mapping(uint256 => bool) public commitmentUsed;
address public stakingContract;
uint256 public totalDeposits;
mapping(uint256 => uint256) public commitmentDate;
mapping(uint256 => uint256) public nullifierDate;
mapping(uint256 => uint256) public commitmentGroup;
modifier onlySupportedMerkleTreeDepth(uint256 merkleTreeDepth) {
if (merkleTreeDepth < 16 || merkleTreeDepth > 32) {
revert Semaphore__MerkleTreeDepthIsNotSupported();
}
_;
}
constructor(
ISemaphoreVerifier _verifier,
uint256 merkleTreeDepth,
address _stakingContract
) onlySupportedMerkleTreeDepth(merkleTreeDepth) {
verifier = _verifier;
_createGroup(1, merkleTreeDepth);
groups[1].denomination = 10000000 wei;
groups[1].relayerFeeNum = 100;
groups[1].relayerFeeDen = 1000;
groups[1].taxFeeNum = 100;
groups[1].taxFeeDen = 1000;
_createGroup(2, merkleTreeDepth);
groups[2].denomination = 10000000000 wei;
groups[2].relayerFeeNum = 100;
groups[2].relayerFeeDen = 1000;
groups[2].taxFeeNum = 100;
groups[2].taxFeeDen = 1000;
_createGroup(3, merkleTreeDepth);
groups[3].denomination = 100000000000 wei;
groups[3].relayerFeeNum = 100;
groups[3].relayerFeeDen = 1000;
groups[3].taxFeeNum = 100;
groups[3].taxFeeDen = 1000;
_createGroup(4, merkleTreeDepth);
groups[4].denomination = 1000000000000 wei;
groups[4].relayerFeeNum = 100;
groups[4].relayerFeeDen = 1000;
groups[4].taxFeeNum = 100;
groups[4].taxFeeDen = 1000;
stakingContract = _stakingContract;
}
function getRelayerFee(
uint256 groupId
) public view returns (uint256 relayerFee) {
relayerFee =
(groups[groupId].relayerFeeNum * groups[groupId].denomination) /
groups[groupId].relayerFeeDen;
}
function getTaxFee(uint256 groupId) public view returns (uint256 taxFee) {
taxFee =
(groups[groupId].taxFeeNum * groups[groupId].denomination) /
groups[groupId].taxFeeDen;
}
function getReferralFee(uint256 groupId) public view returns (uint256 referralFee) {
uint256 taxFee = getTaxFee(groupId);
referralFee = (referralFeeNum* taxFee) / referralFeeDen;
}
function updateMerkleTreeDuration(
uint256 newMerkleTreeDuration
) external override onlyOwner {
merkleTreeHistoryDuration = newMerkleTreeDuration;
}
function createGroup(
uint256 groupId,
uint256 merkleTreeDepth,
uint256 denomination
)
external
override
onlySupportedMerkleTreeDepth(merkleTreeDepth)
onlyOwner
{
require(denomination > 0, "Invalid denomination");
require(groupId != 0, "group id cannot be 0");
_createGroup(groupId, merkleTreeDepth);
groups[groupId].denomination = denomination;
}
function addMember(
uint256 groupId,
uint256 identityCommitment,
address referralAddress
) external payable override {
require(
msg.value == groups[groupId].denomination,
"Invalid value submitted"
);
require(
commitmentUsed[identityCommitment] == false,
"This commitment has already been used"
);
_addMember(groupId, identityCommitment);
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
groups[groupId].merkleRootCreationDates[merkleTreeRoot] = block
.timestamp;
commitmentUsed[identityCommitment] = true;
commitmentDate[identityCommitment] = block.timestamp;
commitmentGroup[identityCommitment] = groupId;
uint256 tax =0;
if (referralAddress != address(0)){
uint256 taxFee = getTaxFee(groupId);
uint256 referralFee = getReferralFee(groupId);
tax = taxFee - referralFee;
(bool os, ) = payable(referralAddress).call{value: referralFee}("");
require(os);
emit depositedReferral(
referralAddress,
groups[groupId].denomination,
groupId,
referralFee,
msg.sender,
block.timestamp
);
}
else {
tax = getTaxFee(groupId);
}
uint256 totalStaked = Staking(payable(stakingContract)).totalStaked();
if (totalStaked == 0) {
(bool os, ) = payable(owner()).call{value: tax}("");
require(os);
} else {
(bool os, ) = payable(stakingContract).call{value: tax}("");
require(os);
}
groups[groupId].totalDeposits++;
totalDeposits++;
emit deposited(
msg.sender,
groups[groupId].denomination,
groupId,
block.timestamp
);
}
function updateRelayerFee(
uint256 _relayerFeeNum,
uint256 _relayerFeeDen,
uint256 _groupId
) external override onlyOwner {
require(groups[_groupId].denomination > 0, "Invalid group Id");
groups[_groupId].relayerFeeDen = _relayerFeeDen;
groups[_groupId].relayerFeeNum = _relayerFeeNum;
}
function updateTaxFee(
uint256 _taxFeeNum,
uint256 _taxFeeDen,
uint256 _groupId
) external override onlyOwner {
require(groups[_groupId].denomination > 0, "Invalid group Id");
groups[_groupId].taxFeeDen = _taxFeeDen;
groups[_groupId].taxFeeNum = _taxFeeNum;
}
function updateReferralFee(
uint256 _referralFeeNum,
uint256 _referralFeeDen
) external override onlyOwner {
referralFeeNum = _referralFeeNum;
referralFeeDen = _referralFeeDen;
}
function verifyProof(
uint256 groupId,
uint256 merkleTreeRoot,
uint256 signal,
uint256 nullifierHash,
uint256 externalNullifier,
uint256[8] calldata proof,
bool calledByRelayer
) external override {
uint256 merkleTreeDepth = getMerkleTreeDepth(groupId);
if (merkleTreeDepth == 0) {
revert Semaphore__GroupDoesNotExist();
}
uint256 currentMerkleTreeRoot = getMerkleTreeRoot(groupId);
if (merkleTreeRoot != currentMerkleTreeRoot) {
uint256 merkleRootCreationDate = groups[groupId]
.merkleRootCreationDates[merkleTreeRoot];
if (merkleRootCreationDate == 0) {
revert Semaphore__MerkleTreeRootIsNotPartOfTheGroup();
}
if (
block.timestamp >
merkleRootCreationDate + merkleTreeHistoryDuration
) {
revert Semaphore__MerkleTreeRootIsExpired();
}
}
if (groups[groupId].nullifierHashes[nullifierHash]) {
revert Semaphore__YouAreUsingTheSameNillifierTwice();
}
verifier.verifyProof(
merkleTreeRoot,
nullifierHash,
signal,
externalNullifier,
proof,
merkleTreeDepth
);
groups[groupId].nullifierHashes[nullifierHash] = true;
nullifierDate[nullifierHash] = block.timestamp;
address recieverAddress = address(uint160(signal));
uint256 totalPayableAmountToReciever = groups[groupId].denomination -
getTaxFee(groupId);
if (calledByRelayer) {
uint256 payableAmountToRelayer = getRelayerFee(groupId);
(bool os, ) = payable(msg.sender).call{
value: payableAmountToRelayer
}("");
require(os);
totalPayableAmountToReciever =
totalPayableAmountToReciever -
payableAmountToRelayer;
}
(bool os1, ) = payable(recieverAddress).call{
value: totalPayableAmountToReciever
}("");
require(os1);
emit ProofVerified(
groupId,
merkleTreeRoot,
nullifierHash,
externalNullifier,
signal
);
emit claimed(
recieverAddress,
groups[groupId].denomination,
groupId,
block.timestamp
);
}
}
文件 12 的 18:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
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);
}
}
文件 13 的 18:Pairing.sol
pragma solidity ^0.8.4;
library Pairing {
error InvalidProof();
uint256 constant BASE_MODULUS = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
uint256 constant SCALAR_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
struct G1Point {
uint256 X;
uint256 Y;
}
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
function P1() public pure returns (G1Point memory) {
return G1Point(1, 2);
}
function P2() public pure returns (G2Point memory) {
return
G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
],
[
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
]
);
}
function negate(G1Point memory p) public pure returns (G1Point memory r) {
if (p.X == 0 && p.Y == 0) {
return G1Point(0, 0);
}
if (p.X >= BASE_MODULUS || p.Y >= BASE_MODULUS) {
revert InvalidProof();
}
return G1Point(p.X, BASE_MODULUS - p.Y);
}
function addition(G1Point memory p1, G1Point memory p2) public view returns (G1Point memory r) {
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
}
if (!success) {
revert InvalidProof();
}
}
function scalar_mul(G1Point memory p, uint256 s) public view returns (G1Point memory r) {
if (s >= SCALAR_MODULUS) {
revert InvalidProof();
}
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
}
if (!success) {
revert InvalidProof();
}
}
function pairingCheck(G1Point[] memory p1, G2Point[] memory p2) public view {
if (p1.length != p2.length) {
revert InvalidProof();
}
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
input[i * 6 + 2] = p2[i].X[0];
input[i * 6 + 3] = p2[i].X[1];
input[i * 6 + 4] = p2[i].Y[0];
input[i * 6 + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
}
if (!success || out[0] != 1) {
revert InvalidProof();
}
}
}
文件 14 的 18:SemaphoreGroups.sol
pragma solidity 0.8.4;
import "../interfaces/ISemaphoreGroups.sol";
import "@zk-kit/incremental-merkle-tree.sol/IncrementalBinaryTree.sol";
import "@openzeppelin/contracts/utils/Context.sol";
abstract contract SemaphoreGroups is Context, ISemaphoreGroups {
using IncrementalBinaryTree for IncrementalTreeData;
mapping(uint256 => IncrementalTreeData) internal merkleTrees;
function _createGroup(uint256 groupId, uint256 merkleTreeDepth) internal virtual {
if (getMerkleTreeDepth(groupId) != 0) {
revert Semaphore__GroupAlreadyExists();
}
uint256 zeroValue = uint256(keccak256(abi.encodePacked(groupId))) >> 8;
merkleTrees[groupId].init(merkleTreeDepth, zeroValue);
emit GroupCreated(groupId, merkleTreeDepth, zeroValue);
}
function _addMember(uint256 groupId, uint256 identityCommitment) internal virtual {
if (getMerkleTreeDepth(groupId) == 0) {
revert Semaphore__GroupDoesNotExist();
}
merkleTrees[groupId].insert(identityCommitment);
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
uint256 index = getNumberOfMerkleTreeLeaves(groupId) - 1;
emit MemberAdded(groupId, index, identityCommitment, merkleTreeRoot);
}
function _updateMember(
uint256 groupId,
uint256 identityCommitment,
uint256 newIdentityCommitment,
uint256[] calldata proofSiblings,
uint8[] calldata proofPathIndices
) internal virtual {
if (getMerkleTreeDepth(groupId) == 0) {
revert Semaphore__GroupDoesNotExist();
}
merkleTrees[groupId].update(identityCommitment, newIdentityCommitment, proofSiblings, proofPathIndices);
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
uint256 index = proofPathIndicesToMemberIndex(proofPathIndices);
emit MemberUpdated(groupId, index, identityCommitment, newIdentityCommitment, merkleTreeRoot);
}
function _removeMember(
uint256 groupId,
uint256 identityCommitment,
uint256[] calldata proofSiblings,
uint8[] calldata proofPathIndices
) internal virtual {
if (getMerkleTreeDepth(groupId) == 0) {
revert Semaphore__GroupDoesNotExist();
}
merkleTrees[groupId].remove(identityCommitment, proofSiblings, proofPathIndices);
uint256 merkleTreeRoot = getMerkleTreeRoot(groupId);
uint256 index = proofPathIndicesToMemberIndex(proofPathIndices);
emit MemberRemoved(groupId, index, identityCommitment, merkleTreeRoot);
}
function getMerkleTreeRoot(uint256 groupId) public view virtual override returns (uint256) {
return merkleTrees[groupId].root;
}
function getMerkleTreeDepth(uint256 groupId) public view virtual override returns (uint256) {
return merkleTrees[groupId].depth;
}
function getNumberOfMerkleTreeLeaves(uint256 groupId) public view virtual override returns (uint256) {
return merkleTrees[groupId].numberOfLeaves;
}
function proofPathIndicesToMemberIndex(uint8[] calldata proofPathIndices) private pure returns (uint256) {
uint256 memberIndex = 0;
for (uint8 i = uint8(proofPathIndices.length); i > 0; ) {
if (memberIndex > 0 || proofPathIndices[i - 1] != 0) {
memberIndex *= 2;
if (proofPathIndices[i - 1] == 1) {
memberIndex += 1;
}
}
unchecked {
--i;
}
}
return memberIndex;
}
}
文件 15 的 18:TaxReward.sol
pragma solidity >=0.8.2 <0.9.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract TaxReward is Ownable {
address public tokenAddress;
uint256 public startdate;
uint256 public totalRewards;
mapping(uint256=>uint256) totalMonthReward;
uint256 public latestMonthShareCalculated;
mapping(address=> uint256) public latestMonthUserShareCalculated;
mapping(address=>mapping(uint256=>uint256)) userMonthClaimedPointOne;
mapping(address=>mapping(uint256=>uint256)) userMonthClaimed;
mapping(address=>uint256) userClaimableAmount;
struct userMonthShareType {
uint256 startingBal;
uint256 endingBal;
uint256 maintainedBal;
}
struct totalMonthShareType {
uint256 currentMonth;
uint256 nextMonth;
}
mapping(address=> mapping(uint256=>userMonthShareType)) public _userMonthShares;
mapping(uint256=>totalMonthShareType) public _totalMonthShares;
mapping(address=> mapping(uint256=>bool)) public userMonthShareCalculated;
constructor(address _tokenAddress, uint256 _startInDays) {
tokenAddress = _tokenAddress;
startdate = block.timestamp + (_startInDays * ( 1 days ));
}
function getCurrentMonth() public view returns(uint256) {
if( block.timestamp < startdate){
return 0;
}
else{
return (((block.timestamp - startdate)/ 30 seconds) + 1);
}
}
function getCurrentYear() public view returns(uint256) {
if( block.timestamp < startdate){
return 0;
}
else{
return (((block.timestamp - startdate)/ 360 seconds) + 1);
}
}
function getYearStartingMonth(uint256 _year) public pure returns(uint256) {
return 12*(_year-1) + 1;
}
function getUserShare (uint256 _month, address _user) public view returns (uint256){
require( _month >= 2, "Rewards do not start before second month");
require ( _month <= getCurrentMonth(), "Invalid month" );
if (latestMonthUserShareCalculated[_user] == _month-1){
userMonthShareType memory userShares = _userMonthShares[_user][latestMonthUserShareCalculated[_user]];
return userShares.maintainedBal;
}
else if (latestMonthUserShareCalculated[_user] < _month-1){
userMonthShareType memory userShares = _userMonthShares[_user][latestMonthUserShareCalculated[_user]];
return userShares.endingBal;
} else {
for (uint256 i= _month-1; i >=0 ; i-- ) {
if (userMonthShareCalculated[_user][i] == true){
if ( i == _month-1){
userMonthShareType memory userShares = _userMonthShares[_user][i];
return userShares.maintainedBal;
} else {
userMonthShareType memory userShares = _userMonthShares[_user][i];
return userShares.endingBal;
}
}
continue ;
}
return 0;
}
}
function getTotalMonthShares (uint256 _month) public view returns (uint256){
require( _month >= 2, "Rewards do not start before second month");
require ( _month <= getCurrentMonth(), "Invalid month" );
totalMonthShareType memory monthShares = _totalMonthShares[latestMonthShareCalculated];
if (latestMonthShareCalculated < _month-1){
return monthShares.nextMonth;
} else {
return monthShares.currentMonth;
}
}
function claimProfits (uint256[] memory _months) public {
require(_months.length <=12, "You cannot claim for more than 12 months together" );
for (uint i=0; i<_months.length; i++){
uint256 userProfits = getUserProfits(_months[i],msg.sender);
if (userProfits > 0){
userMonthClaimedPointOne[msg.sender][_months[i]] = totalMonthReward[_months[i]];
userMonthClaimed[msg.sender][_months[i]] += userProfits;
IERC20(tokenAddress).transfer(msg.sender,userProfits);
}
}
}
function getUserProfits (uint256 _month, address _user) public view returns (uint256){
uint256 totalShares = getTotalMonthShares(_month);
uint256 userShares = getUserShare(_month, _user);
if (totalShares == 0){
return 0;
}
return ((totalMonthReward[_month] - userMonthClaimedPointOne[_user][_month] ) * userShares)/ (totalShares);
}
function getYearMonthRevenue(uint256 _year) public view returns (uint256[12] memory rewards){
if (_year == 0){
return rewards;
}
uint256 startingMonth = getYearStartingMonth(_year);
uint256 counter = 0;
for (uint256 i=startingMonth; i< startingMonth + 12; i++){
rewards[counter] = totalMonthReward[i];
counter++;
}
return rewards;
}
function getUserProfitsByYear(uint256 _year, address _user) public view returns (uint256){
if (_year == 0){
return 0;
}
uint256 profits = 0;
uint256 startingMonth = getYearStartingMonth(_year);
uint256 upperLimit = startingMonth + 12 >= getCurrentMonth() ? getCurrentMonth() : startingMonth + 12;
if (upperLimit <= startingMonth){
return 0;
}
for (uint i=startingMonth; i<= upperLimit; i++){
if (i == 0 || i== 1){
profits+=0;
}
else{
profits += getUserProfits(i,_user);
}
}
return profits;
}
function getUserProfitsClaimedByYear(uint256 _year, address _user) public view returns (uint256){
if (_year == 0){
return 0;
}
uint256 claimed = 0;
uint256 startingMonth = getYearStartingMonth(_year);
for (uint i=startingMonth; i< startingMonth+12; i++){
if (i == 0 || i== 1){
claimed+=0;
}
else{
claimed += userMonthClaimed[_user][i];
}
}
return claimed;
}
function updateUserHoldings(uint256 bal, address _user) public {
uint256 currentMonth = getCurrentMonth();
userMonthShareCalculated[_user][currentMonth] = true;
latestMonthShareCalculated = currentMonth;
if (currentMonth == 0){
userMonthShareType memory userShares = _userMonthShares[_user][currentMonth];
totalMonthShareType memory total_monthShares = _totalMonthShares[currentMonth];
total_monthShares.nextMonth -= total_monthShares.currentMonth;
total_monthShares.currentMonth -= userShares.maintainedBal;
total_monthShares.currentMonth += bal;
total_monthShares.nextMonth += total_monthShares.currentMonth;
_totalMonthShares[currentMonth] = total_monthShares;
userShares.endingBal = bal;
userShares.maintainedBal = bal;
_userMonthShares[_user][currentMonth] = userShares;
}
else {
if (latestMonthUserShareCalculated[_user] != currentMonth){
userMonthShareType memory latestMonthShares = _userMonthShares[_user][latestMonthUserShareCalculated[_user] ];
uint256 maintainedBal = latestMonthShares.endingBal;
if (bal < latestMonthShares.endingBal){
maintainedBal = bal;
}
totalMonthShareType memory total_monthShares = _totalMonthShares[currentMonth];
total_monthShares.currentMonth += maintainedBal;
total_monthShares.nextMonth += bal;
_totalMonthShares[currentMonth] = total_monthShares;
_userMonthShares[_user][currentMonth] = userMonthShareType(latestMonthShares.endingBal,bal,maintainedBal);
latestMonthUserShareCalculated[_user] = currentMonth;
}
else {
userMonthShareType memory currentMonthShares = _userMonthShares[_user][currentMonth];
totalMonthShareType memory total_monthShares = _totalMonthShares[currentMonth];
if (bal >= currentMonthShares.maintainedBal){
total_monthShares.nextMonth -= currentMonthShares.endingBal;
currentMonthShares.endingBal = bal;
_userMonthShares[_user][currentMonth] = currentMonthShares;
total_monthShares.nextMonth += bal;
_totalMonthShares[currentMonth] = total_monthShares;
}
else {
total_monthShares.nextMonth -= currentMonthShares.endingBal;
currentMonthShares.endingBal = bal;
total_monthShares.currentMonth -= currentMonthShares.maintainedBal;
total_monthShares.currentMonth += bal;
total_monthShares.nextMonth += bal;
_totalMonthShares[currentMonth] = total_monthShares;
currentMonthShares.maintainedBal = bal;
_userMonthShares[_user][currentMonth] = currentMonthShares;
}
}
}
}
function receiveTokens(uint256 _amount) public {
uint256 currentMonth = getCurrentMonth();
totalRewards+=_amount;
if (currentMonth == 0 || currentMonth == 1){
totalMonthReward[2] += _amount;
}
else {
totalMonthReward[currentMonth] += _amount;
if (latestMonthShareCalculated < currentMonth-1){
totalMonthShareType memory prev_monthShares = _totalMonthShares[latestMonthShareCalculated];
_totalMonthShares[currentMonth-1] = totalMonthShareType(prev_monthShares.nextMonth,prev_monthShares.nextMonth);
latestMonthShareCalculated = currentMonth-1;
}
}
}
}
文件 16 的 18:Token.sol
pragma solidity >=0.4.22 <0.9.0;
import "./ERC20.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "../Mixer.sol";
contract Token is ERC20 {
address public teamAddress;
uint256 public _rewardsAmountThreshold;
uint256 public _rewardsAmountThresholdCompletionTimestamp;
uint256 public _rewardRate;
uint256 public _reservedForTeam;
uint256 public _rewardsSaleSupply;
mapping(uint256 => uint256) public commitmentRewardClaimDate;
mapping(uint256 => uint256) public commitmentRewardClaimed;
Mixer public mixerContract;
struct signatureInput {
string _nonce;
uint256 _validTill;
uint8 _v;
bytes32 _r;
bytes32 _s;
}
constructor(
string memory name,
string memory symbol,
uint256 reservedForTeam,
uint256 rewardsAmountThreshold,
uint256 rewardRate,
address marketingWallet,
address factoryAddress,
address wethAddress
) ERC20(name, symbol, marketingWallet, factoryAddress, wethAddress) {
_reservedForTeam = reservedForTeam * 1e18;
_rewardsAmountThreshold = rewardsAmountThreshold * 1e18;
teamAddress = msg.sender;
_rewardRate = rewardRate;
_mint(teamAddress, _reservedForTeam);
}
function updateMixerContractAddress(
Mixer contractAddress
) public onlyOwner {
mixerContract = contractAddress;
}
function rewardsMint(
address _mintTo,
uint256 commitment,
uint256 endTime,
signatureInput memory _signature
) public {
uint256 getRewardAmountDuration;
if (endTime == 0) {
if (commitmentRewardClaimDate[commitment] == 0) {
getRewardAmountDuration =
block.timestamp -
mixerContract.commitmentDate(commitment);
} else {
getRewardAmountDuration =
block.timestamp -
commitmentRewardClaimDate[commitment];
}
} else {
if (commitmentRewardClaimDate[commitment] == 0) {
getRewardAmountDuration =
endTime -
mixerContract.commitmentDate(commitment);
} else {
if (commitmentRewardClaimDate[commitment] > endTime) {
getRewardAmountDuration = 0;
} else {
getRewardAmountDuration =
endTime -
commitmentRewardClaimDate[commitment];
}
}
}
uint256 rewardAmount = getRewardAmount(
commitment,
getRewardAmountDuration
);
if (
_rewardsAmountThresholdCompletionTimestamp == 0 &&
(_rewardsSaleSupply + rewardAmount) >= _rewardsAmountThreshold
) {
_rewardsAmountThresholdCompletionTimestamp = block.timestamp;
}
_rewardsSaleSupply += rewardAmount;
commitmentRewardClaimDate[commitment] = block.timestamp;
bytes32 hashStruct = keccak256(
abi.encode(
keccak256(
"Mint(uint256 validTill,string nonce,address mintTo,uint256 commitment,uint256 endTime)"
),
_signature._validTill,
keccak256(bytes(_signature._nonce)),
_mintTo,
commitment,
endTime
)
);
executeSetIfSignatureMatch(
_signature._v,
_signature._r,
_signature._s,
hashStruct
);
commitmentRewardClaimed[commitment] += rewardAmount;
_mint(_mintTo, rewardAmount);
}
function getRewardAmount(
uint256 commitment,
uint256 duration
) public view returns (uint256) {
uint256 depositTime = mixerContract.commitmentDate(commitment);
require(depositTime > 0, "This commitment was never deposited");
if (_rewardsAmountThresholdCompletionTimestamp != 0) {
require(
depositTime < _rewardsAmountThresholdCompletionTimestamp,
"Reward system has ended"
);
if (
(commitmentRewardClaimDate[commitment] + duration) >
_rewardsAmountThresholdCompletionTimestamp
) {
duration =
_rewardsAmountThresholdCompletionTimestamp -
commitmentRewardClaimDate[commitment];
}
}
uint256 rewardAmount = _rewardRate * (duration / 1 minutes);
return rewardAmount;
}
function updateTeamAddress(address newTeamAddress) public onlyOwner {
teamAddress = newTeamAddress;
}
function updateRewardRate(uint256 rewardRate) public onlyOwner {
_rewardRate = rewardRate;
}
function executeSetIfSignatureMatch(
uint8 _v,
bytes32 _r,
bytes32 _s,
bytes32 _hashStruct
) public view {
uint256 chainId = block.chainid;
bytes32 eip712DomainHash = keccak256(
abi.encode(
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
),
keccak256(bytes("Mixer")),
keccak256(bytes("1.0")),
chainId,
address(this)
)
);
bytes32 hash = keccak256(
abi.encodePacked("\x19\x01", eip712DomainHash, _hashStruct)
);
address signer = ecrecover(hash, _v, _r, _s);
require(signer != address(0), "ECDSA: invalid signature");
require(signer == teamAddress, "MyFunction: invalid signature");
}
}
文件 17 的 18:iMixer.sol
pragma solidity ^0.8.4;
interface IMixer {
error Semaphore__MerkleTreeDepthIsNotSupported();
error Semaphore__MerkleTreeRootIsExpired();
error Semaphore__MerkleTreeRootIsNotPartOfTheGroup();
error Semaphore__YouAreUsingTheSameNillifierTwice();
struct Group {
uint256 denomination;
mapping(uint256 => uint256) merkleRootCreationDates;
mapping(uint256 => bool) nullifierHashes;
uint256 totalDeposits;
uint256 relayerFeeNum;
uint256 relayerFeeDen;
uint256 taxFeeNum;
uint256 taxFeeDen;
}
event deposited(
address indexed depositor,
uint256 indexed amount,
uint256 indexed poolId,
uint256 timeStamp
);
event depositedReferral(
address indexed referralAddress,
uint256 indexed amount,
uint256 indexed poolId,
uint256 referralFee,
address depositor,
uint256 timeStamp
);
event claimed(
address indexed sendTo,
uint256 indexed amount,
uint256 indexed poolId,
uint256 timeStamp
);
event GroupMerkleTreeDurationUpdated(
uint256 indexed groupId,
uint256 oldMerkleTreeDuration,
uint256 newMerkleTreeDuration
);
event ProofVerified(
uint256 indexed groupId,
uint256 indexed merkleTreeRoot,
uint256 nullifierHash,
uint256 indexed externalNullifier,
uint256 signal
);
function verifyProof(
uint256 groupId,
uint256 merkleTreeRoot,
uint256 signal,
uint256 nullifierHash,
uint256 externalNullifier,
uint256[8] calldata proof,
bool calledByRelayer
) external;
function createGroup(
uint256 groupId,
uint256 depth,
uint256 denomination
) external;
function updateMerkleTreeDuration(uint256 newMerkleTreeDuration) external;
function addMember(
uint256 groupId,
uint256 identityCommitment,
address referralAddress
) external payable;
function updateRelayerFee(
uint256 _relayerFeeNum,
uint256 _relayerFeeDen,
uint256 _groupId
) external;
function updateTaxFee(
uint256 _taxFeeNum,
uint256 _taxFeeDen,
uint256 _groupId
) external;
function updateReferralFee(
uint256 _referralFeeNum,
uint256 _referralFeeDen
) external;
}
文件 18 的 18:staking.sol
pragma solidity >=0.8.2 <0.9.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract Staking {
address public tokenAddress;
mapping(address => uint256) public stakingAmount;
mapping(address => uint256) public unclaimedPayment;
mapping(address => uint256) public pointOne;
mapping(address => uint256) public released;
uint256 public EthPerToken;
uint256 public totalStaked;
uint256 public totalReleased;
uint256 public movedOverFunds;
uint256 public totalReceived;
constructor(address _tokenAddress) {
tokenAddress = _tokenAddress;
}
function stakeTokens(uint256 _amount) public {
_amount = _amount * 1e18;
require(_amount > 0, "staking amount cannot be 0");
if (stakingAmount[msg.sender] > 0) {
unclaimedPayment[msg.sender] += getUnclaimedPayment(msg.sender);
}
pointOne[msg.sender] = EthPerToken;
stakingAmount[msg.sender] += _amount;
totalStaked += _amount;
IERC20(tokenAddress).transferFrom(msg.sender, address(this), _amount);
}
function getUnclaimedPayment(
address _account
) public view returns (uint256 payment) {
if (totalStaked == 0) {
payment = 0;
} else {
uint256 recievableEthPerToken = EthPerToken - pointOne[_account];
payment =
recievableEthPerToken *
(stakingAmount[_account] / 1 ether);
payment = payment + unclaimedPayment[_account];
}
}
receive() external payable {
totalReceived += msg.value;
if (totalStaked > 0) {
EthPerToken +=
(msg.value + movedOverFunds) /
(totalStaked / 1 ether);
if (EthPerToken == 0) {
movedOverFunds += msg.value;
} else {
movedOverFunds =
(msg.value + movedOverFunds) -
((msg.value + movedOverFunds) / (totalStaked / 1 ether)) *
(totalStaked / 1 ether);
}
}
}
function unstakeTokens() public {
require(
stakingAmount[msg.sender] > 0,
"You do not have any tokens staked"
);
unclaimedPayment[msg.sender] += getUnclaimedPayment(msg.sender);
totalStaked -= stakingAmount[msg.sender];
IERC20(tokenAddress).transfer(msg.sender, stakingAmount[msg.sender]);
stakingAmount[msg.sender] = 0;
}
function release() public {
uint256 payment = getUnclaimedPayment(msg.sender);
require(payment != 0, "No funds to be released");
released[msg.sender] += payment;
totalReleased += payment;
unclaimedPayment[msg.sender] = 0;
pointOne[msg.sender] = EthPerToken;
(bool os, ) = payable(msg.sender).call{value: payment}("");
require(os);
}
}
{
"compilationTarget": {
"contracts/token/Token.sol": "Token"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"reservedForTeam","type":"uint256"},{"internalType":"uint256","name":"rewardsAmountThreshold","type":"uint256"},{"internalType":"uint256","name":"rewardRate","type":"uint256"},{"internalType":"address","name":"marketingWallet","type":"address"},{"internalType":"address","name":"factoryAddress","type":"address"},{"internalType":"address","name":"wethAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_delayTime","type":"uint256"}],"name":"UpdatedPreventDelayTime","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_isExcludedFromFee","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_isExcludedFromRewards","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_reservedForTeam","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_rewardRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_rewardsAmountThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_rewardsAmountThresholdCompletionTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_rewardsSaleSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"commitmentRewardClaimDate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"commitmentRewardClaimed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"dexPair","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"enableTransferFee","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"},{"internalType":"bytes32","name":"_hashStruct","type":"bytes32"}],"name":"executeSetIfSignatureMatch","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxBuyPerWallet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRemainingTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"commitment","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"getRewardAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"holdersFeePercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"marketingWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketingWalletFeePercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxBuy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mixerContract","outputs":[{"internalType":"contract Mixer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_mintTo","type":"address"},{"internalType":"uint256","name":"commitment","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"components":[{"internalType":"string","name":"_nonce","type":"string"},{"internalType":"uint256","name":"_validTill","type":"uint256"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"internalType":"struct Token.signatureInput","name":"_signature","type":"tuple"}],"name":"rewardsMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"taxRewardContract","outputs":[{"internalType":"contract TaxReward","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"teamAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"toggleTransferFee","outputs":[],"stateMutability":"nonpayable","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":"amount","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":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"updateHoldersFeePercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_walletAddress","type":"address"}],"name":"updateMarketingWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"updateMarketingWalletFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"updateMaxBuyLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Mixer","name":"contractAddress","type":"address"}],"name":"updateMixerContractAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"rewardRate","type":"uint256"}],"name":"updateRewardRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTeamAddress","type":"address"}],"name":"updateTeamAddress","outputs":[],"stateMutability":"nonpayable","type":"function"}]