The buyOutEstateNFT
function in the InheritanceManager
contract contains a logic error that causes premature termination of the function's execution. This occurs when a beneficiary attempts to buy out an estate NFT, and the loop to distribute funds to other beneficiaries terminates prematurely after identifying the calling beneficiary, without transferring to other beneficiaries and without burning the NFT. This leads to an inconsistent state where some beneficiaries may not receive their share and the NFT remains active.
https://github.com/CodeHawks-Contests/2025-03-inheritable-smart-contract-wallet/blob/main/src/InheritanceManager.sol#L263-L277
Location: InheritanceManager.so
Function: buyOutEstateNFT
Vulnerability: Premature Return
Description:
The buyOutEstateNFT
function is intended to allow a beneficiary to buy out an estate NFT from the other beneficiaries.
The function calculates the amount to be paid to the other beneficiaries, transfers it from the buyer to the contract, and then iterates through the list of beneficiaries to distribute the funds.
Critical Flaw: Inside the loop, there's a check: if (msg.sender == beneficiaries[i]) { return; }
. This return
statement is executed as soon as the function encounters the address of the calling beneficiary in beneficiaries
.
Consequence: When the calling beneficiary is found, the return
statement immediately exits the function. The function never proceeds to transfer funds to the remaining beneficiaries, nor does it execute the nft.burnEstate(_nftID)
function call. This function is called at the end of the for loop, and since the loop exits early, the NFT is never burned.
Incorrect Logic: The intended logic likely meant to skip the beneficiary who was buying out the NFT, but the return
statement abruptly halts the entire process.
State Inconsistency: This results in the NFT remaining active, and the contract holding some funds that should be distributed.
Consider a scenario where the first user in the beneficiaries array buyouts estate NFT.
Add this test to the test suite InheritanceManagerTest
at path test/InheritanceManagerTest.t.sol
and run the command forge test --mt test_buyOutBug
:
After buyout, funds are locked in the contract and other users were not paid any fund
Partial Fund Distribution: Beneficiaries may not receive their rightful share of the funds when an NFT is bought out.
NFT Remains Active: The estate NFT is not burned after a buyout, leading to potential confusion and errors if the same NFT is subject to multiple buyout attempts or other operations.
Loss of Funds: The funds intended for remaining beneficiaries are held in the contract without being properly transferred.
Manual Code Review
Foundry
Option 1: Refactor buyOutEstateNFT
Logic:
Replace the return
statement with continue
. This will skip the current iteration (when the calling beneficiary is encountered) but will allow the loop to continue processing other beneficiaries.
Move nft.burnEstate(_nftID)
before the for loop, so it will burn the NFT regardless of who is buying.
Option 2: Revised Code Snippet: Skip if its the beneficiary buying the NFT
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.