文件 1 的 9:Address.sol
pragma solidity ^0.7.0;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 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) private 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 的 9:Context.sol
pragma solidity >=0.6.0 <0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this;
return msg.data;
}
}
文件 3 的 9:FairAuction.sol
pragma solidity =0.7.6;
pragma abicoder v2;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "./interfaces/IWETH.sol";
contract FairAuction is Ownable, ReentrancyGuard {
using SafeMath for uint256;
using SafeERC20 for IERC20;
using Address for address;
struct UserInfo {
uint256 allocation;
uint256 contribution;
bool whitelisted;
uint256 whitelistCap;
uint256 discount;
uint256 discountEligibleAmount;
bool hasClaimed;
}
IERC20 public immutable PROJECT_TOKEN;
IERC20 public immutable PROJECT_TOKEN_2;
IERC20 public immutable SALE_TOKEN;
IERC20 public immutable LP_TOKEN;
uint256 public immutable START_TIME;
uint256 public immutable END_TIME;
mapping(address => UserInfo) public userInfo;
uint256 public totalRaised;
uint256 public totalAllocation;
uint256 public immutable MAX_PROJECT_TOKENS_TO_DISTRIBUTE;
uint256 public immutable MAX_PROJECT_TOKENS_2_TO_DISTRIBUTE;
uint256 public immutable MIN_TOTAL_RAISED_FOR_MAX_PROJECT_TOKEN;
uint256 public immutable MAX_RAISE_AMOUNT;
uint256 public immutable CAP_PER_WALLET;
address public immutable treasury;
bool public whitelistOnly;
bool public unsoldTokensWithdrew;
bool public forceClaimable;
address public weth = 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1;
constructor(
IERC20 projectToken, IERC20 projectToken2, IERC20 saleToken, IERC20 lpToken,
uint256 startTime, uint256 endTime, address treasury_,
uint256 maxToDistribute, uint256 maxToDistribute2, uint256 minToRaise, uint256 maxToRaise, uint256 capPerWallet
) {
require(startTime < endTime, "invalid dates");
require(treasury_ != address(0), "invalid treasury");
PROJECT_TOKEN = projectToken;
PROJECT_TOKEN_2 = projectToken2;
SALE_TOKEN = saleToken;
LP_TOKEN = lpToken;
START_TIME = startTime;
END_TIME = endTime;
treasury = treasury_;
MAX_PROJECT_TOKENS_TO_DISTRIBUTE = maxToDistribute;
MAX_PROJECT_TOKENS_2_TO_DISTRIBUTE = maxToDistribute2;
MIN_TOTAL_RAISED_FOR_MAX_PROJECT_TOKEN = minToRaise;
if(maxToRaise == 0) {
maxToRaise = type(uint256).max;
}
MAX_RAISE_AMOUNT = maxToRaise;
if(capPerWallet == 0) {
capPerWallet = type(uint256).max;
}
CAP_PER_WALLET = capPerWallet;
}
event Buy(address indexed user, uint256 amount);
event Claim(address indexed user, uint256 amount, uint256 amount2);
event DiscountUpdated();
event WhitelistUpdated();
event EmergencyWithdraw(address token, uint256 amount);
event SetWhitelistOnly(bool status);
modifier isSaleActive() {
require(hasStarted() && !hasEnded(), "isActive: sale is not active");
require(PROJECT_TOKEN.balanceOf(address(this)) >= MAX_PROJECT_TOKENS_TO_DISTRIBUTE, "isActive: sale not filled");
if(address(PROJECT_TOKEN_2) != address(0)) {
require(PROJECT_TOKEN_2.balanceOf(address(this)) >= MAX_PROJECT_TOKENS_2_TO_DISTRIBUTE, "isActive: sale not filled 2");
}
_;
}
modifier isClaimable(){
require(hasEnded(), "isClaimable: sale has not ended");
require(forceClaimable || LP_TOKEN.totalSupply() > 0, "isClaimable: no LP tokens");
_;
}
function getRemainingTime() external view returns (uint256){
if (hasEnded()) return 0;
return END_TIME.sub(_currentBlockTimestamp());
}
function hasStarted() public view returns (bool) {
return _currentBlockTimestamp() >= START_TIME;
}
function hasEnded() public view returns (bool){
return END_TIME <= _currentBlockTimestamp();
}
function projectTokensToDistribute() public view returns (uint256){
if (MIN_TOTAL_RAISED_FOR_MAX_PROJECT_TOKEN > totalRaised) {
return MAX_PROJECT_TOKENS_TO_DISTRIBUTE.mul(totalRaised).div(MIN_TOTAL_RAISED_FOR_MAX_PROJECT_TOKEN);
}
return MAX_PROJECT_TOKENS_TO_DISTRIBUTE;
}
function projectTokens2ToDistribute() public view returns (uint256){
if(address(PROJECT_TOKEN_2) == address(0)) {
return 0;
}
if (MIN_TOTAL_RAISED_FOR_MAX_PROJECT_TOKEN > totalRaised) {
return MAX_PROJECT_TOKENS_2_TO_DISTRIBUTE.mul(totalRaised).div(MIN_TOTAL_RAISED_FOR_MAX_PROJECT_TOKEN);
}
return MAX_PROJECT_TOKENS_2_TO_DISTRIBUTE;
}
function tokensToDistribute() public view returns (uint256){
return projectTokensToDistribute().add(projectTokens2ToDistribute());
}
function getExpectedClaimAmount(address account) public view returns (uint256 projectTokenAmount, uint256 projectToken2Amount) {
if(totalAllocation == 0) return (0, 0);
UserInfo memory user = userInfo[account];
projectTokenAmount = user.allocation.mul(projectTokensToDistribute()).div(totalAllocation);
projectToken2Amount = user.allocation.mul(projectTokens2ToDistribute()).div(totalAllocation);
}
function buyETH() external isSaleActive nonReentrant payable {
require(address(SALE_TOKEN) == weth, "non ETH sale");
uint256 amount = msg.value;
IWETH(weth).deposit{value: amount}();
_buy(amount);
}
function buy(uint256 amount) external isSaleActive nonReentrant {
SALE_TOKEN.safeTransferFrom(msg.sender, address(this), amount);
_buy(amount);
}
function _buy(uint256 amount) internal {
require(amount > 0, "buy: zero amount");
require(totalRaised.add(amount) <= MAX_RAISE_AMOUNT, "buy: hardcap reached");
UserInfo storage user = userInfo[msg.sender];
if(whitelistOnly) {
require(user.whitelisted, "buy: not whitelisted");
require(user.contribution.add(amount) <= user.whitelistCap, "buy: whitelist wallet cap reached");
}
else{
uint256 userWalletCap = CAP_PER_WALLET > user.whitelistCap ? CAP_PER_WALLET : user.whitelistCap;
require(user.contribution.add(amount) <= userWalletCap, "buy: wallet cap reached");
}
uint256 allocation = amount;
if (user.discount > 0 && user.contribution < user.discountEligibleAmount) {
uint256 discountEligibleAmount = user.discountEligibleAmount.sub(user.contribution);
if (discountEligibleAmount > amount) {
discountEligibleAmount = amount;
}
allocation = allocation.add(discountEligibleAmount.mul(user.discount).div(100));
}
user.contribution = user.contribution.add(amount);
totalRaised = totalRaised.add(amount);
user.allocation = user.allocation.add(allocation);
totalAllocation = totalAllocation.add(allocation);
emit Buy(msg.sender, amount);
SALE_TOKEN.safeTransfer(treasury, amount);
}
function claim() external isClaimable {
UserInfo storage user = userInfo[msg.sender];
require(totalAllocation > 0 && user.allocation > 0, "claim: zero allocation");
require(!user.hasClaimed, "claim: already claimed");
user.hasClaimed = true;
(uint256 token1Amount, uint256 token2Amount) = getExpectedClaimAmount(msg.sender);
emit Claim(msg.sender, token1Amount, token2Amount);
if(token1Amount > 0) {
_safeClaimTransfer(PROJECT_TOKEN, msg.sender, token1Amount);
}
if(token2Amount > 0) {
_safeClaimTransfer(PROJECT_TOKEN_2, msg.sender, token2Amount);
}
}
struct DiscountSettings {
address account;
uint256 discount;
uint256 eligibleAmount;
}
function setUsersDiscount(DiscountSettings[] calldata users) public onlyOwner {
for (uint256 i = 0; i < users.length; ++i) {
DiscountSettings memory userDiscount = users[i];
UserInfo storage user = userInfo[userDiscount.account];
require(userDiscount.discount <= 35, "discount too high");
user.discount = userDiscount.discount;
user.discountEligibleAmount = userDiscount.eligibleAmount;
}
emit DiscountUpdated();
}
struct WhitelistSettings {
address account;
bool whitelisted;
uint256 whitelistCap;
}
function setUsersWhitelist(WhitelistSettings[] calldata users) public onlyOwner {
for (uint256 i = 0; i < users.length; ++i) {
WhitelistSettings memory userWhitelist = users[i];
UserInfo storage user = userInfo[userWhitelist.account];
user.whitelisted = userWhitelist.whitelisted;
user.whitelistCap = userWhitelist.whitelistCap;
}
emit WhitelistUpdated();
}
function setWhitelistOnly(bool value) external onlyOwner {
whitelistOnly = value;
emit SetWhitelistOnly(value);
}
function withdrawUnsoldTokens() external onlyOwner {
require(hasEnded(), "withdrawUnsoldTokens: presale has not ended");
require(!unsoldTokensWithdrew, "withdrawUnsoldTokens: already burnt");
uint256 totalTokenSold = projectTokensToDistribute();
uint256 totalToken2Sold = projectTokens2ToDistribute();
unsoldTokensWithdrew = true;
if(totalTokenSold > 0) PROJECT_TOKEN.transfer(msg.sender, MAX_PROJECT_TOKENS_TO_DISTRIBUTE.sub(totalTokenSold));
if(totalToken2Sold > 0) PROJECT_TOKEN_2.transfer(msg.sender, MAX_PROJECT_TOKENS_2_TO_DISTRIBUTE.sub(totalToken2Sold));
}
function emergencyWithdrawFunds(address token, uint256 amount) external onlyOwner {
IERC20(token).safeTransfer(msg.sender, amount);
emit EmergencyWithdraw(token, amount);
}
function setForceClaimable() external onlyOwner {
forceClaimable = true;
}
function _safeClaimTransfer(IERC20 token, address to, uint256 amount) internal {
uint256 balance = token.balanceOf(address(this));
bool transferSuccess = false;
if (amount > balance) {
transferSuccess = token.transfer(to, balance);
} else {
transferSuccess = token.transfer(to, amount);
}
require(transferSuccess, "safeClaimTransfer: Transfer failed");
}
function _currentBlockTimestamp() internal view virtual returns (uint256) {
return block.timestamp;
}
}
文件 4 的 9:IERC20.sol
pragma solidity ^0.7.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 5 的 9:IWETH.sol
pragma solidity >=0.5.0;
interface IWETH {
function deposit() external payable;
function transfer(address to, uint value) external returns (bool);
function withdraw(uint) external;
}
文件 6 的 9:Ownable.sol
pragma solidity ^0.7.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor () {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
文件 7 的 9:ReentrancyGuard.sol
pragma solidity ^0.7.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor () {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 8 的 9:SafeERC20.sol
pragma solidity ^0.7.0;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
library SafeERC20 {
using SafeMath for uint256;
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).add(value);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
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");
}
}
}
文件 9 的 9:SafeMath.sol
pragma solidity ^0.7.0;
library SafeMath {
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
{
"compilationTarget": {
"contracts/FairAuction.sol": "FairAuction"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 20000
},
"remappings": []
}
[{"inputs":[{"internalType":"contract IERC20","name":"projectToken","type":"address"},{"internalType":"contract IERC20","name":"projectToken2","type":"address"},{"internalType":"contract IERC20","name":"saleToken","type":"address"},{"internalType":"contract IERC20","name":"lpToken","type":"address"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"address","name":"treasury_","type":"address"},{"internalType":"uint256","name":"maxToDistribute","type":"uint256"},{"internalType":"uint256","name":"maxToDistribute2","type":"uint256"},{"internalType":"uint256","name":"minToRaise","type":"uint256"},{"internalType":"uint256","name":"maxToRaise","type":"uint256"},{"internalType":"uint256","name":"capPerWallet","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Buy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount2","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[],"name":"DiscountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EmergencyWithdraw","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":false,"internalType":"bool","name":"status","type":"bool"}],"name":"SetWhitelistOnly","type":"event"},{"anonymous":false,"inputs":[],"name":"WhitelistUpdated","type":"event"},{"inputs":[],"name":"CAP_PER_WALLET","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"END_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LP_TOKEN","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PROJECT_TOKENS_2_TO_DISTRIBUTE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PROJECT_TOKENS_TO_DISTRIBUTE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_RAISE_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_TOTAL_RAISED_FOR_MAX_PROJECT_TOKEN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROJECT_TOKEN","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROJECT_TOKEN_2","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SALE_TOKEN","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"START_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"buy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"buyETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"emergencyWithdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"forceClaimable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getExpectedClaimAmount","outputs":[{"internalType":"uint256","name":"projectTokenAmount","type":"uint256"},{"internalType":"uint256","name":"projectToken2Amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRemainingTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hasEnded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hasStarted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"projectTokens2ToDistribute","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"projectTokensToDistribute","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setForceClaimable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"discount","type":"uint256"},{"internalType":"uint256","name":"eligibleAmount","type":"uint256"}],"internalType":"struct FairAuction.DiscountSettings[]","name":"users","type":"tuple[]"}],"name":"setUsersDiscount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"whitelisted","type":"bool"},{"internalType":"uint256","name":"whitelistCap","type":"uint256"}],"internalType":"struct FairAuction.WhitelistSettings[]","name":"users","type":"tuple[]"}],"name":"setUsersWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"value","type":"bool"}],"name":"setWhitelistOnly","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tokensToDistribute","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAllocation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRaised","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unsoldTokensWithdrew","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userInfo","outputs":[{"internalType":"uint256","name":"allocation","type":"uint256"},{"internalType":"uint256","name":"contribution","type":"uint256"},{"internalType":"bool","name":"whitelisted","type":"bool"},{"internalType":"uint256","name":"whitelistCap","type":"uint256"},{"internalType":"uint256","name":"discount","type":"uint256"},{"internalType":"uint256","name":"discountEligibleAmount","type":"uint256"},{"internalType":"bool","name":"hasClaimed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"whitelistOnly","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawUnsoldTokens","outputs":[],"stateMutability":"nonpayable","type":"function"}]