Improper logic in the ::removeBeneficiary function means that a selected beneficiary is not properly removed from the beneficiaries list.
function test_distribution_error() public {
address son = makeAddr("wayward_son");
address daughter = makeAddr("good_daughter");
deal(address(im), 100e18);
vm.startPrank(owner);
im.addBeneficiery(son);
im.addBeneficiery(daughter);
vm.stopPrank();
vm.prank(owner);
im.removeBeneficiary(son);
vm.warp(1 + 90 days);
vm.prank(daughter);
im.inherit();
assert(im.getOwner() != daughter);
vm.prank(daughter);
im.withdrawInheritedFunds(address(0));
assert(daughter.balance == 50e18);
}
[PASS] test_distribution_error() (gas: 186100)
Traces:
[206000] InheritanceManagerTest::test_distribution_error()
├─ [0] VM::addr(<pk>) [staticcall]
│ └─ ← [Return] wayward_son: [0x4C8995C378022554e38829a7c0486Cf7b655a037]
├─ [0] VM::label(wayward_son: [0x4C8995C378022554e38829a7c0486Cf7b655a037], "wayward_son")
│ └─ ← [Return]
├─ [0] VM::addr(<pk>) [staticcall]
│ └─ ← [Return] good_daughter: [0x7c499a12c8d15a71b329941b8d5816b011c8f861]
├─ [0] VM::label(good_daughter: [0x7c499a12c8d15a71b329941b8d5816b011c8f861], "good_daughter")
│ └─ ← [Return]
├─ [0] VM::deal(InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA], 100000000000000000000 [1e20])
│ └─ ← [Return]
├─ [0] VM::startPrank(owner: [0x7c8999dC9a822c1f0Df42023113EDB4FDd543266])
│ └─ ← [Return]
├─ [69404] InheritanceManager::addBeneficiery(wayward_son: [0x4C8995C378022554e38829a7c0486Cf7b655a037])
│ └─ ← [Stop]
├─ [23504] InheritanceManager::addBeneficiery(good_daughter: [0x7c499a12c8d15a71b329941b8d5816b011c8f861])
│ └─ ← [Stop]
├─ [0] VM::stopPrank()
│ └─ ← [Return]
├─ [0] VM::prank(owner: [0x7c8999dC9a822c1f0Df42023113EDB4FDd543266])
│ └─ ← [Return]
├─ [1708] InheritanceManager::removeBeneficiary(wayward_son: [0x4C8995C378022554e38829a7c0486Cf7b655a037])
│ └─ ← [Stop]
├─ [0] VM::warp(7776001 [7.776e6])
│ └─ ← [Return]
├─ [0] VM::prank(good_daughter: [0x7c499a12c8d15a71b329941b8d5816b011c8f861])
│ └─ ← [Return]
├─ [22791] InheritanceManager::inherit()
│ └─ ← [Stop]
├─ [604] InheritanceManager::getOwner() [staticcall]
│ └─ ← [Return] owner: [0x7c8999dC9a822c1f0Df42023113EDB4FDd543266]
├─ [0] VM::prank(good_daughter: [0x7c499a12c8d15a71b329941b8d5816b011c8f861])
│ └─ ← [Return]
├─ [68495] InheritanceManager::withdrawInheritedFunds(0x0000000000000000000000000000000000000000)
│ ├─ [0] 0x0000000000000000000000000000000000000000::fallback{value: 50000000000000000000}() 👈🏾👈🏾
│ │ └─ ← [Stop]
│ ├─ [0] good_daughter::fallback{value: 50000000000000000000}()
│ │ └─ ← [Stop]
│ └─ ← [Stop]
└─ ← [Stop]
This means that removals are properly handled, and distribution of inheritance is calculated properly.
+ mapping(address => bool) isBeneficiary;
function addBeneficiery(address _beneficiary) external onlyOwner {
+ require(!isBeneficiary[_beneficiary], "Already a beneficiary!!!");
beneficiaries.push(_beneficiary);
_setDeadline();
+ isBeneficiary[_beneficiary] = true;
}
function removeBeneficiary(address _beneficiary) external onlyOwner {
- uint256 indexToRemove = _getBeneficiaryIndex(_beneficiary);
- delete beneficiaries[indexToRemove];
+ uint256 bl = beneficiaries.length; // bl = beneficiaries_length
+ for (uint256 b = 0; b < bl; b++) {
+ if (beneficiaries[b] == _beneficiary) {
+ beneficiaries[b] = beneficiaries[bl - 1]; // replace with last element
+ beneficiaries.pop(); // remove last element
+ break;
+ }
+ }
+ isBeneficiary[_beneficiary] = false;
}