The contract handles LINK tokens for Chainlink Automation (Keepers). Users deposit LINK when minting an NFT with _registerKeeper = true. This LINK is intended to fund the upkeep for that NFT. However, there are scenarios where these LINK tokens can become permanently locked:
Failed Keeper Registration: If IAutomationRegistrarInterface(s_keeperRegistrar).registerUpkeep() in fulfillMintRequest fails for any reason (e.g., temporary registrar issue, misconfiguration, insufficient gas provided by the user calling fulfillMintRequest), the transaction may revert. The _initLinkDeposit amount, already transferred to the contract in requestMintWeatherNFT, remains in the contract with no mechanism for the user to reclaim it.
No De-registration/Withdrawal Function: Once an upkeep is successfully registered, its initial funding (_initLinkDeposit) is transferred to the Chainlink Automation system. The contract (address(this)) is set as the adminAddress for the upkeep. There are no functions in WeatherNft.sol to allow the NFT owner (or contract owner) to:
Cancel an active upkeep (e.g., if the user no longer wants automated updates).
Withdraw remaining LINK funds from a canceled or completed upkeep.
Withdraw LINK funds if an NFT is burned or transferred, and automation is no longer desired/possible for the original owner.
This means any LINK committed to an upkeep or stuck in the contract due to registration failure is effectively lost to the user.
Likelihood: High
Keeper registration can fail due to external reasons or gas limits.
Users will likely want to stop automation or recover funds if they no longer use the NFT or the service, which is a standard feature for such systems. The absence of this feature guarantees LINK will be locked eventually for many upkeeps.
Impact: Medium
Permanent Loss of LINK: Users permanently lose their _initLinkDeposit if registration fails and it's stuck in the contract, or they lose any unspent LINK in the Automation system once an upkeep is registered and later becomes unwanted/unused.
Reduced Capital Efficiency: Locked LINK cannot be repurposed by users.
Contract Bloat (Minor): LINK tokens may accumulate in the contract address if many registrations fail.
Scenario 1: Failed Registration
Alice calls requestMintWeatherNFT with _registerKeeper = true and deposits 5 LINK. The 5 LINK is transferred to the WeatherNft contract.
Alice calls fulfillMintRequest. During the execution, IAutomationRegistrarInterface(s_keeperRegistrar).registerUpkeep() fails (e.g., the registrar is temporarily paused by Chainlink admins, or the specific call runs out of gas).
The fulfillMintRequest transaction reverts.
Alice's 5 LINK remains in the WeatherNft contract. There is no function Alice can call to get her 5 LINK back.
Scenario 2: No De-registration
Bob mints an NFT with automation, and 5 LINK is successfully used to fund the upkeep via registerUpkeep. s_weatherNftInfo[tokenId].upkeepId is set.
After some time, Bob sells the NFT or no longer wants automated updates. The upkeep has 3 LINK remaining in its balance within the Chainlink Automation system.
Bob (or the new owner) cannot cancel the upkeep or withdraw the remaining 3 LINK because WeatherNft.sol does not provide any functions to interact with the s_keeperRegistry for upkeep management (cancel, withdraw funds). The 3 LINK remains locked in the Automation system, associated with that upkeep ID.
Implement functions to manage the lifecycle of automations and associated funds:
Refund LINK on Registration Failure: If registerUpkeep can fail, and the fulfillMintRequest transaction doesn't revert fully (or if it does, provide a way to claim LINK stuck in contract), ensure users can reclaim their _initLinkDeposit that's held by the contract. This is linked to the general "funds loss" vulnerability.
Cancel Upkeep: Add a function, callable by the NFT owner (or contract owner, with appropriate checks), to cancel an upkeep using IAutomationRegistryMaster(s_keeperRegistry).cancelUpkeep(upkeepId). The upkeepId is stored in s_weatherNftInfo[tokenId].upkeepId.
Withdraw Funds from Upkeep: Add a function, callable by the NFT owner (or contract owner), to withdraw remaining funds from a (typically canceled) upkeep using IAutomationRegistryMaster(s_keeperRegistry).withdrawFunds(upkeepId, recipientAddress). The funds would be sent to the specified recipientAddress.
Ownership/Admin Control: Decide who should have the authority to cancel and withdraw (NFT owner vs. contract owner). If NFT owner, ensure proper ownership checks.
Note: The exact implementation of withdrawNftAutomationFunds depends on how Chainlink Automation handles fund withdrawals (e.g., if funds are returned to the admin contract first, or can be sent directly to a user-specified address). The IAutomationRegistryMaster interface includes withdrawFunds(uint256 id, address to), which suggests direct withdrawal to a specified address is possible.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.