Jumping into Solidity — The ERC721 Standard (Part 7)

Photo by Sanwal Deen on Unsplash

A quick note for the long time readers

onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data)

The Enumerable Extension

function totalSupply() external view returns (uint256);function tokenByIndex(uint256 _index) external view returns (uint256);function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
contract TokenERC721Enumerable is TokenERC721, ERC721Enumerable {
uint[] a = [1,2,3,4];
delete a[1];
a = [1,0,3,4];
a = [1,4,3];
uint[] internal tokenIndexes;
mapping(uint => uint) internal indexTokens;
mapping(address => uint[]) internal ownerTokenIndexes;
mapping(uint => uint) internal tokenTokenIndexes;
ownerTokenIndexes[ownerAddress][tokenIndex] = tokenId;
tokenTokenIndexes[tokenId] = tokenIndex;
constructor(uint _initialSupply) public TokenERC721(_initialSupply){
for(uint i = 0; i < _initialSupply; i++){
tokenTokenIndexes[i+1] = i;
ownerTokenIndexes[creator].push(i+1);
tokenIndexes.push(i+1);
indexTokens[i + 1] = i;
}

//Add to ERC165 Interface Check
supportedInterfaces[
this.totalSupply.selector ^
this.tokenByIndex.selector ^
this.tokenOfOwnerByIndex.selector
] = true;
}
function totalSupply() external view returns (uint256){
return tokenIndexes.length;
}
function tokenByIndex(uint256 _index) external view returns(uint256){
require(_index < tokenIndexes.length);
return tokenIndexes[_index];
}
function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256){
require(_index < balances[_owner]);
return ownerTokenIndexes[_owner][_index];
}
ownerTokenIndexes[0xAAA] => [1, 2, 3, 4];
ownerTokenIndexes[0xBBB] => [5, 6, 7, 8];
tokenTokenIndexes[1] => 0;
tokenTokenIndexes[2] => 1;
tokenTokenIndexes[3] => 2;
tokenTokenIndexes[4] => 3;
tokenTokenIndexes[5] => 0;
tokenTokenIndexes[6] => 1;
tokenTokenIndexes[7] => 2;
tokenTokenIndexes[8] => 3;
//Temporarily store the old index because we need to reference it a few times
uint
oldIndex = tokenTokenIndexes[2];
//Overwrite the value at oldIndex (2) with whatever is
// at the end of the ownerTokenIndexes[0xAAA] array (
4).
ownerTokenIndexes[0xAAA][oldIndex] =
ownerTokenIndexes[0xAAA][ ownerTokenIndexes[0xAAA].length - 1 ];
//Update tokenTokenIndexes for whatever token is
// now at ownerTokenIndexes[0xAAA][oldIndex] (
4).
tokenTokenIndexes[ownerTokenIndexes[0xAAA][oldIndex]] = oldIndex;
//Update tokentkenIndexes[2] to be the length of
// ownerTokenIndexes[0xBBB], since this will be its new position.
tokenTokenIndexes[2] = ownerTokenIndexes[0xBBB].length;
//Add 2 to the end of ownerTokenIndexes[0xBBB].ownerTokenIndexes[0xBBB].push(2);
//Decrement ownerTokenIndexes[0xAAA].length by 1ownerTokenIndexes[0xAAA].length--;
function transferFrom(address _from, address _to, uint256 _tokenId) public {
address owner = ownerOf(_tokenId);
require ( owner == msg.sender
|| allowance[_tokenId] == msg.sender
|| authorised[owner][msg.sender]
);
require(owner == _from);
require(_to != 0x0);

emit
Transfer(_from, _to, _tokenId);

owners[_tokenId] = _to;
balances[_from]--;
balances[_to]++;
if(allowance[_tokenId] != 0x0){
delete allowance[_tokenId];
}


//=== Enumerable Additions ===
uint oldIndex = tokenTokenIndexes[_tokenId];
//If the token isn't the last one in the owner's index
if(oldIndex != ownerTokenIndexes[_from].length - 1){
//Move the old one in the index list
ownerTokenIndexes[_from][oldIndex] = ownerTokenIndexes[_from][ownerTokenIndexes[_from].length - 1];
//Update the token's reference to its place in the index list
tokenTokenIndexes[ownerTokenIndexes[_from][oldIndex]] = oldIndex;
}
ownerTokenIndexes[_from].length--;
tokenTokenIndexes[_tokenId] = ownerTokenIndexes[_to].length;
ownerTokenIndexes[_to].push(_tokenId);
}
function burnToken(uint256 _tokenId) external{
address owner = ownerOf(_tokenId);
require ( owner == msg.sender
|| allowance[_tokenId] == msg.sender
|| authorised[owner][msg.sender]
);
burned[_tokenId] = true;
balances[owner]--;
emit Transfer(owner, 0x0, _tokenId);
//=== Enumerable Additions ===
uint oldIndex = tokenTokenIndexes[_tokenId];
if(oldIndex != ownerTokenIndexes[owner].length - 1){ //Move last token to old index
ownerTokenIndexes[owner][oldIndex] = ownerTokenIndexes[owner][ownerTokenIndexes[owner].length - 1];
//update token self reference to new position
tokenTokenIndexes[ownerTokenIndexes[owner][oldIndex]] = oldIndex;
}
ownerTokenIndexes[owner].length--;
delete tokenTokenIndexes[_tokenId];
//This part deals with tokenIndexes
oldIndex = indexTokens[_tokenId];
if(oldIndex != tokenIndexes.length - 1){
//Move last token to old index
tokenIndexes[oldIndex] = tokenIndexes[tokenIndexes.length - 1];
}
tokenIndexes.length--;

}
uint newId = maxId.add(1); //Using SafeMath to prevent overflows.//Assign the new token its index in ownerTokenIndexes
tokenTokenIndexes[newId] = ownerTokenIndexes[msg.sender].length;
//Add the tokenId to the end of ownerTokenIndexes
ownerTokenIndexes[creator].push(newId);
//Add the token to the end of tokenIndexes and indexTokens
indexTokens[thisId] = tokenIndexes.length;
tokenIndexes.push(thisId);
function issueTokens(uint256 _extraTokens) public{
require(msg.sender == creator);
balances[msg.sender] = balances[msg.sender].add(_extraTokens);

uint thisId; //We'll reuse this for each iteration below.
for(uint i = 0; i < _extraTokens; i++){
thisId = maxId.add(i).add(1); //SafeMath to be safe!
//Assign the new token its index in ownerTokenIndexes
tokenTokenIndexes[thisId] = ownerTokenIndexes[creator].length;
//Add the tokenId to the end of ownerTokenIndexes
ownerTokenIndexes[creator].push(thisId);

//Add the token to the end of tokenIndexes
indexTokens[thisId] = tokenIndexes.length;
tokenIndexes.push(thisId);


emit Transfer(0x0, creator, thisId);
}
//Note: This used to be before the loop
// (loop was slightly different).
maxId = maxId.add(_extraTokens);

}

Wrapping up

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store