Open code423n4 opened 2 years ago
Pasting from another issue:
It's unlikely a contract will have all the setup required to interact with PuttyV2 but not be able to handle ERC721 tokens. Adding a check via safeMint adds a gas overhead as well as another re-entrancy attack vector so there is a tradeoff (as noted in the issue report^^).
Report: Contracts that can’t handle ERC721 tokens will lose their Putty ERC721 position tokens
In addition, some contracts may have custom logic in their onERC721Received()
implementation that is triggered only by the safe methods and not their "unsafe" counterparts.
Lines of code
https://github.com/code-423n4/2022-06-putty/blob/3b6b844bc39e897bd0bbb69897f2deff12dc3893/contracts/src/PuttyV2.sol#L302-L308 https://github.com/code-423n4/2022-06-putty/blob/3b6b844bc39e897bd0bbb69897f2deff12dc3893/contracts/src/PuttyV2Nft.sol#L11-L18
Vulnerability details
Putty uses ERC721
safeTransfer
andsafeTransferFrom
throughout the codebase to ensure that ERC721 tokens are not transferred to non ERC721 receivers. However, the initial position mint infillOrder
uses_mint
rather than_safeMint
and does not check that the receiver accepts ERC721 token transfers:PuttyV2#fillOrder
PuttyV2Nft#_mint
Impact: If a maker or taker are a contract unable to receive ERC721 tokens, their options positions may be locked and nontransferable. If the receiving contract does not provide a mechanism for interacting with Putty, they will be unable to exercise their position or withdraw assets.
Recommendation: Consider implementing the
require
check in Solmate'sERC721#_safeMint
in your own mint function:However, note that calling
_safeMint
introduces a reentrancy opportunity! If you make this change, ensure that the mint is treated as an interaction rather than an effect, and consider adding a reentrancy guard:Alternatively, document the design decision to use
_mint
and the associated risk for end users.