Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
My implementation of the ERC721 token standard. WARNING: THIS CODE IS FOR EDUCATIONAL PURPOSES. DO NOT DEPLOY TO THE NETWORK.
pragma solidity ^0.4.19;
contract ERC721 {
string constant private tokenName = "My ERC721 Token";
string constant private tokenSymbol = "MET";
uint256 constant private totalTokens = 1000000;
mapping(address => uint) private balances;
mapping(uint256 => address) private tokenOwners;
mapping(uint256 => bool) private tokenExists;
mapping(address => mapping (address => uint256)) private allowed;
mapping(address => mapping(uint256 => uint256)) private ownerTokens;
mapping(uint256 => string) tokenLinks;
function removeFromTokenList(address owner, uint256 _tokenId) private {
for(uint256 i = 0;ownerTokens[owner][i] != _tokenId;i++){
ownerTokens[owner][i] = 0;
}
}
function name() public constant returns (string){
return tokenName;
}
function symbol() public constant returns (string) {
return tokenSymbol;
}
function totalSupply() public constant returns (uint256){
return totalTokens;
}
function balanceOf(address _owner) constant returns (uint){
return balances[_owner];
}
function ownerOf(uint256 _tokenId) constant returns (address){
require(tokenExists[_tokenId]);
return tokenOwners[_tokenId];
}
function approve(address _to, uint256 _tokenId){
require(msg.sender == ownerOf(_tokenId));
require(msg.sender != _to);
allowed[msg.sender][_to] = _tokenId;
Approval(msg.sender, _to, _tokenId);
}
function takeOwnership(uint256 _tokenId){
require(tokenExists[_tokenId]);
address oldOwner = ownerOf(_tokenId);
address newOwner = msg.sender;
require(newOwner != oldOwner);
require(allowed[oldOwner][newOwner] == _tokenId);
balances[oldOwner] -= 1;
tokenOwners[_tokenId] = newOwner;
balances[oldOwner] += 1;
Transfer(oldOwner, newOwner, _tokenId);
}
function transfer(address _to, uint256 _tokenId){
address currentOwner = msg.sender;
address newOwner = _to;
require(tokenExists[_tokenId]);
require(currentOwner == ownerOf(_tokenId));
require(currentOwner != newOwner);
require(newOwner != address(0));
removeFromTokenList(_tokenId);
balances[currentOwner] -= 1;
tokenOwners[_tokenId] = newOwner;
balances[newOwner] += 1;
Transfer(currentOwner, newOwner, _tokenId);
}
function tokenOfOwnerByIndex(address _owner, uint256 _index) constant returns (uint tokenId){
return ownerTokens[_owner][_index];
}
function tokenMetadata(uint256 _tokenId) constant returns (string infoUrl){
return tokenLinks[_tokenId];
}
event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);
}
@jnmclarty

This comment has been minimized.

Copy link

@jnmclarty jnmclarty commented Dec 30, 2017

Has anybody implemented an ERC-721 compliant contract in production use-cases yet? I'm looking at doing something with it, in a prod-like setting.
Edit: Crypto Kitties...duh

@trongcauhcmus

This comment has been minimized.

Copy link

@trongcauhcmus trongcauhcmus commented Jan 16, 2018

i see a logic bug here

@JesseBusman

This comment has been minimized.

Copy link

@JesseBusman JesseBusman commented Jan 19, 2018

The function removeFromTokenList has two parameters, but it is only given one argument on line 58. The contract does not compile for this reason.

@vlugansky

This comment has been minimized.

Copy link

@vlugansky vlugansky commented Jan 20, 2018

@JesseBusman

What argument did you add as the second one?

@TBBle

This comment has been minimized.

Copy link

@TBBle TBBle commented Jan 23, 2018

@vlugansky
It looks like the call should be removeFromTokenList(currentOwner, _tokenId);. That said, it looks like removeFromTokenList does the wrong thing, clearing the record of owner->token up to but not including the token passed in, corrupting the results of tokenOfOwnerByIndex.

There's a reason there's a note at the top saying DO NOT DEPLOY TO THE NETWORK. It's way off-spec in the handling of approval events, as well.

@dexX7

This comment has been minimized.

Copy link

@dexX7 dexX7 commented Feb 6, 2018

Hey @aunyks, I think this also needs a way to add meta-data to a token, e.g.:

function setTokenMetadata(uint256 _tokenId, string infoUrl) {
    require(msg.sender == ownerOf(_tokenId));
    tokenLinks[_tokenId] = infoUrl;
}

The check require(tokenExists[_tokenId]) in L54 seems redundant, given that the existance check is also done in ownerOf().

@DZGoldman

This comment has been minimized.

Copy link

@DZGoldman DZGoldman commented Apr 25, 2018

Shouldn't line 48 be:

balances[newOwner] += 1;

(newOwner instead of oldOwner)

@olekashiwa

This comment has been minimized.

Copy link

@olekashiwa olekashiwa commented May 31, 2018

Thanks a lot!

@tonysparks5000

This comment has been minimized.

Copy link

@tonysparks5000 tonysparks5000 commented Aug 25, 2018

i have a suspicion this is what you want

function removeFromTokenList(address owner, uint256 _tokenId) private {
     for(uint256 i = 0;ownerTokens[owner][i] == _tokenId;i++){
      //not 
      //for(uint256 i = 0;ownerTokens[owner][i] != _tokenId;i++){
       ownerTokens[owner][i] = 0;
     }
   } 

also add addToTokenList under line 48 after turning
balances[oldOwner] += 1;
into

balances[newOwner] += 1;
addToTokenList(newOwner,_tokenId);
function addToTokenList(address owner, uint256 _tokenId) private {
       ownerTokens[owner][i] = _tokenId;
   }
@haozheng95

This comment has been minimized.

Copy link

@haozheng95 haozheng95 commented Oct 8, 2018

[
Why not?

ownerTokens[owner][_tokenId] = 0

@jackz-jones

This comment has been minimized.

Copy link

@jackz-jones jackz-jones commented Nov 9, 2018

So many bugs !!! improvements above all should add into it !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.