Weather Witness

First Flight #40
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: high
Valid

Locked Ether Due to Missing Withdrawal Functionality

Root + Impact

The contract collects ETH through the requestMintWeatherNFT payable function, but it does not implement any withdrawal mechanism to retrieve this ETH. As a result, the ETH becomes permanently locked in the contract’s balance.

•	Funds paid by users during minting are permanently locked and cannot be retrieved by the contract owner or protocol treasury.
•	This undermines the financial utility of the protocol — if ETH was intended as payment or revenue, it becomes irretrievably stuck, resulting in lost funds.
•	In a live deployment, this could lead to real monetary losses, protocol mismanagement, or a negative trust perception from users and contributors.

Description

  • The contract allows users to mint NFTs by sending ETH through the WeatherNft::requestMintWeatherNFT function, which is marked payable.

  • However, the contract does not implement any mechanism for withdrawing the accumulated ETH, effectively locking the funds in the contract permanently.


function requestMintWeatherNFT(
string memory _pincode,
string memory _isoCode,
bool _registerKeeper,
uint256 _heartbeat,
uint256 _initLinkDeposit
) external payable returns (bytes32 _reqId) {
require(
msg.value == s_currentMintPrice,
WeatherNft__InvalidAmountSent()
);
s_currentMintPrice += s_stepIncreasePerMint;
...
}

Risk

Likelihood:

  • Users regularly interact with the requestMintWeatherNFT function during normal minting operations.

  • Each call to this function transfers ETH to the contract, but with no retrieval mechanism, this ETH will accumulate and be permanently inaccessible.


Impact:

  • ETH sent to the contract is locked and cannot be withdrawn or reused, resulting in a permanent loss of funds.

  • If ETH was intended to be collected for protocol operations (e.g., treasury, revenue), this breaks financial functionality.


Proof of Concept

// Call mint function with correct ETH
weatherNft.requestMintWeatherNFT{value: weatherNft.s_currentMintPrice()}(
"560001", // pincode
"IN", // ISO country code
false, // no keeper
0, // heartbeat
0 // no LINK
);
// Check that the contract received ETH
assert(address(weatherNft).balance > 0);
// But contract has no withdraw() function to access this balance
// Ether is permanently locked

Recommended Mitigation

// Add a withdraw function to withdraw the funds form the contract
+ function withdraw() external onlyOwner {
+ uint256 balance = address(this).balance;
+ (bool success, ) = payable(msg.sender).call{value: balance}("");
+ require(success, "Withdraw failed");
+ }
Updates

Appeal created

bube Lead Judge about 1 month ago
Submission Judgement Published
Validated
Assigned finding tags:

Lack of `withdraw` function

The contract collects funds for minting a WeatherNFT, but there is no function that allows the owner to withdraw these funds.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.