-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathERC721.sol
159 lines (140 loc) · 6.48 KB
/
ERC721.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
pragma solidity ^0.4.24;
import "./ERC165.sol";
import "./ERC721Receiver.sol";
contract ERC721 is ERC165 {
event Transfer(address indexed from, address indexed to, uint indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool value);
mapping (address => uint) private ownerToTokens;
mapping (uint => address) private tokenToOwner;
uint public totalSupply;
mapping (uint => address) public getApproved;
mapping (address => mapping (address => bool)) public isApprovedForAll;
constructor() public {
supportedInterfaces[0x80ac58cd] = true;
supportedInterfaces[0x780e9d63] = true;
}
function balanceOf(address owner) external view returns (uint) {
uint count = 0;
uint tokens = ownerToTokens[owner];
while (tokens != 0) {
count++;
tokens &= tokens - 1;
}
return count;
}
function ownerOf(uint tokenId) external view returns (address) {
address owner = tokenToOwner[tokenId];
require(owner != 0);
return owner;
}
function tokenOfOwnerByIndex(address owner, uint index) public view returns (uint) {
uint tokens = ownerToTokens[owner];
while (index > 0) {
tokens &= tokens - 1;
index--;
}
require(tokens != 0);
tokens &= -tokens;
uint tokenId = 255;
if (tokens & 0x00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF != 0) { tokenId -= 128; }
if (tokens & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF != 0) { tokenId -= 64; }
if (tokens & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF != 0) { tokenId -= 32; }
if (tokens & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF != 0) { tokenId -= 16; }
if (tokens & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF != 0) { tokenId -= 8; }
if (tokens & 0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F != 0) { tokenId -= 4; }
if (tokens & 0x3333333333333333333333333333333333333333333333333333333333333333 != 0) { tokenId -= 2; }
if (tokens & 0x5555555555555555555555555555555555555555555555555555555555555555 != 0) { tokenId -= 1; }
return tokenId;
}
function tokenByIndex(uint index) external view returns (uint) {
require(index < totalSupply);
return index;
}
function transferFrom(address from, address to, uint tokenId) public {
require(to != 0);
address owner = tokenToOwner[tokenId];
address approved = getApproved[tokenId];
require(from == owner);
require(msg.sender == owner || msg.sender == approved || isApprovedForAll[owner][msg.sender]);
ownerToTokens[from] &= ~(1 << tokenId);
ownerToTokens[to] |= 1 << tokenId;
tokenToOwner[tokenId] = to;
if (approved != 0) {
delete getApproved[tokenId];
}
emit Transfer(from, to, tokenId);
}
function safeTransferFrom(address from, address to, uint tokenId, bytes data) public {
transferFrom(from, to, tokenId);
uint size;
assembly { size := extcodesize(to) }
if (size > 0) {
bytes4 magic = ERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, data);
require(magic == 0x150b7a02);
}
}
function safeTransferFrom(address from, address to, uint tokenId) external {
safeTransferFrom(from, to, tokenId, "");
}
function transferMultipleFrom(address from, address to, uint tokens) public {
require(to != 0);
require(ownerToTokens[from] & tokens == tokens);
require(msg.sender == from || isApprovedForAll[from][msg.sender]);
ownerToTokens[from] &= ~tokens;
ownerToTokens[to] |= tokens;
while (tokens != 0) {
uint lsbs = tokens & -tokens;
uint tokenId = 255;
if (lsbs & 0x00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF != 0) { tokenId -= 128; }
if (lsbs & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF != 0) { tokenId -= 64; }
if (lsbs & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF != 0) { tokenId -= 32; }
if (lsbs & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF != 0) { tokenId -= 16; }
if (lsbs & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF != 0) { tokenId -= 8; }
if (lsbs & 0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F != 0) { tokenId -= 4; }
if (lsbs & 0x3333333333333333333333333333333333333333333333333333333333333333 != 0) { tokenId -= 2; }
if (lsbs & 0x5555555555555555555555555555555555555555555555555555555555555555 != 0) { tokenId -= 1; }
tokenToOwner[tokenId] = to;
if (getApproved[tokenId] != 0) {
delete getApproved[tokenId];
}
emit Transfer(from, to, tokenId);
tokens ^= lsbs;
}
}
function approve(address approved, uint tokenId) external {
address owner = tokenToOwner[tokenId];
require(msg.sender == owner || isApprovedForAll[owner][msg.sender]);
require(approved != owner);
getApproved[tokenId] = approved;
emit Approval(owner, approved, tokenId);
}
function setApprovalForAll(address operator, bool value) external {
require(msg.sender != operator);
isApprovedForAll[msg.sender][operator] = value;
emit ApprovalForAll(msg.sender, operator, value);
}
function _exists(uint tokenId) internal view returns (bool) {
return tokenId < totalSupply;
}
function _mint(address to) internal {
require(to != 0);
uint tokenId = totalSupply;
require(tokenId < 256);
totalSupply++;
ownerToTokens[to] |= 1 << tokenId;
tokenToOwner[tokenId] = to;
emit Transfer(0, to, tokenId);
}
function _mintMultiple(address to, uint amount) internal {
require(to != 0);
uint firstTokenId = totalSupply;
require(firstTokenId + amount <= 256);
totalSupply += amount;
ownerToTokens[to] |= ((1 << amount) - 1) << firstTokenId;
for (uint i = 0; i < amount; i++) {
tokenToOwner[firstTokenId + i] = to;
emit Transfer(0, to, firstTokenId + i);
}
}
}