Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: low
Valid

Beneficiary is not able to buy asset due to multiple times creating estate NFT.

Description

while creating estet NFT we call `InheritanceManager::createEstateNFT` function which creates nft and set the address of tokens in which the benificiary have to pay for buying the asset. But if owner create asset multiple time with diffrent token address, there is no any data thet refers the actual token for perticuler asset the beneficiary have to pay.
```javascript
function createEstateNFT(string memory _description, uint256 _value, address _asset) external onlyOwner {
uint256 nftID = nft.createEstate(_description);
nftValue[nftID] = _value;
@> assetToPay = _asset;
}
```

Impact

creating assets multiple times with diffrent token address will change the paying token, So the final payable token will be diffrent from another tokens while creating erlier asset.

Proof of Concept

Add this test function into `InheritanceManagerTest.t.sol` file
Proof Of Code:
```javascript
function testFinalTokenIsChanged() public {
address user2 = makeAddr("user2");
address user3 = makeAddr("user3");
ERC20Mock inch = new ERC20Mock();
vm.startPrank(owner);
im.addBeneficiery(user2);
im.addBeneficiery(user3);
im.createEstateNFT("abc0",20,address(usdc));
im.createEstateNFT("dhv",10,address(weth));
im.createEstateNFT("sdjn", 1, address(inch));
vm.stopPrank();
usdc.mint(user3, 50);
weth.mint(user3, 50);
inch.mint(user3, 50);
assertEq(usdc.balanceOf(user3), 50);
assertEq(weth.balanceOf(user3), 50);
assertEq(inch.balanceOf(user3), 50);
vm.warp(1 + 90 days);
vm.startPrank(user3);
usdc.approve(address(im),50);
weth.approve(address(im),50);
inch.approve(address(im),50);
im.inherit();
im.buyOutEstateNFT(1);
vm.stopPrank();
assertEq(inch.balanceOf(user3), 40);
assertEq(usdc.balanceOf(user3), 50);
}
```
```diff
[PASS] testFinalTokenIsChanged() (gas: 1185047)
Traces:
[1185047] InheritanceManagerTest::testFinalTokenIsChanged()
├─ [0] VM::addr(<pk>) [staticcall]
│ └─ ← [Return] user2: [0x537C8f3d3E18dF5517a58B3fB9D9143697996802]
├─ [0] VM::label(user2: [0x537C8f3d3E18dF5517a58B3fB9D9143697996802], "user2")
│ └─ ← [Return]
├─ [0] VM::addr(<pk>) [staticcall]
│ └─ ← [Return] user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec]
├─ [0] VM::label(user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec], "user3")
│ └─ ← [Return]
├─ [436357] → new ERC20Mock@0xF62849F9A0B5Bf2913b396098F7c7019b51A820a
│ └─ ← [Return] 1954 bytes of code
├─ [0] VM::startPrank(owner: [0x7c8999dC9a822c1f0Df42023113EDB4FDd543266])
│ └─ ← [Return]
├─ [69020] InheritanceManager::addBeneficiery(user2: [0x537C8f3d3E18dF5517a58B3fB9D9143697996802])
│ └─ ← [Stop]
├─ [23120] InheritanceManager::addBeneficiery(user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec])
│ └─ ← [Stop]
├─ [145826] InheritanceManager::createEstateNFT("abc0", 20, ERC20Mock: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f])
│ ├─ [95512] NFTFactory::createEstate("abc0")
│ │ ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA], tokenId: 1)
│ │ ├─ emit MetadataUpdate(_tokenId: 1)
│ │ └─ ← [Return] 1
│ └─ ← [Stop]
├─ [73626] InheritanceManager::createEstateNFT("dhv", 10, ERC20Mock: [0x2e234DAe75C793f67A35089C9d99245E1C58470b])
│ ├─ [49712] NFTFactory::createEstate("dhv")
│ │ ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA], tokenId: 2)
│ │ ├─ emit MetadataUpdate(_tokenId: 2)
│ │ └─ ← [Return] 2
│ └─ ← [Stop]
├─ [73626] InheritanceManager::createEstateNFT("sdjn", 1, ERC20Mock: [0xF62849F9A0B5Bf2913b396098F7c7019b51A820a])
│ ├─ [49712] NFTFactory::createEstate("sdjn")
│ │ ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA], tokenId: 3)
│ │ ├─ emit MetadataUpdate(_tokenId: 3)
│ │ └─ ← [Return] 3
│ └─ ← [Stop]
├─ [0] VM::stopPrank()
│ └─ ← [Return]
├─ [46784] ERC20Mock::mint(user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec], 50)
│ ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec], value: 50)
│ └─ ← [Stop]
├─ [46784] ERC20Mock::mint(user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec], 50)
│ ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec], value: 50)
│ └─ ← [Stop]
├─ [46784] ERC20Mock::mint(user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec], 50)
│ ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec], value: 50)
│ └─ ← [Stop]
├─ [559] ERC20Mock::balanceOf(user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec]) [staticcall]
│ └─ ← [Return] 50
├─ [0] VM::assertEq(50, 50) [staticcall]
│ └─ ← [Return]
├─ [559] ERC20Mock::balanceOf(user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec]) [staticcall]
│ └─ ← [Return] 50
├─ [0] VM::assertEq(50, 50) [staticcall]
│ └─ ← [Return]
├─ [559] ERC20Mock::balanceOf(user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec]) [staticcall]
│ └─ ← [Return] 50
├─ [0] VM::assertEq(50, 50) [staticcall]
│ └─ ← [Return]
├─ [0] VM::warp(7776001 [7.776e6])
│ └─ ← [Return]
├─ [0] VM::startPrank(user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec])
│ └─ ← [Return]
├─ [24735] ERC20Mock::approve(InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA], 50)
│ ├─ emit Approval(owner: user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec], spender: InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA], value: 50)
│ └─ ← [Return] true
├─ [24735] ERC20Mock::approve(InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA], 50)
│ ├─ emit Approval(owner: user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec], spender: InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA], value: 50)
│ └─ ← [Return] true
├─ [24735] ERC20Mock::approve(InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA], 50)
│ ├─ emit Approval(owner: user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec], spender: InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA], value: 50)
│ └─ ← [Return] true
├─ [22686] InheritanceManager::inherit()
│ └─ ← [Stop]
├─ [55920] InheritanceManager::buyOutEstateNFT(1)
│ ├─ [26058] ERC20Mock::transferFrom(user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec], InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA], 10)
│ │ ├─ emit Transfer(from: user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec], to: InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA], value: 10)
│ │ └─ ← [Return] true
│ ├─ [25204] ERC20Mock::transfer(user2: [0x537C8f3d3E18dF5517a58B3fB9D9143697996802], 5)
│ │ ├─ emit Transfer(from: InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA], to: user2: [0x537C8f3d3E18dF5517a58B3fB9D9143697996802], value: 5)
│ │ └─ ← [Return] true
│ └─ ← [Stop]
├─ [0] VM::stopPrank()
│ └─ ← [Return]
├─ [559] ERC20Mock::balanceOf(user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec]) [staticcall]
│ └─ ← [Return] 40
├─ [0] VM::assertEq(40, 40) [staticcall]
│ └─ ← [Return]
├─ [559] ERC20Mock::balanceOf(user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec]) [staticcall]
│ └─ ← [Return] 50
├─ [0] VM::assertEq(50, 50) [staticcall]
│ └─ ← [Return]
└─ ← [Stop]
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 16.32ms (2.64ms CPU time)
```
As you can observe we have buy out nft with id `1` which has the `usdc` token has setted to pay. but at last the beneficiary has to pay in `inch` token instead of `usdc` token.

Recommended Mitigation

The wallet should have the track or mapping that store the token info alogside the NFT.
For example:
Id - 1 -> usdc
Id - 2 -> weth
etc.
For implementing the mapping add the following into `Trustee` contract.
```diff
- address assetToPay;
+ mapping(uint256 => address) nftTotoken;
```
Also make this changes into the `InheritanceMAnager::createEstateNFT` function.
```diff
function createEstateNFT(string memory _description, uint256 _value, address _asset) external onlyOwner {
uint256 nftID = nft.createEstate(_description);
nftValue[nftID] = _value;
+ nftTotoken[nftID] = _asset;
- assetToPay = _asset;
}
```
by this method the contract have track of the asset to pay for the nft.
Updates

Lead Judging Commences

0xtimefliez Lead Judge 6 months ago
Submission Judgement Published
Validated
Assigned finding tags:

global asset in NFT values

Support

FAQs

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