Skip to content

Commit cfe398c

Browse files
committed
ERC721 and ERC20 facets
1 parent 46ce3c8 commit cfe398c

File tree

4 files changed

+127
-44
lines changed

4 files changed

+127
-44
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
pragma solidity >=0.8.30;
33

44

5-
contract ERC20 {
5+
contract ERC20Facet {
66

77
// ERC-6093: Custom errors for ERC-20
88
error ERC20InsufficientBalance(address _sender, uint256 _balance, uint256 _needed);

src/ERC20/ERC20/libraries/LibERC20.sol

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,34 @@ library LibERC20 {
3131
assembly {
3232
s.slot := position
3333
}
34-
}
34+
}
3535

36-
function transfer(address _to, uint256 _value) internal {
36+
function mint(address _account, uint256 _value) internal {
3737
ERC20Storage storage s = getStorage();
38-
if (_to == address(0)) {
38+
if (_account == address(0)) {
3939
revert ERC20InvalidReceiver(address(0));
4040
}
41-
uint256 fromBalance = s.balanceOf[msg.sender];
42-
if (fromBalance < _value) {
43-
revert ERC20InsufficientBalance(msg.sender, fromBalance, _value);
41+
unchecked {
42+
s.totalSupply += _value;
43+
s.balanceOf[_account] += _value;
44+
}
45+
emit Transfer(address(0), _account, _value);
46+
}
47+
48+
function burn(address _account, uint256 _value) internal {
49+
ERC20Storage storage s = getStorage();
50+
if (_account == address(0)) {
51+
revert ERC20InvalidSender(address(0));
52+
}
53+
uint256 accountBalance = s.balanceOf[_account];
54+
if (accountBalance < _value) {
55+
revert ERC20InsufficientBalance(_account, accountBalance, _value);
4456
}
4557
unchecked {
46-
s.balanceOf[msg.sender] = fromBalance - _value;
47-
s.balanceOf[_to] += _value;
58+
s.balanceOf[_account] = accountBalance - _value;
59+
s.totalSupply -= _value;
4860
}
49-
emit Transfer(msg.sender, _to, _value);
61+
emit Transfer(_account, address(0), _value);
5062
}
5163

5264
function transferFrom(address _from, address _to, uint256 _value) internal {
@@ -71,5 +83,7 @@ library LibERC20 {
7183
s.balanceOf[_to] += _value;
7284
}
7385
emit Transfer(_from, _to, _value);
74-
}
86+
}
87+
88+
7589
}
Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// SPDX-License-Identifier: UNLICENSED
1+
// SPDX-License-Identifier: MIT
22
pragma solidity >=0.8.30;
33

44

@@ -12,7 +12,7 @@ interface IERC721Receiver {
1212
/// @notice A complete, dependency-free ERC-721 implementation using the project's storage pattern.
1313
/// @dev This contract provides metadata, ownership, approvals, safe transfers (with local IERC721Receiver check),
1414
/// minting, burning, and helpers. It intentionally avoids external imports.
15-
contract ERC721 {
15+
contract ERC721Facet {
1616

1717
// ERC-6093: Custom errors for ERC-721
1818
error ERC721InvalidOwner(address _owner);
@@ -168,6 +168,8 @@ contract ERC721 {
168168
// non-IERC721Receiver implementer
169169
revert ERC721InvalidReceiver(_to);
170170
} else {
171+
// Return the revert reason
172+
// "memory-safe" means we used memory safely so Solidity does not disable optimizations
171173
assembly ("memory-safe") {
172174
revert(add(reason, 0x20), mload(reason))
173175
}
@@ -212,41 +214,13 @@ contract ERC721 {
212214
// non-IERC721Receiver implementer
213215
revert ERC721InvalidReceiver(_to);
214216
} else {
217+
// Return the revert reason
218+
// "memory-safe" means we used memory safely so Solidity does not disable optimizations
215219
assembly ("memory-safe") {
216220
revert(add(reason, 0x20), mload(reason))
217221
}
218222
}
219223
}
220224
}
221-
}
222-
223-
function _mint(address _to, uint256 _tokenId) internal {
224-
ERC721Storage storage s = getStorage();
225-
if (_to == address(0)) {
226-
revert ERC721InvalidReceiver(address(0));
227-
}
228-
if (s.ownerOf[_tokenId] != address(0)) {
229-
revert ERC721NonexistentToken(_tokenId);
230-
}
231-
s.ownerOf[_tokenId] = _to;
232-
unchecked {
233-
s.balanceOf[_to]++;
234-
}
235-
emit Transfer(address(0), _to, _tokenId);
236-
}
237-
238-
function _burn(uint256 _tokenId) internal {
239-
ERC721Storage storage s = getStorage();
240-
address owner = s.ownerOf[_tokenId];
241-
if (owner == address(0)) {
242-
revert ERC721NonexistentToken(_tokenId);
243-
}
244-
delete s.ownerOf[_tokenId];
245-
delete s.approved[_tokenId];
246-
unchecked {
247-
s.balanceOf[owner]--;
248-
}
249-
emit Transfer(owner, address(0), _tokenId);
250-
}
251-
225+
}
252226
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity >=0.8.30;
3+
4+
library LibERC721 {
5+
6+
// ERC-6093: Custom errors for ERC-721
7+
error ERC721NonexistentToken(uint256 _tokenId);
8+
error ERC721IncorrectOwner(address _sender, uint256 _tokenId, address _owner);
9+
error ERC721InvalidSender(address _sender);
10+
error ERC721InvalidReceiver(address _receiver);
11+
error ERC721InsufficientApproval(address _operator, uint256 _tokenId);
12+
13+
14+
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
15+
16+
// Struct storage position defined by keccak256 hash
17+
// of diamond storage identifier
18+
bytes32 constant STORAGE_POSITION = keccak256("compose.erc721");
19+
20+
// Storage defined using the ERC-8042 standard
21+
// @custom:storage-location erc8042:compose.erc721
22+
struct ERC721Storage {
23+
string name;
24+
string symbol;
25+
mapping(uint256 tokenId => address owner) ownerOf;
26+
mapping(address owner => uint256 balance) balanceOf;
27+
mapping(uint256 tokenId => address approved) approved;
28+
mapping(address owner => mapping(address operator => bool approved)) isApprovedForAll;
29+
}
30+
31+
function getStorage() internal pure returns (ERC721Storage storage s) {
32+
bytes32 position = STORAGE_POSITION;
33+
assembly {
34+
s.slot := position
35+
}
36+
}
37+
38+
function transferFrom(address _from, address _to, uint256 _tokenId) internal {
39+
ERC721Storage storage s = getStorage();
40+
if (_to == address(0)) {
41+
revert ERC721InvalidReceiver(address(0));
42+
}
43+
address owner = s.ownerOf[_tokenId];
44+
if (owner == address(0)) {
45+
revert ERC721NonexistentToken(_tokenId);
46+
}
47+
if (owner != _from) {
48+
revert ERC721IncorrectOwner(_from, _tokenId, owner);
49+
}
50+
if (msg.sender != _from) {
51+
if(!s.isApprovedForAll[_from][msg.sender] && msg.sender != s.approved[_tokenId]) {
52+
revert ERC721InsufficientApproval(msg.sender, _tokenId);
53+
}
54+
}
55+
delete s.approved[_tokenId];
56+
unchecked {
57+
s.balanceOf[_from]--;
58+
s.balanceOf[_to]++;
59+
}
60+
s.ownerOf[_tokenId] = _to;
61+
emit Transfer(_from, _to, _tokenId);
62+
}
63+
64+
function mint(address _to, uint256 _tokenId) internal {
65+
ERC721Storage storage s = getStorage();
66+
if (_to == address(0)) {
67+
revert ERC721InvalidReceiver(address(0));
68+
}
69+
if (s.ownerOf[_tokenId] != address(0)) {
70+
revert ERC721InvalidSender(address(0));
71+
}
72+
s.ownerOf[_tokenId] = _to;
73+
unchecked {
74+
s.balanceOf[_to]++;
75+
}
76+
emit Transfer(address(0), _to, _tokenId);
77+
}
78+
79+
function burn(uint256 _tokenId) internal {
80+
ERC721Storage storage s = getStorage();
81+
address owner = s.ownerOf[_tokenId];
82+
if (owner == address(0)) {
83+
revert ERC721NonexistentToken(_tokenId);
84+
}
85+
delete s.ownerOf[_tokenId];
86+
delete s.approved[_tokenId];
87+
unchecked {
88+
s.balanceOf[owner]--;
89+
}
90+
emit Transfer(owner, address(0), _tokenId);
91+
}
92+
93+
94+
95+
}

0 commit comments

Comments
 (0)