Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save yousuf-hossain-shanto/769bff44f6d0c3f0a10bc767737b9f26 to your computer and use it in GitHub Desktop.

Select an option

Save yousuf-hossain-shanto/769bff44f6d0c3f0a10bc767737b9f26 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=
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
/// @custom:security-contact yousuf.hossain.shanto@gmail.com
contract BlocICO is ReentrancyGuard, Ownable {
using SafeERC20 for IERC20Metadata;
uint256 public constant totalPresaleAllocation = 5_000_000 * 10**18; // 5 million tokens (assuming 18 decimals on BLOC)
uint256 public soldTokens = 0; // 18 decimals points
AggregatorV3Interface public constant EthToUsdFeed = AggregatorV3Interface(0x694AA1769357215DE4FAC081bf1f309aDC325306); // Sepolia Testnet
IERC20Metadata public constant BLOC = IERC20Metadata(0x8835958755971c8febd3E367dC4A5CB6A92a3dd8); // Sepolia Testnet
IERC20Metadata public constant USDC = IERC20Metadata(0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238); // Sepolia Testnet USDC
uint256 public constant blocPriceInUSDC = 0.02 * 10**18; // 0.02 USDC per BLOC. converting to 18 decimals
event TokensPurchased(address indexed buyer, uint256 amount, uint256 priceInUSDC, uint256 priceInETH, string paymentMethod);
constructor() Ownable(msg.sender) {}
// Buy tokens using ETH (ETH is sent as msg.value). msg.value must be in 18 decimals
function buyWithETH() external payable nonReentrant {
uint256 ethAmount = msg.value;
// Calculate how many BLOC tokens the user will get based on current ETH price
(uint256 tokensToReceive, uint256 needToReturn) = getTokensAmount(ethAmount, true);
require(tokensToReceive > 0, "Invalid ETH amount");
if (needToReturn > 0) {
(bool success, ) = msg.sender.call{value: needToReturn}("");
require(success, "ETH refund failed");
}
_processPurchase(msg.sender, tokensToReceive, (ethAmount-needToReturn), true);
}
// Buy tokens using USDC. usdcAmount must be in 18 decimals
function buyWithUSDC(uint256 usdcAmount) external nonReentrant {
(uint256 tokensToReceive, uint256 needToReturn) = getTokensAmount(usdcAmount, false);
require(tokensToReceive > 0, "Invalid USDC amount");
USDC.safeTransferFrom(msg.sender, address(this), ((usdcAmount-needToReturn) / 10**18) * 10**6); // as USDC maintains 6 decimals
_processPurchase(msg.sender, tokensToReceive, (usdcAmount-needToReturn), false);
}
// Calculate token amount based on ETH/USDC sent. providedAmount must be in 18 decimals
function getTokensAmount(uint256 providedAmount, bool isETH) public view returns (uint256, uint256) {
uint256 remaining = totalPresaleAllocation - soldTokens;
uint256 blocUnitPrice; // 18 decimals points
if (isETH) {
blocUnitPrice = getBlocPriceInEth(blocPriceInUSDC); // Calculate ETH price dynamically
} else {
blocUnitPrice = blocPriceInUSDC;
}
uint256 tokensToReceive = (providedAmount / blocUnitPrice) * 10**18; // convert 18 decimals to tokens
tokensToReceive = tokensToReceive > remaining ? remaining : tokensToReceive;
uint256 needToReturn = providedAmount - ((tokensToReceive / (10**18)) * blocUnitPrice);
return (tokensToReceive, needToReturn);
}
// Fetch the latest price of ETH in USD from Chainlink
function getEthPrice() public view returns (uint256) {
(, int256 price, , , ) = EthToUsdFeed.latestRoundData(); // ETH/USD price from Chainlink
return uint256(price * 10**10); // Convert price to 18 decimals (Chainlink provides 8 decimals)
}
// Calculate ETH equivalent price for BLOC tokens
function getBlocPriceInEth(uint256 usdcPrice) public view returns (uint256) {
uint256 ethPriceInUsd = getEthPrice(); // Fetch the current ETH price in USD
// return ((usdcPrice/(10**18))/(ethPriceInUsd/(10**18))) * 10**18; // Convert USDC price to ETH wei
return (usdcPrice * 10**18) / ethPriceInUsd;
}
// Process the purchase and transfer tokens
function _processPurchase(address buyer, uint256 tokenAmount, uint256 paidAmount, bool isETH) internal {
require(tokenAmount > 0, "Invalid token amount");
require(soldTokens + tokenAmount <= totalPresaleAllocation, "Exceeds presale allocation");
// Transfer BLOC tokens to the buyer
BLOC.safeTransfer(buyer, tokenAmount);
soldTokens += tokenAmount;
// Emit event
emit TokensPurchased(buyer, tokenAmount, isETH ? 0 : paidAmount, isETH ? paidAmount : 0, isETH ? "ETH" : "USDC");
}
// Withdraw funds (ETH and USDC). amount must be 18 decimals
function withdrawFunds(uint256 amount, bool isEth) external onlyOwner nonReentrant {
if (isEth) {
payable(owner()).transfer(amount); // Withdraw ETH
} else {
USDC.safeTransfer(owner(), (amount / 10**18) * 10**6);
}
}
function withdrawBloc(uint256 amount) external onlyOwner nonReentrant {
BLOC.safeTransfer(owner(), amount);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment