Weather Witness

First Flight #40
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Impact: medium
Likelihood: medium
Invalid

Lack of Mechanism to Stop Upkeep

Root + Impact

Description: No Mechanism to Pause or Stop Upkeep, The contract does not allow stopping or pausing upkeep for destroyed or transferred NFTs.

function checkUpkeep(
bytes calldata checkData
)
external
view
override
returns (bool upkeepNeeded, bytes memory performData)
{
uint256 _tokenId = abi.decode(checkData, (uint256));
if (_ownerOf(_tokenId) == address(0)) {
upkeepNeeded = false;
}
else {
upkeepNeeded = (block.timestamp >= s_weatherNftInfo[_tokenId].lastFulfilledAt + s_weatherNftInfo[_tokenId].heartbeat);
if (upkeepNeeded) {
performData = checkData;
}
}
}

Risk: The contract lacks a function to pause or stop upkeep for specific NFTs.
Initial State: An NFT is destroyed or transferred.
Step 1: The upkeep continues to run for the NFT.
Outcome: LINK tokens are consumed unnecessarily.
Implications: This leads to wasted funds and inefficiency.

Impact:

  • Impact: NFT owners and the project team: Owners lose funds, and the team faces inefficiencies


Recommended Mitigation: To address this issue, introduce a function to pause or stop upkeep for specific NFTs. Update the checkUpkeep and performUpkeep functions to respect the paused state.

// Add a mapping to track paused NFTs
mapping(uint256 => bool) private s_pausedUpkeep;
// Function to pause upkeep for a specific NFT
function pauseUpkeep(uint256 tokenId) external {
require(_ownerOf(tokenId) == msg.sender, "WeatherNft__NotOwner");
s_pausedUpkeep[tokenId] = true;
emit UpkeepPaused(tokenId);
}
// Function to resume upkeep for a specific NFT
function resumeUpkeep(uint256 tokenId) external {
require(_ownerOf(tokenId) == msg.sender, "WeatherNft__NotOwner");
s_pausedUpkeep[tokenId] = false;
emit UpkeepResumed(tokenId);
}
update checkUpKeep
function checkUpkeep(
bytes calldata checkData
)
external
view
override
returns (bool upkeepNeeded, bytes memory performData)
{
uint256 _tokenId = abi.decode(checkData, (uint256));
if (_ownerOf(_tokenId) == address(0) || s_pausedUpkeep[_tokenId]) {
upkeepNeeded = false;
}
else {
upkeepNeeded = (block.timestamp >= s_weatherNftInfo[_tokenId].lastFulfilledAt + s_weatherNftInfo[_tokenId].heartbeat);
if (upkeepNeeded) {
performData = checkData;
}
}
}
update performUpKeep
function performUpkeep(bytes calldata performData) external override {
uint256 _tokenId = abi.decode(performData, (uint256));
require(!s_pausedUpkeep[_tokenId], "WeatherNft__UpkeepPaused");
uint256 upkeepId = s_weatherNftInfo[_tokenId].upkeepId;
s_weatherNftInfo[_tokenId].lastFulfilledAt = block.timestamp;
// Make functions request
string memory pincode = s_weatherNftInfo[_tokenId].pincode;
string memory isoCode = s_weatherNftInfo[_tokenId].isoCode;
bytes32 _reqId = _sendFunctionsWeatherFetchRequest(pincode, isoCode);
s_funcReqIdToTokenIdUpdate[_reqId] = _tokenId;
emit NftWeatherUpdateRequestSend(_tokenId, _reqId, upkeepId);
}
Updates

Appeal created

bube Lead Judge 3 days ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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