Within the `deposit()` in the `Treasury.sol`, after processing the deposit, the code updates the global total:
```solidity
_totalValue += amount;
```
This update does not account for the fact that different tokens may have different values or decimal representations. Aggregating all deposits into a single `_totalValue` can be misleading when the tokens involved are not homogeneous in value.
### Proof of Concept
Consider the following scenario:
User A deposits 100 units of Token X (high value).
User B deposits 100 units of Token Y (low value).
Both deposits are summed into `_totalValue` without differentiation. Subsequent calculations that rely on `_totalValue` will treat both tokens equally, potentially causing errors in value-based distributions.
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "forge-std/Test.sol";
import "../../../contracts/core/collectors/Treasury.sol";
import "lib/openzeppelin-contracts/contracts/mocks/token/ERC20Mock.sol";
contract MockERC20 is ERC20 {
constructor(string memory name, string memory symbol) ERC20(name, symbol) {
_mint(msg.sender, 100_000 * 10 ** 18); // Mint 100k tokens to deployer
}
}
contract TreasuryTest is Test {
Treasury treasury;
MockERC20 token;
address admin = address(0x1);
address manager = address(0x2);
address allocator = address(0x3);
address user = address(0x7);
address userA = address(0x4);
address userB = address(0x6);
address recipient = address(0x5);
// Role hashes
bytes32 constant MANAGER_ROLE = keccak256("MANAGER_ROLE");
bytes32 constant ALLOCATOR_ROLE = keccak256("ALLOCATOR_ROLE");
function setUp() public {
// Deploy mock token
token = new MockERC20("Mock Token", "MTK");
// Deploy Treasury contract with admin
vm.prank(admin);
treasury = new Treasury(admin);
// Grant roles
vm.startPrank(admin);
treasury.grantRole(MANAGER_ROLE, manager);
treasury.grantRole(ALLOCATOR_ROLE, allocator);
vm.stopPrank();
// Transfer some tokens to user for testing deposits
token.transfer(userA, 10_000 * 10 ** 18);
token.transfer(userB, 10_000 * 10 ** 18);
}
function testTotalValueMisrepresentsTokenValue() public {
// Deploy two tokens with same decimals but implied different values
MockERC20 tokenX = new MockERC20("Token X", "TKX"); // High-value token, e.g., $100/unit
MockERC20 tokenY = new MockERC20("Token Y", "TKY"); // Low-value token, e.g., $0.01/unit
// Transfer tokens to users
tokenX.transfer(userA, 1_000 * 10**18); // 1000 units of Token X
tokenY.transfer(userB, 1_000 * 10**18); // 1000 units of Token Y
// User A deposits 100 units of Token X
uint256 depositAmountX = 100 * 10**18; // 100 Token X
vm.startPrank(userA);
tokenX.approve(address(treasury), depositAmountX);
treasury.deposit(address(tokenX), depositAmountX);
vm.stopPrank();
// User B deposits 100 units of Token Y
uint256 depositAmountY = 100 * 10**18; // 100 Token Y
vm.startPrank(userB);
tokenY.approve(address(treasury), depositAmountY);
treasury.deposit(address(tokenY), depositAmountY);
vm.stopPrank();
// Check individual balances
assertEq(treasury.getBalance(address(tokenX)), depositAmountX, "Token X balance incorrect");
assertEq(treasury.getBalance(address(tokenY)), depositAmountY, "Token Y balance incorrect");
// Check totalValue
uint256 actualTotalValue = treasury.getTotalValue();
uint256 rawSum = depositAmountX + depositAmountY; // 100 * 10^18 + 100 * 10^18 = 200 * 10^18
// Log values for inspection
console.log("Token X Deposited (high value):", depositAmountX / 10**18, "units");
console.log("Token Y Deposited (low value):", depositAmountY / 10**18, "units");
console.log("Raw Total Value:", actualTotalValue / 10**18, "units");
// Assertion matches current logic but highlights the issue
assertEq(actualTotalValue, rawSum, "Total value matches raw sum but misrepresents real value");
// Commentary: In reality, if Token X = $100/unit and Token Y = $0.01/unit:
// - 100 Token X = $10,000
// - 100 Token Y = $1
// - Real total value = $10,001, but _totalValue = 200 units, which is misleading
console.log("Note: Total Value treats 100 high-value Token X and 100 low-value Token Y as equal (200 units)");
}
}
```
the result
```solidity
Ran 1 test for test/foundry/Collectors/TreasuryTest.t.sol:TreasuryTest
[PASS] testTotalValueMisrepresentsTokenValue() (gas: 1905432)
Logs:
Token X Deposited (high value): 100 units
Token Y Deposited (low value): 100 units
Raw Total Value: 200 units
Note: Total Value treats 100 high-value Token X and 100 low-value Token Y as equal (200 units)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.00ms (742.13µs CPU time)
Ran 1 test suite in 11.38ms (2.00ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)
```