1
+ pragma solidity ^ 0.4.24 ;
2
+
3
+ import "openzeppelin-solidity/contracts/token/ERC721/ERC721.sol " ;
4
+ import "openzeppelin-solidity/contracts/token/ERC721/ERC721BasicToken.sol " ;
5
+
6
+ contract MyNFT is ERC721BasicToken , ERC721 {
7
+
8
+ // Token name
9
+ string internal name_;
10
+
11
+ // Token symbol
12
+ string internal symbol_;
13
+
14
+ // Mapping from owner to list of owned token IDs
15
+ mapping (address => uint256 []) internal ownedTokens;
16
+
17
+ // Mapping from token ID to index of the owner tokens list
18
+ mapping (uint256 => uint256 ) internal ownedTokensIndex;
19
+
20
+ // Array with all token ids, used for enumeration
21
+ uint256 [] internal allTokens;
22
+
23
+ // Mapping from token id to position in the allTokens array
24
+ mapping (uint256 => uint256 ) internal allTokensIndex;
25
+
26
+ // Optional mapping for token URIs
27
+ mapping (uint256 => string ) internal tokenURIs;
28
+
29
+ /**
30
+ * @dev Constructor function
31
+ */
32
+ constructor (uint256 _initialId , string _name , string _symbol , uint8 _nothing ) public {
33
+ name_ = _name;
34
+ symbol_ = _symbol;
35
+
36
+ _mint (msg .sender , _initialId);
37
+ }
38
+
39
+ /**
40
+ * @dev Gets the token name
41
+ * @return string representing the token name
42
+ */
43
+ function name () external view returns (string ) {
44
+ return name_;
45
+ }
46
+
47
+ /**
48
+ * @dev Gets the token symbol
49
+ * @return string representing the token symbol
50
+ */
51
+ function symbol () external view returns (string ) {
52
+ return symbol_;
53
+ }
54
+
55
+ /**
56
+ * @dev Returns an URI for a given token ID
57
+ * Throws if the token ID does not exist. May return an empty string.
58
+ * @param _tokenId uint256 ID of the token to query
59
+ */
60
+ function tokenURI (uint256 _tokenId ) public view returns (string ) {
61
+ require (exists (_tokenId));
62
+ return tokenURIs[_tokenId];
63
+ }
64
+
65
+ /**
66
+ * @dev Gets the token ID at a given index of the tokens list of the requested owner
67
+ * @param _owner address owning the tokens list to be accessed
68
+ * @param _index uint256 representing the index to be accessed of the requested tokens list
69
+ * @return uint256 token ID at the given index of the tokens list owned by the requested address
70
+ */
71
+ function tokenOfOwnerByIndex (
72
+ address _owner ,
73
+ uint256 _index
74
+ )
75
+ public
76
+ view
77
+ returns (uint256 )
78
+ {
79
+ require (_index < balanceOf (_owner));
80
+ return ownedTokens[_owner][_index];
81
+ }
82
+
83
+ /**
84
+ * @dev Gets the total amount of tokens stored by the contract
85
+ * @return uint256 representing the total amount of tokens
86
+ */
87
+ function totalSupply () public view returns (uint256 ) {
88
+ return allTokens.length ;
89
+ }
90
+
91
+ /**
92
+ * @dev Gets the token ID at a given index of all the tokens in this contract
93
+ * Reverts if the index is greater or equal to the total number of tokens
94
+ * @param _index uint256 representing the index to be accessed of the tokens list
95
+ * @return uint256 token ID at the given index of the tokens list
96
+ */
97
+ function tokenByIndex (uint256 _index ) public view returns (uint256 ) {
98
+ require (_index < totalSupply ());
99
+ return allTokens[_index];
100
+ }
101
+
102
+ /**
103
+ * @dev Internal function to set the token URI for a given token
104
+ * Reverts if the token ID does not exist
105
+ * @param _tokenId uint256 ID of the token to set its URI
106
+ * @param _uri string URI to assign
107
+ */
108
+ function _setTokenURI (uint256 _tokenId , string _uri ) internal {
109
+ require (exists (_tokenId));
110
+ tokenURIs[_tokenId] = _uri;
111
+ }
112
+
113
+ /**
114
+ * @dev Internal function to add a token ID to the list of a given address
115
+ * @param _to address representing the new owner of the given token ID
116
+ * @param _tokenId uint256 ID of the token to be added to the tokens list of the given address
117
+ */
118
+ function addTokenTo (address _to , uint256 _tokenId ) internal {
119
+ super .addTokenTo (_to, _tokenId);
120
+ uint256 length = ownedTokens[_to].length ;
121
+ ownedTokens[_to].push (_tokenId);
122
+ ownedTokensIndex[_tokenId] = length;
123
+ }
124
+
125
+ /**
126
+ * @dev Internal function to remove a token ID from the list of a given address
127
+ * @param _from address representing the previous owner of the given token ID
128
+ * @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address
129
+ */
130
+ function removeTokenFrom (address _from , uint256 _tokenId ) internal {
131
+ super .removeTokenFrom (_from, _tokenId);
132
+
133
+ // To prevent a gap in the array, we store the last token in the index of the token to delete, and
134
+ // then delete the last slot.
135
+ uint256 tokenIndex = ownedTokensIndex[_tokenId];
136
+ uint256 lastTokenIndex = ownedTokens[_from].length .sub (1 );
137
+ uint256 lastToken = ownedTokens[_from][lastTokenIndex];
138
+
139
+ ownedTokens[_from][tokenIndex] = lastToken;
140
+ ownedTokens[_from].length -- ; // This also deletes the contents at the last position of the array
141
+
142
+ // Note that this will handle single-element arrays. In that case, both tokenIndex and lastTokenIndex are going to
143
+ // be zero. Then we can make sure that we will remove _tokenId from the ownedTokens list since we are first swapping
144
+ // the lastToken to the first position, and then dropping the element placed in the last position of the list
145
+
146
+ ownedTokensIndex[_tokenId] = 0 ;
147
+ ownedTokensIndex[lastToken] = tokenIndex;
148
+ }
149
+
150
+ /**
151
+ * @dev Internal function to mint a new token
152
+ * Reverts if the given token ID already exists
153
+ * @param _to address the beneficiary that will own the minted token
154
+ * @param _tokenId uint256 ID of the token to be minted by the msg.sender
155
+ */
156
+ function _mint (address _to , uint256 _tokenId ) internal {
157
+ super ._mint (_to, _tokenId);
158
+
159
+ allTokensIndex[_tokenId] = allTokens.length ;
160
+ allTokens.push (_tokenId);
161
+ }
162
+
163
+ /**
164
+ * @dev Internal function to burn a specific token
165
+ * Reverts if the token does not exist
166
+ * @param _owner owner of the token to burn
167
+ * @param _tokenId uint256 ID of the token being burned by the msg.sender
168
+ */
169
+ function _burn (address _owner , uint256 _tokenId ) internal {
170
+ super ._burn (_owner, _tokenId);
171
+
172
+ // Clear metadata (if any)
173
+ if (bytes (tokenURIs[_tokenId]).length != 0 ) {
174
+ delete tokenURIs[_tokenId];
175
+ }
176
+
177
+ // Reorg all tokens array
178
+ uint256 tokenIndex = allTokensIndex[_tokenId];
179
+ uint256 lastTokenIndex = allTokens.length .sub (1 );
180
+ uint256 lastToken = allTokens[lastTokenIndex];
181
+
182
+ allTokens[tokenIndex] = lastToken;
183
+ allTokens[lastTokenIndex] = 0 ;
184
+
185
+ allTokens.length -- ;
186
+ allTokensIndex[_tokenId] = 0 ;
187
+ allTokensIndex[lastToken] = tokenIndex;
188
+ }
189
+
190
+ }
0 commit comments