// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Address.sol)
pragma solidity ^0.8.20;
import {Errors} from "./Errors.sol";
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert Errors.InsufficientBalance(address(this).balance, amount);
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert Errors.FailedCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {Errors.FailedCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
* of an unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {Errors.FailedCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly ("memory-safe") {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert Errors.FailedCall();
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// solhint-disable-next-line interface-starts-with-i
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);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Pausable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IElumphantStaking} from "./ElumphantStaking.sol";
interface IERC20WithDecimals is IERC20 {
function decimals() external view returns (uint8);
}
/**
* @title ElumphantPresale
* @dev A presale contract for the Elumphant token, supporting purchases in ETH and USDT.
* This contract facilitates the sale of Elumphant token at a dynamic price that increases
* after a specified number of tokens are sold. Purchasers can claim their tokens after
* the claim period begins. The contract uses Chainlink to fetch ETH/USD price data.
*/
contract ElumphantPresale is Ownable, Pausable, ReentrancyGuard {
/// @notice The Elumphant token being sold in the presale.
IERC20WithDecimals public immutable token;
/// @notice USDT token contract address for purchases in USDT.
IERC20WithDecimals public immutable usdt;
/// @notice The ElumphantStaking contract address.
IElumphantStaking public stakingContract;
/// @notice Chainlink price feed for the ETH/USD pair.
AggregatorV3Interface public immutable ethPriceFeed;
/// @notice Price of one token in USD.
uint256 public tokenPriceInUSD;
/// @notice Number of tokens sold in a price step before the price increases.
uint256 public immutable tokensPerStep;
/// @notice Increment in token price (in USD) after each step.
uint256 public immutable priceIncrement;
/// @notice Total tokens sold in the current price step.
uint256 public tokensSoldInCurStep;
/// @notice Total number of tokens purchased during the presale.
uint256 public totalTokensPurchased;
/// @notice Total number of tokens staked during the presale.
uint256 public totalTokensStaked;
/// @notice Minimum purchase amount in USD.
uint256 public minPurchaseInUSD;
/// @notice Start time of the presale (UNIX timestamp).
uint256 public presaleStartTime;
/// @notice End time of the presale (UNIX timestamp).
uint256 public presaleEndTime;
/// @notice Start time for token claiming (UNIX timestamp).
uint256 public claimStartTime;
/// @notice Maximum number of steps to externally pump the price.
uint256 public constant MAX_PRICE_PUMP_STEPS = 100;
/// @notice Tracks the number of tokens purchased but not yet claimed by each user.
mapping(address => uint256) public purchasedTokens;
/// @notice Tracks the number of tokens staked by each user.
mapping(address => uint256) public stakedTokens;
/// @notice Event emitted when tokens are purchased.
/// @param buyer The address of the purchaser.
/// @param amount The number of tokens purchased.
/// @param cost The cost of the purchase in ETH or USDT.
/// @param paymentMethod The method used for payment ("ETH" or "USDT").
event TokensPurchased(
address indexed buyer,
uint256 amount,
uint256 cost,
string paymentMethod,
uint256 costInUSD,
uint256 totalPurchased
);
/// @notice Event emitted when tokens are successfully claimed.
/// @param claimer The address of the user claiming tokens.
/// @param amount The number of tokens claimed.
event TokensClaimed(address indexed claimer, uint256 amount);
/// @notice Event emitted when tokens are successfully claimed.
/// @param claimer The address of the user claiming tokens.
/// @param amount The number of tokens claimed.
event TokensClaimedAndStaked(address indexed claimer, uint256 amount);
/// @notice Event emitted when tokens are deposited into the contract.
/// @param depositor The address of the user depositing tokens.
/// @param amount The number of tokens deposited.
event TokensDeposited(address indexed depositor, uint256 amount);
/// @notice Event emitted when the contract owner withdraws funds.
/// @param recipient The address receiving the withdrawn funds.
/// @param amount The amount of funds withdrawn.
/// @param asset The type of asset withdrawn ("ETH", "USDT", or "Tokens").
event Withdrawn(address indexed recipient, uint256 amount, string asset);
/// @notice Event emitted when the token price is updated.
/// @param oldPrice Old token price.
/// @param newPrice Updated token price.
event TokenPriceUpdated(uint256 oldPrice, uint256 newPrice);
/**
* @notice Initializes the presale contract with the given parameters.
* @param _initialOwner The address of the contract owner.
* @param _token The address of the ElumphantToken contract.
* @param _usdt The address of the USDT contract.
* @param _ethPriceFeed The address of the Chainlink ETH/USD price feed.
* @param _tokenPriceInUSD Initial price of one token in USD (scaled by 1e6).
* @param _tokensPerStep Number of tokens sold in each step before price increases.
* @param _priceIncrement The price increment in USD after each step (scaled by 1e6).
* @param _minPurchaseInUSD The minimum purchase amount in USD.
*/
constructor(
address _initialOwner,
address _token,
address _usdt,
address _ethPriceFeed,
uint256 _tokenPriceInUSD,
uint256 _tokensPerStep,
uint256 _priceIncrement,
uint256 _minPurchaseInUSD
) Ownable(_initialOwner) {
token = IERC20WithDecimals(_token);
usdt = IERC20WithDecimals(_usdt);
ethPriceFeed = AggregatorV3Interface(_ethPriceFeed);
tokenPriceInUSD = _tokenPriceInUSD;
tokensPerStep = _tokensPerStep;
priceIncrement = _priceIncrement;
minPurchaseInUSD = _minPurchaseInUSD;
}
/**
* @dev Ensures the function is called during the presale period.
*/
modifier beforePresale() {
require(
presaleStartTime == 0 || block.timestamp < presaleStartTime,
"Presale already started!"
);
_;
}
/**
* @dev Ensures the function is called during the presale period.
*/
modifier duringPresale() {
require(
block.timestamp >= presaleStartTime &&
block.timestamp <= presaleEndTime,
"Presale is not active"
);
_;
}
/**
* @dev Ensures the function is called after the presale ends.
*/
modifier afterPresale() {
require(block.timestamp > presaleEndTime, "Presale has not ended yet");
_;
}
/**
* @notice Allows users to purchase tokens using ETH.
*/
function buyWithETH()
external
payable
whenNotPaused
duringPresale
nonReentrant
{
require(msg.value > 0, "Must send ETH to purchase tokens");
uint256 ethPrice = getLatestETHPrice();
uint256 costInUSD = (msg.value * ethPrice) /
10 ** (18 + ethPriceFeed.decimals() - usdt.decimals());
require(
costInUSD >= minPurchaseInUSD,
"Amount less than minimum limit"
);
uint256 tokensToBuy = (costInUSD * 10 ** token.decimals()) /
tokenPriceInUSD;
require(tokensToBuy > 0, "Insufficient ETH for any tokens");
_updateTokenPrice(tokensToBuy);
purchasedTokens[msg.sender] += tokensToBuy;
totalTokensPurchased += tokensToBuy;
emit TokensPurchased(
msg.sender,
tokensToBuy,
msg.value,
"ETH",
costInUSD,
totalTokensPurchased
);
}
/**
* @notice Allows users to purchase tokens using USDT.
* @param _amount The amount of USDT sent for the purchase.
*/
function buyWithUSDT(
uint256 _amount
) external whenNotPaused duringPresale nonReentrant {
require(_amount >= minPurchaseInUSD, "Amount less than minimum limit");
uint256 tokensToBuy = (_amount * 10 ** token.decimals()) /
tokenPriceInUSD;
require(tokensToBuy > 0, "Insufficient USDT for any tokens");
_updateTokenPrice(tokensToBuy);
purchasedTokens[msg.sender] += tokensToBuy;
totalTokensPurchased += tokensToBuy;
(bool success, ) = address(usdt).call(
abi.encodeWithSignature(
"transferFrom(address,address,uint256)",
msg.sender,
address(this),
_amount
)
);
require(success, "Token transfer failed");
emit TokensPurchased(
msg.sender,
tokensToBuy,
_amount,
"USDT",
_amount,
totalTokensPurchased
);
}
/**
* @notice Allows users to claim their purchased tokens after the claim start time.
*/
function claim() external whenNotPaused nonReentrant {
require(
block.timestamp >= claimStartTime,
"Claiming is not allowed yet"
);
uint256 tokensStaked = stakedTokens[msg.sender];
uint256 tokensClaimable = purchasedTokens[msg.sender] - tokensStaked;
require(tokensClaimable > 0, "No tokens to claim");
purchasedTokens[msg.sender] = tokensStaked;
bool success = token.transfer(msg.sender, tokensClaimable);
require(success, "Token transfer failed");
emit TokensClaimed(msg.sender, tokensClaimable);
}
function claimAndStake(uint256 amount) external whenNotPaused nonReentrant {
require(
address(stakingContract) != address(0),
"Staking contract has not been set"
);
uint256 tokensClaimable = purchasedTokens[msg.sender] -
stakedTokens[msg.sender];
require(amount > 0 && amount <= tokensClaimable, "Invalid amount!");
stakedTokens[msg.sender] += amount;
totalTokensStaked += amount;
token.approve(address(stakingContract), amount);
stakingContract.depositByPresale(msg.sender, amount);
emit TokensClaimedAndStaked(msg.sender, amount);
}
/**
* @notice Allows to deposit Elumphant Tokens into the contract.
* @param _amount The number of tokens to deposit.
*/
function depositTokens(uint256 _amount) external {
require(_amount > 0, "Deposit amount must be greater than zero");
// Transfer tokens from the sender to the contract
bool success = token.transferFrom(msg.sender, address(this), _amount);
require(success, "Token transfer failed");
emit TokensDeposited(msg.sender, _amount);
}
/**
* @notice Sets the presale and claim start/end times.
* @param _presaleStartTime The start time of the presale (UNIX timestamp).
* @param _presaleEndTime The end time of the presale (UNIX timestamp).
* @param _claimStartTime The start time for token claiming (UNIX timestamp).
*/
function setTimes(
uint256 _presaleStartTime,
uint256 _presaleEndTime,
uint256 _claimStartTime
) external onlyOwner beforePresale {
require(
block.timestamp <= _presaleEndTime &&
_presaleStartTime < _presaleEndTime &&
_presaleEndTime <= _claimStartTime,
"Invalid time configuration"
);
presaleStartTime = _presaleStartTime;
presaleEndTime = _presaleEndTime;
claimStartTime = _claimStartTime;
}
/**
* @notice Updates the presale end and claim start times.
* @param _presaleEndTime The end time of the presale (UNIX timestamp).
* @param _claimStartTime The start time for token claiming (UNIX timestamp).
*/
function updatePresaleEndTime(
uint256 _presaleEndTime,
uint256 _claimStartTime
) external onlyOwner {
require(
presaleStartTime < _presaleEndTime &&
block.timestamp <= _presaleEndTime &&
_presaleEndTime <= _claimStartTime,
"Invalid time configuration"
);
presaleEndTime = _presaleEndTime;
claimStartTime = _claimStartTime;
}
/**
* @notice Allows the owner to update the minimum purchase amount in USD.
* @param _minPurchaseInUSD The new minimum purchase amount (scaled by 1e6).
*/
function setMinPurchaseInUSD(uint256 _minPurchaseInUSD) external onlyOwner {
require(
_minPurchaseInUSD > 0,
"Minimum purchase must be greater than zero"
);
minPurchaseInUSD = _minPurchaseInUSD;
}
/**
* @notice Allows the owner to update the staking contract address.
* @param _stakingContractAddress The new staking contract address.
*/
function setStakingContractAddress(
address _stakingContractAddress
) external onlyOwner {
require(
_stakingContractAddress != address(0),
"Minimum purchase must be greater than zero"
);
stakingContract = IElumphantStaking(_stakingContractAddress);
}
/**
* @notice Pauses the presale contract, preventing certain actions.
* Only callable by the contract owner.
*/
function pause() external onlyOwner {
_pause();
}
/**
* @notice Unpauses the presale contract, allowing actions to resume.
* Only callable by the contract owner.
*/
function unpause() external onlyOwner {
_unpause();
}
/**
* @notice Allows the contract owner to withdraw ETH.
* @param _recipient The address to receive the withdrawn ETH.
*/
function withdrawETH(address _recipient) external onlyOwner nonReentrant {
uint256 balance = address(this).balance;
require(balance > 0, "No ETH to withdraw");
(bool success, ) = payable(_recipient).call{value: balance}("");
require(success, "ETH transfer failed");
emit Withdrawn(_recipient, balance, "ETH");
}
/**
* @notice Allows the contract owner to withdraw USDT.
* @param _recipient The address to receive the withdrawn USDT.
*/
function withdrawUSDT(address _recipient) external onlyOwner nonReentrant {
uint256 balance = usdt.balanceOf(address(this));
require(balance > 0, "No USDT to withdraw");
(bool success, ) = address(usdt).call(
abi.encodeWithSignature(
"transfer(address,uint256)",
_recipient,
balance
)
);
require(success, "Token transfer failed");
emit Withdrawn(_recipient, balance, "USDT");
}
/**
* @notice Allows the contract owner to withdraw unsold tokens after the presale ends.
* @param _recipient The address to receive the unsold tokens.
*/
function withdrawUnsoldTokens(
address _recipient
) external onlyOwner afterPresale nonReentrant {
uint256 balance = token.balanceOf(address(this));
uint256 soldTokens = totalTokensPurchased - totalTokensStaked;
uint256 unsoldTokens = balance - soldTokens;
require(unsoldTokens > 0, "No unsold tokens to withdraw");
bool success = token.transfer(_recipient, unsoldTokens);
require(success, "Token transfer failed");
emit Withdrawn(_recipient, unsoldTokens, "Tokens");
}
/**
* @notice Allows the owner to airdrop tokens to multiple recipients.
* @param _recipients The array of recipient addresses.
* @param _amount The number of tokens to airdrop to each recipient.
*/
function airdrop(
address[] calldata _recipients,
uint256 _amount
) external onlyOwner {
require(_recipients.length > 0, "Recipients array should not be empty");
require(_amount > 0, "Airdrop amount must be greater than zero");
_updateTokenPrice(_amount * _recipients.length);
totalTokensPurchased += (_amount * _recipients.length);
for (uint256 i = 0; i < _recipients.length; i++) {
purchasedTokens[_recipients[i]] += _amount;
emit TokensPurchased(
_recipients[i],
_amount,
0,
"Airdrop",
_amount * tokenPriceInUSD,
totalTokensPurchased
);
}
}
/**
* @notice Allows the owner to update the token price.
* @param _newPrice New token price in USD.
*/
function updateTokenPrice(uint256 _newPrice) public onlyOwner {
uint256 oldPrice = tokenPriceInUSD;
tokenPriceInUSD = _newPrice;
emit TokenPriceUpdated(oldPrice, _newPrice);
}
/**
* @notice Updates the token price when the step threshold is crossed.
* @param _tokensToBuy The number of tokens purchased in the transaction.
*/
function _updateTokenPrice(uint256 _tokensToBuy) internal {
tokensSoldInCurStep += _tokensToBuy;
if (tokensSoldInCurStep >= tokensPerStep) {
uint256 steps = tokensSoldInCurStep / tokensPerStep;
tokensSoldInCurStep %= tokensPerStep; // Reset counter for the next step
uint256 oldPrice = tokenPriceInUSD;
uint256 newPrice = oldPrice + steps * priceIncrement;
tokenPriceInUSD = newPrice;
emit TokenPriceUpdated(oldPrice, newPrice);
}
}
/**
* @notice Fetches the current ETH/USD price from the Chainlink price feed.
* @return The latest ETH price in USD.
*/
function getLatestETHPrice() public view returns (uint256) {
(, int256 price, , , ) = ethPriceFeed.latestRoundData();
require(price > 0, "Invalid price feed data");
return uint256(price);
}
}
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Pausable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
interface IElumphantStaking {
function depositByPresale(address _user, uint256 _amount) external;
}
contract ElumphantStaking is IElumphantStaking, Ownable {
using SafeERC20 for IERC20; // Wrappers around ERC20 operations that throw on failure
IERC20 public token; // Token to be staked and rewarded
address public presaleContract; //presale contract address
uint256 public tokensStakedByPresale; //total tokens staked by preSale
uint256 public tokensStaked; // Total tokens staked
uint256 private lastRewardedBlock; // Last block number the user had their rewards calculated
uint256 private accumulatedRewardsPerShare; // Accumulated rewards per share times REWARDS_PRECISION
uint256 public rewardTokensPerBlock; // Number of reward tokens minted per block
uint256 private constant REWARDS_PRECISION = 1e12; // A big number to perform mul and div operations
uint256 public lockedTime; //To lock the tokens in contract for definite time.
bool public harvestLock = true; //To lock the harvest/claim.
uint public endBlock; //At this block,the rewards generation will be stopped.
uint256 public claimStart; //Users can claim after this time in epoch.
// Staking user for a pool
struct PoolStaker {
uint256 amount; // The tokens quantity the user has staked.
uint256 stakedTime; //the time at tokens staked
uint256 Harvestedrewards; // The reward tokens quantity the user harvested
uint256 rewardDebt; // The amount relative to accumulatedRewardsPerShare the user can't get as reward
}
// staker address => PoolStaker
mapping(address => PoolStaker) public poolStakers;
mapping(address => bool) public isBlacklisted;
mapping(address => uint) public userLockedRewards;
// Events
event Deposit(address indexed user, uint256 amount);
event Withdraw(address indexed user, uint256 amount);
event HarvestRewards(address indexed user, uint256 amount);
constructor(
address _initialOwner,
address _tokenAddress,
address _presaleContract,
uint256 _rewardTokensPerBlock,
uint _lockTime,
uint _endBlock
) Ownable(_initialOwner) {
token = IERC20(_tokenAddress);
presaleContract = _presaleContract;
rewardTokensPerBlock = _rewardTokensPerBlock;
lockedTime = _lockTime;
endBlock = _endBlock;
harvestLock = true;
}
modifier onlyPresale() {
require(
msg.sender == presaleContract,
"This method can be called by only the Presale contract"
);
_;
}
/**
* @dev Deposit tokens to the pool
*/
function deposit(uint256 _amount) external {
require(block.number < endBlock, "staking has been ended");
require(_amount > 0, "Deposit amount can't be zero");
PoolStaker storage staker = poolStakers[msg.sender];
// Update pool stakers
harvestRewards();
// Update current staker
staker.amount += _amount;
staker.rewardDebt =
(staker.amount * accumulatedRewardsPerShare) /
REWARDS_PRECISION;
staker.stakedTime = block.timestamp;
// Update pool
tokensStaked += _amount;
// Deposit tokens
emit Deposit(msg.sender, _amount);
token.safeTransferFrom(msg.sender, address(this), _amount);
}
/**
* @dev Deposit tokens to pool by presale contract
*/
function depositByPresale(
address _user,
uint256 _amount
) external override onlyPresale {
require(block.number < endBlock, "staking has been ended");
require(_amount > 0, "Deposit amount can't be zero");
PoolStaker storage staker = poolStakers[_user];
// Update pool stakers
_harvestRewards(_user);
// Update current staker
staker.amount += _amount;
staker.rewardDebt =
(staker.amount * accumulatedRewardsPerShare) /
REWARDS_PRECISION;
staker.stakedTime = block.timestamp;
// Update pool
tokensStaked += _amount;
tokensStakedByPresale += _amount;
// Deposit tokens
emit Deposit(_user, _amount);
token.safeTransferFrom(presaleContract, address(this), _amount);
}
/**
* @dev Withdraw all tokens from existing pool
*/
function withdraw() external {
PoolStaker memory staker = poolStakers[msg.sender];
uint256 amount = staker.amount;
require(
staker.stakedTime + lockedTime <= block.timestamp &&
claimStart + lockedTime <= block.timestamp,
"you are not allowed to withdraw before locked Time"
);
require(amount > 0, "Withdraw amount can't be zero");
// Pay rewards
harvestRewards();
//delete staker
delete poolStakers[msg.sender];
// Update pool
tokensStaked -= amount;
// Withdraw tokens
emit Withdraw(msg.sender, amount);
token.safeTransfer(msg.sender, amount);
}
/**
* @dev Harvest user rewards
*/
function harvestRewards() public {
_harvestRewards(msg.sender);
}
/**
* @dev Harvest user rewards
*/
function _harvestRewards(address _user) private {
require(!isBlacklisted[_user], "This Address is Blacklisted");
updatePoolRewards();
PoolStaker storage staker = poolStakers[_user];
uint256 rewardsToHarvest = ((staker.amount *
accumulatedRewardsPerShare) / REWARDS_PRECISION) -
staker.rewardDebt;
if (rewardsToHarvest == 0) {
return;
}
staker.Harvestedrewards += rewardsToHarvest;
staker.rewardDebt =
(staker.amount * accumulatedRewardsPerShare) /
REWARDS_PRECISION;
if (!harvestLock) {
if (userLockedRewards[_user] > 0) {
rewardsToHarvest += userLockedRewards[_user];
userLockedRewards[_user] = 0;
}
emit HarvestRewards(_user, rewardsToHarvest);
token.safeTransfer(_user, rewardsToHarvest);
} else {
userLockedRewards[_user] += rewardsToHarvest;
}
}
/**
* @dev Update pool's accumulatedRewardsPerShare and lastRewardedBlock
*/
function updatePoolRewards() private {
if (tokensStaked == 0) {
lastRewardedBlock = block.number;
return;
}
uint256 blocksSinceLastReward = block.number > endBlock
? endBlock - lastRewardedBlock
: block.number - lastRewardedBlock;
uint256 rewards = blocksSinceLastReward * rewardTokensPerBlock;
accumulatedRewardsPerShare =
accumulatedRewardsPerShare +
((rewards * REWARDS_PRECISION) / tokensStaked);
lastRewardedBlock = block.number > endBlock ? endBlock : block.number;
}
/**
*@dev To get the number of rewards that user can get
*/
function getRewards(address _user) public view returns (uint) {
if (tokensStaked == 0) {
return 0;
}
uint256 blocksSinceLastReward = block.number > endBlock
? endBlock - lastRewardedBlock
: block.number - lastRewardedBlock;
uint256 rewards = blocksSinceLastReward * rewardTokensPerBlock;
uint256 accCalc = accumulatedRewardsPerShare +
((rewards * REWARDS_PRECISION) / tokensStaked);
PoolStaker memory staker = poolStakers[_user];
return
((staker.amount * accCalc) / REWARDS_PRECISION) -
staker.rewardDebt +
userLockedRewards[_user];
}
function setHarvestLock(bool _harvestlock) external onlyOwner {
harvestLock = _harvestlock;
}
function setPresaleContract(address _presaleContract) external onlyOwner {
presaleContract = _presaleContract;
}
function setLockedTime(uint _time) external onlyOwner {
lockedTime = _time;
}
function setEndBlock(uint _endBlock) external onlyOwner {
endBlock = _endBlock;
}
function setClaimStart(uint _claimStart) external onlyOwner {
claimStart = _claimStart;
}
/**
* @dev To add users to blacklist which restricts blacklisted users from claiming
* @param _usersToBlacklist addresses of the users
*/
function blacklistUsers(
address[] calldata _usersToBlacklist
) external onlyOwner {
for (uint256 i = 0; i < _usersToBlacklist.length; i++) {
isBlacklisted[_usersToBlacklist[i]] = true;
}
}
/**
* @dev To remove users from blacklist which restricts blacklisted users from claiming
* @param _userToRemoveFromBlacklist addresses of the users
*/
function removeFromBlacklist(
address[] calldata _userToRemoveFromBlacklist
) external onlyOwner {
for (uint256 i = 0; i < _userToRemoveFromBlacklist.length; i++) {
isBlacklisted[_userToRemoveFromBlacklist[i]] = false;
}
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of common custom errors used in multiple contracts
*
* IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
* It is recommended to avoid relying on the error API for critical functionality.
*
* _Available since v5.1._
*/
library Errors {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error InsufficientBalance(uint256 balance, uint256 needed);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedCall();
/**
* @dev The deployment failed.
*/
error FailedDeployment();
/**
* @dev A necessary precompile is missing.
*/
error MissingPrecompile(address);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
bool private _paused;
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}
{
"compilationTarget": {
"contracts/ElumphantPresale.sol": "ElumphantPresale"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_initialOwner","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_usdt","type":"address"},{"internalType":"address","name":"_ethPriceFeed","type":"address"},{"internalType":"uint256","name":"_tokenPriceInUSD","type":"uint256"},{"internalType":"uint256","name":"_tokensPerStep","type":"uint256"},{"internalType":"uint256","name":"_priceIncrement","type":"uint256"},{"internalType":"uint256","name":"_minPurchaseInUSD","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"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":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPrice","type":"uint256"}],"name":"TokenPriceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"claimer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"claimer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensClaimedAndStaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cost","type":"uint256"},{"indexed":false,"internalType":"string","name":"paymentMethod","type":"string"},{"indexed":false,"internalType":"uint256","name":"costInUSD","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalPurchased","type":"uint256"}],"name":"TokensPurchased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"string","name":"asset","type":"string"}],"name":"Withdrawn","type":"event"},{"inputs":[],"name":"MAX_PRICE_PUMP_STEPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_recipients","type":"address[]"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"airdrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"buyWithETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"buyWithUSDT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"claimAndStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"depositTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ethPriceFeed","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLatestETHPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minPurchaseInUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"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":"presaleEndTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"presaleStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceIncrement","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"purchasedTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minPurchaseInUSD","type":"uint256"}],"name":"setMinPurchaseInUSD","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stakingContractAddress","type":"address"}],"name":"setStakingContractAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_presaleStartTime","type":"uint256"},{"internalType":"uint256","name":"_presaleEndTime","type":"uint256"},{"internalType":"uint256","name":"_claimStartTime","type":"uint256"}],"name":"setTimes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stakedTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingContract","outputs":[{"internalType":"contract IElumphantStaking","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract IERC20WithDecimals","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenPriceInUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokensPerStep","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokensSoldInCurStep","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalTokensPurchased","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalTokensStaked","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":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_presaleEndTime","type":"uint256"},{"internalType":"uint256","name":"_claimStartTime","type":"uint256"}],"name":"updatePresaleEndTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newPrice","type":"uint256"}],"name":"updateTokenPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"usdt","outputs":[{"internalType":"contract IERC20WithDecimals","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"}],"name":"withdrawETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"}],"name":"withdrawUSDT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"}],"name":"withdrawUnsoldTokens","outputs":[],"stateMutability":"nonpayable","type":"function"}]