If the buyer is early in the beneficiaries array (e.g., the first or second beneficiary), the function will exit entirely when it finds the buyer:
function test_buyOutEstateNFTIssues() public {
address user2 = makeAddr("user2");
address user3 = makeAddr("user3");
vm.startPrank(owner);
im.addBeneficiery(user1);
im.addBeneficiery(user2);
im.addBeneficiery(user3);
im.createEstateNFT("Beach House", 100e18, address(usdc));
vm.stopPrank();
vm.warp(block.timestamp + 91 days);
vm.prank(user1);
im.inherit();
assertEq(true, im.getIsInherited());
console.log("\n=== TEST 1: EARLY RETURN ISSUE ===");
console.log("Scenario: First beneficiary (index 0) buys the NFT");
usdc.mint(user1, 1000e18);
uint256 nftValue = 100e18;
uint256 numBeneficiaries = 3;
uint256 sharePerBeneficiary = nftValue / numBeneficiaries;
uint256 finalAmount = sharePerBeneficiary * (numBeneficiaries - 1);
console.log("NFT value:", nftValue / 1e18);
console.log("Fair share per beneficiary:", sharePerBeneficiary / 1e18);
console.log("Buyer pays:", finalAmount / 1e18);
console.log("\nInitial balances:");
console.log(
"Contract token balance:",
usdc.balanceOf(address(im)) / 1e18
);
console.log(
"Buyer (user1) token balance:",
usdc.balanceOf(user1) / 1e18
);
console.log(
"Beneficiary2 token balance:",
usdc.balanceOf(user2) / 1e18
);
console.log(
"Beneficiary3 token balance:",
usdc.balanceOf(user3) / 1e18
);
vm.startPrank(user1);
usdc.approve(address(im), finalAmount);
im.buyOutEstateNFT(1);
vm.stopPrank();
console.log("\nFinal balances:");
console.log(
"Contract token balance:",
usdc.balanceOf(address(im)) / 1e18
);
uint256 user1balanceAfterTest1 = usdc.balanceOf(user1);
console.log(
"Buyer (user1) token balance:",
user1balanceAfterTest1 / 1e18
);
console.log(
"Beneficiary2 token balance:",
usdc.balanceOf(user2) / 1e18
);
console.log(
"Beneficiary3 token balance:",
usdc.balanceOf(user3) / 1e18
);
assertEq(
usdc.balanceOf(address(im)),
finalAmount,
"All tokens should remain in contract"
);
assertEq(
usdc.balanceOf(user2),
0,
"Beneficiary2 should receive nothing due to early return"
);
assertEq(
usdc.balanceOf(user3),
0,
"Beneficiary3 should receive nothing due to early return"
);
console.log(
"\nVerdict for Test 1: CRITICAL ISSUE - Early return prevents any distributions"
);
console.log(
"Expected: Tokens should be distributed to beneficiaries 2 and 3"
);
console.log("Actual: All tokens remain stuck in the contract");
vm.warp(1);
vm.prank(owner);
im = new InheritanceManager();
console.log("\n=== TEST 2: CALCULATION ISSUE ===");
console.log("Scenario: Last beneficiary (index 2) buys the NFT");
vm.startPrank(owner);
im.addBeneficiery(user1);
im.addBeneficiery(user2);
im.addBeneficiery(user3);
im.createEstateNFT("Beach House", 100e18, address(usdc));
vm.stopPrank();
vm.warp(block.timestamp + 91 days);
vm.prank(user1);
im.inherit();
usdc.mint(user3, 1000e18);
nftValue = 100e18;
numBeneficiaries = 3;
sharePerBeneficiary = nftValue / numBeneficiaries;
finalAmount = sharePerBeneficiary * (numBeneficiaries - 1);
uint256 currentDistribution = finalAmount / numBeneficiaries;
uint256 correctDistribution = finalAmount / (numBeneficiaries - 1);
uint256 expectedStuck = finalAmount -
(currentDistribution * (numBeneficiaries - 1));
console.log("NFT value:", nftValue / 1e18);
console.log("Fair share per beneficiary:", sharePerBeneficiary / 1e18);
console.log("Buyer pays:", finalAmount / 1e18);
console.log(
"Current distribution per beneficiary:",
currentDistribution / 1e18
);
console.log(
"Correct distribution per beneficiary:",
correctDistribution / 1e18
);
console.log("\nInitial balances:");
console.log(
"Contract token balance:",
usdc.balanceOf(address(im)) / 1e18
);
console.log(
"Buyer (user3) token balance:",
usdc.balanceOf(user3) / 1e18
);
console.log(
"Beneficiary1 token balance:",
usdc.balanceOf(user1) / 1e18
);
console.log(
"Beneficiary2 token balance:",
usdc.balanceOf(user2) / 1e18
);
vm.startPrank(user3);
usdc.approve(address(im), finalAmount);
im.buyOutEstateNFT(1);
vm.stopPrank();
console.log("\nFinal balances:");
console.log(
"Contract token balance:",
usdc.balanceOf(address(im)) / 1e18
);
console.log(
"Buyer (user3) token balance:",
usdc.balanceOf(user3) / 1e18
);
console.log(
"Beneficiary1 token balance:",
usdc.balanceOf(user1) / 1e18
);
console.log(
"Beneficiary2 token balance:",
usdc.balanceOf(user2) / 1e18
);
assertEq(
usdc.balanceOf(user1) - user1balanceAfterTest1,
currentDistribution,
"Beneficiary1 should receive the incorrect amount"
);
assertEq(
usdc.balanceOf(user2),
currentDistribution,
"Beneficiary2 should receive the incorrect amount"
);
uint256 stuckPercentage = (expectedStuck * 100) / finalAmount;
console.log(
"\nVerdict for Test 2: HIGH SEVERITY ISSUE - Calculation error causes stuck funds"
);
console.log(
"Expected: Each beneficiary should receive",
correctDistribution / 1e18,
"tokens"
);
console.log(
"Actual: Each beneficiary receives",
currentDistribution / 1e18,
"tokens"
);
console.log(
"Result:",
stuckPercentage,
"% of funds remain stuck in contract"
);
}
[⠊] Compiling...
[⠘] Compiling 1 files with Solc 0.8.26
[⠃] Solc 0.8.26 finished in 712.61ms
Compiler run successful!
Ran 1 test for test/InheritanceManagerTest.t.sol:InheritanceManagerTest
[PASS] test_buyOutEstateNFTIssues() (gas: 4785728)
Logs:
=== TEST 1: EARLY RETURN ISSUE ===
Scenario: First beneficiary (index 0) buys the NFT
NFT value: 100
Fair share per beneficiary: 33
Buyer pays: 66
Initial balances:
Contract token balance: 0
Buyer (user1) token balance: 1000
Beneficiary2 token balance: 0
Beneficiary3 token balance: 0
Final balances:
Contract token balance: 66
Buyer (user1) token balance: 933
Beneficiary2 token balance: 0
Beneficiary3 token balance: 0
Verdict for Test 1: CRITICAL ISSUE - Early return prevents any distributions
Expected: Tokens should be distributed to beneficiaries 2 and 3
Actual: All tokens remain stuck in the contract
=== TEST 2: CALCULATION ISSUE ===
Scenario: Last beneficiary (index 2) buys the NFT
NFT value: 100
Fair share per beneficiary: 33
Buyer pays: 66
Current distribution per beneficiary: 22
Correct distribution per beneficiary: 33
Initial balances:
Contract token balance: 0
Buyer (user3) token balance: 1000
Beneficiary1 token balance: 933
Beneficiary2 token balance: 0
Final balances:
Contract token balance: 22
Buyer (user3) token balance: 933
Beneficiary1 token balance: 955
Beneficiary2 token balance: 22
Verdict for Test 2: HIGH SEVERITY ISSUE - Calculation error causes stuck funds
Expected: Each beneficiary should receive 33 tokens
Actual: Each beneficiary receives 22 tokens
Result: 33 % of funds remain stuck in contract
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 9.07ms (2.63ms CPU time)
Ran 1 test suite in 158.38ms (9.07ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)