The buyPresent
function is implemented contrary to the README (which says it requires 2e18 SantaToken
), and the function comments, which says it should only be callable by those with SantaToken
s AND that you'll need to approve SantasList
to spend your SantaToken
s.
Apart from the implementation seeming to be contrary to what's intended, it allows anyone to mint NFTs from an EXTRA_NICE user, which is very naughty.
buyPresent
does not check for token approval by itself, and requiring approval for calling burn on an ERC20 token is not part of the standard, so it's not in solmate
. Further buyPresent
does not check for any balance of SantaToken
from msg.sender
, nor does it burn any SantaToken
from msg.sender
. Instead, it burns the SantaToken
from a selected victim, while sadly the parameter is called presentReceiver
, this address is the victim, and the NFT receiver is msg.sender
. There is a constant for the purchase cost, but it's never used. Note: if it were used, it should probably also be in SantaToken
(or passed into it), so it didn't use magic numbers in SantaToken.mint
and SantaToken.burn
The biggest issue here is that it allows anyone to mint NFTs from those that have 1e18 SantaToken
, while burning the victim's 1e18 SantaToken
.
There's a somewhat smaller impact in that the cost of the NFT is only 1e18, contrary to the stated 2e18. This is somewhat mitigated by the fact that only 1e18 SantaToken
are issued to EXTRA_NICE users, so they could still (in theory) buy an NFT for a friend (if it weren't stolen before then as above).
Similar to the issue with the rug-pull user being able to transfer all SantaToken
, thieves would be most effective at this by listening for the Transfer
event on SantaToken
, to be able to mint NFTs very quickly after the token were minted.
forge test
. Wrote a test where the msg.sender
a) doesn't have any SantaToken
, b) didn't approve spend (no one did) c) presentReceiver
didn't have 2e18 (contrary to README). The thief ended up with the NFT, and the EXTRA_NICE user ended up with just their own NFT.
In buyPresent
, Check for required SantaToken
balance from msg.sender
, utilize the PURCHASED_PRESENT_COST
constant.
Use the PURCHASED_PRESENT_COST
constant in SantaToken
as well, or pass in the value to the burn
and mint
functions.
Check for token approval before burning if that's what is intended
Burn SantaToken
from msg.sender
, not from presentReceiver
Don't call _mintAndIncrement
, as that mints the NFT to the msg.sender
, where the intention here is to mint to someone else, call _safeMint
directly, passing presentReceiver
as the to
address
.
Write tests for all intended functionality, as well as test proving that contrary conditions don't allow unintended functionality.
Current implementation allows a malicious actor to burn someone else's tokens as the burn function doesn't actually check for approvals.
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.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.