Assessment reports>Deposit Contract>High findings>Tokens with callback support can inflate the ,actualAmount
Category: Coding Mistakes

Tokens with callback support can inflate the actualAmount

High Severity
High Impact
Low Likelihood

Description

The depositFor function uses before- and after-balance checks during token transfers to account for the actual amount of transferred tokens.

function depositFor(address _token, address _for, uint256 _amount) whenNotPaused external {
    if (_amount == 0) revert DepositAmountCannotBeZero();
    if (_for == address(0)) revert CannotDepositForZeroAddress();
    if (!tokenAllowlist[_token]) revert TokenNotAllowedForStaking();
    if (capsEnabled && caps[_token] < getTokenTotalStaked(_token) + _amount) revert CapReached();
    
    uint256 balanceBefore = IERC20Metadata(_token).balanceOf(address(this));
    IERC20Metadata(_token).safeTransferFrom(msg.sender, address(this), _amount);
    uint256 actualAmount = IERC20Metadata(_token).balanceOf(address(this)) - balanceBefore;

    emit Deposit(++eventId, _for, _token, actualAmount);

    ReceiptToken(tokenMap[_token]).mint(_for, actualAmount);
}

However, tokens that support callbacks during transfer (such as ERC-777) can reenter the depositFor function, compromising ulterior calculations.

For example, a user transfers 100 tokens during a depositFor call. The initial value of balanceBefore is 0. If a callback function is invoked in the token contract and the user reenters the depositFor() function, the new balanceBefore would be equal to 100 tokens. During the reentered call, another 100 tokens would be transferred, resulting in the actualAmount being calculated as 200 minus balanceBefore (which is 100), giving an actualAmount of 100.

Meanwhile, in the initial call, the actualAmount would be calculated as 200 minus balanceBefore (which is 0), resulting in an actualAmount of 200. This creates a situation where the total accounted token amount is 300, even though only 200 tokens have actually been transferred.

Impact

This issue can lead to an inflated actualAmount value, which impairs the correct accounting of the total staked tokens.

Recommendations

We recommend implementing a reentrancy-protection mechanism to prevent such attacks, especially if tokens with callback support are allowed to be used with the SatlayerPoolV2 contract.

Remediation

This issue has been acknowledged by SatLayer, and a fix was implemented in commit 07f66277. In addition, the SatLayer team has stated that they do not plan to integrate such tokens, and they will be mindful of this issue in the future.

Zellic © 2025Back to top ↑