Contract Balance Issue After NFT Creation
I deployed a smart contract on the sepolia network but I’m confused about why the contract’s ETH balance remains unchanged when someone buys an NFT. The minting process works fine and tokens get created successfully, but the contract balance doesn’t go up.
uint256 public constant MAX_TOKENS = 50;
uint256 public constant TOKEN_COST = 0.05 ether;
uint256 public constant MAX_PER_WALLET = 5;
function createTokens(address buyer, uint256 amount) public payable {
uint256 nextId = tokenCounter.current();
require(nextId < MAX_TOKENS, "All tokens minted");
require(
amount > 0 && amount <= MAX_PER_WALLET,
"Invalid mint amount"
);
require(
msg.value == TOKEN_COST * amount,
"Incorrect payment amount"
);
for (uint256 j = 0; j < amount; j++) {
tokenCounter.increment();
uint256 tokenId = tokenCounter.current();
_safeMint(buyer, tokenId);
}
bool sent = false;
(sent, ) = contractOwner().call{value: msg.value}("");
require(sent, "Transfer to owner failed");
}
I’m using this hardhat script to test the minting:
task("create-nft", "Creates new NFT tokens")
.addParam("wallet", "Recipient wallet address")
.setAction(async function (args, hre) {
const nftContract = await getContract("MyNFT", hre);
const tx = await nftContract.createTokens(args.wallet, 1, {
gasLimit: 300_000,
value: ethers.utils.parseEther("0.05")
});
console.log(`TX Hash: ${tx.hash}`);
});
The transaction goes through but the contract balance doesn’t increase. What am I missing here?
yeah, that’s totally right. ur code sends the ETH to the owner right away, so the contract balance stays at zero. the ETH doesn’t stay - it just moves straight to contractOwner(). if u want the contract to keep some ETH, don’t transfer it all out right away.
Oh wait, I see what’s happening! Your contract’s working exactly as designed - the balance stays zero because you’re immediately transferring all the ETH to the contract owner in that same transaction. Look at this part:
(sent, ) = contractOwner().call{value: msg.value}("");
The ETH comes in with msg.value (your 0.05 ether) but gets sent out to the owner right away in the same function call. So the contract never actually “holds” the money - it just passes through.
This is pretty common for NFT contracts where the owner wants immediate access to funds rather than having them sit in the contract. But are you expecting the contract to keep the funds? Maybe you want to implement royalties or delayed withdrawal?
Also - when you check the contract balance, are you doing it right after the transaction or waiting? And have you verified that contractOwner() is returning the address you expect? Might be worth adding some events to track where the funds are going.
What was your original intention with fund management? Did you want the contract to hold the ETH or send it to the owner immediately?
Your contract balance stays at zero because you’re sending all the ETH to the owner immediately. Check the end of your createTokens function - there’s a line contractOwner().call{value: msg.value}("") that forwards the entire payment straight to the owner’s wallet. The ETH never actually stays in the contract. It passes through during execution but gets sent out before the transaction finishes. Want the contract to keep some funds? Either remove that transfer call or modify it to only send part of the payment. I ran into the exact same thing with my first NFT contract - kept wondering why my balance was always empty even though sales were working. Turns out the funds were going exactly where I coded them to go, just not where I thought they’d end up.