code-423n4 / 2024-07-traitforge-findings

0 stars 0 forks source link

Excess ether sent during forging are not refunded and lost to the `EntityForging` contract #27

Closed c4-bot-2 closed 1 month ago

c4-bot-2 commented 2 months ago

Lines of code

https://github.com/code-423n4/2024-07-traitforge/blob/main/contracts/EntityForging/EntityForging.sol#L125-L126 https://github.com/code-423n4/2024-07-traitforge/blob/main/contracts/EntityForging/EntityForging.sol#L146-L148 https://github.com/code-423n4/2024-07-traitforge/blob/main/contracts/EntityForging/EntityForging.sol#L156-L159

Vulnerability details

Impact

Given the scenario below:

Outcome becomes:

Thus the merger ends up losing the excess ethers sent. Given that a similar scenario is handled below in the TraitForge contract, this issue requires mitigation as well during token forging.

TraitForge.sol

function mintToken(
    bytes32[] calldata proof
  )
    public
    payable
    whenNotPaused
    nonReentrant
    onlyWhitelisted(proof, keccak256(abi.encodePacked(msg.sender)))
  {
    uint256 mintPrice = calculateMintPrice();
    require(msg.value >= mintPrice, 'Insufficient ETH send for minting.');

    ...

    uint256 excessPayment = msg.value - mintPrice;
    if (excessPayment > 0) { // @note refunds excess during token mints
      (bool refundSuccess, ) = msg.sender.call{ value: excessPayment }('');
      require(refundSuccess, 'Refund of excess payment failed.');
    }
  }

Proof of Concept

EntityForging.sol

function forgeWithListed(
    uint256 forgerTokenId,
    uint256 mergerTokenId
  ) external payable whenNotPaused nonReentrant returns (uint256) {
    ...

@>   uint256 forgingFee = _forgerListingInfo.fee;
@>   require(msg.value >= forgingFee, 'Insufficient fee for forging');
    ...

@>  uint256 devFee = forgingFee / taxCut;
@>  uint256 forgerShare = forgingFee - devFee;
    address payable forgerOwner = payable(nftContract.ownerOf(forgerTokenId));
   ...

@>  (bool success, ) = nukeFundAddress.call{ value: devFee }('');
    require(success, 'Failed to send to NukeFund');
@>  (bool success_forge, ) = forgerOwner.call{ value: forgerShare }('');
    require(success_forge, 'Failed to send to Forge Owner');
    ...

    return newTokenId;
  }

Tools Used

Manual review

Recommended Mitigation Steps

- require(msg.value >= forgingFee, 'Insufficient fee for forging');
+ require(msg.value == forgingFee, 'Insufficient fee for forging');

Assessed type

Payable

c4-judge commented 2 months ago

koolexcrypto changed the severity to QA (Quality Assurance)

c4-judge commented 1 month ago

koolexcrypto marked the issue as grade-c

c4-judge commented 1 month ago

This previously downgraded issue has been upgraded by koolexcrypto

c4-judge commented 1 month ago

koolexcrypto marked the issue as duplicate of #687

c4-judge commented 1 month ago

koolexcrypto marked the issue as duplicate of #218

c4-judge commented 1 month ago

koolexcrypto changed the severity to QA (Quality Assurance)