DevStation / LaunchKit / Templates / SimpleERC721

SimpleERC721

A standard ERC-721 collection with base URI, max supply cap, and owner-controlled sequential minting.

Deploy This Template
SimpleERC721.sol
solidity
1// SPDX-License-Identifier: MIT
2pragma solidity ^0.8.20;
3 
4interface IERC721Receiver {
5 function onERC721Received(address, address, uint256, bytes calldata) external returns (bytes4);
6}
7 
8contract SimpleERC721 {
9 string public name;
10 string public symbol;
11 string private baseURI;
12 address public owner;
13 uint256 public immutable maxSupply;
14 uint256 public nextTokenId;
15 
16 mapping(uint256 => address) public ownerOf;
17 mapping(address => uint256) public balanceOf;
18 mapping(uint256 => address) public getApproved;
19 mapping(address => mapping(address => bool)) public isApprovedForAll;
20 
21 event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
22 event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
23 event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
24 
25 constructor(string memory name_, string memory symbol_, string memory baseURI_, uint256 maxSupply_) {
26 name = name_;
27 symbol = symbol_;
28 baseURI = baseURI_;
29 maxSupply = maxSupply_;
30 owner = msg.sender;
31 }
32 
33 function mint(address to) external returns (uint256) {
34 require(msg.sender == owner, "NOT_OWNER");
35 require(nextTokenId < maxSupply, "SOLD_OUT");
36 uint256 id = nextTokenId++;
37 ownerOf[id] = to;
38 balanceOf[to] += 1;
39 emit Transfer(address(0), to, id);
40 return id;
41 }
42 
43 function approve(address to, uint256 tokenId) external {
44 address holder = ownerOf[tokenId];
45 require(msg.sender == holder || isApprovedForAll[holder][msg.sender], "NOT_AUTHORIZED");
46 getApproved[tokenId] = to;
47 emit Approval(holder, to, tokenId);
48 }
49 
50 function setApprovalForAll(address operator, bool approved) external {
51 isApprovedForAll[msg.sender][operator] = approved;
52 emit ApprovalForAll(msg.sender, operator, approved);
53 }
54 
55 function transferFrom(address from, address to, uint256 tokenId) public {
56 require(ownerOf[tokenId] == from, "WRONG_FROM");
57 require(to != address(0), "ZERO_ADDR");
58 require(
59 msg.sender == from || isApprovedForAll[from][msg.sender] || getApproved[tokenId] == msg.sender,
60 "NOT_AUTHORIZED"
61 );
62 delete getApproved[tokenId];
63 balanceOf[from] -= 1;
64 balanceOf[to] += 1;
65 ownerOf[tokenId] = to;
66 emit Transfer(from, to, tokenId);
67 }
68 
69 function safeTransferFrom(address from, address to, uint256 tokenId) external {
70 transferFrom(from, to, tokenId);
71 if (to.code.length != 0) {
72 require(
73 IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, "") ==
74 IERC721Receiver.onERC721Received.selector,
75 "UNSAFE_RECIPIENT"
76 );
77 }
78 }
79 
80 function tokenURI(uint256 tokenId) external view returns (string memory) {
81 require(ownerOf[tokenId] != address(0), "NOT_MINTED");
82 return string(abi.encodePacked(baseURI, _toString(tokenId)));
83 }
84 
85 function supportsInterface(bytes4 id) external pure returns (bool) {
86 return id == 0x80ac58cd || id == 0x01ffc9a7;
87 }
88 
89 function _toString(uint256 v) internal pure returns (string memory) {
90 if (v == 0) return "0";
91 uint256 j = v;
92 uint256 len;
93 while (j != 0) { len++; j /= 10; }
94 bytes memory b = new bytes(len);
95 while (v != 0) { len--; b[len] = bytes1(uint8(48 + v % 10)); v /= 10; }
96 return string(b);
97 }
98}
DevStation
Loading console…