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_, address initialOwner_) {
26 require(initialOwner_ != address(0), "ZERO_OWNER");
27 name = name_;
28 symbol = symbol_;
29 baseURI = baseURI_;
30 maxSupply = maxSupply_;
31 owner = initialOwner_;
32 }
33 
34 function mint(address to) external returns (uint256) {
35 require(msg.sender == owner, "NOT_OWNER");
36 require(nextTokenId < maxSupply, "SOLD_OUT");
37 uint256 id = nextTokenId++;
38 ownerOf[id] = to;
39 balanceOf[to] += 1;
40 emit Transfer(address(0), to, id);
41 return id;
42 }
43 
44 function approve(address to, uint256 tokenId) external {
45 address holder = ownerOf[tokenId];
46 require(msg.sender == holder || isApprovedForAll[holder][msg.sender], "NOT_AUTHORIZED");
47 getApproved[tokenId] = to;
48 emit Approval(holder, to, tokenId);
49 }
50 
51 function setApprovalForAll(address operator, bool approved) external {
52 isApprovedForAll[msg.sender][operator] = approved;
53 emit ApprovalForAll(msg.sender, operator, approved);
54 }
55 
56 function transferFrom(address from, address to, uint256 tokenId) public {
57 require(ownerOf[tokenId] == from, "WRONG_FROM");
58 require(to != address(0), "ZERO_ADDR");
59 require(
60 msg.sender == from || isApprovedForAll[from][msg.sender] || getApproved[tokenId] == msg.sender,
61 "NOT_AUTHORIZED"
62 );
63 delete getApproved[tokenId];
64 balanceOf[from] -= 1;
65 balanceOf[to] += 1;
66 ownerOf[tokenId] = to;
67 emit Transfer(from, to, tokenId);
68 }
69 
70 function safeTransferFrom(address from, address to, uint256 tokenId) external {
71 transferFrom(from, to, tokenId);
72 if (to.code.length != 0) {
73 require(
74 IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, "") ==
75 IERC721Receiver.onERC721Received.selector,
76 "UNSAFE_RECIPIENT"
77 );
78 }
79 }
80 
81 function tokenURI(uint256 tokenId) external view returns (string memory) {
82 require(ownerOf[tokenId] != address(0), "NOT_MINTED");
83 return string(abi.encodePacked(baseURI, _toString(tokenId)));
84 }
85 
86 function supportsInterface(bytes4 id) external pure returns (bool) {
87 return id == 0x80ac58cd || id == 0x01ffc9a7;
88 }
89 
90 function _toString(uint256 v) internal pure returns (string memory) {
91 if (v == 0) return "0";
92 uint256 j = v;
93 uint256 len;
94 while (j != 0) { len++; j /= 10; }
95 bytes memory b = new bytes(len);
96 while (v != 0) { len--; b[len] = bytes1(uint8(48 + v % 10)); v /= 10; }
97 return string(b);
98 }
99}
DevStation
Loading console…