Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: high
Valid

Incorrect code logic: SantasList::buyPresent() burns Token from wrong address (burns present receiver token instead of the caller).

Summary

To align the buyPresent and _mintAndIncrement function with the intended logic (https://github.com/Cyfrin/2023-11-Santas-List/blob/6627a6387adab89ae2ba2e82b38296723261c08a/src/SantasList.sol#L168C1-L171C8) that the caller (not the present receiver) pays for the present with their SantaToken, we would need to modify the function to burn the tokens from the caller's balance instead of the present receiver's balance. Additionally, we would need to ensure that the caller has approved the SantasList contract to spend the PURCHASED_PRESENT_COST amount of SantaToken.

Recommendations

Here's how we can modify the buyPresent function:

  1. Import ERC20Burnable.sol from Openzeppelin:

import {ERC20Burnable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
  1. Modify buyPresent():

function buyPresent(address presentReceiver) external {
// Burn the SantaTokens from the caller's balance, not the presentReceiver's balance
- i_santaToken.burn(presentReceiver);
+ i_santaToken.burnFrom(msg.sender, PURCHASED_PRESENT_COST);
// Mint the NFT to the presentReceiver
- _mintAndIncrement();
+ _mintAndIncrement(presentReceiver);
}

In the modified function, burnFrom is used instead of burn. The burnFrom function is typically part of an ERC20 token's implementation and allows a contract to burn tokens from a user's balance, provided that the user has set an appropriate allowance for the contract.

The burnFrom function should check that the SantasList contract has been approved by the caller to spend at least PURCHASED_PRESENT_COST amount of SantaToken. If the allowance is less than the cost, the burnFrom function should revert.

  1. The _mintAndIncrement function should also be modified to accept an address parameter so that the NFT can be minted directly to the presentReceiver:

- function _mintAndIncrement() private {
+ function _mintAndIncrement(address to) private {
- _safeMint(msg.sender, s_tokenCounter++);
+ _safeMint(to, s_tokenCounter++);
}

With these changes, the buyPresent function will correctly implement the logic described in the comment, requiring users to approve the SantasList contract to spend their SantaToken before they can call buyPresent. The caller will be the one paying for the present, and the NFT will be minted to the specified presentReceiver.

Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

buyPresent should use msg.sender

Current implementation allows a malicious actor to burn someone else's tokens as the burn function doesn't actually check for approvals.

Price is not enforced in buyPresent

This line indicates that the intended cost of presents for naughty people should be 2e18: https://github.com/Cyfrin/2023-11-Santas-List/blob/6627a6387adab89ae2ba2e82b38296723261c08a/src/SantasList.sol#L87 PURCHASE_PRESENT_COST should be implemented to enforce the cost of presents.

buyPresent should send to presentReceiver

Support

FAQs

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