Skip to content

Latest commit

 

History

History
295 lines (212 loc) · 7.32 KB

RACE-8.md

File metadata and controls

295 lines (212 loc) · 7.32 KB

Note: All 8 questions in this RACE are based on the InSecureumERC721 contract. This is the same contract you will see for all the 8 questions in this RACE. InSecureumERC721 is adapted from a well-known contract. The question is below the shown contract.

pragma solidity >=0.8.0;

abstract contract InSecureumERC721 {

   event Transfer(address indexed from, address indexed to, uint256 indexed id);

   event Approval(address indexed owner, address indexed spender, uint256 indexed id);

   event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

   string public name;

   string public symbol;

   function tokenURI(uint256 id) public view virtual returns (string memory);

   mapping(uint256 => address) internal _ownerOf;

   mapping(address => uint256) internal _balanceOf;

   function ownerOf(uint256 id) public view virtual returns (address owner) {
       require((owner = _ownerOf[id]) != address(0), "NOT_MINTED");
   }

   function balanceOf(address owner) public view virtual returns (uint256) {
       require(owner != address(0), "ZERO_ADDRESS");

       return _balanceOf[owner];
   }

   mapping(uint256 => address) public getApproved;

   mapping(address => mapping(address => bool)) public isApprovedForAll;

   constructor(string memory _name, string memory _symbol) {
       name = _name;
       symbol = _symbol;
   }

   function approve(address spender, uint256 id) public virtual {
       address owner = _ownerOf[id];

       require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED");

       getApproved[id] = spender;

       emit Approval(owner, spender, id);
   }

   function setApprovalForAll(address operator, bool approved) public virtual {
       isApprovedForAll[msg.sender][operator] = approved;

       emit ApprovalForAll(msg.sender, operator, approved);
   }

   function transferFrom(
       address from,
       address to,
       uint256 id
   ) public virtual {
       require(to != address(0), "INVALID_RECIPIENT");

       require(
           msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],
           "NOT_AUTHORIZED"
       );

       unchecked {
           _balanceOf[from]--;

           _balanceOf[to]++;
       }

       _ownerOf[id] = to;

       delete getApproved[id];

       emit Transfer(from, to, id);
   }

   function safeTransferFrom(
       address from,
       address to,
       uint256 id
   ) public virtual {
       transferFrom(from, to, id);

       require(
           to.code.length == 0 ||
               ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") ==
               ERC721TokenReceiver.onERC721Received.selector,
           "UNSAFE_RECIPIENT"
       );
   }

   function safeTransferFrom(
       address from,
       address to,
       uint256 id,
       bytes calldata data
   ) public virtual {
       transferFrom(from, to, id);

       require(
           to.code.length == 0 ||
               ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==
               ERC721TokenReceiver.onERC721Received.selector,
           "UNSAFE_RECIPIENT"
       );
   }

   function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
       return
           interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
           interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
           interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
   }

   function _mint(address to, uint256 id) internal virtual {
       require(to != address(0), "INVALID_RECIPIENT");

       require(_ownerOf[id] == address(0), "ALREADY_MINTED");

       unchecked {
           _balanceOf[to]++;
       }

       _ownerOf[id] = to;

       emit Transfer(address(0), to, id);
   }

   function _burn(uint256 id) external virtual {
       address owner = _ownerOf[id];

       require(owner != address(0), "NOT_MINTED");

       unchecked {
           _balanceOf[owner]--;
       }

       delete _ownerOf[id];

       delete getApproved[id];

       emit Transfer(owner, address(0), id);
   }

   function _safeMint(address to, uint256 id) internal virtual {
       _mint(to, id);

       require(
           to.code.length == 0 ||
               ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") ==
               ERC721TokenReceiver.onERC721Received.selector,
           "UNSAFE_RECIPIENT"
       );
   }

   function _safeMint(
       address to,
       uint256 id,
       bytes memory data
   ) internal virtual {
       _mint(to, id);

       require(
           to.code.length == 0 ||
               ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==
               ERC721TokenReceiver.onERC721Received.selector,
           "UNSAFE_RECIPIENT"
       );
   }
}

abstract contract ERC721TokenReceiver {
   function onERC721Received(
       address,
       address,
       uint256,
       bytes calldata
   ) external virtual returns (bytes4) {
       return ERC721TokenReceiver.onERC721Received.selector;
   }
}

[Q1] Which of the following is/are true?

(A): NFT ownership is tracked by _ownerOf
(B): NFT balance is tracked by _balanceOf
(C): NFT approvals are tracked by getApproved
(D): NFT operator can transfer all of owner’s NFTs

[Answers] A, B, C, D

[Q2] InSecureumERC721 recognizes the following role(s)

(A): Owner
(B): Spender (Approved address)
(C): Operator
(D): None of the above

[Answers] A, B, C

[Q3] The security concern(s) addressed explicitly in _mint include

(A): Prevent minting to zero address
(B): Prevent reminting of NFTs
(C): Transparency by emitting event
(D): None of the above

[Answers] A, B, C

[Q4] The security concerns in _burn include

(A): Anyone can arbitrarily burn NFTs
(B): Potential integer underflow because of unchecked
(C): Incorrect emission of event
(D): None of the above

[Answers] A

[Q5] The security concern(s) addressed explicitly in _safeMint include

(A): Validating if the recipient is an EOA
(B): Ensuring that the recipient can only be an EOA
(C): Validating if the recipient is an ERC721 aware contract
(D): None of the above

[Answers] A, C

[Q6] Function approve

(A): Allows the NFT owner to approve a spender
(B): Allows the NFT spender to approve an operator
(C): Allows the NFT operator to approve a spender
(D): None of the above

[Answers] A, C

[Q7] Function setApprovalForAll

(A): Approves msg.sender to manage operator’s NFTs
(B): Gives everyone approval to manage msg.sender’s NFTs
(C): Revokes everyone’s approvals to manage msg.sender’s NFTs
(D): None of the above

[Answers] D

[Q8] The security concern(s) in transferFrom include

(A): Allowing the msg.sender to transfer any NFT
(B): NFTs potentially stuck in recipient contracts
(C): Potential integer underflow
(D): None of the above

[Answers] A, B, C