@@ -3,13 +3,10 @@ pragma solidity 0.8.24;
33
44import {IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol " ;
55import {IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol " ;
6- import {IERC721Receiver } from "@openzeppelin/contracts/interfaces/IERC721Receiver.sol " ;
76import {ContextUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol " ;
87import {IERC20Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol " ;
98import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol " ;
109import {IERC165 } from "@openzeppelin/contracts/interfaces/IERC165.sol " ;
11- import "./interfaces/IERC404.sol " ;
12- import "./lib/DoubleEndedQueue.sol " ;
1310
1411/// @title ERC404NullOwnerCappedUpgradeable
1512/// @notice Hybrid ERC20/ERC721 implementation with null owner support, supply cap, and upgradeability
@@ -20,11 +17,8 @@ abstract contract ERC404NullOwnerCappedUpgradeable is
2017 IERC165 ,
2118 IERC20 ,
2219 IERC20Metadata ,
23- IERC20Errors ,
24- IERC404
20+ IERC20Errors
2521{
26- using DoubleEndedQueue for DoubleEndedQueue.Uint256Deque;
27-
2822 struct TokenData {
2923 address owner; // current owner (can be address(0) for null-owner)
3024 uint88 index; // position in owned[owner] array
@@ -43,44 +37,26 @@ abstract contract ERC404NullOwnerCappedUpgradeable is
4337 uint256 totalSupply;
4438 uint256 cap;
4539
46- // === ERC404 NFT State ===
47- DoubleEndedQueue.Uint256Deque storedERC721Ids;
4840 mapping (address => uint256 []) owned;
4941 mapping (uint256 => TokenData) tokens;
5042 mapping (uint256 => address ) getApproved;
5143 mapping (address => mapping (address => bool )) isApprovedForAll;
52- mapping (address => bool ) erc721TransferExempt;
5344 uint256 minted; // Number of NFTs minted
5445 uint256 units; // Units for NFT minting (e.g., 1000 * 10^18)
55- uint256 initialChainId;
56- bytes32 initialDomainSeparator;
57- mapping (address => uint256 ) nonces;
5846
5947 // === Metadata ===
6048 string name;
6149 string symbol;
6250 }
63-
64- // =============================================================
65- // CONSTANTS
66- // =============================================================
67-
68- /// @dev Unique storage slot for EIP-7201 namespaced storage
69- /// keccak256(abi.encode(uint256(keccak256("ethscriptions.storage.ERC404NullOwnerCapped")) - 1)) & ~bytes32(uint256(0xff))
70- bytes32 private constant STORAGE_LOCATION = 0x8a0c9d8e5f7b3a2c1d4e6f8a9b7c5d3e2f1a4b6c8d9e7f5a3b2c1d4e6f8a9b00 ;
71-
51+
7252 // =============================================================
7353 // EVENTS
7454 // =============================================================
7555
7656 // ERC20 Events are inherited from IERC20 (Transfer, Approval)
7757
7858 // ERC721 Events (using different names to avoid conflicts with ERC20)
79- // event Transfer(address indexed from, address indexed to, uint256 value);
80- event ERC20Transfer (address indexed from , address indexed to , uint256 value );
8159 event ERC721Transfer (address indexed from , address indexed to , uint256 indexed id );
82- event ERC721Approval (address indexed owner , address indexed spender , uint256 indexed id );
83- event ApprovalForAll (address indexed owner , address indexed operator , bool approved );
8460
8561 // =============================================================
8662 // CUSTOM ERRORS
@@ -91,14 +67,22 @@ abstract contract ERC404NullOwnerCappedUpgradeable is
9167 error ERC20InvalidCap (uint256 cap );
9268 error InvalidUnits (uint256 units );
9369 error NotImplemented ();
70+ error NotFound ();
71+ error InvalidTokenId ();
72+ error AlreadyExists ();
73+ error InvalidRecipient ();
74+ error Unauthorized ();
75+ error OwnedIndexOverflow ();
9476
9577 // =============================================================
9678 // STORAGE ACCESSOR
9779 // =============================================================
9880
9981 function _getS () internal pure returns (TokenStorage storage $) {
82+ bytes32 slot = keccak256 ("ethscriptions.storage.ERC404NullOwnerCapped " );
83+
10084 assembly {
101- $.slot := STORAGE_LOCATION
85+ $.slot := slot
10286 }
10387 }
10488
@@ -132,38 +116,36 @@ abstract contract ERC404NullOwnerCappedUpgradeable is
132116 $.symbol = symbol_;
133117 $.cap = cap_;
134118 $.units = units_;
135- $.initialChainId = block .chainid ;
136- $.initialDomainSeparator = _computeDomainSeparator ();
137119 }
138120
139121 // =============================================================
140122 // ERC20 METADATA VIEWS
141123 // =============================================================
142124
143- function name () public view virtual override (IERC404 , IERC20Metadata ) returns (string memory ) {
125+ function name () public view virtual override (IERC20Metadata ) returns (string memory ) {
144126 TokenStorage storage $ = _getS ();
145127 return $.name;
146128 }
147129
148- function symbol () public view virtual override (IERC404 , IERC20Metadata ) returns (string memory ) {
130+ function symbol () public view virtual override (IERC20Metadata ) returns (string memory ) {
149131 TokenStorage storage $ = _getS ();
150132 return $.symbol;
151133 }
152134
153- function decimals () public pure override (IERC404 , IERC20Metadata ) returns (uint8 ) {
135+ function decimals () public pure override (IERC20Metadata ) returns (uint8 ) {
154136 return 18 ;
155137 }
156138
157139 // =============================================================
158140 // ERC20 VIEWS
159141 // =============================================================
160142
161- function totalSupply () public view virtual override ( IERC404 , IERC20 ) returns (uint256 ) {
143+ function totalSupply () public view virtual override returns (uint256 ) {
162144 TokenStorage storage $ = _getS ();
163145 return $.totalSupply;
164146 }
165147
166- function balanceOf (address account ) public view virtual override ( IERC404 , IERC20 ) returns (uint256 ) {
148+ function balanceOf (address account ) public view virtual override returns (uint256 ) {
167149 TokenStorage storage $ = _getS ();
168150 return $.balances[account];
169151 }
@@ -179,7 +161,7 @@ abstract contract ERC404NullOwnerCappedUpgradeable is
179161 return t.owner == owner_ ? 1 : 0 ;
180162 }
181163
182- function allowance (address owner , address spender ) public view virtual override ( IERC404 , IERC20 ) returns (uint256 ) {
164+ function allowance (address owner , address spender ) public view virtual override returns (uint256 ) {
183165 TokenStorage storage $ = _getS ();
184166 return $.allowances[owner][spender];
185167 }
@@ -196,17 +178,17 @@ abstract contract ERC404NullOwnerCappedUpgradeable is
196178 // ERC721 VIEWS
197179 // =============================================================
198180
199- function erc721TotalSupply () public view virtual override ( IERC404 ) returns (uint256 ) {
181+ function erc721TotalSupply () public view virtual returns (uint256 ) {
200182 TokenStorage storage $ = _getS ();
201183 return $.minted;
202184 }
203185
204- function erc721BalanceOf (address owner_ ) public view virtual override ( IERC404 ) returns (uint256 ) {
186+ function erc721BalanceOf (address owner_ ) public view virtual returns (uint256 ) {
205187 TokenStorage storage $ = _getS ();
206188 return $.owned[owner_].length ;
207189 }
208190
209- function ownerOf (uint256 id_ ) public view virtual override ( IERC404 ) returns (address ) {
191+ function ownerOf (uint256 id_ ) public view virtual returns (address ) {
210192 _validateTokenId (id_);
211193 TokenStorage storage $ = _getS ();
212194 TokenData storage t = $.tokens[id_];
@@ -216,7 +198,7 @@ abstract contract ERC404NullOwnerCappedUpgradeable is
216198 return t.owner;
217199 }
218200
219- function owned (address owner_ ) public view virtual override ( IERC404 ) returns (uint256 [] memory ) {
201+ function owned (address owner_ ) public view virtual returns (uint256 [] memory ) {
220202 TokenStorage storage $ = _getS ();
221203 return $.owned[owner_];
222204 }
@@ -229,42 +211,11 @@ abstract contract ERC404NullOwnerCappedUpgradeable is
229211 return $.getApproved[id_];
230212 }
231213
232- function isApprovedForAll (address owner_ , address operator_ ) public view virtual override ( IERC404 ) returns (bool ) {
214+ function isApprovedForAll (address owner_ , address operator_ ) public view virtual returns (bool ) {
233215 TokenStorage storage $ = _getS ();
234216 return $.isApprovedForAll[owner_][operator_];
235217 }
236218
237- function erc721TransferExempt (address account_ ) public view virtual override returns (bool ) {
238- TokenStorage storage $ = _getS ();
239- return $.erc721TransferExempt[account_];
240- }
241-
242- // =============================================================
243- // QUEUE VIEWS
244- // =============================================================
245-
246- function getERC721QueueLength () public view virtual override returns (uint256 ) {
247- TokenStorage storage $ = _getS ();
248- return $.storedERC721Ids.length ();
249- }
250-
251- function getERC721TokensInQueue (
252- uint256 start_ ,
253- uint256 count_
254- ) public view virtual override returns (uint256 [] memory ) {
255- TokenStorage storage $ = _getS ();
256- uint256 [] memory tokensInQueue = new uint256 [](count_);
257-
258- for (uint256 i = start_; i < start_ + count_;) {
259- tokensInQueue[i - start_] = $.storedERC721Ids.at (i);
260- unchecked {
261- ++ i;
262- }
263- }
264-
265- return tokensInQueue;
266- }
267-
268219 // =============================================================
269220 // OTHER VIEWS
270221 // =============================================================
@@ -285,57 +236,53 @@ abstract contract ERC404NullOwnerCappedUpgradeable is
285236 }
286237
287238 /// @notice tokenURI must be implemented by child contract
288- function tokenURI (uint256 id_ ) public view virtual override ( IERC404 ) returns (string memory );
239+ function tokenURI (uint256 id_ ) public view virtual returns (string memory );
289240
290241 // =============================================================
291242 // ERC20 OPERATIONS
292243 // =============================================================
293244
294- function transfer (address , uint256 ) public pure virtual override ( IERC404 , IERC20 ) returns (bool ) {
245+ function transfer (address , uint256 ) public pure virtual override returns (bool ) {
295246 revert NotImplemented ();
296247 }
297248
298- function approve (address , uint256 ) public pure virtual override ( IERC404 , IERC20 ) returns (bool ) {
249+ function approve (address , uint256 ) public pure virtual override returns (bool ) {
299250 revert NotImplemented ();
300251 }
301252
302- function transferFrom (address , address , uint256 ) public pure virtual override ( IERC404 , IERC20 ) returns (bool ) {
253+ function transferFrom (address , address , uint256 ) public pure virtual override returns (bool ) {
303254 revert NotImplemented ();
304255 }
305256
306- function erc20Approve (address , uint256 ) public pure virtual override returns (bool ) {
257+ function erc20Approve (address , uint256 ) public pure virtual returns (bool ) {
307258 revert NotImplemented ();
308259 }
309260
310- function erc20TransferFrom (address , address , uint256 ) public pure virtual override returns (bool ) {
261+ function erc20TransferFrom (address , address , uint256 ) public pure virtual returns (bool ) {
311262 revert NotImplemented ();
312263 }
313264
314265 // =============================================================
315266 // ERC721 OPERATIONS
316267 // =============================================================
317268
318- function erc721Approve (address , uint256 ) public pure virtual override {
269+ function erc721Approve (address , uint256 ) public pure virtual {
319270 revert NotImplemented ();
320271 }
321272
322- function erc721TransferFrom (address , address , uint256 ) public pure virtual override {
273+ function erc721TransferFrom (address , address , uint256 ) public pure virtual {
323274 revert NotImplemented ();
324275 }
325276
326- function setApprovalForAll (address , bool ) public pure virtual override {
277+ function setApprovalForAll (address , bool ) public pure virtual {
327278 revert NotImplemented ();
328279 }
329280
330- function safeTransferFrom (address , address , uint256 ) public pure virtual override {
281+ function safeTransferFrom (address , address , uint256 ) public pure virtual {
331282 revert NotImplemented ();
332283 }
333284
334- function safeTransferFrom (address , address , uint256 , bytes memory ) public pure virtual override {
335- revert NotImplemented ();
336- }
337-
338- function setSelfERC721TransferExempt (bool ) public pure virtual override {
285+ function safeTransferFrom (address , address , uint256 , bytes memory ) public pure virtual {
339286 revert NotImplemented ();
340287 }
341288
@@ -367,7 +314,6 @@ abstract contract ERC404NullOwnerCappedUpgradeable is
367314 }
368315
369316 emit Transfer (from_, to_, value_);
370- // emit ERC20Transfer(from_, to_, value_);
371317 }
372318
373319 /// @notice Transfer an ERC721 token
@@ -454,44 +400,6 @@ abstract contract ERC404NullOwnerCappedUpgradeable is
454400 return
455401 interfaceId == type (IERC165 ).interfaceId ||
456402 interfaceId == type (IERC20 ).interfaceId ||
457- interfaceId == type (IERC20Metadata ).interfaceId ||
458- interfaceId == type (IERC404 ).interfaceId;
459- }
460-
461- /// @notice Internal function to compute domain separator for EIP-2612 permits
462- function _computeDomainSeparator () internal view virtual returns (bytes32 ) {
463- return
464- keccak256 (
465- abi.encode (
466- keccak256 (
467- "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract) "
468- ),
469- keccak256 (bytes (name ())),
470- keccak256 ("1 " ),
471- block .chainid ,
472- address (this )
473- )
474- );
475- }
476-
477- function permit (
478- address owner_ ,
479- address spender_ ,
480- uint256 value_ ,
481- uint256 deadline_ ,
482- uint8 v_ ,
483- bytes32 r_ ,
484- bytes32 s_
485- ) public virtual {
486- revert NotImplemented ();
487- }
488-
489- /// @notice EIP-2612 domain separator
490- function DOMAIN_SEPARATOR () public view virtual returns (bytes32 ) {
491- TokenStorage storage $ = _getS ();
492- return
493- block .chainid == $.initialChainId
494- ? $.initialDomainSeparator
495- : _computeDomainSeparator ();
403+ interfaceId == type (IERC20Metadata ).interfaceId;
496404 }
497405}
0 commit comments