Created
February 28, 2022 08:29
-
-
Save z0r0z/5c4d786c491e52eabde00ee47933e37d to your computer and use it in GitHub Desktop.
what ERC-721 could have been
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: AGPL-3.0-only | |
pragma solidity >=0.8.0; | |
/// @notice Modern and gas efficient NFT implementation adhering as closely to ERC20 interface. | |
/// @author Ross, modified from (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol) | |
abstract contract NFT { | |
/*/////////////////////////////////////////////////////////////// | |
EVENTS | |
//////////////////////////////////////////////////////////////*/ | |
event Transfer(address indexed from, address indexed to, uint256 indexed id); | |
event Approval(address indexed owner, address indexed spender, uint256 indexed id); | |
/*/////////////////////////////////////////////////////////////// | |
METADATA STORAGE/LOGIC | |
//////////////////////////////////////////////////////////////*/ | |
string public name; | |
string public symbol; | |
uint8 public constant decimals = 0; | |
function tokenURI(uint256 id) public view virtual returns (string memory); | |
/*/////////////////////////////////////////////////////////////// | |
NFT STORAGE | |
//////////////////////////////////////////////////////////////*/ | |
uint256 public totalSupply; | |
mapping(address => uint256) public balanceOf; | |
mapping(uint256 => address) public ownerOf; | |
mapping(uint256 => address) public getApproved; | |
/*/////////////////////////////////////////////////////////////// | |
CONSTRUCTOR | |
//////////////////////////////////////////////////////////////*/ | |
constructor(string memory _name, string memory _symbol) { | |
name = _name; | |
symbol = _symbol; | |
} | |
/*/////////////////////////////////////////////////////////////// | |
NFT LOGIC | |
//////////////////////////////////////////////////////////////*/ | |
function approve(address spender, uint256 id) public virtual returns (bool) { | |
address owner = ownerOf[id]; | |
require(msg.sender == owner, "NOT_OWNER"); | |
getApproved[id] = spender; | |
emit Approval(owner, spender, id); | |
return true; | |
} | |
function transfer(address to, uint256 id) public virtual returns (bool) { | |
address owner = ownerOf[id]; | |
require(msg.sender == owner, "NOT_OWNER"); | |
// Underflow of the sender's balance is impossible because we check for | |
// ownership above and the recipient's balance can't realistically overflow. | |
unchecked { | |
balanceOf[owner]--; | |
balanceOf[to]++; | |
} | |
delete getApproved[id]; | |
ownerOf[id] = to; | |
emit Transfer(owner, to, id); | |
return true; | |
} | |
function transferFrom( | |
address from, | |
address to, | |
uint256 id | |
) public virtual returns (bool) { | |
require(from == ownerOf[id], "WRONG_FROM"); | |
require(msg.sender == from || msg.sender == getApproved[id], "NOT_AUTHORIZED"); | |
// Underflow of the sender's balance is impossible because we check for | |
// ownership above and the recipient's balance can't realistically overflow. | |
unchecked { | |
balanceOf[from]--; | |
balanceOf[to]++; | |
} | |
ownerOf[id] = to; | |
delete getApproved[id]; | |
emit Transfer(from, to, id); | |
return true; | |
} | |
/*/////////////////////////////////////////////////////////////// | |
INTERNAL MINT/BURN LOGIC | |
//////////////////////////////////////////////////////////////*/ | |
function _mint(address to, uint256 id) internal virtual { | |
require(ownerOf[id] == address(0), "ALREADY_MINTED"); | |
// Counter overflow is incredibly unrealistic. | |
unchecked { | |
balanceOf[to]++; | |
} | |
ownerOf[id] = to; | |
emit Transfer(address(0), to, id); | |
} | |
function _burn(uint256 id) internal virtual { | |
address owner = ownerOf[id]; | |
require(ownerOf[id] != address(0), "NOT_MINTED"); | |
// Ownership check above ensures no underflow. | |
unchecked { | |
balanceOf[owner]--; | |
} | |
delete ownerOf[id]; | |
delete getApproved[id]; | |
emit Transfer(owner, address(0), id); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment