🔧 AI Nachrichten Major AI platforms go down in unprecedented simultaneous outage(03.09.2026 um 17:34 Uhr)
🔧 AI Nachrichten ChatGPT, Claude, and Grok Down? Users Report Widespread Outages(03.09.2026 um 19:14 Uhr)
🔧 AI Nachrichten OpenAI Launches GPT-6 Astra, Says We May Have Entered the AGI Era(03.09.2026 um 22:08 Uhr)
🔧 AI Nachrichten Claude Comes to CarPlay as Fifth Major AI Chatbot App(05.09.2026 um 05:31 Uhr)
🔧 AI Nachrichten OpenAI’s GPT-6 Astra Is AGI, Says NVIDIA CEO Jensen Huang(07.09.2026 um 06:31 Uhr)
🔧 AI Nachrichten Blame AI companies for Mac mini and Mac Studio shortage(31.08.2026 um 10:32 Uhr)
🔧 AI Nachrichten Major AI platforms go down in unprecedented simultaneous outage(03.09.2026 um 17:34 Uhr)
🔧 AI Nachrichten ChatGPT, Claude, and Grok Down? Users Report Widespread Outages(03.09.2026 um 19:14 Uhr)
🔧 AI Nachrichten OpenAI Launches GPT-6 Astra, Says We May Have Entered the AGI Era(03.09.2026 um 22:08 Uhr)
🔧 AI Nachrichten Claude Comes to CarPlay as Fifth Major AI Chatbot App(05.09.2026 um 05:31 Uhr)
🔧 AI Nachrichten OpenAI’s GPT-6 Astra Is AGI, Says NVIDIA CEO Jensen Huang(07.09.2026 um 06:31 Uhr)
🔧 AI Nachrichten Blame AI companies for Mac mini and Mac Studio shortage(31.08.2026 um 10:32 Uhr)

🔧 Programmierung 🕛 kürzlich 7 Min Lesezeit
0

Comprehensive guide to write ERC20 token presale smart contract on Ethereum blockchain using Solidity

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

Introduction



This article will give you a comprehensive guide to build a presale contract that accepts ETH and major stablecoins step by step.



Key Features



  • Multiple payment options(ETH, USDT, USDC, DAI)

  • Early Investor bonus system

  • Staged token buying campaign



Prerequisites



  • Hardhat development environment

  • Openzeppelin contracts

  • Ethereum development experience

  • Basic understanding of ERC20 tokens



Token features



  • Type: ERC20

  • Name: Silver Phoenix

  • Symbol: SPX

  • Decimal: 18

  • Total Supply: 100 billion



Presale Features



  • Presale Supply: 10 billion (10%)

  • Presale Period: 30 days

  • Presale Stage: 4

  • Softcap: 500000 USDT

  • Hardcap: 1020000 USDT

  • Price and token amounts for each stage:





























Stage Price Token Amount
1
0.00008 USDT
3 billion
2
0.00010 USDT
4 billion
3
0.00012 USDT
2 billion
4
0.00014 USDT
1 billion



  • Options for buying tokens: ETH, USDT, USDC, DAI

  • Claim time: After second public sale ends

  • Minimum amount for buying tokens: 100 USDT



Investors who bought tokens before softcap reached are listed on early investors and can get bonus tokens after presale ends if unsold tokens exist.



How to implement step by step



Key functions:



  • buyWithETH

  • buyWithStableCoin

  • Helper functions for calculating token amounts available with ETH or Stable coin and vice versa

  • Claim

  • Withdraw

  • Refund

  • Several helper functions like set and get functions






Buy SPX token with ETH





CODE
function buyWithETH() external payable whenNotPaused nonReentrant {
require(
block.timestamp >= startTime && block.timestamp <= endTime,
"Invalid time for buying the token"
);

uint256 _estimatedTokenAmount = estimatedTokenAmountAvailableWithETH(
msg.value
);
uint256 _tokensAvailable = tokensAvailable();

require(
_estimatedTokenAmount <= _tokensAvailable &&
_estimatedTokenAmount > 0,
"Invalid token amount to buy"
);

uint256 minUSDTOutput = (_estimatedTokenAmount * 90) / 100;
// Swap ETH for USDT
address[] memory path = new address[](2);
path[0] = router.WETH();
path[1] = USDT;

uint256[] memory amounts = router.swapExactETHForTokens{
value: msg.value
}(minUSDTOutput, path, address(this), block.timestamp + 15 minutes);

// Ensure the swap was successful
require(amounts.length > 1, "Swap failed, no USDT received");
uint256 _usdtAmount = amounts[1];

// Calculate final token amount
uint256 _tokenAmount = estimatedTokenAmountAvailableWithCoin(
_usdtAmount,
USDTInterface
);

//Update investor records
_updateInvestorRecords(
msg.sender,
_tokenAmount,
USDTInterface,
_usdtAmount
);

//Update presale stats
_updatePresaleStats(_tokenAmount, _usdtAmount, 6);

emit TokensBought(
msg.sender,
_tokenAmount,
_usdtAmount,
block.timestamp
);
}






First, this function checks if presale is ongoing or not.

Next, it estimates how much tokens investor can buy with specific ETH amount and checks if this amount is availbale for purchase.

Next, it swaps ETH to USDT using Uniswap V2 Router for buying SPX tokens and returns USDT amount equivalent.

Next, it calculates how much tokens investor can buy with swapped USDT equivalent.

Next, it updates investor and investment status.




CODE
function _updateInvestorRecords(
address investor_,
uint256 tokenAmount_,
IERC20 coin_,
uint256 coinAmount_
) private {
if (investorTokenBalance[investor_] == 0) {
investors.push(investor_);
if (fundsRaised < softcap && !earlyInvestorsMapping[investor_]) {
earlyInvestorsMapping[investor_] = true;
earlyInvestors.push(investor_);
}
}

investorTokenBalance[investor_] += tokenAmount_;
investments[investor_][address(coin_)] += coinAmount_;
}






Next, it updates presale status.




CODE
function _updatePresaleStats(
uint256 tokenAmount_,
uint256 coinAmount_,
uint8 coinDecimals_
) private {
totalTokensSold += tokenAmount_;
fundsRaised += coinAmount_ / (10 ** (coinDecimals_ - 6));
}






Last, it emits TokensBought event.






Buy SPX token with Stable Coins





CODE
function _buyWithCoin(
IERC20 coin_,
uint256 tokenAmount_
) internal checkSaleState(tokenAmount_) whenNotPaused nonReentrant {
uint256 _coinAmount = estimatedCoinAmountForTokenAmount(
tokenAmount_,
coin_
);
uint8 _coinDecimals = getCoinDecimals(coin_);

//Check allowances and balances
require(
_coinAmount <= coin_.allowance(msg.sender, address(this)),
"Insufficient allowance"
);
require(
_coinAmount <= coin_.balanceOf(msg.sender),
"Insufficient balance."
);

//Send the coin to the contract
SafeERC20.safeTransferFrom(
coin_,
msg.sender,
address(this),
_coinAmount
);

//Update the investor status
_updateInvestorRecords(msg.sender, tokenAmount_, coin_, _coinAmount);

// Update presale stats
_updatePresaleStats(tokenAmount_, _coinAmount, _coinDecimals);

emit TokensBought(
msg.sender,
tokenAmount_,
_coinAmount,
block.timestamp
);
}






First, this function checks if presale is ongoing, tokenAmount that investor wants to buy is available, and so on.(modifiers)

Next, it calculates how much coins are needed to buy those amount of tokens and checks if investor has sufficient balance and allowance.

Next, it transfers Stable coins to presale contract.

Then, it updates investor & investment status and presale status, finally, emits TokensBought event.



Each functions for buying token with specific stable coins can be written as follows:




CODE
function buyWithUSDT(uint256 tokenAmount_) external whenNotPaused {
_buyWithCoin(USDTInterface, tokenAmount_);
}









Helper function to calculate SPX token amount with ETH and vice versa





CODE
function estimatedTokenAmountAvailableWithETH(
uint256 ethAmount_
) public view returns (uint256) {
// Swap ETH for USDT
address[] memory path = new address[](2);
path[0] = router.WETH();
path[1] = USDT;
uint256[] memory amounts = router.getAmountsOut(ethAmount_, path);
require(amounts.length > 1, "Invalid path");
uint256 _usdtAmount = amounts[1];

// Calculate token amount
return
estimatedTokenAmountAvailableWithCoin(_usdtAmount, USDTInterface);
}






This function calculates how much tokens user can buy with specific eth amount using Uniswap V2 Router and estimatedTokenAmountAvailableWithCoin function.






Helper function to calculate SPX token amount with Stable Coin and vice versa





CODE
    function estimatedTokenAmountAvailableWithCoin(
uint256 coinAmount_,
IERC20 coin_
) public view returns (uint256) {
uint256 tokenAmount = 0;
uint256 remainingCoinAmount = coinAmount_;
uint8 _coinDecimals = getCoinDecimals(coin_);

for (uint8 i = 0; i < thresholds.length; i++) {
// Get the current token price at the index
uint256 _priceAtCurrentTier = getCurrentTokenPriceForIndex(i);
uint256 _currentThreshold = thresholds[i];

// Determine the number of tokens available at this tier
uint256 numTokensAvailableAtTier = _currentThreshold >
totalTokensSold
? _currentThreshold - totalTokensSold
: 0;

// Calculate the maximum number of tokens that can be bought with the remaining coin amount
uint256 maxTokensAffordable = (remainingCoinAmount *
(10 ** (18 - _coinDecimals + 6))) / _priceAtCurrentTier;

// Determine how many tokens can actually be bought at this tier
uint256 tokensToBuyAtTier = numTokensAvailableAtTier <
maxTokensAffordable
? numTokensAvailableAtTier
: maxTokensAffordable;

// Update amounts
tokenAmount += tokensToBuyAtTier;
remainingCoinAmount -=
(tokensToBuyAtTier * _priceAtCurrentTier) /
(10 ** (18 - _coinDecimals + 6));

// If there is no remaining coin amount, break out of the loop
if (remainingCoinAmount == 0) {
break;
}
}

return tokenAmount;
}






This function ensures:




  • Accurate token calculations across different price tiers

  • Proper decimal handling for different stablecoins

  • Maximum token availability limits per tier

  • Efficient use of remaining purchase amount



The implementation supports the presale's tiered pricing structure while maintaining precision in token calculations.






Claim function





CODE
function claim(address investor_) external nonReentrant {
require(
block.timestamp > claimTime && claimTime > 0,
"It's not claiming time yet."
);

require(
fundsRaised >= softcap,
"Can not claim as softcap not reached. Instead you can be refunded."
);

uint256 _tokenAmountforUser = getTokenAmountForInvestor(investor_);
uint256 _bonusTokenAmount = getBonusTokenAmount();

if (isEarlyInvestors(investor_))
_tokenAmountforUser += _bonusTokenAmount;
require(_tokenAmountforUser > 0, "No tokens claim.");
investorTokenBalance[investor_] = 0;
earlyInvestorsMapping[investor_] = false;

SafeERC20.safeTransfer(token, investor_, _tokenAmountforUser);
emit TokensClaimed(investor_, _tokenAmountforUser);
}






This function




  • checks claim time and softcap requirements

  • calculates total tokens including bonuses

  • resets investor balances and early investor status

  • uses SafeERC20 for token transfers

  • emits TokensClaimed event






Withdraw function





CODE
function withdraw() external onlyOwner nonReentrant {
require(
block.timestamp > endTime,
"Cannot withdraw because presale is still in progress."
);

require(wallet != address(0), "Wallet not set");

require(
fundsRaised > softcap,
"Can not withdraw as softcap not reached."
);

uint256 _usdtBalance = USDTInterface.balanceOf(address(this));
uint256 _usdcBalance = USDCInterface.balanceOf(address(this));
uint256 _daiBalance = DAIInterface.balanceOf(address(this));

require(
_usdtBalance > 0 && _usdcBalance > 0 && _daiBalance > 0,
"No funds to withdraw"
);

if (_usdtBalance > 0)
SafeERC20.safeTransfer(USDTInterface, wallet, _usdtBalance);
if (_usdcBalance > 0)
SafeERC20.safeTransfer(USDCInterface, wallet, _usdcBalance);
if (_daiBalance > 0)
SafeERC20.safeTransfer(DAIInterface, wallet, _daiBalance);
}






This function




  • validates if predefined multisig wallet address is set

  • ensures presale is already ended

  • verifies sufficient funds exist

  • uses SafeERC20 for transfers






Refund function





CODE
function refund() external onlyOwner nonReentrant {
require(
block.timestamp > endTime,
"Cannot refund because presale is still in progress."
);
require(fundsRaised < softcap, "Softcap reached, refund not available");

// refund all funds to investors
for (uint256 i = 0; i < investors.length; i++) {
address investor = investors[i];

//Refund USDT
uint256 _usdtAmount = investments[investor][address(USDTInterface)];
if (_usdtAmount > 0) {
investments[investor][address(USDTInterface)] = 0;
SafeERC20.safeTransfer(USDTInterface, investor, _usdtAmount);
emit FundsRefunded(investor, _usdtAmount, block.timestamp);
}

//Refund USDC
uint256 _usdcAmount = investments[investor][address(USDCInterface)];
if (_usdcAmount > 0) {
investments[investor][address(USDCInterface)] = 0;
SafeERC20.safeTransfer(USDCInterface, investor, _usdcAmount);
emit FundsRefunded(investor, _usdcAmount, block.timestamp);
}

//Refund DAI
uint256 _daiAmount = investments[investor][address(DAIInterface)];
if (_daiAmount > 0) {
investments[investor][address(DAIInterface)] = 0;
SafeERC20.safeTransfer(DAIInterface, investor, _daiAmount);
emit FundsRefunded(investor, _daiAmount, block.timestamp);
}
}

fundsRaised = 0;
delete investors;
}






This function




  • loops through all investors

  • checks and refunds each stable coin separately

  • Resets investment records to zero

  • Emits FundsRefunded events

  • Clears global state(fundsRaised and investors array)






Conclusion



This SPX token presale smart contract demonstrates a robust and versatile implementation that effectively handles multiple payment methods including ETH, USDT, USDC, and DAI.

This implementation serves as an excellent template for future presale contracts, offering a balance of security, functionality, and user accessibility.

It's architecture ensures fair distribution while protecting both investor and project owner interests through its well-structured validation and distribution mechanisms.

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
3 Quellen
GPT-6 Astra Release Today? OpenAI’s Next Major AI Model Is Almost Here
1 Quelle
Apple accuses OpenAI of destroying evidence as trade-secrets fight intensifies
1 Quelle
Major AI platforms go down in unprecedented simultaneous outage
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Comprehensive guide to write ERC20 token presale smart contract on Ethereum blockchain using Solidity

Thematisch verwandte Begriffe: Comprehensive, guide, write, ERC20 · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...