Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: low
Valid

Treasury's allocated funds not tracked during withdrawals leads to accounting issue where recepient can receive more than allocated funds.

Summary

The Treasury contract maintains an allocation system that tracks fund allocations to recipients but fails to decrease these allocations when actual withdrawals occur, leading to an inconsistent state between allocated and actual funds.

Vulnerability Details

When manager allocates funds, it is added to the mapping, but when the withdraw happens there is no check to see if manager is withdrawing more than allocated funds for that recipeint.

function allocateFunds(address recipient, uint256 amount) external override onlyRole(ALLOCATOR_ROLE) {
// ...
_allocations[msg.sender][recipient] = amount; // @audit this is ok.

The core issue lies when withdrawing:

function withdraw(address token, uint256 amount, address recipient)
external
override
nonReentrant
onlyRole(MANAGER_ROLE)
{
// @audit no check to stop overspending for the recipients
// Decreases balance and transfers tokens
_balances[token] -= amount;
_totalValue -= amount;
IERC20(token).transfer(recipient, amount);
// @audit No corresponding decrease in allocations
// Should have: _allocations[allocator][recipient] -= amount;
}

When a withdrawal happens, the actual tokens are transferred, but the allocation records remain unchanged. This means:

  1. An allocator could allocate 100 tokens to a recipient

  2. The tokens could be withdrawn to that recipient

  3. The allocation still shows 100 tokens even though they've been withdrawn

  4. The managers can overspend on recepients.

This creates a phantom allocation where the system thinks funds are still allocated even after they've been disbursed.

PoC

  1. Alice (Allocator) allocates 100 tokens to Bob: allocateFunds(bob, 100)

  2. Manager withdraws 100 tokens to Bob: withdraw(token, 100, bob)

  3. Check allocation: getAllocation(alice, bob) still returns 100

  4. But actual tokens have been transferred and _balances is reduced

  5. This creates an inconsistent state where allocations don't reflect reality

  6. Manager can now withdraw more than allocated tokens to the Bob.

Impact

  • Risk of double-spending against allocations

  • Incorrect allocation tracking

  • Potential over-allocation of funds

  • Misleading allocation records

Tools Used

Manual code review

Recommendations

Update the withdraw function to handle allocations:

function withdraw(address token, uint256 amount, address recipient)
external
override
nonReentrant
onlyRole(MANAGER_ROLE)
{
if (token == address(0)) revert InvalidAddress();
if (recipient == address(0)) revert InvalidRecipient();
if (_balances[token] < amount) revert InsufficientBalance();
_balances[token] -= amount;
_totalValue -= amount;
// Decrease allocation if it exists
if (_allocations[msg.sender][recipient] > 0) {
_allocations[msg.sender][recipient] -= amount;
}
IERC20(token).transfer(recipient, amount);
emit Withdrawn(token, amount, recipient);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 3 months ago
Submission Judgement Published
Validated
Assigned finding tags:

What do people do with allocations

Support

FAQs

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