编译器
0.8.18+commit.87f61d96
文件 1 的 15:AccessControl.sol
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(uint160(account), 20),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}
文件 2 的 15: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);
}
}
}
}
文件 3 的 15:AggregatorV3Interface.sol
pragma solidity ^0.8.0;
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(uint80 _roundId)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}
文件 4 的 15: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;
}
}
文件 5 的 15:ERC165.sol
pragma solidity ^0.8.0;
import "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 6 的 15:GarbageSale.sol
pragma solidity 0.8.18;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "./IGarbageSale.sol";
import "./IGarbageVesting.sol";
contract GarbageSale is Pausable, AccessControl, IGarbageSale {
using SafeERC20 for IERC20;
struct Stage {
uint256 tokensToSale;
uint256 tokensSold;
uint256 priceInUSD;
}
Stage[] public stages;
IERC20 public garbageToken;
IERC20 public usdt;
IGarbageVesting public vestingContract;
address public treasury;
uint256 public maxClaimableAmountInUSD;
uint256 public currentStage;
uint256 public saleStartDate;
uint256 public saleDeadline;
uint256 public claimDate;
uint256 public bloggerRewardPercent;
uint256 public userRewardPercent;
uint256 public totalTokensToBeDistributed;
uint256 public totalTokensSold;
uint256 public totalTokensClaimed;
uint256 public totalRewardsClaimedEth;
uint256 public totalRewardsClaimedUsdt;
uint256 public totalRewardsEth;
uint256 public totalRewardsUsdt;
uint256 public constant PERCENT_DENOMINATOR = 10000;
bytes32 public constant WERT_ROLE = keccak256("WERT_ROLE");
bytes32 public constant BLOGGER_ROLE = keccak256("BLOGGER_ROLE");
bytes32 public constant REFERRER_ROLE = keccak256("REFERRER_ROLE");
bytes32 public constant AFFILIATE_ADMIN_ROLE = keccak256("AFFILIATE_ADMIN_ROLE");
bytes32 public constant MEME_ADMIN_ROLE = keccak256("MEME_ADMIN_ROLE");
mapping(address => uint256) public referralRewardsEth;
mapping(address => uint256) public referralRewardsUsdt;
mapping(address => uint256) public claimableTokens;
mapping(address => uint256) public totalGarbageBoughtInUSD;
AggregatorV3Interface public priceFeedUsdt;
AggregatorV3Interface public priceFeedEth;
event ClaimDateExtended(uint256 newClaimDate);
event DeadlineExtended(uint256 newDeadline);
event GarbageTokenChanged(address newGarbageToken);
event PriceFeedEthChanged(address newPriceFeedEth);
event PriceFeedUsdtChanged(address newPriceFeedUsdt);
event RewardCalculated(uint256 reward, address referrer);
event RewardPaid(address referrer, uint256 amountEth, uint256 amountUsdt);
event RewardPercentChanged(uint256 bloggerRewardPercent, uint256 userRewardPercent);
event RemainderWithdrawn(address treasury, uint256 amountWithdrawn);
event StageAdded(uint256 tokens, uint256 priceInUSD);
event TokensBought(address buyer, uint256 amount);
event TokensClaimed(address claimer, uint256 amount);
event TreasuryChanged(address newTreasury);
event UsdtChanged(address newUsdt);
event VestingContractChanged(address newVestingContract);
error AllStagesCompleted();
error CallerIsNotAdmin();
error CallerIsNotAffiliateAdmin();
error ClaimDateNotReached();
error ContractPaused();
error DeadlineNotReached();
error NewDeadlineIsInPast();
error NotEnoughTokensInLastStage();
error NotEnoughTokensInNextStage();
error NotEnoughTokensInStageToDistribute();
error PercentEqualOrGreaterThanDenominator();
error ReferrerIsNotRegistered();
error ReferrerIsSender();
error SaleIsStarted();
error SaleIsNotStarted();
error TokenSaleEnded();
error TransferFailed();
error ZeroAddress();
error ZeroAmount();
modifier nonZeroAddress(address addr) {
if (addr == address(0)) revert ZeroAddress();
_;
}
modifier nonZeroAmount(uint256 amount) {
if (amount == 0) revert ZeroAmount();
_;
}
modifier whenActive() {
if (saleStartDate > block.timestamp) {
revert SaleIsNotStarted();
}
if (block.timestamp >= saleDeadline) revert TokenSaleEnded();
if (currentStage >= stages.length) revert AllStagesCompleted();
if (paused()) revert ContractPaused();
_;
}
modifier beforeSaleStart() {
if (block.timestamp > saleStartDate) {
revert SaleIsStarted();
}
_;
}
constructor(
IERC20 _token,
IERC20 _usdt,
IGarbageVesting _vestingContract,
address _priceFeedEth,
address _priceFeedUsdt,
address _treasury
) {
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
setMaxClaimableAmountInUSD(50_000 * 1e8);
setSaleStartDate(1698168600);
setSaleDeadline(saleStartDate + 4 * 30 days);
setClaimDate(saleDeadline + 1825 days);
setVestingContract(_vestingContract);
setTreasury(_treasury);
setUsdt(_usdt);
bloggerRewardPercent = 1000;
userRewardPercent = 500;
setPriceFeedEth(_priceFeedEth);
setPriceFeedUsdt(_priceFeedUsdt);
_addStages();
setGarbageToken(_token);
_setupRole(AFFILIATE_ADMIN_ROLE, msg.sender);
_setRoleAdmin(BLOGGER_ROLE, AFFILIATE_ADMIN_ROLE);
_setRoleAdmin(REFERRER_ROLE, AFFILIATE_ADMIN_ROLE);
}
receive() external payable {}
function pause() public onlyRole(DEFAULT_ADMIN_ROLE) {
_pause();
}
function unpause() public onlyRole(DEFAULT_ADMIN_ROLE) {
_unpause();
}
function buyTokensWithEth(address referrer) public payable whenActive nonZeroAmount(msg.value) {
uint256 reward = _calculateRewardReferral(referrer, msg.sender, msg.value, true);
uint256 remaining = msg.value - reward;
_buyTokens(msg.value, true, msg.sender);
(bool success, ) = payable(treasury).call{value: remaining}("");
if (!success) revert TransferFailed();
}
function buyTokensWithUsdt(uint256 usdtAmount, address referrer) public whenActive nonZeroAmount(usdtAmount) {
uint256 reward = _calculateRewardReferral(referrer, msg.sender, usdtAmount, false);
uint256 remaining = usdtAmount - reward;
usdt.safeTransferFrom(msg.sender, treasury, remaining);
usdt.safeTransferFrom(msg.sender, address(this), reward);
_buyTokens(usdtAmount, false, msg.sender);
}
function buyTokensWithEthWert(address referrer, address user)
public
payable
whenActive
onlyRole(WERT_ROLE)
nonZeroAmount(msg.value)
{
uint256 reward = _calculateRewardReferral(referrer, user, msg.value, true);
uint256 remaining = msg.value - reward;
_buyTokens(msg.value, true, user);
(bool success, ) = payable(treasury).call{value: remaining}("");
if (!success) revert TransferFailed();
}
function claimTokens() external {
if (block.timestamp < claimDate) {
revert ClaimDateNotReached();
}
uint256 amount = claimableTokens[msg.sender];
claimableTokens[msg.sender] = 0;
totalTokensClaimed += amount;
garbageToken.safeTransfer(msg.sender, amount);
emit TokensClaimed(msg.sender, amount);
}
function claimReferralReward() external {
uint256 amountEth = referralRewardsEth[msg.sender];
if (amountEth != 0) {
referralRewardsEth[msg.sender] = 0;
totalRewardsClaimedEth += amountEth;
(bool success, ) = payable(msg.sender).call{value: amountEth}("");
if (!success) revert TransferFailed();
}
uint256 amountUsdt = referralRewardsUsdt[msg.sender];
if (amountUsdt != 0) {
referralRewardsUsdt[msg.sender] = 0;
totalRewardsClaimedUsdt += amountUsdt;
usdt.safeTransfer(msg.sender, amountUsdt);
}
emit RewardPaid(msg.sender, amountEth, amountUsdt);
}
function withdrawRemainder(uint256 amount) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (block.timestamp < saleDeadline || currentStage < stages.length) {
revert DeadlineNotReached();
}
garbageToken.safeTransfer(treasury, amount);
emit RemainderWithdrawn(treasury, amount);
}
function _buyTokens(
uint256 amount,
bool isEth,
address user
) internal {
uint256 alreadyBoughtInUSD = totalGarbageBoughtInUSD[user];
uint256 amountInUSD = getCurrencyInUSD(amount, isEth);
totalGarbageBoughtInUSD[user] += amountInUSD;
if (alreadyBoughtInUSD >= maxClaimableAmountInUSD) {
_vestTokens(amount, isEth, user);
return;
}
uint256 claimableAmount = amount;
if (alreadyBoughtInUSD + amountInUSD > maxClaimableAmountInUSD) {
uint256 amountToVestInUSD = alreadyBoughtInUSD + amountInUSD - maxClaimableAmountInUSD;
uint256 amountToVest = getUSDinCurrency(amountToVestInUSD, isEth);
_vestTokens(amountToVest, isEth, user);
claimableAmount = amount - amountToVest;
}
(uint256 currentStageTokens, uint256 tokensNextStage) = _calculateTokenAmountFromCurrencyAmount(
claimableAmount,
isEth
);
_subtractTokensFromCurrentStage(currentStageTokens);
if (tokensNextStage > 0) {
_subtractTokensFromCurrentStage(tokensNextStage);
}
claimableTokens[user] += currentStageTokens + tokensNextStage;
emit TokensBought(user, currentStageTokens + tokensNextStage);
}
function _vestTokens(
uint256 amount,
bool isEth,
address user
) internal {
(uint256 currentStageTokens, uint256 tokensNextStage) = _calculateTokenAmountFromCurrencyAmount(amount, isEth);
_subtractTokensFromCurrentStage(currentStageTokens);
if (tokensNextStage > 0) {
_subtractTokensFromCurrentStage(tokensNextStage);
}
garbageToken.approve(address(vestingContract), currentStageTokens + tokensNextStage);
vestingContract.addAmountToBeneficiary(user, currentStageTokens + tokensNextStage);
emit TokensBought(user, currentStageTokens + tokensNextStage);
}
function _getRateInCurrency(uint256 stageId, bool isEth) internal view returns (uint256) {
Stage storage stage = stages[stageId];
uint256 currentPrice = (isEth ? _getEthPrice() : _getUsdtPrice()) * 1e10;
uint256 priceInUSDDecimals = 1e8;
uint256 rateInCurrency = (priceInUSDDecimals * currentPrice) / stage.priceInUSD;
return rateInCurrency;
}
function _subtractTokensFromCurrentStage(uint256 tokens) internal {
Stage storage stage = stages[currentStage];
if (stage.tokensToSale - stage.tokensSold < tokens) revert NotEnoughTokensInStageToDistribute();
stage.tokensSold += tokens;
totalTokensSold += tokens;
if (stage.tokensSold == stage.tokensToSale) {
currentStage++;
}
}
function _calculateRewardReferral(
address referrer,
address user,
uint256 amount,
bool isEth
) internal returns (uint256 reward) {
if (referrer == user) revert ReferrerIsSender();
if (referrer != address(0)) {
if (!hasRole(REFERRER_ROLE, referrer) && !hasRole(BLOGGER_ROLE, referrer)) revert ReferrerIsNotRegistered();
bool isBlogger = hasRole(BLOGGER_ROLE, referrer);
uint256 rewardPercent = isBlogger ? bloggerRewardPercent : userRewardPercent;
reward = (amount * rewardPercent) / PERCENT_DENOMINATOR;
if (isEth) {
referralRewardsEth[referrer] += reward;
totalRewardsEth += reward;
} else {
referralRewardsUsdt[referrer] += reward;
totalRewardsUsdt += reward;
}
}
emit RewardCalculated(reward, referrer);
return reward;
}
function _addStages() internal {
_addStage(51_282_051, 1950000);
_addStage(47_483_381, 2106000);
_addStage(43_966_093, 2274480);
_addStage(40_709_346, 2456438);
_addStage(36_874_407, 2711908);
_addStage(32_923_578, 3037337);
_addStage(29_396_052, 3401817);
_addStage(26_014_205, 3844054);
_addStage(22_819_478, 4382221);
_addStage(18_531_329, 5396267);
}
function _addStage(uint256 tokensToSale, uint256 priceInUSD) internal {
uint256 tokensToSaleWithDecimals = tokensToSale * 10**18;
stages.push(Stage(tokensToSaleWithDecimals, 0, priceInUSD));
totalTokensToBeDistributed += tokensToSaleWithDecimals;
emit StageAdded(tokensToSale, priceInUSD);
}
function setTreasury(address _treasury) public onlyRole(DEFAULT_ADMIN_ROLE) nonZeroAddress(_treasury) {
treasury = _treasury;
emit TreasuryChanged(_treasury);
}
function setGarbageToken(IERC20 _token)
public
beforeSaleStart
onlyRole(DEFAULT_ADMIN_ROLE)
nonZeroAddress(address(_token))
{
garbageToken = _token;
emit GarbageTokenChanged(address(_token));
}
function setUsdt(IERC20 _usdt) public onlyRole(DEFAULT_ADMIN_ROLE) nonZeroAddress(address(_usdt)) {
usdt = _usdt;
emit UsdtChanged(address(_usdt));
}
function setPriceFeedEth(address _priceFeedEth) public onlyRole(DEFAULT_ADMIN_ROLE) nonZeroAddress(_priceFeedEth) {
priceFeedEth = AggregatorV3Interface(_priceFeedEth);
emit PriceFeedEthChanged(_priceFeedEth);
}
function setPriceFeedUsdt(address _priceFeedUsdt)
public
onlyRole(DEFAULT_ADMIN_ROLE)
nonZeroAddress(_priceFeedUsdt)
{
priceFeedUsdt = AggregatorV3Interface(_priceFeedUsdt);
emit PriceFeedUsdtChanged(_priceFeedUsdt);
}
function setSaleStartDate(uint256 _saleStartDate) public onlyRole(DEFAULT_ADMIN_ROLE) {
if (_saleStartDate < block.timestamp) {
revert NewDeadlineIsInPast();
}
if (block.timestamp > saleStartDate && saleStartDate > 0) {
revert SaleIsStarted();
}
saleStartDate = _saleStartDate;
}
function setClaimDate(uint256 _claimDate) public onlyRole(DEFAULT_ADMIN_ROLE) {
if (_claimDate < block.timestamp) {
revert NewDeadlineIsInPast();
}
claimDate = _claimDate;
emit ClaimDateExtended(_claimDate);
}
function setSaleDeadline(uint256 newDeadline) public onlyRole(DEFAULT_ADMIN_ROLE) {
if (newDeadline < block.timestamp || newDeadline < saleDeadline) {
revert NewDeadlineIsInPast();
}
saleDeadline = newDeadline;
emit DeadlineExtended(newDeadline);
}
function setMaxClaimableAmountInUSD(uint256 _maxClaimableAmountInUSD) public onlyRole(DEFAULT_ADMIN_ROLE) {
maxClaimableAmountInUSD = _maxClaimableAmountInUSD;
}
function setVestingContract(IGarbageVesting _vestingContract)
public
beforeSaleStart
onlyRole(DEFAULT_ADMIN_ROLE)
nonZeroAddress(address(_vestingContract))
{
vestingContract = _vestingContract;
emit VestingContractChanged(address(_vestingContract));
}
function getStagesLength() external view returns (uint256) {
return stages.length;
}
function getCurrentStageInfo()
external
view
returns (
uint256 tokensToSale,
uint256 tokensSold,
uint256 priceInUSD,
uint256 _currentStage,
uint256 nextStagePriceInUsd
)
{
uint256 stageId = currentStage;
nextStagePriceInUsd = stageId == stages.length - 1 ? 0 : stages[stageId + 1].priceInUSD;
return (
stages[stageId].tokensToSale,
stages[stageId].tokensSold,
stages[stageId].priceInUSD,
currentStage,
nextStagePriceInUsd
);
}
function getRewardsForReferrer(address referrer) external view returns (uint256, uint256) {
return (referralRewardsEth[referrer], referralRewardsUsdt[referrer]);
}
function getUserBalances(address user)
external
view
returns (
uint256 garbageBalance,
uint256 usdtBalance,
uint256 ethBalance
)
{
garbageBalance = garbageToken.balanceOf(user);
usdtBalance = usdt.balanceOf(user);
ethBalance = address(user).balance;
}
function getTokenAmountFromCurrencyAmount(uint256 amount, bool isEth) public view returns (uint256 tokens) {
(uint256 currentStageTokens, uint256 nextStageTokens) = _calculateTokenAmountFromCurrencyAmount(amount, isEth);
return currentStageTokens + nextStageTokens;
}
function getCurrencyInUSD(uint256 currencyAmount, bool isEth) public view returns (uint256) {
uint256 currentPrice = (isEth ? _getEthPrice() : _getUsdtPrice());
uint256 currencyDecimals = isEth ? 1e18 : 1e6;
uint256 usdValue = (currencyAmount * currentPrice) / currencyDecimals;
return usdValue;
}
function getUSDinCurrency(uint256 usdAmount, bool isEth) public view returns (uint256) {
uint256 currentPrice = (isEth ? _getEthPrice() : _getUsdtPrice());
uint256 currencyDecimals = isEth ? 1e18 : 1e6;
uint256 currencyValue = (usdAmount * currencyDecimals) / currentPrice;
return currencyValue;
}
function _calculateTokenAmountFromCurrencyAmount(uint256 amount, bool isEth)
internal
view
returns (uint256 tokensAmount, uint256 tokensAmountNextStage)
{
Stage storage stage = stages[currentStage];
uint256 _currentStage = currentStage;
uint256 rateInCurrency = _getRateInCurrency(_currentStage, isEth);
uint256 tokens = (amount * rateInCurrency) / (isEth ? 1e18 : 1e6);
if (stage.tokensToSale - stage.tokensSold >= tokens) {
return (tokens, 0);
}
_currentStage++;
uint256 remainingTokens = stage.tokensToSale - stage.tokensSold;
uint256 usedAmount = (remainingTokens * (isEth ? 1e18 : 1e6)) / rateInCurrency;
uint256 excessAmount = amount - usedAmount;
if (excessAmount == 0) return (remainingTokens, 0);
if (_currentStage >= stages.length) {
uint256 checkGarbageAmount = (excessAmount * rateInCurrency) / (isEth ? 1e18 : 1e6);
if (checkGarbageAmount <= 1 ether) {
return (remainingTokens, 0);
} else {
revert NotEnoughTokensInLastStage();
}
}
Stage storage nextStage = stages[_currentStage];
uint256 nextRateInCurrency = _getRateInCurrency(_currentStage, isEth);
uint256 nextTokens = (excessAmount * nextRateInCurrency) / (isEth ? 1e18 : 1e6);
if (nextTokens > nextStage.tokensToSale) revert NotEnoughTokensInNextStage();
return (remainingTokens, nextTokens);
}
function getCurrencyAmountFromTokenAmount(uint256 tokens, bool isEth) external view returns (uint256 amount) {
Stage storage stage = stages[currentStage];
uint256 rateInCurrency = _getRateInCurrency(currentStage, isEth);
if (stage.tokensToSale - stage.tokensSold >= tokens) {
amount = (tokens * (isEth ? 1e18 : 1e6)) / rateInCurrency;
return amount;
}
uint256 _currentStage = currentStage;
uint256 remainingTokens = stage.tokensToSale - stage.tokensSold;
uint256 usedAmount = (remainingTokens * (isEth ? 1e18 : 1e6)) / rateInCurrency;
uint256 excessTokens = tokens - remainingTokens;
_currentStage++;
if (_currentStage >= stages.length) {
if (excessTokens > 1 ether) {
revert NotEnoughTokensInLastStage();
} else {
amount = (tokens * (isEth ? 1e18 : 1e6)) / rateInCurrency;
return amount;
}
}
Stage storage nextStage = stages[_currentStage];
uint256 nextRateInCurrency = _getRateInCurrency(_currentStage, isEth);
uint256 nextAmount = (excessTokens * (isEth ? 1e18 : 1e6)) / nextRateInCurrency;
if (excessTokens > nextStage.tokensToSale) revert NotEnoughTokensInNextStage();
amount = usedAmount + nextAmount;
}
function _getEthPrice() internal view returns (uint256) {
(, int256 price, , , ) = priceFeedEth.latestRoundData();
return uint256(price);
}
function _getUsdtPrice() internal view returns (uint256) {
(, int256 price, , , ) = priceFeedUsdt.latestRoundData();
return uint256(price);
}
}
文件 7 的 15:IAccessControl.sol
pragma solidity ^0.8.0;
interface IAccessControl {
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address account) external;
}
文件 8 的 15:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 9 的 15: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);
}
文件 10 的 15:IGarbageSale.sol
pragma solidity 0.8.18;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IGarbageSale {
function garbageToken() external view returns (IERC20);
function usdt() external view returns (IERC20);
function treasury() external view returns (address);
function currentStage() external view returns (uint256);
function saleDeadline() external view returns (uint256);
function claimDate() external view returns (uint256);
function bloggerRewardPercent() external view returns (uint256);
function userRewardPercent() external view returns (uint256);
function totalTokensToBeDistributed() external view returns (uint256);
function totalTokensSold() external view returns (uint256);
function totalTokensClaimed() external view returns (uint256);
function referralRewardsEth(address referrer) external view returns (uint256);
function referralRewardsUsdt(address referrer) external view returns (uint256);
function claimableTokens(address claimer) external view returns (uint256);
function getStagesLength() external view returns (uint256);
function getCurrentStageInfo()
external
view
returns (
uint256,
uint256,
uint256,
uint256,
uint256
);
function getCurrencyAmountFromTokenAmount(uint256 tokens, bool isEth) external view returns (uint256 amount);
function getTokenAmountFromCurrencyAmount(uint256 amount, bool isEth) external view returns (uint256 tokens);
function buyTokensWithEth(address referrer) external payable;
function buyTokensWithUsdt(uint256 amount, address referrer) external;
function setSaleDeadline(uint256 newDeadline) external;
function claimTokens() external;
function pause() external;
function unpause() external;
function withdrawRemainder(uint256 amount) external;
}
文件 11 的 15:IGarbageVesting.sol
pragma solidity 0.8.18;
interface IGarbageVesting {
function addAmountToBeneficiary(address _beneficiary, uint256 _amount) external;
}
文件 12 的 15:Pausable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Pausable is Context {
event Paused(address account);
event Unpaused(address account);
bool private _paused;
constructor() {
_paused = false;
}
modifier whenNotPaused() {
_requireNotPaused();
_;
}
modifier whenPaused() {
_requirePaused();
_;
}
function paused() public view virtual returns (bool) {
return _paused;
}
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
文件 13 的 15:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 14 的 15:Strings.sol
pragma solidity ^0.8.0;
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
function toString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}
文件 15 的 15:draft-IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
{
"compilationTarget": {
"contracts/GarbageSale.sol": "GarbageSale"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"contract IERC20","name":"_usdt","type":"address"},{"internalType":"contract IGarbageVesting","name":"_vestingContract","type":"address"},{"internalType":"address","name":"_priceFeedEth","type":"address"},{"internalType":"address","name":"_priceFeedUsdt","type":"address"},{"internalType":"address","name":"_treasury","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AllStagesCompleted","type":"error"},{"inputs":[],"name":"CallerIsNotAdmin","type":"error"},{"inputs":[],"name":"CallerIsNotAffiliateAdmin","type":"error"},{"inputs":[],"name":"ClaimDateNotReached","type":"error"},{"inputs":[],"name":"ContractPaused","type":"error"},{"inputs":[],"name":"DeadlineNotReached","type":"error"},{"inputs":[],"name":"NewDeadlineIsInPast","type":"error"},{"inputs":[],"name":"NotEnoughTokensInLastStage","type":"error"},{"inputs":[],"name":"NotEnoughTokensInNextStage","type":"error"},{"inputs":[],"name":"NotEnoughTokensInStageToDistribute","type":"error"},{"inputs":[],"name":"PercentEqualOrGreaterThanDenominator","type":"error"},{"inputs":[],"name":"ReferrerIsNotRegistered","type":"error"},{"inputs":[],"name":"ReferrerIsSender","type":"error"},{"inputs":[],"name":"SaleIsNotStarted","type":"error"},{"inputs":[],"name":"SaleIsStarted","type":"error"},{"inputs":[],"name":"TokenSaleEnded","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newClaimDate","type":"uint256"}],"name":"ClaimDateExtended","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newDeadline","type":"uint256"}],"name":"DeadlineExtended","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newGarbageToken","type":"address"}],"name":"GarbageTokenChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newPriceFeedEth","type":"address"}],"name":"PriceFeedEthChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newPriceFeedUsdt","type":"address"}],"name":"PriceFeedUsdtChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"treasury","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountWithdrawn","type":"uint256"}],"name":"RemainderWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"},{"indexed":false,"internalType":"address","name":"referrer","type":"address"}],"name":"RewardCalculated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"referrer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountEth","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountUsdt","type":"uint256"}],"name":"RewardPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"bloggerRewardPercent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"userRewardPercent","type":"uint256"}],"name":"RewardPercentChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"priceInUSD","type":"uint256"}],"name":"StageAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensBought","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"claimer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newTreasury","type":"address"}],"name":"TreasuryChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newUsdt","type":"address"}],"name":"UsdtChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newVestingContract","type":"address"}],"name":"VestingContractChanged","type":"event"},{"inputs":[],"name":"AFFILIATE_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BLOGGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MEME_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERCENT_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFERRER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WERT_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bloggerRewardPercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"referrer","type":"address"}],"name":"buyTokensWithEth","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"referrer","type":"address"},{"internalType":"address","name":"user","type":"address"}],"name":"buyTokensWithEthWert","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdtAmount","type":"uint256"},{"internalType":"address","name":"referrer","type":"address"}],"name":"buyTokensWithUsdt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimDate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimReferralReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"claimableTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentStage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"garbageToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokens","type":"uint256"},{"internalType":"bool","name":"isEth","type":"bool"}],"name":"getCurrencyAmountFromTokenAmount","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"currencyAmount","type":"uint256"},{"internalType":"bool","name":"isEth","type":"bool"}],"name":"getCurrencyInUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentStageInfo","outputs":[{"internalType":"uint256","name":"tokensToSale","type":"uint256"},{"internalType":"uint256","name":"tokensSold","type":"uint256"},{"internalType":"uint256","name":"priceInUSD","type":"uint256"},{"internalType":"uint256","name":"_currentStage","type":"uint256"},{"internalType":"uint256","name":"nextStagePriceInUsd","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"referrer","type":"address"}],"name":"getRewardsForReferrer","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStagesLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"isEth","type":"bool"}],"name":"getTokenAmountFromCurrencyAmount","outputs":[{"internalType":"uint256","name":"tokens","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdAmount","type":"uint256"},{"internalType":"bool","name":"isEth","type":"bool"}],"name":"getUSDinCurrency","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserBalances","outputs":[{"internalType":"uint256","name":"garbageBalance","type":"uint256"},{"internalType":"uint256","name":"usdtBalance","type":"uint256"},{"internalType":"uint256","name":"ethBalance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxClaimableAmountInUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeedEth","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeedUsdt","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"referralRewardsEth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"referralRewardsUsdt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"saleDeadline","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"saleStartDate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_claimDate","type":"uint256"}],"name":"setClaimDate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"}],"name":"setGarbageToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxClaimableAmountInUSD","type":"uint256"}],"name":"setMaxClaimableAmountInUSD","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_priceFeedEth","type":"address"}],"name":"setPriceFeedEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_priceFeedUsdt","type":"address"}],"name":"setPriceFeedUsdt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newDeadline","type":"uint256"}],"name":"setSaleDeadline","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_saleStartDate","type":"uint256"}],"name":"setSaleStartDate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_usdt","type":"address"}],"name":"setUsdt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IGarbageVesting","name":"_vestingContract","type":"address"}],"name":"setVestingContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"stages","outputs":[{"internalType":"uint256","name":"tokensToSale","type":"uint256"},{"internalType":"uint256","name":"tokensSold","type":"uint256"},{"internalType":"uint256","name":"priceInUSD","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalGarbageBoughtInUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRewardsClaimedEth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRewardsClaimedUsdt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRewardsEth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRewardsUsdt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalTokensClaimed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalTokensSold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalTokensToBeDistributed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"usdt","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"userRewardPercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vestingContract","outputs":[{"internalType":"contract IGarbageVesting","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawRemainder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]