DeFiFoundry
50,000 USDC
View results
Submission Details
Severity: low
Invalid

Unchecked ERC-20 Transfer in _transferToken

Summary

The _transferToken function in PerpetualVault.sol uses unsafe ERC-20 transfer operations, which do not check return values. This could lead to silent transaction failures, causing funds to be lost, stuck, or misdirected if a token does not return true as expected.

Vulnerability Details

In PerpetualVault.sol, the _transferToken function calls transfer() without verifying the return value. Certain tokens (e.g., USDT, BNB) do not return true on success, which can cause issues.

function _transferToken(uint256 depositId, uint256 amount) internal {
uint256 fee;
if (amount > depositInfo[depositId].amount) {
fee = (amount - depositInfo[depositId].amount) * governanceFee / BASIS_POINTS_DIVISOR;
if (fee > 0) {
collateralToken.safeTransfer(treasury, fee);
}
}
try collateralToken.transfer(depositInfo[depositId].recipient, amount - fee) {}
catch {
@>> collateralToken.transfer(treasury, amount - fee);
emit TokenTranferFailed(depositInfo[depositId].recipient, amount - fee);
}
totalDepositAmount -= depositInfo[depositId].amount;
emit GovernanceFeeCollected(address(collateralToken), fee);
}

PoC

function _transferToken(uint256 depositId, uint256 amount) private {
uint256 fee = _calculateFee(amount);
try collateralToken.transfer(depositInfo[depositId].recipient, amount - fee) {}
catch { emit TokenTranferFailed(depositInfo[depositId].recipient, amount - fee); }
collateralToken.transfer(treasury, fee);
}

Steps to Reproduce:

  • Deploy a custom ERC-20 token that does not return a boolean value for transfer().

  • Call _transferToken() using this token.

  • The transfer may fail silently, leaving the contract in an inconsistent state.

  • The funds may not reach the recipient or treasury, yet the function execution continues.

Impact

  • Loss of Funds: If collateralToken.transfer() fails, funds may be permanently stuck or lost.

  • Incomplete Transactions: The contract assumes success and does not revert, leading to incorrect accounting.

  • Compatibility Issues: Certain tokens like USDT or BNB do not return true, which can cause execution to break.

Tools Used

Manual Review

Recommendations

SafeERC20.safeTransfer() correctly handles ERC-20 return values and reverts on failure.

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
function _transferToken(uint256 depositId, uint256 amount) private {
uint256 fee = _calculateFee(amount);
try SafeERC20.safeTransfer(collateralToken, depositInfo[depositId].recipient, amount - fee) {}
catch { emit TokenTranferFailed(depositInfo[depositId].recipient, amount - fee); }
SafeERC20.safeTransfer(collateralToken, treasury, fee);
}
  • Check Transfer Return Values

Ensure that transfers succeed before continuing execution.

  • Emit Failure Events & Handle Errors

If a transfer fails, halt execution instead of continuing with an inconsistent state.

Updates

Lead Judging Commences

n0kto Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Out of scope
Assigned finding tags:

Suppositions

There is no real proof, concrete root cause, specific impact, or enough details in those submissions. Examples include: "It could happen" without specifying when, "If this impossible case happens," "Unexpected behavior," etc. Make a Proof of Concept (PoC) using external functions and realistic parameters. Do not test only the internal function where you think you found something.

n0kto Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Out of scope
Assigned finding tags:

Suppositions

There is no real proof, concrete root cause, specific impact, or enough details in those submissions. Examples include: "It could happen" without specifying when, "If this impossible case happens," "Unexpected behavior," etc. Make a Proof of Concept (PoC) using external functions and realistic parameters. Do not test only the internal function where you think you found something.

Support

FAQs

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

Give us feedback!