# Overlap Between ERC721.transferFrom() and ERC20.transferFrom() Allows order.erc20Assets or order.baseAsset To Be ERC721 Rather Than ERC20

ERC721 and ERC20 transferFrom share selector 0x23b872dd, letting an ERC721 be passed as baseAsset/erc20Assets and permanently stuck in PuttyV2.

- Payout: Contest reward
- Severity: medium
- Program: Putty
- Credited: kirk-baird
- Disclosed: 2022-06-27
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-06-putty-findings/issues/52
- Library page: https://bugbountylibrary.com/r/c4%3A2022-06-putty%3AM-08
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:business-logic

**Target:** PuttyV2 order fill/exercise/withdraw asset transfer logic
**Root cause:** ERC20.transferFrom and ERC721.transferFrom share the same 4-byte selector 0x23b872dd, so the contract's incoming transferFrom call succeeds for an ERC721 passed as an ERC20 asset, but the outgoing ERC20.safeTransfer/transfer call has no matching ERC721 function.
**Steps:**
1. Create an order where baseAsset or erc20Assets is an ERC721 contract address instead of ERC20.
2. Call `fillOrder()`; the incoming `transferFrom(address,address,uint256)` (selector `0x23b872dd`) matches ERC721.transferFrom and moves the NFT into PuttyV2.
3. Attempt `exercise()` or `withdraw()`; outgoing `ERC20.safeTransfer()` calls `transfer(to, amount)` which does not exist on ERC721, so the transfer reverts.
4. NFT remains permanently stuck in the contract.
**How found:** Noticed that ERC20.transferFrom and ERC721.transferFrom have identical signatures/selectors (0x23b872dd) and reasoned that the contract's asset-type-agnostic transferFrom call would accept an ERC721 where an ERC20 is expected.
**Exploitation:** Attacker or careless user supplies an ERC721 address as an ERC20 asset in an order; fillOrder pulls the NFT in via the colliding transferFrom selector, and no exercise/withdraw path can move it out, locking the token.
**Insight:** When a contract calls transferFrom on an address typed only as 'asset', check whether ERC721 and ERC20 share the selector and whether the outbound path (transfer vs safeTransfer) is symmetric; asymmetric in/out interfaces can trap tokens.
