文件 1 的 18:Address.sol
pragma solidity >=0.6.2 <0.8.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 的 18:CappedTokenSoldCrowdsaleHelper.sol
pragma solidity ^0.7.6;
import "@openzeppelin/contracts/math/SafeMath.sol";
contract CappedTokenSoldCrowdsaleHelper {
using SafeMath for uint256;
uint256 private _tokenCap;
constructor(uint256 tokenCap_) {
require(tokenCap_ > 0, "CappedTokenSoldHelper: zero cap");
_tokenCap = tokenCap_;
}
modifier tokenCapNotExceeded(uint256 tokensSold, uint256 tokenAmount) {
require(
tokensSold.add(tokenAmount) <= _tokenCap,
"CappedTokenSoldHelper: cap exceeded"
);
_;
}
function tokenCap() public view returns (uint256 tokenCap_) {
tokenCap_ = _tokenCap;
}
function tokenCapReached(uint256 tokensSold)
external
view
returns (bool tokenCapReached_)
{
tokenCapReached_ = (tokensSold >= _tokenCap);
}
}
文件 3 的 18: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;
}
}
文件 4 的 18:Crowdsale.sol
pragma solidity ^0.7.6;
pragma abicoder v2;
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/utils/Pausable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "./interfaces/ICrowdsale.sol";
contract Crowdsale is ReentrancyGuard, ICrowdsale {
using SafeMath for uint256;
using SafeERC20 for IERC20;
uint256 public constant MAX_NUM_PAYMENT_TOKENS = 10;
uint256 public constant TOKEN_MAX_DECIMALS = 18;
uint256 public constant TOKEN_SELLING_SCALE = 10**TOKEN_MAX_DECIMALS;
uint256 public tokensSold;
address private _tokenSelling;
LotsInfo private _lotsInfo;
address[] private _paymentTokens;
mapping(address => uint256) private _paymentDecimals;
mapping(address => bool) private _isPaymentTokens;
address private _wallet;
mapping(address => uint256) private _rates;
mapping(address => uint256) private _weiRaised;
constructor(
address wallet_,
address tokenSelling_,
LotsInfo memory lotsInfo,
PaymentTokenInfo[] memory paymentTokensInfo
) {
require(wallet_ != address(0), "Crowdsale: zero wallet address");
require(
tokenSelling_ != address(0),
"Crowdsale: zero token selling address"
);
require(lotsInfo.lotSize > 0, "Crowdsale: zero lot size");
require(lotsInfo.maxLots > 0, "Crowdsale: zero max lots");
require(paymentTokensInfo.length > 0, "Crowdsale: zero payment tokens");
require(
paymentTokensInfo.length < MAX_NUM_PAYMENT_TOKENS,
"Crowdsale: exceed max payment tokens"
);
_wallet = wallet_;
_tokenSelling = tokenSelling_;
_lotsInfo = lotsInfo;
for (uint256 i = 0; i < paymentTokensInfo.length; i++) {
uint256 paymentDecimal = paymentTokensInfo[i].paymentDecimal;
require(
paymentDecimal <= TOKEN_MAX_DECIMALS,
"Crowdsale: decimals exceed 18"
);
address paymentToken = paymentTokensInfo[i].paymentToken;
require(
paymentToken != address(0),
"Crowdsale: zero payment token address"
);
uint256 rate_ = paymentTokensInfo[i].rate;
require(rate_ > 0, "Crowdsale: zero rate");
_isPaymentTokens[paymentToken] = true;
_paymentTokens.push(paymentToken);
_paymentDecimals[paymentToken] = paymentDecimal;
_rates[paymentToken] = rate_;
}
}
function tokenSelling()
external
view
override
returns (address tokenSelling_)
{
tokenSelling_ = _tokenSelling;
}
function wallet() external view override returns (address wallet_) {
wallet_ = _wallet;
}
function paymentTokens()
external
view
override
returns (address[] memory paymentTokens_)
{
paymentTokens_ = _paymentTokens;
}
function rate(address paymentToken)
external
view
override
returns (uint256 rate_)
{
require(
paymentToken != address(0),
"Crowdsale: zero payment token address"
);
require(
isPaymentToken(paymentToken),
"Crowdsale: payment token unaccepted"
);
rate_ = _rate(paymentToken);
}
function lotSize() public view override returns (uint256 lotSize_) {
lotSize_ = _lotsInfo.lotSize;
}
function maxLots() external view override returns (uint256 maxLots_) {
maxLots_ = _lotsInfo.maxLots;
}
function weiRaisedFor(address paymentToken)
external
view
override
returns (uint256 weiRaised_)
{
weiRaised_ = _weiRaisedFor(paymentToken);
}
function isPaymentToken(address paymentToken)
public
view
override
returns (bool isPaymentToken_)
{
require(
paymentToken != address(0),
"Crowdsale: zero payment token address"
);
isPaymentToken_ = _isPaymentTokens[paymentToken];
}
function getTokenAmount(uint256 lots)
external
view
override
returns (uint256 tokenAmount)
{
require(lots > 0, "Crowdsale: zero lots");
tokenAmount = _getTokenAmount(lots);
}
function getWeiAmount(address paymentToken, uint256 lots)
external
view
override
returns (uint256 weiAmount)
{
require(
paymentToken != address(0),
"Crowdsale: zero payment token address"
);
require(lots > 0, "Crowdsale: zero lots");
require(
isPaymentToken(paymentToken),
"Crowdsale: payment token unaccepted"
);
weiAmount = _getWeiAmount(paymentToken, lots);
}
function buyTokens(address paymentToken, uint256 lots) external override {
_buyTokensFor(msg.sender, paymentToken, lots);
}
function buyTokensFor(
address beneficiary,
address paymentToken,
uint256 lots
) external override {
_buyTokensFor(beneficiary, paymentToken, lots);
}
function _buyTokensFor(
address beneficiary,
address paymentToken,
uint256 lots
) internal nonReentrant {
require(
beneficiary != address(0),
"Crowdsale: zero beneficiary address"
);
require(
paymentToken != address(0),
"Crowdsale: zero payment token address"
);
require(lots > 0, "Crowdsale: zero lots");
require(
isPaymentToken(paymentToken),
"Crowdsale: payment token unaccepted"
);
uint256 tokenAmount = _getTokenAmount(lots);
uint256 weiAmount = _getWeiAmount(paymentToken, lots);
_preValidatePurchase(beneficiary, paymentToken, weiAmount, tokenAmount);
_weiRaised[paymentToken] = _weiRaised[paymentToken].add(weiAmount);
tokensSold = tokensSold.add(tokenAmount);
_updatePurchasingState(
beneficiary,
paymentToken,
weiAmount,
tokenAmount
);
emit TokensPurchased(
msg.sender,
beneficiary,
paymentToken,
lots,
weiAmount,
tokenAmount
);
_processPurchase(beneficiary, tokenAmount);
_forwardFunds(paymentToken, weiAmount);
_postValidatePurchase(
beneficiary,
paymentToken,
weiAmount,
tokenAmount
);
}
function _weiRaisedFor(address paymentToken)
internal
view
virtual
returns (uint256 weiRaised_)
{
require(
paymentToken != address(0),
"Crowdsale: zero payment token address"
);
require(
isPaymentToken(paymentToken),
"Crowdsale: payment token unaccepted"
);
weiRaised_ = _weiRaised[paymentToken];
}
function _rate(address paymentToken)
internal
view
virtual
returns (uint256 rate_)
{
rate_ = _rates[paymentToken];
}
function _preValidatePurchase(
address beneficiary,
address paymentToken,
uint256 weiAmount,
uint256 tokenAmount
) internal view virtual {
}
function _postValidatePurchase(
address beneficiary,
address paymentToken,
uint256 weiAmount,
uint256 tokenAmount
) internal view virtual {
}
function _deliverTokens(address beneficiary, uint256 tokenAmount)
internal
virtual
{
IERC20(_tokenSelling).safeTransfer(beneficiary, tokenAmount);
}
function _processPurchase(address beneficiary, uint256 tokenAmount)
internal
virtual
{
_deliverTokens(beneficiary, tokenAmount);
}
function _updatePurchasingState(
address beneficiary,
address paymentToken,
uint256 weiAmount,
uint256 tokenAmount
) internal virtual {
}
function _getTokenAmount(uint256 lots)
internal
view
virtual
returns (uint256 tokenAmount)
{
tokenAmount = lots.mul(_lotsInfo.lotSize).mul(TOKEN_SELLING_SCALE);
}
function _getWeiAmount(address paymentToken, uint256 lots)
internal
view
virtual
returns (uint256 weiAmount)
{
uint256 rate_ = _rate(paymentToken);
uint256 tokenAmount = _getTokenAmount(lots);
weiAmount = tokenAmount.mul(rate_).div(TOKEN_SELLING_SCALE);
}
function _forwardFunds(address paymentToken, uint256 weiAmount)
internal
virtual
{
uint256 amount = weiAmount;
if (_paymentDecimals[paymentToken] < TOKEN_MAX_DECIMALS) {
uint256 decimalsDiff = uint256(TOKEN_MAX_DECIMALS).sub(
_paymentDecimals[paymentToken]
);
amount = weiAmount.div(10**decimalsDiff);
}
IERC20(paymentToken).safeTransferFrom(msg.sender, _wallet, amount);
}
}
文件 5 的 18:EjsCrowdsale.sol
pragma solidity ^0.7.6;
pragma abicoder v2;
import "@openzeppelin/contracts/utils/Pausable.sol";
import "./CappedTokenSoldCrowdsaleHelper.sol";
import "./IndividuallyCappedCrowdsaleHelper.sol";
import "./TimedCrowdsaleHelper.sol";
import "./VestedCrowdsale.sol";
import "./WhitelistCrowdsaleHelper.sol";
import "./interfaces/IEjsCrowdsale.sol";
contract EjsCrowdsale is
VestedCrowdsale,
CappedTokenSoldCrowdsaleHelper,
IndividuallyCappedCrowdsaleHelper,
TimedCrowdsaleHelper,
WhitelistCrowdsaleHelper,
Pausable,
IEjsCrowdsale
{
using SafeMath for uint256;
struct EjsCrowdsaleInfo {
uint256 tokenCap;
address vestingContract;
address whitelistContract;
}
address public governanceAccount;
address public crowdsaleAdmin;
constructor(
address wallet_,
address tokenSelling_,
EjsCrowdsaleInfo memory crowdsaleInfo,
LotsInfo memory lotsInfo,
Timeframe memory timeframe,
PaymentTokenInfo[] memory paymentTokensInfo
)
Crowdsale(wallet_, tokenSelling_, lotsInfo, paymentTokensInfo)
VestedCrowdsale(crowdsaleInfo.vestingContract)
CappedTokenSoldCrowdsaleHelper(crowdsaleInfo.tokenCap)
IndividuallyCappedCrowdsaleHelper(
lotsInfo.maxLots.mul(lotsInfo.lotSize).mul(TOKEN_SELLING_SCALE)
)
TimedCrowdsaleHelper(timeframe)
WhitelistCrowdsaleHelper(crowdsaleInfo.whitelistContract)
{
governanceAccount = msg.sender;
crowdsaleAdmin = msg.sender;
}
modifier onlyBy(address account) {
require(msg.sender == account, "EjsCrowdsale: sender unauthorized");
_;
}
function getAvailableLotsFor(address beneficiary)
external
view
override
returns (uint256 availableLots)
{
if (!whitelisted(beneficiary)) {
return 0;
}
availableLots = _getAvailableTokensFor(beneficiary).div(lotSize()).div(
TOKEN_SELLING_SCALE
);
}
function getRemainingLots()
external
view
override
returns (uint256 remainingLots)
{
uint256 remainingTokens = tokenCap().sub(tokensSold);
remainingLots = remainingTokens.div(lotSize());
}
function pause() external override onlyBy(crowdsaleAdmin) {
_pause();
}
function unpause() external override onlyBy(crowdsaleAdmin) {
_unpause();
}
function extendTime(uint256 newClosingTime)
external
override
onlyBy(crowdsaleAdmin)
{
_extendTime(newClosingTime);
}
function startDistribution(uint256 scheduleStartTimestamp)
external
override
onlyBy(crowdsaleAdmin)
{
require(
scheduleStartTimestamp > closingTime(),
"EjsCrowdsale: must be after closing time"
);
_startDistribution(scheduleStartTimestamp);
}
function setGovernanceAccount(address account)
external
override
onlyBy(governanceAccount)
{
require(account != address(0), "EjsCrowdsale: zero account");
governanceAccount = account;
}
function setCrowdsaleAdmin(address account)
external
override
onlyBy(governanceAccount)
{
require(account != address(0), "EjsCrowdsale: zero account");
crowdsaleAdmin = account;
}
function _preValidatePurchase(
address beneficiary,
address paymentToken,
uint256 weiAmount,
uint256 tokenAmount
)
internal
view
override
tokenCapNotExceeded(tokensSold, tokenAmount)
beneficiaryCapNotExceeded(beneficiary, tokenAmount)
whenNotPaused
onlyWhileOpen
isWhitelisted(beneficiary)
{
super._preValidatePurchase(
beneficiary,
paymentToken,
weiAmount,
tokenAmount
);
}
function _updatePurchasingState(
address beneficiary,
address paymentToken,
uint256 weiAmount,
uint256 tokenAmount
) internal override {
super._updatePurchasingState(
beneficiary,
paymentToken,
weiAmount,
tokenAmount
);
_updateBeneficiaryTokensPurchased(beneficiary, tokenAmount);
}
}
文件 6 的 18:ICrowdsale.sol
pragma solidity ^0.7.6;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface ICrowdsale {
struct LotsInfo {
uint256 lotSize;
uint256 maxLots;
}
struct PaymentTokenInfo {
address paymentToken;
uint256 paymentDecimal;
uint256 rate;
}
function tokenSelling() external view returns (address tokenSelling_);
function wallet() external view returns (address wallet_);
function paymentTokens()
external
view
returns (address[] memory paymentTokens_);
function rate(address paymentToken) external view returns (uint256 rate_);
function lotSize() external view returns (uint256 lotSize_);
function maxLots() external view returns (uint256 maxLots_);
function weiRaisedFor(address paymentToken)
external
view
returns (uint256 weiRaised_);
function isPaymentToken(address paymentToken)
external
view
returns (bool isPaymentToken_);
function getTokenAmount(uint256 lots)
external
view
returns (uint256 tokenAmount);
function getWeiAmount(address paymentToken, uint256 lots)
external
view
returns (uint256 weiAmount);
function buyTokens(address paymentToken, uint256 lots) external;
function buyTokensFor(
address beneficiary,
address paymentToken,
uint256 lots
) external;
event TokensPurchased(
address indexed purchaser,
address indexed beneficiary,
address indexed paymentToken,
uint256 lots,
uint256 weiAmount,
uint256 tokenAmount
);
}
文件 7 的 18:IERC20.sol
pragma solidity >=0.6.0 <0.8.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);
}
文件 8 的 18:IEjsCrowdsale.sol
pragma solidity ^0.7.6;
import "./ICrowdsale.sol";
interface IEjsCrowdsale is ICrowdsale {
function getAvailableLotsFor(address beneficiary)
external
view
returns (uint256 availableLots);
function getRemainingLots() external view returns (uint256 remainingLots);
function pause() external;
function unpause() external;
function extendTime(uint256 newClosingTime) external;
function startDistribution(uint256 scheduleStartTimestamp) external;
function setGovernanceAccount(address account) external;
function setCrowdsaleAdmin(address account) external;
}
文件 9 的 18:IVesting.sol
pragma solidity ^0.7.6;
interface IVesting {
enum ReleaseMethod {
IntervalEnd,
LinearlyPerSecond
}
function addVestingGrant(
address account,
uint256 grantAmount,
bool isRevocable
) external;
function revokeVestingGrant(address account) external;
function release() external;
function transferUnusedTokens() external;
function addVestingGrantsBatch(
address[] memory accounts,
uint256[] memory grantAmounts,
bool[] memory isRevocables
) external;
function setScheduleStartTimestamp(uint256 scheduleStartTimestamp_)
external;
function setGovernanceAccount(address account) external;
function setVestingAdmin(address account) external;
function getVestingSchedule()
external
view
returns (
uint256 cliffDurationDays,
uint256 percentReleaseAtGrantStart,
uint256 percentReleaseAtIntervalStart,
uint256 intervalDays,
uint256 gapDays,
uint256 numberOfIntervals,
ReleaseMethod releaseMethod
);
function vestingGrantFor(address account)
external
view
returns (
uint256 grantAmount,
bool isRevocable,
bool isRevoked,
bool isActive
);
function revoked(address account) external view returns (bool isRevoked);
function releasedAmountFor(address account)
external
view
returns (uint256 releasedAmount);
function releasableAmountFor(address account)
external
view
returns (uint256 unreleasedAmount);
function vestedAmountFor(address account)
external
view
returns (uint256 vestedAmount);
function unvestedAmountFor(address account)
external
view
returns (uint256 unvestedAmount);
event VestingGrantAdded(
address indexed account,
uint256 indexed grantAmount,
bool isRevocable
);
event VestingGrantRevoked(
address indexed account,
uint256 remainderAmount,
uint256 grantAmount,
uint256 releasedAmount
);
event TokensReleased(address indexed account, uint256 amount);
event ScheduleStartTimestampSet(
address indexed account,
uint256 newScheduleStartTimestamp,
uint256 oldScheduleStartTimestamp
);
}
文件 10 的 18:IWhitelist.sol
pragma solidity ^0.7.6;
interface IWhitelist {
function addWhitelisted(address account) external;
function removeWhitelisted(address account) external;
function addWhitelistedBatch(address[] memory accounts) external;
function removeWhitelistedBatch(address[] memory accounts) external;
function setGovernanceAccount(address account) external;
function setWhitelistAdmin(address account) external;
function isWhitelisted(address account)
external
view
returns (bool isWhitelisted_);
event WhitelistedAdded(address indexed account);
event WhitelistedRemoved(address indexed account);
}
文件 11 的 18:IndividuallyCappedCrowdsaleHelper.sol
pragma solidity ^0.7.6;
import "@openzeppelin/contracts/math/SafeMath.sol";
contract IndividuallyCappedCrowdsaleHelper {
using SafeMath for uint256;
mapping(address => uint256) private _tokensPurchased;
uint256 private _tokenCap;
constructor(uint256 tokenCap) {
require(tokenCap > 0, "IndividuallyCappedCrowdsaleHelper: zero cap");
_tokenCap = tokenCap;
}
modifier beneficiaryCapNotExceeded(
address beneficiary,
uint256 tokenAmount
) {
require(
_tokensPurchased[beneficiary].add(tokenAmount) <= _tokenCap,
"IndividuallyCappedCrowdsaleHelper: beneficiary cap exceeded"
);
_;
}
function getBeneficiaryCap() public view returns (uint256 tokenCap) {
tokenCap = _tokenCap;
}
function getTokensPurchasedBy(address beneficiary)
public
view
returns (uint256 tokensPurchased)
{
require(
beneficiary != address(0),
"IndividuallyCappedCrowdsale: zero beneficiary address"
);
tokensPurchased = _tokensPurchased[beneficiary];
}
function _updateBeneficiaryTokensPurchased(
address beneficiary,
uint256 tokenAmount
) internal {
_tokensPurchased[beneficiary] = _tokensPurchased[beneficiary].add(
tokenAmount
);
}
function _getAvailableTokensFor(address beneficiary)
internal
view
returns (uint256 availableTokens)
{
availableTokens = getBeneficiaryCap().sub(
getTokensPurchasedBy(beneficiary)
);
}
}
文件 12 的 18:Pausable.sol
pragma solidity >=0.6.0 <0.8.0;
import "./Context.sol";
abstract contract Pausable is Context {
event Paused(address account);
event Unpaused(address account);
bool private _paused;
constructor () internal {
_paused = false;
}
function paused() public view virtual returns (bool) {
return _paused;
}
modifier whenNotPaused() {
require(!paused(), "Pausable: paused");
_;
}
modifier whenPaused() {
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 的 18:ReentrancyGuard.sol
pragma solidity >=0.6.0 <0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor () internal {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 14 的 18:SafeERC20.sol
pragma solidity >=0.6.0 <0.8.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");
}
}
}
文件 15 的 18:SafeMath.sol
pragma solidity >=0.6.0 <0.8.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;
}
}
文件 16 的 18:TimedCrowdsaleHelper.sol
pragma solidity ^0.7.6;
pragma abicoder v2;
import "@openzeppelin/contracts/math/SafeMath.sol";
contract TimedCrowdsaleHelper {
using SafeMath for uint256;
struct Timeframe {
uint256 openingTime;
uint256 closingTime;
}
Timeframe private _timeframe;
event TimedCrowdsaleExtended(
uint256 prevClosingTime,
uint256 newClosingTime
);
modifier onlyWhileOpen() {
require(isOpen(), "TimedCrowdsaleHelper: not open");
_;
}
constructor(Timeframe memory timeframe) {
require(
timeframe.openingTime >= block.timestamp,
"TimedCrowdsaleHelper: opening time is before current time"
);
require(
timeframe.closingTime > timeframe.openingTime,
"TimedCrowdsaleHelper: closing time is before opening time"
);
_timeframe.openingTime = timeframe.openingTime;
_timeframe.closingTime = timeframe.closingTime;
}
function openingTime() external view returns (uint256) {
return _timeframe.openingTime;
}
function closingTime() public view returns (uint256) {
return _timeframe.closingTime;
}
function isOpen() public view returns (bool) {
return
block.timestamp >= _timeframe.openingTime &&
block.timestamp <= _timeframe.closingTime;
}
function hasClosed() public view returns (bool) {
return block.timestamp > _timeframe.closingTime;
}
function _extendTime(uint256 newClosingTime) internal {
require(!hasClosed(), "TimedCrowdsaleHelper: already closed");
uint256 oldClosingTime = _timeframe.closingTime;
require(
newClosingTime > oldClosingTime,
"TimedCrowdsaleHelper: before current closing time"
);
_timeframe.closingTime = newClosingTime;
emit TimedCrowdsaleExtended(oldClosingTime, newClosingTime);
}
}
文件 17 的 18:VestedCrowdsale.sol
pragma solidity ^0.7.6;
import "./Crowdsale.sol";
import "./interfaces/IVesting.sol";
abstract contract VestedCrowdsale is Crowdsale {
address public vestingContract;
constructor(address vestingContract_) {
require(
vestingContract_ != address(0),
"VestedCrowdsale: zero vesting address"
);
vestingContract = vestingContract_;
}
function _startDistribution(uint256 scheduleStartTimestamp) internal {
IVesting(vestingContract).setScheduleStartTimestamp(
scheduleStartTimestamp
);
}
function _deliverTokens(address beneficiary, uint256 tokenAmount)
internal
override
{
IVesting(vestingContract).addVestingGrant(
beneficiary,
tokenAmount,
false
);
}
}
文件 18 的 18:WhitelistCrowdsaleHelper.sol
pragma solidity ^0.7.6;
import "./interfaces/IWhitelist.sol";
contract WhitelistCrowdsaleHelper {
address public whitelistContract;
constructor(address whitelistContract_) {
require(
whitelistContract_ != address(0),
"WhitelistCrowdsaleHelper: zero whitelist address"
);
whitelistContract = whitelistContract_;
}
modifier isWhitelisted(address account) {
require(
IWhitelist(whitelistContract).isWhitelisted(account),
"WhitelistCrowdsaleHelper: account not whitelisted"
);
_;
}
function whitelisted(address account)
public
view
returns (bool whitelisted_)
{
whitelisted_ = IWhitelist(whitelistContract).isWhitelisted(account);
}
}
{
"compilationTarget": {
"contracts/EjsCrowdsale.sol": "EjsCrowdsale"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"wallet_","type":"address"},{"internalType":"address","name":"tokenSelling_","type":"address"},{"components":[{"internalType":"uint256","name":"tokenCap","type":"uint256"},{"internalType":"address","name":"vestingContract","type":"address"},{"internalType":"address","name":"whitelistContract","type":"address"}],"internalType":"struct EjsCrowdsale.EjsCrowdsaleInfo","name":"crowdsaleInfo","type":"tuple"},{"components":[{"internalType":"uint256","name":"lotSize","type":"uint256"},{"internalType":"uint256","name":"maxLots","type":"uint256"}],"internalType":"struct ICrowdsale.LotsInfo","name":"lotsInfo","type":"tuple"},{"components":[{"internalType":"uint256","name":"openingTime","type":"uint256"},{"internalType":"uint256","name":"closingTime","type":"uint256"}],"internalType":"struct TimedCrowdsaleHelper.Timeframe","name":"timeframe","type":"tuple"},{"components":[{"internalType":"address","name":"paymentToken","type":"address"},{"internalType":"uint256","name":"paymentDecimal","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"}],"internalType":"struct ICrowdsale.PaymentTokenInfo[]","name":"paymentTokensInfo","type":"tuple[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"prevClosingTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newClosingTime","type":"uint256"}],"name":"TimedCrowdsaleExtended","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"purchaser","type":"address"},{"indexed":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":true,"internalType":"address","name":"paymentToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"lots","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"weiAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"TokensPurchased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"MAX_NUM_PAYMENT_TOKENS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_MAX_DECIMALS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_SELLING_SCALE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"paymentToken","type":"address"},{"internalType":"uint256","name":"lots","type":"uint256"}],"name":"buyTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"address","name":"paymentToken","type":"address"},{"internalType":"uint256","name":"lots","type":"uint256"}],"name":"buyTokensFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"closingTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"crowdsaleAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newClosingTime","type":"uint256"}],"name":"extendTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"beneficiary","type":"address"}],"name":"getAvailableLotsFor","outputs":[{"internalType":"uint256","name":"availableLots","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBeneficiaryCap","outputs":[{"internalType":"uint256","name":"tokenCap","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRemainingLots","outputs":[{"internalType":"uint256","name":"remainingLots","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"lots","type":"uint256"}],"name":"getTokenAmount","outputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"beneficiary","type":"address"}],"name":"getTokensPurchasedBy","outputs":[{"internalType":"uint256","name":"tokensPurchased","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"paymentToken","type":"address"},{"internalType":"uint256","name":"lots","type":"uint256"}],"name":"getWeiAmount","outputs":[{"internalType":"uint256","name":"weiAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governanceAccount","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hasClosed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isOpen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"paymentToken","type":"address"}],"name":"isPaymentToken","outputs":[{"internalType":"bool","name":"isPaymentToken_","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lotSize","outputs":[{"internalType":"uint256","name":"lotSize_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLots","outputs":[{"internalType":"uint256","name":"maxLots_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"openingTime","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":"paymentTokens","outputs":[{"internalType":"address[]","name":"paymentTokens_","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"paymentToken","type":"address"}],"name":"rate","outputs":[{"internalType":"uint256","name":"rate_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"setCrowdsaleAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"setGovernanceAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"scheduleStartTimestamp","type":"uint256"}],"name":"startDistribution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tokenCap","outputs":[{"internalType":"uint256","name":"tokenCap_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokensSold","type":"uint256"}],"name":"tokenCapReached","outputs":[{"internalType":"bool","name":"tokenCapReached_","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenSelling","outputs":[{"internalType":"address","name":"tokenSelling_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokensSold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vestingContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wallet","outputs":[{"internalType":"address","name":"wallet_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"paymentToken","type":"address"}],"name":"weiRaisedFor","outputs":[{"internalType":"uint256","name":"weiRaised_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"whitelistContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"whitelisted","outputs":[{"internalType":"bool","name":"whitelisted_","type":"bool"}],"stateMutability":"view","type":"function"}]