Part 2

Zaros
PerpetualsDEXFoundrySolidity
70,000 USDC
View results
Submission Details
Severity: medium
Invalid

Inaccurate Staking Due to Unverified Token Transfers

Summary

The stake function in the VaultRouterBranch contract does not verify the actual number of tokens transferred, leading to potential discrepancies in staked shares if the indexToken has transfer fees or non-standard behaviors.

The stake function records the full amount of shares as staked without verifying that the safeTransferFrom call actually transferred the intended number of tokens. If the indexToken implements a fee on transfer or alters the amount received, the contract's internal accounting for staked shares will not reflect the actual tokens received. This mismatch can lead to inconsistencies, allowing attackers to manipulate their staked share balance relative to the actual tokens held by the contract. This breaks the security guarantee of accurate accounting, as the contract assumes that the number of tokens transferred matches the number of shares recorded.

Impact

The impact is significant because it can lead to inaccurate accounting of staked shares. This discrepancy can be exploited by attackers to manipulate their staked share balance, potentially leading to unauthorized rewards or affecting the distribution of staking rewards. The financial integrity of the staking mechanism is compromised, as the actual tokens held by the contract may not match the recorded staked shares. But it also depends on whether the indexToken implements transfer fees or non-standard behaviors. If such tokens are used, the risk is higher, as the discrepancy between transferred tokens and recorded shares becomes more pronounced.

Tools Used

manual review

An attacker can exploit this vulnerability by staking tokens with transfer fees:

1. Assume a Token with Transfer Fees:

  • The indexToken charges a 1% fee on transfers.

2. Staking Tokens:

  • The attacker calls the stake function with 1000 shares.

  • The safeTransferFrom call transfers only 990 tokens due to the 1% fee.

3.Discrepancy in Accounting:

  • The contract records 1000 shares as staked, but only 990 tokens are actually received.

  • The attacker effectively stakes fewer tokens than recorded, potentially gaining an advantage in reward distribution.

// Attacker calls stake with 1000 shares
vaultRouterBranch.stake(vaultId, 1000);
// Due to transfer fee, only 990 tokens are transferred
IERC20(vault.indexToken).safeTransferFrom(msg.sender, address(this), 1000);

Recommendations

Implement a check to verify the actual number of tokens transferred by safeTransferFrom and adjust the internal accounting accordingly.

function stake(uint128 vaultId, uint128 shares) external {
// Transfer shares from actor and verify the actual amount received
uint256 initialBalance = IERC20(vault.indexToken).balanceOf(address(this));
IERC20(vault.indexToken).safeTransferFrom(msg.sender, address(this), shares);
uint256 finalBalance = IERC20(vault.indexToken).balanceOf(address(this));
uint256 actualReceivedShares = finalBalance - initialBalance;
// Use actualReceivedShares for accounting
UD60x18 updatedActorShares = ud60x18(actor.shares).add(ud60x18(actualReceivedShares));
// Update actor staked shares
wethRewardDistribution.setActorShares(actorId, updatedActorShares);
// Emit an event
emit LogStake(vaultId, msg.sender, actualReceivedShares);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Out of scope

Support

FAQs

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