Created
October 9, 2024 07:00
-
-
Save yousuf-hossain-shanto/ebe58387b4cc91dd7a088a3175da6e90 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.8.24+commit.e11b9ed9.js&optimize=true&runs=200&gist=
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // SPDX-License-Identifier: UNLICENSED | |
| pragma solidity ^0.8.24; | |
| import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; | |
| import "@openzeppelin/contracts/access/Ownable.sol"; | |
| import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; | |
| interface Aggregator { | |
| function latestRoundData() | |
| external | |
| view | |
| returns ( | |
| uint80 roundId, | |
| int256 answer, | |
| uint256 startedAt, | |
| uint256 updatedAt, | |
| uint80 answeredInRound | |
| ); | |
| } | |
| contract Bloc_PresaleV4 is ReentrancyGuard, Ownable { | |
| uint256 public overalllRaised; | |
| uint256 public presaleId; | |
| uint256 public USDT_MULTIPLIER; | |
| uint256 public ETH_MULTIPLIER; | |
| address public fundReceiver; | |
| uint256 public uniqueBuyers; | |
| struct PresaleData { | |
| uint256 startTime; | |
| uint256 endTime; | |
| uint256 price; // how much BLOC's can be purchased in 1 USD. 18 decimals | |
| uint256 nextStagePrice; // how much BLOC's can be purchased in 1 USD. 18 decimals. | |
| uint256 Sold; | |
| uint256 tokensToSell; // how much BLOC's to sell. In 18 decimals. | |
| uint256 UsdtHardcap; // (usdtPrice*tokensToSell). In 6 decimals | |
| uint256 amountRaised; | |
| bool Active; | |
| } | |
| struct UserData { | |
| uint256 investedAmount; | |
| uint256 receivedTokenAmount; | |
| } | |
| IERC20Metadata public USDTInterface; | |
| IERC20Metadata public USDCInterface; | |
| Aggregator internal aggregatorInterface; | |
| mapping(uint256 => bool) public paused; | |
| mapping(uint256 => PresaleData) public presale; | |
| mapping(address => mapping(uint256 => UserData)) public userData; | |
| mapping(address => bool) public isExcludeMinToken; | |
| mapping(address => bool) public isBlackList; | |
| mapping(address => bool) public isExist; | |
| uint256 public MinTokenTobuy; | |
| uint256 public currentSale; | |
| address public SaleToken; | |
| event PresaleCreated( | |
| uint256 indexed _id, | |
| uint256 _totalTokens, | |
| uint256 _startTime, | |
| uint256 _endTime | |
| ); | |
| event PresaleUpdated( | |
| bytes32 indexed key, | |
| uint256 prevValue, | |
| uint256 newValue, | |
| uint256 timestamp | |
| ); | |
| event TokensBought( | |
| address indexed user, | |
| uint256 indexed id, | |
| address indexed purchaseToken, | |
| uint256 tokensBought, | |
| uint256 amountPaid, | |
| uint256 timestamp | |
| ); | |
| event TokensClaimed( | |
| address indexed user, | |
| uint256 indexed id, | |
| uint256 amount, | |
| uint256 timestamp | |
| ); | |
| event PresalePaused(uint256 indexed id, uint256 timestamp); | |
| event PresaleUnpaused(uint256 indexed id, uint256 timestamp); | |
| constructor( | |
| address _oracle, | |
| address _usdt, | |
| address _usdc, | |
| address _SaleToken, | |
| uint256 _MinTokenTobuy | |
| ) Ownable(msg.sender) { | |
| aggregatorInterface = Aggregator(_oracle); | |
| SaleToken = _SaleToken; | |
| MinTokenTobuy = _MinTokenTobuy; | |
| USDTInterface = IERC20Metadata(_usdt); | |
| USDCInterface = IERC20Metadata(_usdc); | |
| ETH_MULTIPLIER = (10**18); | |
| USDT_MULTIPLIER = (10**6); | |
| fundReceiver = msg.sender; | |
| } | |
| function createPresale( | |
| uint256 _price, | |
| uint256 _nextStagePrice, | |
| uint256 _tokensToSell, | |
| uint256 _UsdtHardcap | |
| ) external onlyOwner { | |
| require(_price > 0, "Zero price"); | |
| require(_tokensToSell > 0, "Zero tokens to sell"); | |
| presaleId++; | |
| presale[presaleId] = PresaleData( | |
| 0, | |
| 0, | |
| _price, | |
| _nextStagePrice, | |
| 0, | |
| _tokensToSell, | |
| _UsdtHardcap, | |
| 0, | |
| false | |
| ); | |
| emit PresaleCreated(presaleId, _tokensToSell, 0, 0); | |
| } | |
| function setPresaleStage(uint256 _id) public onlyOwner { | |
| require(presale[_id].tokensToSell > 0, "Presale don't exist"); | |
| if (currentSale != 0) { | |
| presale[currentSale].endTime = block.timestamp; | |
| presale[currentSale].Active = false; | |
| } | |
| presale[_id].startTime = block.timestamp; | |
| presale[_id].Active = true; | |
| currentSale = _id; | |
| } | |
| function updatePresale( | |
| uint256 _id, | |
| uint256 _price, | |
| uint256 _nextStagePrice, | |
| uint256 _tokensToSell, | |
| uint256 _Hardcap | |
| ) external onlyOwner { | |
| require(_price > 0, "Zero price"); | |
| require(_tokensToSell > 0, "Zero tokens to sell"); | |
| require(_Hardcap > 0, "Zero harcap"); | |
| presale[_id].price = _price; | |
| presale[_id].nextStagePrice = _nextStagePrice; | |
| presale[_id].tokensToSell = _tokensToSell; | |
| presale[_id].UsdtHardcap = _Hardcap; | |
| } | |
| function changeFundWallet(address _wallet) external onlyOwner { | |
| require(_wallet != address(0), "Invalid parameters"); | |
| fundReceiver = _wallet; | |
| } | |
| function changeUSDTToken(address _newAddress) external onlyOwner { | |
| require(_newAddress != address(0), "Zero token address"); | |
| USDTInterface = IERC20Metadata(_newAddress); | |
| } | |
| function changeUSDCToken(address _newAddress) external onlyOwner { | |
| require(_newAddress != address(0), "Zero token address"); | |
| USDCInterface = IERC20Metadata(_newAddress); | |
| } | |
| function pausePresale(uint256 _id) external checkPresaleId(_id) onlyOwner { | |
| require(!paused[_id], "Already paused"); | |
| paused[_id] = true; | |
| emit PresalePaused(_id, block.timestamp); | |
| } | |
| function unPausePresale(uint256 _id) | |
| external | |
| checkPresaleId(_id) | |
| onlyOwner | |
| { | |
| require(paused[_id], "Not paused"); | |
| paused[_id] = false; | |
| emit PresaleUnpaused(_id, block.timestamp); | |
| } | |
| function getLatestPrice() public view returns (uint256) { | |
| (, int256 price, , , ) = aggregatorInterface.latestRoundData(); | |
| price = (price * (10**10)); | |
| return uint256(price); | |
| } | |
| modifier checkPresaleId(uint256 _id) { | |
| require(_id > 0 && _id == currentSale, "Invalid presale id"); | |
| _; | |
| } | |
| modifier checkSaleState(uint256 _id, uint256 amount) { | |
| require(presale[_id].Active == true, "preSAle not Active"); | |
| require( | |
| amount > 0 && | |
| amount <= presale[_id].tokensToSell - presale[_id].Sold, | |
| "Invalid sale amount" | |
| ); | |
| _; | |
| } | |
| function ExcludeAccouctFromMinBuy(address _user, bool _status) | |
| external | |
| onlyOwner | |
| { | |
| isExcludeMinToken[_user] = _status; | |
| } | |
| function blackListUser(address _user, bool _value) public onlyOwner { | |
| isBlackList[_user] = _value; | |
| } | |
| function buyWithUSDT(uint256 usdAmount) | |
| external | |
| checkPresaleId(currentSale) | |
| checkSaleState(currentSale, usdToTokens(currentSale, usdAmount)) | |
| nonReentrant | |
| returns (bool) | |
| { | |
| require(!paused[currentSale], "Presale paused"); | |
| require( | |
| presale[currentSale].Active == true, | |
| "Presale is not active yet" | |
| ); | |
| require(!isBlackList[msg.sender], "Account is blackListed"); | |
| require( | |
| presale[currentSale].amountRaised + usdAmount <= | |
| presale[currentSale].UsdtHardcap, | |
| "Amount should be less than leftHardcap" | |
| ); | |
| if (!isExist[msg.sender]) { | |
| isExist[msg.sender] = true; | |
| uniqueBuyers++; | |
| } | |
| uint256 tokens = usdToTokens(currentSale, usdAmount); | |
| presale[currentSale].Sold += tokens; | |
| presale[currentSale].amountRaised += usdAmount; | |
| overalllRaised += usdAmount; | |
| if (isExcludeMinToken[msg.sender] == false) { | |
| require(tokens >= MinTokenTobuy, "Less than min amount"); | |
| } | |
| userData[_msgSender()][currentSale].investedAmount += usdAmount; | |
| userData[_msgSender()][currentSale].receivedTokenAmount += tokens; | |
| uint256 ourAllowance = USDTInterface.allowance( | |
| _msgSender(), | |
| address(this) | |
| ); | |
| require(usdAmount <= ourAllowance, "Make sure to add enough allowance"); | |
| (bool success, ) = address(USDTInterface).call( | |
| abi.encodeWithSignature( | |
| "transferFrom(address,address,uint256)", | |
| _msgSender(), | |
| fundReceiver, | |
| usdAmount | |
| ) | |
| ); | |
| require(success, "Token payment failed"); | |
| bool status = IERC20(SaleToken).transfer( | |
| _msgSender(), | |
| tokens | |
| ); | |
| require(status, "Token transfer failed"); | |
| emit TokensBought( | |
| _msgSender(), | |
| currentSale, | |
| address(USDTInterface), | |
| tokens, | |
| usdAmount, | |
| block.timestamp | |
| ); | |
| return true; | |
| } | |
| function buyWithUSDC(uint256 usdcAmount) | |
| external | |
| checkPresaleId(currentSale) | |
| checkSaleState(currentSale, usdToTokens(currentSale, usdcAmount)) | |
| nonReentrant | |
| returns (bool) | |
| { | |
| require(!paused[currentSale], "Presale paused"); | |
| require( | |
| presale[currentSale].Active == true, | |
| "Presale is not active yet" | |
| ); | |
| require( | |
| presale[currentSale].amountRaised + usdcAmount <= | |
| presale[currentSale].UsdtHardcap, | |
| "Amount should be less than leftHardcap" | |
| ); | |
| require(!isBlackList[msg.sender], "Account is blackListed"); | |
| if (!isExist[msg.sender]) { | |
| isExist[msg.sender] = true; | |
| uniqueBuyers++; | |
| } | |
| uint256 tokens = usdToTokens(currentSale, usdcAmount); | |
| presale[currentSale].Sold += tokens; | |
| presale[currentSale].amountRaised += usdcAmount; | |
| overalllRaised += usdcAmount; | |
| if (isExcludeMinToken[msg.sender] == false) { | |
| require(tokens >= MinTokenTobuy, "Less than min amount"); | |
| } | |
| userData[_msgSender()][currentSale].investedAmount += usdcAmount; | |
| userData[_msgSender()][currentSale].receivedTokenAmount += tokens; | |
| uint256 ourAllowance = USDTInterface.allowance( | |
| _msgSender(), | |
| address(this) | |
| ); | |
| require( | |
| usdcAmount <= ourAllowance, | |
| "Make sure to add enough allowance" | |
| ); | |
| (bool success, ) = address(USDCInterface).call( | |
| abi.encodeWithSignature( | |
| "transferFrom(address,address,uint256)", | |
| _msgSender(), | |
| fundReceiver, | |
| usdcAmount | |
| ) | |
| ); | |
| require(success, "Token payment failed"); | |
| bool status = IERC20(SaleToken).transfer( | |
| _msgSender(), | |
| tokens | |
| ); | |
| require(status, "Token transfer failed"); | |
| emit TokensBought( | |
| _msgSender(), | |
| currentSale, | |
| address(USDTInterface), | |
| tokens, | |
| usdcAmount, | |
| block.timestamp | |
| ); | |
| return true; | |
| } | |
| function buyWithEth() | |
| external | |
| payable | |
| checkPresaleId(currentSale) | |
| checkSaleState(currentSale, ethToTokens(currentSale, msg.value)) | |
| nonReentrant | |
| returns (bool) | |
| { | |
| uint256 usdAmount = (msg.value * getLatestPrice() * USDT_MULTIPLIER) / | |
| (ETH_MULTIPLIER * ETH_MULTIPLIER); | |
| require( | |
| presale[currentSale].amountRaised + usdAmount <= | |
| presale[currentSale].UsdtHardcap, | |
| "Amount should be less than leftHardcap" | |
| ); | |
| require(!isBlackList[msg.sender], "Account is blackListed"); | |
| require(!paused[currentSale], "Presale paused"); | |
| require( | |
| presale[currentSale].Active == true, | |
| "Presale is not active yet" | |
| ); | |
| if (!isExist[msg.sender]) { | |
| isExist[msg.sender] = true; | |
| uniqueBuyers++; | |
| } | |
| uint256 tokens = usdToTokens(currentSale, usdAmount); | |
| if (isExcludeMinToken[msg.sender] == false) { | |
| require(tokens >= MinTokenTobuy, "Insufficient Amount!"); | |
| } | |
| presale[currentSale].Sold += tokens; | |
| presale[currentSale].amountRaised += usdAmount; | |
| overalllRaised += usdAmount; | |
| userData[_msgSender()][currentSale].investedAmount += usdAmount; | |
| userData[_msgSender()][currentSale].receivedTokenAmount += tokens; | |
| sendValue(payable(fundReceiver), msg.value); | |
| bool status = IERC20(SaleToken).transfer( | |
| _msgSender(), | |
| tokens | |
| ); | |
| require(status, "Token transfer failed"); | |
| emit TokensBought( | |
| _msgSender(), | |
| currentSale, | |
| address(0), | |
| tokens, | |
| msg.value, | |
| block.timestamp | |
| ); | |
| return true; | |
| } | |
| function ethBuyHelper(uint256 _id, uint256 amount) | |
| external | |
| view | |
| returns (uint256 ethAmount) | |
| { | |
| uint256 usdPrice = (amount * presale[_id].price); | |
| ethAmount = | |
| (usdPrice * ETH_MULTIPLIER) / | |
| (getLatestPrice() * 10**IERC20Metadata(SaleToken).decimals()); | |
| } | |
| function usdBuyHelper(uint256 _id, uint256 amount) | |
| external | |
| view | |
| returns (uint256 usdPrice) | |
| { | |
| usdPrice = | |
| (amount * presale[_id].price) / | |
| 10**IERC20Metadata(SaleToken).decimals(); | |
| } | |
| function ethToTokens(uint256 _id, uint256 amount) | |
| public | |
| view | |
| returns (uint256 _tokens) | |
| { | |
| uint256 usdAmount = (amount * getLatestPrice() * USDT_MULTIPLIER) / | |
| (ETH_MULTIPLIER * ETH_MULTIPLIER); | |
| _tokens = usdToTokens(_id, usdAmount); | |
| } | |
| function usdToTokens(uint256 _id, uint256 amount) | |
| public | |
| view | |
| returns (uint256 _tokens) | |
| { | |
| _tokens = (amount * presale[_id].price) / USDT_MULTIPLIER; | |
| } | |
| function sendValue(address payable recipient, uint256 amount) internal { | |
| require(address(this).balance >= amount, "Low balance"); | |
| (bool success, ) = recipient.call{value: amount}(""); | |
| require(success, "ETH Payment failed"); | |
| } | |
| function WithdrawTokens(address _token, uint256 amount) external onlyOwner { | |
| IERC20(_token).transfer(fundReceiver, amount); | |
| } | |
| function WithdrawContractFunds(uint256 amount) external onlyOwner { | |
| sendValue(payable(fundReceiver), amount); | |
| } | |
| function ChangeSaleToken(address _token) public onlyOwner { | |
| SaleToken = _token; | |
| } | |
| function ChangeMinTokenToBuy(uint256 _amount) public onlyOwner { | |
| MinTokenTobuy = _amount; | |
| } | |
| function ChangeOracleAddress(address _oracle) public onlyOwner { | |
| aggregatorInterface = Aggregator(_oracle); | |
| } | |
| function blockTimeStamp() public view returns(uint256) { | |
| return block.timestamp; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment