Hi everyone !
I am trying to create 2 smart contracts : one for an ERC20 and the other for sale the ERC20 token. What I want to do now is to buy a token of ERC20 by sending USDT(0xc2132D05D31c914a87C6611C10748AEb04B58e8F) amount to the seller. I am deployed this on ploygon network.
When I call the purchaseTokens function at sales contract , get the error like ERC20: transfer amount exceeds balance.
The sales contract already hold the minted token.
The contract code are below
Thanks for your support !
Code to reproduce
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
// Token Contract
contract NarutoToken is ERC20, Ownable, ERC20Permit {
uint256 public constant MAX_SUPPLY = 10_000_000 * 10**18; // 10 million tokens
constructor(address initialOwner)
ERC20("NarutoToken", "NATO")
Ownable(initialOwner)
ERC20Permit("NarutoToken")
{
_mint(initialOwner, 1_000_000 * 10**18); // Initial mint of 1 million tokens
}
function mint(address to, uint256 amount) public onlyOwner {
require(totalSupply() + amount <= MAX_SUPPLY, "Exceeds max supply");
_mint(to, amount);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract NarutoTokenSaleContract {
// Use IERC20 for the custom token to ensure compatibility
IERC20 public token;
IERC20 public usdtToken;
address public owner;
uint256 public tokenPrice; // Price in USDT
uint256 public totalTokensSold;
uint256 public maxTokensToSell;
mapping(address => uint256) public tokensPurchased;
event TokensPurchased(
address indexed buyer,
uint256 usdtAmount,
uint256 tokenAmount
);
event PriceUpdated(uint256 newPrice);
event SaleParametersChanged(uint256 maxTokens);
constructor(
address _tokenAddress,
address _usdtTokenAddress,
uint256 _initialPrice,
uint256 _maxTokensToSell
) {
// Use IERC20 interface for token interaction
token = IERC20(_tokenAddress);
usdtToken = IERC20(_usdtTokenAddress);
owner = msg.sender;
tokenPrice = _initialPrice; // Price in USDT (e.g., 0.1 * 10**6)
maxTokensToSell = _maxTokensToSell;
}
modifier onlyOwner() {
require(msg.sender == owner, "Not authorized");
_;
}
function purchaseTokens(uint256 usdtAmount) public {
// Validate purchase amount
require(usdtAmount > 0, "Purchase amount must be greater than 0");
// Calculate tokens to receive
uint256 tokensToReceive = (usdtAmount * 10**18) / tokenPrice;
// Check sale limits
require(
totalTokensSold + tokensToReceive <= maxTokensToSell,
"Exceeds maximum tokens for sale"
);
// Transfer USDT from buyer to contract
require(
usdtToken.transferFrom(msg.sender, address(this), usdtAmount),
"USDT transfer failed"
);
// Transfer tokens to buyer
require(
token.transfer(msg.sender, tokensToReceive),
"Token transfer failed"
);
// Update tracking
totalTokensSold += tokensToReceive;
tokensPurchased[msg.sender] += tokensToReceive;
emit TokensPurchased(msg.sender, usdtAmount, tokensToReceive);
}
// Owner functions for contract management
function updateTokenPrice(uint256 _newPrice) external onlyOwner {
require(_newPrice > 0, "Invalid price");
tokenPrice = _newPrice;
emit PriceUpdated(_newPrice);
}
function updateMaxTokensToSell(uint256 _maxTokens) external onlyOwner {
maxTokensToSell = _maxTokens;
emit SaleParametersChanged(_maxTokens);
}
function withdrawUSDT(uint256 amount) external onlyOwner {
require(
usdtToken.transfer(owner, amount),
"USDT withdrawal failed"
);
}
function withdrawRemainingTokens() external onlyOwner {
uint256 remainingTokens = token.balanceOf(address(this));
require(
token.transfer(owner, remainingTokens),
"Token withdrawal failed"
);
}
// View functions
function getRemainingTokensForSale() public view returns (uint256) {
return maxTokensToSell - totalTokensSold;
}
}
Environment
polygon mainnet