├── .gitignore ├── README.md ├── build └── contracts │ ├── AddressUtils.json │ ├── Avatar.json │ ├── Composable.json │ ├── ERC721.json │ ├── ERC721Basic.json │ ├── ERC721BasicToken.json │ ├── ERC721Enumerable.json │ ├── ERC721Metadata.json │ ├── ERC721Receiver.json │ ├── ERC721Token.json │ ├── Ethmoji.json │ ├── EthmojiProxy.json │ ├── Migrations.json │ ├── Ownable.json │ ├── OwnableProxy.json │ ├── Pausable.json │ ├── Proxy.json │ ├── PullPayment.json │ └── SafeMath.json ├── contracts ├── Avatar.sol ├── Composable.sol ├── Ethmoji.sol ├── EthmojiProxy.sol ├── Migrations.sol ├── OwnableProxy.sol └── Proxy.sol ├── index.js ├── migrations ├── 1_initial_migration.js └── 2_deploy_contracts.js ├── package-lock.json ├── package.json ├── test └── ethmoji │ ├── AvatarTest.js │ ├── EthmojiProxyTest.js │ └── EthmojiTest.js ├── truffle.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log 5 | yarn-error.log 6 | 7 | # Runtime data 8 | pids 9 | *.pid 10 | *.seed 11 | 12 | # Directory for instrumented libs generated by jscoverage/JSCover 13 | lib-cov 14 | 15 | # Coverage directory used by tools like istanbul 16 | coverage 17 | 18 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 19 | .grunt 20 | 21 | # node-waf configuration 22 | .lock-wscript 23 | 24 | # Compiled binary addons (http://nodejs.org/api/addons.html) 25 | build/Release 26 | .eslintcache 27 | 28 | # Dependency directory 29 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 30 | node_modules 31 | 32 | # OSX 33 | .DS_Store 34 | 35 | # App packaged 36 | dist 37 | 38 | .idea 39 | .env 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ethmoji :heart_eyes: 2 | 3 | Smart contracts for Ethmoji — composable art on the blockchain. 4 | 5 | ### Getting started 6 | 7 | Install packages 8 | 9 | ``` 10 | truffle 11 | ``` 12 | 13 | Make sure you have truffle version v4.1.5 (core: 4.1.5) or higher with Solidity v0.4.21 (solc-js) or higher 14 | 15 | ``` 16 | yarn 17 | ``` 18 | 19 | Start a local blockchain like [Ganache](https://github.com/trufflesuite/ganache). You can use [Ganache CLI](https://github.com/trufflesuite/ganache-cli) or the [desktop client](http://truffleframework.com/ganache/). 20 | 21 | ``` 22 | ganache-cli 23 | ``` 24 | 25 | Compile and migrate your local smart contracts. 26 | 27 | ``` 28 | truffle migrate --reset 29 | ``` 30 | -------------------------------------------------------------------------------- /build/contracts/AddressUtils.json: -------------------------------------------------------------------------------- 1 | { 2 | "contractName": "AddressUtils", 3 | "abi": [], 4 | "bytecode": "0x604c602c600b82828239805160001a60731460008114601c57601e565bfe5b5030600052607381538281f30073000000000000000000000000000000000000000030146080604052600080fd00a165627a7a723058206fc4e482901738e00db750b2b150e59fdb6dcad8781783675c61cca8668a80500029", 5 | "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fd00a165627a7a723058206fc4e482901738e00db750b2b150e59fdb6dcad8781783675c61cca8668a80500029", 6 | "sourceMap": "87:922:2:-;;132:2:-1;166:7;155:9;146:7;137:37;252:7;246:14;243:1;238:23;232:4;229:33;270:1;265:20;;;;222:63;;265:20;274:9;222:63;;298:9;295:1;288:20;328:4;319:7;311:22;352:7;343;336:24", 7 | "deployedSourceMap": "87:922:2:-;;;;;;;;", 8 | "source": "pragma solidity ^0.4.21;\n\n\n/**\n * Utility library of inline functions on addresses\n */\nlibrary AddressUtils {\n\n /**\n * Returns whether the target address is a contract\n * @dev This function will return false if invoked during the constructor of a contract,\n * as the code is not actually created until after the constructor finishes.\n * @param addr address to check\n * @return whether the target address is a contract\n */\n function isContract(address addr) internal view returns (bool) {\n uint256 size;\n // XXX Currently there is no better way to check if there is a contract in an address\n // than to check the size of the code at that address.\n // See https://ethereum.stackexchange.com/a/14016/36603\n // for more details about how this works.\n // TODO Check this again before the Serenity release, because all addresses will be\n // contracts then.\n assembly { size := extcodesize(addr) } // solium-disable-line security/no-inline-assembly\n return size > 0;\n }\n\n}\n", 9 | "sourcePath": "zeppelin-solidity/contracts/AddressUtils.sol", 10 | "ast": { 11 | "absolutePath": "zeppelin-solidity/contracts/AddressUtils.sol", 12 | "exportedSymbols": { 13 | "AddressUtils": [ 14 | 1203 15 | ] 16 | }, 17 | "id": 1204, 18 | "nodeType": "SourceUnit", 19 | "nodes": [ 20 | { 21 | "id": 1186, 22 | "literals": [ 23 | "solidity", 24 | "^", 25 | "0.4", 26 | ".21" 27 | ], 28 | "nodeType": "PragmaDirective", 29 | "src": "0:24:2" 30 | }, 31 | { 32 | "baseContracts": [], 33 | "contractDependencies": [], 34 | "contractKind": "library", 35 | "documentation": "Utility library of inline functions on addresses", 36 | "fullyImplemented": true, 37 | "id": 1203, 38 | "linearizedBaseContracts": [ 39 | 1203 40 | ], 41 | "name": "AddressUtils", 42 | "nodeType": "ContractDefinition", 43 | "nodes": [ 44 | { 45 | "body": { 46 | "id": 1201, 47 | "nodeType": "Block", 48 | "src": "501:505:2", 49 | "statements": [ 50 | { 51 | "assignments": [], 52 | "declarations": [ 53 | { 54 | "constant": false, 55 | "id": 1194, 56 | "name": "size", 57 | "nodeType": "VariableDeclaration", 58 | "scope": 1202, 59 | "src": "507:12:2", 60 | "stateVariable": false, 61 | "storageLocation": "default", 62 | "typeDescriptions": { 63 | "typeIdentifier": "t_uint256", 64 | "typeString": "uint256" 65 | }, 66 | "typeName": { 67 | "id": 1193, 68 | "name": "uint256", 69 | "nodeType": "ElementaryTypeName", 70 | "src": "507:7:2", 71 | "typeDescriptions": { 72 | "typeIdentifier": "t_uint256", 73 | "typeString": "uint256" 74 | } 75 | }, 76 | "value": null, 77 | "visibility": "internal" 78 | } 79 | ], 80 | "id": 1195, 81 | "initialValue": null, 82 | "nodeType": "VariableDeclarationStatement", 83 | "src": "507:12:2" 84 | }, 85 | { 86 | "externalReferences": [ 87 | { 88 | "size": { 89 | "declaration": 1194, 90 | "isOffset": false, 91 | "isSlot": false, 92 | "src": "902:4:2", 93 | "valueSize": 1 94 | } 95 | }, 96 | { 97 | "addr": { 98 | "declaration": 1188, 99 | "isOffset": false, 100 | "isSlot": false, 101 | "src": "922:4:2", 102 | "valueSize": 1 103 | } 104 | } 105 | ], 106 | "id": 1196, 107 | "nodeType": "InlineAssembly", 108 | "operations": "{\n size := extcodesize(addr)\n}", 109 | "src": "891:101:2" 110 | }, 111 | { 112 | "expression": { 113 | "argumentTypes": null, 114 | "commonType": { 115 | "typeIdentifier": "t_uint256", 116 | "typeString": "uint256" 117 | }, 118 | "id": 1199, 119 | "isConstant": false, 120 | "isLValue": false, 121 | "isPure": false, 122 | "lValueRequested": false, 123 | "leftExpression": { 124 | "argumentTypes": null, 125 | "id": 1197, 126 | "name": "size", 127 | "nodeType": "Identifier", 128 | "overloadedDeclarations": [], 129 | "referencedDeclaration": 1194, 130 | "src": "993:4:2", 131 | "typeDescriptions": { 132 | "typeIdentifier": "t_uint256", 133 | "typeString": "uint256" 134 | } 135 | }, 136 | "nodeType": "BinaryOperation", 137 | "operator": ">", 138 | "rightExpression": { 139 | "argumentTypes": null, 140 | "hexValue": "30", 141 | "id": 1198, 142 | "isConstant": false, 143 | "isLValue": false, 144 | "isPure": true, 145 | "kind": "number", 146 | "lValueRequested": false, 147 | "nodeType": "Literal", 148 | "src": "1000:1:2", 149 | "subdenomination": null, 150 | "typeDescriptions": { 151 | "typeIdentifier": "t_rational_0_by_1", 152 | "typeString": "int_const 0" 153 | }, 154 | "value": "0" 155 | }, 156 | "src": "993:8:2", 157 | "typeDescriptions": { 158 | "typeIdentifier": "t_bool", 159 | "typeString": "bool" 160 | } 161 | }, 162 | "functionReturnParameters": 1192, 163 | "id": 1200, 164 | "nodeType": "Return", 165 | "src": "986:15:2" 166 | } 167 | ] 168 | }, 169 | "documentation": "Returns whether the target address is a contract\n@dev This function will return false if invoked during the constructor of a contract,\n as the code is not actually created until after the constructor finishes.\n@param addr address to check\n@return whether the target address is a contract", 170 | "id": 1202, 171 | "implemented": true, 172 | "isConstructor": false, 173 | "isDeclaredConst": true, 174 | "modifiers": [], 175 | "name": "isContract", 176 | "nodeType": "FunctionDefinition", 177 | "parameters": { 178 | "id": 1189, 179 | "nodeType": "ParameterList", 180 | "parameters": [ 181 | { 182 | "constant": false, 183 | "id": 1188, 184 | "name": "addr", 185 | "nodeType": "VariableDeclaration", 186 | "scope": 1202, 187 | "src": "458:12:2", 188 | "stateVariable": false, 189 | "storageLocation": "default", 190 | "typeDescriptions": { 191 | "typeIdentifier": "t_address", 192 | "typeString": "address" 193 | }, 194 | "typeName": { 195 | "id": 1187, 196 | "name": "address", 197 | "nodeType": "ElementaryTypeName", 198 | "src": "458:7:2", 199 | "typeDescriptions": { 200 | "typeIdentifier": "t_address", 201 | "typeString": "address" 202 | } 203 | }, 204 | "value": null, 205 | "visibility": "internal" 206 | } 207 | ], 208 | "src": "457:14:2" 209 | }, 210 | "payable": false, 211 | "returnParameters": { 212 | "id": 1192, 213 | "nodeType": "ParameterList", 214 | "parameters": [ 215 | { 216 | "constant": false, 217 | "id": 1191, 218 | "name": "", 219 | "nodeType": "VariableDeclaration", 220 | "scope": 1202, 221 | "src": "495:4:2", 222 | "stateVariable": false, 223 | "storageLocation": "default", 224 | "typeDescriptions": { 225 | "typeIdentifier": "t_bool", 226 | "typeString": "bool" 227 | }, 228 | "typeName": { 229 | "id": 1190, 230 | "name": "bool", 231 | "nodeType": "ElementaryTypeName", 232 | "src": "495:4:2", 233 | "typeDescriptions": { 234 | "typeIdentifier": "t_bool", 235 | "typeString": "bool" 236 | } 237 | }, 238 | "value": null, 239 | "visibility": "internal" 240 | } 241 | ], 242 | "src": "494:6:2" 243 | }, 244 | "scope": 1203, 245 | "src": "438:568:2", 246 | "stateMutability": "view", 247 | "superFunction": null, 248 | "visibility": "internal" 249 | } 250 | ], 251 | "scope": 1204, 252 | "src": "87:922:2" 253 | } 254 | ], 255 | "src": "0:1010:2" 256 | }, 257 | "legacyAST": { 258 | "absolutePath": "zeppelin-solidity/contracts/AddressUtils.sol", 259 | "exportedSymbols": { 260 | "AddressUtils": [ 261 | 1203 262 | ] 263 | }, 264 | "id": 1204, 265 | "nodeType": "SourceUnit", 266 | "nodes": [ 267 | { 268 | "id": 1186, 269 | "literals": [ 270 | "solidity", 271 | "^", 272 | "0.4", 273 | ".21" 274 | ], 275 | "nodeType": "PragmaDirective", 276 | "src": "0:24:2" 277 | }, 278 | { 279 | "baseContracts": [], 280 | "contractDependencies": [], 281 | "contractKind": "library", 282 | "documentation": "Utility library of inline functions on addresses", 283 | "fullyImplemented": true, 284 | "id": 1203, 285 | "linearizedBaseContracts": [ 286 | 1203 287 | ], 288 | "name": "AddressUtils", 289 | "nodeType": "ContractDefinition", 290 | "nodes": [ 291 | { 292 | "body": { 293 | "id": 1201, 294 | "nodeType": "Block", 295 | "src": "501:505:2", 296 | "statements": [ 297 | { 298 | "assignments": [], 299 | "declarations": [ 300 | { 301 | "constant": false, 302 | "id": 1194, 303 | "name": "size", 304 | "nodeType": "VariableDeclaration", 305 | "scope": 1202, 306 | "src": "507:12:2", 307 | "stateVariable": false, 308 | "storageLocation": "default", 309 | "typeDescriptions": { 310 | "typeIdentifier": "t_uint256", 311 | "typeString": "uint256" 312 | }, 313 | "typeName": { 314 | "id": 1193, 315 | "name": "uint256", 316 | "nodeType": "ElementaryTypeName", 317 | "src": "507:7:2", 318 | "typeDescriptions": { 319 | "typeIdentifier": "t_uint256", 320 | "typeString": "uint256" 321 | } 322 | }, 323 | "value": null, 324 | "visibility": "internal" 325 | } 326 | ], 327 | "id": 1195, 328 | "initialValue": null, 329 | "nodeType": "VariableDeclarationStatement", 330 | "src": "507:12:2" 331 | }, 332 | { 333 | "externalReferences": [ 334 | { 335 | "size": { 336 | "declaration": 1194, 337 | "isOffset": false, 338 | "isSlot": false, 339 | "src": "902:4:2", 340 | "valueSize": 1 341 | } 342 | }, 343 | { 344 | "addr": { 345 | "declaration": 1188, 346 | "isOffset": false, 347 | "isSlot": false, 348 | "src": "922:4:2", 349 | "valueSize": 1 350 | } 351 | } 352 | ], 353 | "id": 1196, 354 | "nodeType": "InlineAssembly", 355 | "operations": "{\n size := extcodesize(addr)\n}", 356 | "src": "891:101:2" 357 | }, 358 | { 359 | "expression": { 360 | "argumentTypes": null, 361 | "commonType": { 362 | "typeIdentifier": "t_uint256", 363 | "typeString": "uint256" 364 | }, 365 | "id": 1199, 366 | "isConstant": false, 367 | "isLValue": false, 368 | "isPure": false, 369 | "lValueRequested": false, 370 | "leftExpression": { 371 | "argumentTypes": null, 372 | "id": 1197, 373 | "name": "size", 374 | "nodeType": "Identifier", 375 | "overloadedDeclarations": [], 376 | "referencedDeclaration": 1194, 377 | "src": "993:4:2", 378 | "typeDescriptions": { 379 | "typeIdentifier": "t_uint256", 380 | "typeString": "uint256" 381 | } 382 | }, 383 | "nodeType": "BinaryOperation", 384 | "operator": ">", 385 | "rightExpression": { 386 | "argumentTypes": null, 387 | "hexValue": "30", 388 | "id": 1198, 389 | "isConstant": false, 390 | "isLValue": false, 391 | "isPure": true, 392 | "kind": "number", 393 | "lValueRequested": false, 394 | "nodeType": "Literal", 395 | "src": "1000:1:2", 396 | "subdenomination": null, 397 | "typeDescriptions": { 398 | "typeIdentifier": "t_rational_0_by_1", 399 | "typeString": "int_const 0" 400 | }, 401 | "value": "0" 402 | }, 403 | "src": "993:8:2", 404 | "typeDescriptions": { 405 | "typeIdentifier": "t_bool", 406 | "typeString": "bool" 407 | } 408 | }, 409 | "functionReturnParameters": 1192, 410 | "id": 1200, 411 | "nodeType": "Return", 412 | "src": "986:15:2" 413 | } 414 | ] 415 | }, 416 | "documentation": "Returns whether the target address is a contract\n@dev This function will return false if invoked during the constructor of a contract,\n as the code is not actually created until after the constructor finishes.\n@param addr address to check\n@return whether the target address is a contract", 417 | "id": 1202, 418 | "implemented": true, 419 | "isConstructor": false, 420 | "isDeclaredConst": true, 421 | "modifiers": [], 422 | "name": "isContract", 423 | "nodeType": "FunctionDefinition", 424 | "parameters": { 425 | "id": 1189, 426 | "nodeType": "ParameterList", 427 | "parameters": [ 428 | { 429 | "constant": false, 430 | "id": 1188, 431 | "name": "addr", 432 | "nodeType": "VariableDeclaration", 433 | "scope": 1202, 434 | "src": "458:12:2", 435 | "stateVariable": false, 436 | "storageLocation": "default", 437 | "typeDescriptions": { 438 | "typeIdentifier": "t_address", 439 | "typeString": "address" 440 | }, 441 | "typeName": { 442 | "id": 1187, 443 | "name": "address", 444 | "nodeType": "ElementaryTypeName", 445 | "src": "458:7:2", 446 | "typeDescriptions": { 447 | "typeIdentifier": "t_address", 448 | "typeString": "address" 449 | } 450 | }, 451 | "value": null, 452 | "visibility": "internal" 453 | } 454 | ], 455 | "src": "457:14:2" 456 | }, 457 | "payable": false, 458 | "returnParameters": { 459 | "id": 1192, 460 | "nodeType": "ParameterList", 461 | "parameters": [ 462 | { 463 | "constant": false, 464 | "id": 1191, 465 | "name": "", 466 | "nodeType": "VariableDeclaration", 467 | "scope": 1202, 468 | "src": "495:4:2", 469 | "stateVariable": false, 470 | "storageLocation": "default", 471 | "typeDescriptions": { 472 | "typeIdentifier": "t_bool", 473 | "typeString": "bool" 474 | }, 475 | "typeName": { 476 | "id": 1190, 477 | "name": "bool", 478 | "nodeType": "ElementaryTypeName", 479 | "src": "495:4:2", 480 | "typeDescriptions": { 481 | "typeIdentifier": "t_bool", 482 | "typeString": "bool" 483 | } 484 | }, 485 | "value": null, 486 | "visibility": "internal" 487 | } 488 | ], 489 | "src": "494:6:2" 490 | }, 491 | "scope": 1203, 492 | "src": "438:568:2", 493 | "stateMutability": "view", 494 | "superFunction": null, 495 | "visibility": "internal" 496 | } 497 | ], 498 | "scope": 1204, 499 | "src": "87:922:2" 500 | } 501 | ], 502 | "src": "0:1010:2" 503 | }, 504 | "compiler": { 505 | "name": "solc", 506 | "version": "0.4.23+commit.124ca40d.Emscripten.clang" 507 | }, 508 | "networks": {}, 509 | "schemaVersion": "2.0.0", 510 | "updatedAt": "2018-05-13T21:06:29.986Z" 511 | } -------------------------------------------------------------------------------- /build/contracts/ERC721Metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "contractName": "ERC721Metadata", 3 | "abi": [ 4 | { 5 | "constant": true, 6 | "inputs": [ 7 | { 8 | "name": "_tokenId", 9 | "type": "uint256" 10 | } 11 | ], 12 | "name": "getApproved", 13 | "outputs": [ 14 | { 15 | "name": "_operator", 16 | "type": "address" 17 | } 18 | ], 19 | "payable": false, 20 | "stateMutability": "view", 21 | "type": "function" 22 | }, 23 | { 24 | "constant": false, 25 | "inputs": [ 26 | { 27 | "name": "_to", 28 | "type": "address" 29 | }, 30 | { 31 | "name": "_tokenId", 32 | "type": "uint256" 33 | } 34 | ], 35 | "name": "approve", 36 | "outputs": [], 37 | "payable": false, 38 | "stateMutability": "nonpayable", 39 | "type": "function" 40 | }, 41 | { 42 | "constant": false, 43 | "inputs": [ 44 | { 45 | "name": "_from", 46 | "type": "address" 47 | }, 48 | { 49 | "name": "_to", 50 | "type": "address" 51 | }, 52 | { 53 | "name": "_tokenId", 54 | "type": "uint256" 55 | } 56 | ], 57 | "name": "transferFrom", 58 | "outputs": [], 59 | "payable": false, 60 | "stateMutability": "nonpayable", 61 | "type": "function" 62 | }, 63 | { 64 | "constant": false, 65 | "inputs": [ 66 | { 67 | "name": "_from", 68 | "type": "address" 69 | }, 70 | { 71 | "name": "_to", 72 | "type": "address" 73 | }, 74 | { 75 | "name": "_tokenId", 76 | "type": "uint256" 77 | } 78 | ], 79 | "name": "safeTransferFrom", 80 | "outputs": [], 81 | "payable": false, 82 | "stateMutability": "nonpayable", 83 | "type": "function" 84 | }, 85 | { 86 | "constant": true, 87 | "inputs": [ 88 | { 89 | "name": "_tokenId", 90 | "type": "uint256" 91 | } 92 | ], 93 | "name": "exists", 94 | "outputs": [ 95 | { 96 | "name": "_exists", 97 | "type": "bool" 98 | } 99 | ], 100 | "payable": false, 101 | "stateMutability": "view", 102 | "type": "function" 103 | }, 104 | { 105 | "constant": true, 106 | "inputs": [ 107 | { 108 | "name": "_tokenId", 109 | "type": "uint256" 110 | } 111 | ], 112 | "name": "ownerOf", 113 | "outputs": [ 114 | { 115 | "name": "_owner", 116 | "type": "address" 117 | } 118 | ], 119 | "payable": false, 120 | "stateMutability": "view", 121 | "type": "function" 122 | }, 123 | { 124 | "constant": true, 125 | "inputs": [ 126 | { 127 | "name": "_owner", 128 | "type": "address" 129 | } 130 | ], 131 | "name": "balanceOf", 132 | "outputs": [ 133 | { 134 | "name": "_balance", 135 | "type": "uint256" 136 | } 137 | ], 138 | "payable": false, 139 | "stateMutability": "view", 140 | "type": "function" 141 | }, 142 | { 143 | "constant": false, 144 | "inputs": [ 145 | { 146 | "name": "_operator", 147 | "type": "address" 148 | }, 149 | { 150 | "name": "_approved", 151 | "type": "bool" 152 | } 153 | ], 154 | "name": "setApprovalForAll", 155 | "outputs": [], 156 | "payable": false, 157 | "stateMutability": "nonpayable", 158 | "type": "function" 159 | }, 160 | { 161 | "constant": false, 162 | "inputs": [ 163 | { 164 | "name": "_from", 165 | "type": "address" 166 | }, 167 | { 168 | "name": "_to", 169 | "type": "address" 170 | }, 171 | { 172 | "name": "_tokenId", 173 | "type": "uint256" 174 | }, 175 | { 176 | "name": "_data", 177 | "type": "bytes" 178 | } 179 | ], 180 | "name": "safeTransferFrom", 181 | "outputs": [], 182 | "payable": false, 183 | "stateMutability": "nonpayable", 184 | "type": "function" 185 | }, 186 | { 187 | "constant": true, 188 | "inputs": [ 189 | { 190 | "name": "_owner", 191 | "type": "address" 192 | }, 193 | { 194 | "name": "_operator", 195 | "type": "address" 196 | } 197 | ], 198 | "name": "isApprovedForAll", 199 | "outputs": [ 200 | { 201 | "name": "", 202 | "type": "bool" 203 | } 204 | ], 205 | "payable": false, 206 | "stateMutability": "view", 207 | "type": "function" 208 | }, 209 | { 210 | "anonymous": false, 211 | "inputs": [ 212 | { 213 | "indexed": true, 214 | "name": "_from", 215 | "type": "address" 216 | }, 217 | { 218 | "indexed": true, 219 | "name": "_to", 220 | "type": "address" 221 | }, 222 | { 223 | "indexed": false, 224 | "name": "_tokenId", 225 | "type": "uint256" 226 | } 227 | ], 228 | "name": "Transfer", 229 | "type": "event" 230 | }, 231 | { 232 | "anonymous": false, 233 | "inputs": [ 234 | { 235 | "indexed": true, 236 | "name": "_owner", 237 | "type": "address" 238 | }, 239 | { 240 | "indexed": true, 241 | "name": "_approved", 242 | "type": "address" 243 | }, 244 | { 245 | "indexed": false, 246 | "name": "_tokenId", 247 | "type": "uint256" 248 | } 249 | ], 250 | "name": "Approval", 251 | "type": "event" 252 | }, 253 | { 254 | "anonymous": false, 255 | "inputs": [ 256 | { 257 | "indexed": true, 258 | "name": "_owner", 259 | "type": "address" 260 | }, 261 | { 262 | "indexed": true, 263 | "name": "_operator", 264 | "type": "address" 265 | }, 266 | { 267 | "indexed": false, 268 | "name": "_approved", 269 | "type": "bool" 270 | } 271 | ], 272 | "name": "ApprovalForAll", 273 | "type": "event" 274 | }, 275 | { 276 | "constant": true, 277 | "inputs": [], 278 | "name": "name", 279 | "outputs": [ 280 | { 281 | "name": "_name", 282 | "type": "string" 283 | } 284 | ], 285 | "payable": false, 286 | "stateMutability": "view", 287 | "type": "function" 288 | }, 289 | { 290 | "constant": true, 291 | "inputs": [], 292 | "name": "symbol", 293 | "outputs": [ 294 | { 295 | "name": "_symbol", 296 | "type": "string" 297 | } 298 | ], 299 | "payable": false, 300 | "stateMutability": "view", 301 | "type": "function" 302 | }, 303 | { 304 | "constant": true, 305 | "inputs": [ 306 | { 307 | "name": "_tokenId", 308 | "type": "uint256" 309 | } 310 | ], 311 | "name": "tokenURI", 312 | "outputs": [ 313 | { 314 | "name": "", 315 | "type": "string" 316 | } 317 | ], 318 | "payable": false, 319 | "stateMutability": "view", 320 | "type": "function" 321 | } 322 | ], 323 | "bytecode": "0x", 324 | "deployedBytecode": "0x", 325 | "sourceMap": "", 326 | "deployedSourceMap": "", 327 | "source": "pragma solidity ^0.4.21;\n\nimport \"./ERC721Basic.sol\";\n\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension\n * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md\n */\ncontract ERC721Enumerable is ERC721Basic {\n function totalSupply() public view returns (uint256);\n function tokenOfOwnerByIndex(address _owner, uint256 _index) public view returns (uint256 _tokenId);\n function tokenByIndex(uint256 _index) public view returns (uint256);\n}\n\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md\n */\ncontract ERC721Metadata is ERC721Basic {\n function name() public view returns (string _name);\n function symbol() public view returns (string _symbol);\n function tokenURI(uint256 _tokenId) public view returns (string);\n}\n\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, full implementation interface\n * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md\n */\ncontract ERC721 is ERC721Basic, ERC721Enumerable, ERC721Metadata {\n}\n", 328 | "sourcePath": "zeppelin-solidity/contracts/token/ERC721/ERC721.sol", 329 | "ast": { 330 | "absolutePath": "zeppelin-solidity/contracts/token/ERC721/ERC721.sol", 331 | "exportedSymbols": { 332 | "ERC721": [ 333 | 1555 334 | ], 335 | "ERC721Enumerable": [ 336 | 1528 337 | ], 338 | "ERC721Metadata": [ 339 | 1548 340 | ] 341 | }, 342 | "id": 1556, 343 | "nodeType": "SourceUnit", 344 | "nodes": [ 345 | { 346 | "id": 1503, 347 | "literals": [ 348 | "solidity", 349 | "^", 350 | "0.4", 351 | ".21" 352 | ], 353 | "nodeType": "PragmaDirective", 354 | "src": "0:24:7" 355 | }, 356 | { 357 | "absolutePath": "zeppelin-solidity/contracts/token/ERC721/ERC721Basic.sol", 358 | "file": "./ERC721Basic.sol", 359 | "id": 1504, 360 | "nodeType": "ImportDirective", 361 | "scope": 1556, 362 | "sourceUnit": 1663, 363 | "src": "26:27:7", 364 | "symbolAliases": [], 365 | "unitAlias": "" 366 | }, 367 | { 368 | "baseContracts": [ 369 | { 370 | "arguments": null, 371 | "baseName": { 372 | "contractScope": null, 373 | "id": 1505, 374 | "name": "ERC721Basic", 375 | "nodeType": "UserDefinedTypeName", 376 | "referencedDeclaration": 1662, 377 | "src": "244:11:7", 378 | "typeDescriptions": { 379 | "typeIdentifier": "t_contract$_ERC721Basic_$1662", 380 | "typeString": "contract ERC721Basic" 381 | } 382 | }, 383 | "id": 1506, 384 | "nodeType": "InheritanceSpecifier", 385 | "src": "244:11:7" 386 | } 387 | ], 388 | "contractDependencies": [ 389 | 1662 390 | ], 391 | "contractKind": "contract", 392 | "documentation": "@title ERC-721 Non-Fungible Token Standard, optional enumeration extension\n@dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md", 393 | "fullyImplemented": false, 394 | "id": 1528, 395 | "linearizedBaseContracts": [ 396 | 1528, 397 | 1662 398 | ], 399 | "name": "ERC721Enumerable", 400 | "nodeType": "ContractDefinition", 401 | "nodes": [ 402 | { 403 | "body": null, 404 | "documentation": null, 405 | "id": 1511, 406 | "implemented": false, 407 | "isConstructor": false, 408 | "isDeclaredConst": true, 409 | "modifiers": [], 410 | "name": "totalSupply", 411 | "nodeType": "FunctionDefinition", 412 | "parameters": { 413 | "id": 1507, 414 | "nodeType": "ParameterList", 415 | "parameters": [], 416 | "src": "280:2:7" 417 | }, 418 | "payable": false, 419 | "returnParameters": { 420 | "id": 1510, 421 | "nodeType": "ParameterList", 422 | "parameters": [ 423 | { 424 | "constant": false, 425 | "id": 1509, 426 | "name": "", 427 | "nodeType": "VariableDeclaration", 428 | "scope": 1511, 429 | "src": "304:7:7", 430 | "stateVariable": false, 431 | "storageLocation": "default", 432 | "typeDescriptions": { 433 | "typeIdentifier": "t_uint256", 434 | "typeString": "uint256" 435 | }, 436 | "typeName": { 437 | "id": 1508, 438 | "name": "uint256", 439 | "nodeType": "ElementaryTypeName", 440 | "src": "304:7:7", 441 | "typeDescriptions": { 442 | "typeIdentifier": "t_uint256", 443 | "typeString": "uint256" 444 | } 445 | }, 446 | "value": null, 447 | "visibility": "internal" 448 | } 449 | ], 450 | "src": "303:9:7" 451 | }, 452 | "scope": 1528, 453 | "src": "260:53:7", 454 | "stateMutability": "view", 455 | "superFunction": null, 456 | "visibility": "public" 457 | }, 458 | { 459 | "body": null, 460 | "documentation": null, 461 | "id": 1520, 462 | "implemented": false, 463 | "isConstructor": false, 464 | "isDeclaredConst": true, 465 | "modifiers": [], 466 | "name": "tokenOfOwnerByIndex", 467 | "nodeType": "FunctionDefinition", 468 | "parameters": { 469 | "id": 1516, 470 | "nodeType": "ParameterList", 471 | "parameters": [ 472 | { 473 | "constant": false, 474 | "id": 1513, 475 | "name": "_owner", 476 | "nodeType": "VariableDeclaration", 477 | "scope": 1520, 478 | "src": "345:14:7", 479 | "stateVariable": false, 480 | "storageLocation": "default", 481 | "typeDescriptions": { 482 | "typeIdentifier": "t_address", 483 | "typeString": "address" 484 | }, 485 | "typeName": { 486 | "id": 1512, 487 | "name": "address", 488 | "nodeType": "ElementaryTypeName", 489 | "src": "345:7:7", 490 | "typeDescriptions": { 491 | "typeIdentifier": "t_address", 492 | "typeString": "address" 493 | } 494 | }, 495 | "value": null, 496 | "visibility": "internal" 497 | }, 498 | { 499 | "constant": false, 500 | "id": 1515, 501 | "name": "_index", 502 | "nodeType": "VariableDeclaration", 503 | "scope": 1520, 504 | "src": "361:14:7", 505 | "stateVariable": false, 506 | "storageLocation": "default", 507 | "typeDescriptions": { 508 | "typeIdentifier": "t_uint256", 509 | "typeString": "uint256" 510 | }, 511 | "typeName": { 512 | "id": 1514, 513 | "name": "uint256", 514 | "nodeType": "ElementaryTypeName", 515 | "src": "361:7:7", 516 | "typeDescriptions": { 517 | "typeIdentifier": "t_uint256", 518 | "typeString": "uint256" 519 | } 520 | }, 521 | "value": null, 522 | "visibility": "internal" 523 | } 524 | ], 525 | "src": "344:32:7" 526 | }, 527 | "payable": false, 528 | "returnParameters": { 529 | "id": 1519, 530 | "nodeType": "ParameterList", 531 | "parameters": [ 532 | { 533 | "constant": false, 534 | "id": 1518, 535 | "name": "_tokenId", 536 | "nodeType": "VariableDeclaration", 537 | "scope": 1520, 538 | "src": "398:16:7", 539 | "stateVariable": false, 540 | "storageLocation": "default", 541 | "typeDescriptions": { 542 | "typeIdentifier": "t_uint256", 543 | "typeString": "uint256" 544 | }, 545 | "typeName": { 546 | "id": 1517, 547 | "name": "uint256", 548 | "nodeType": "ElementaryTypeName", 549 | "src": "398:7:7", 550 | "typeDescriptions": { 551 | "typeIdentifier": "t_uint256", 552 | "typeString": "uint256" 553 | } 554 | }, 555 | "value": null, 556 | "visibility": "internal" 557 | } 558 | ], 559 | "src": "397:18:7" 560 | }, 561 | "scope": 1528, 562 | "src": "316:100:7", 563 | "stateMutability": "view", 564 | "superFunction": null, 565 | "visibility": "public" 566 | }, 567 | { 568 | "body": null, 569 | "documentation": null, 570 | "id": 1527, 571 | "implemented": false, 572 | "isConstructor": false, 573 | "isDeclaredConst": true, 574 | "modifiers": [], 575 | "name": "tokenByIndex", 576 | "nodeType": "FunctionDefinition", 577 | "parameters": { 578 | "id": 1523, 579 | "nodeType": "ParameterList", 580 | "parameters": [ 581 | { 582 | "constant": false, 583 | "id": 1522, 584 | "name": "_index", 585 | "nodeType": "VariableDeclaration", 586 | "scope": 1527, 587 | "src": "441:14:7", 588 | "stateVariable": false, 589 | "storageLocation": "default", 590 | "typeDescriptions": { 591 | "typeIdentifier": "t_uint256", 592 | "typeString": "uint256" 593 | }, 594 | "typeName": { 595 | "id": 1521, 596 | "name": "uint256", 597 | "nodeType": "ElementaryTypeName", 598 | "src": "441:7:7", 599 | "typeDescriptions": { 600 | "typeIdentifier": "t_uint256", 601 | "typeString": "uint256" 602 | } 603 | }, 604 | "value": null, 605 | "visibility": "internal" 606 | } 607 | ], 608 | "src": "440:16:7" 609 | }, 610 | "payable": false, 611 | "returnParameters": { 612 | "id": 1526, 613 | "nodeType": "ParameterList", 614 | "parameters": [ 615 | { 616 | "constant": false, 617 | "id": 1525, 618 | "name": "", 619 | "nodeType": "VariableDeclaration", 620 | "scope": 1527, 621 | "src": "478:7:7", 622 | "stateVariable": false, 623 | "storageLocation": "default", 624 | "typeDescriptions": { 625 | "typeIdentifier": "t_uint256", 626 | "typeString": "uint256" 627 | }, 628 | "typeName": { 629 | "id": 1524, 630 | "name": "uint256", 631 | "nodeType": "ElementaryTypeName", 632 | "src": "478:7:7", 633 | "typeDescriptions": { 634 | "typeIdentifier": "t_uint256", 635 | "typeString": "uint256" 636 | } 637 | }, 638 | "value": null, 639 | "visibility": "internal" 640 | } 641 | ], 642 | "src": "477:9:7" 643 | }, 644 | "scope": 1528, 645 | "src": "419:68:7", 646 | "stateMutability": "view", 647 | "superFunction": null, 648 | "visibility": "public" 649 | } 650 | ], 651 | "scope": 1556, 652 | "src": "215:274:7" 653 | }, 654 | { 655 | "baseContracts": [ 656 | { 657 | "arguments": null, 658 | "baseName": { 659 | "contractScope": null, 660 | "id": 1529, 661 | "name": "ERC721Basic", 662 | "nodeType": "UserDefinedTypeName", 663 | "referencedDeclaration": 1662, 664 | "src": "675:11:7", 665 | "typeDescriptions": { 666 | "typeIdentifier": "t_contract$_ERC721Basic_$1662", 667 | "typeString": "contract ERC721Basic" 668 | } 669 | }, 670 | "id": 1530, 671 | "nodeType": "InheritanceSpecifier", 672 | "src": "675:11:7" 673 | } 674 | ], 675 | "contractDependencies": [ 676 | 1662 677 | ], 678 | "contractKind": "contract", 679 | "documentation": "@title ERC-721 Non-Fungible Token Standard, optional metadata extension\n@dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md", 680 | "fullyImplemented": false, 681 | "id": 1548, 682 | "linearizedBaseContracts": [ 683 | 1548, 684 | 1662 685 | ], 686 | "name": "ERC721Metadata", 687 | "nodeType": "ContractDefinition", 688 | "nodes": [ 689 | { 690 | "body": null, 691 | "documentation": null, 692 | "id": 1535, 693 | "implemented": false, 694 | "isConstructor": false, 695 | "isDeclaredConst": true, 696 | "modifiers": [], 697 | "name": "name", 698 | "nodeType": "FunctionDefinition", 699 | "parameters": { 700 | "id": 1531, 701 | "nodeType": "ParameterList", 702 | "parameters": [], 703 | "src": "704:2:7" 704 | }, 705 | "payable": false, 706 | "returnParameters": { 707 | "id": 1534, 708 | "nodeType": "ParameterList", 709 | "parameters": [ 710 | { 711 | "constant": false, 712 | "id": 1533, 713 | "name": "_name", 714 | "nodeType": "VariableDeclaration", 715 | "scope": 1535, 716 | "src": "728:12:7", 717 | "stateVariable": false, 718 | "storageLocation": "default", 719 | "typeDescriptions": { 720 | "typeIdentifier": "t_string_memory_ptr", 721 | "typeString": "string" 722 | }, 723 | "typeName": { 724 | "id": 1532, 725 | "name": "string", 726 | "nodeType": "ElementaryTypeName", 727 | "src": "728:6:7", 728 | "typeDescriptions": { 729 | "typeIdentifier": "t_string_storage_ptr", 730 | "typeString": "string" 731 | } 732 | }, 733 | "value": null, 734 | "visibility": "internal" 735 | } 736 | ], 737 | "src": "727:14:7" 738 | }, 739 | "scope": 1548, 740 | "src": "691:51:7", 741 | "stateMutability": "view", 742 | "superFunction": null, 743 | "visibility": "public" 744 | }, 745 | { 746 | "body": null, 747 | "documentation": null, 748 | "id": 1540, 749 | "implemented": false, 750 | "isConstructor": false, 751 | "isDeclaredConst": true, 752 | "modifiers": [], 753 | "name": "symbol", 754 | "nodeType": "FunctionDefinition", 755 | "parameters": { 756 | "id": 1536, 757 | "nodeType": "ParameterList", 758 | "parameters": [], 759 | "src": "760:2:7" 760 | }, 761 | "payable": false, 762 | "returnParameters": { 763 | "id": 1539, 764 | "nodeType": "ParameterList", 765 | "parameters": [ 766 | { 767 | "constant": false, 768 | "id": 1538, 769 | "name": "_symbol", 770 | "nodeType": "VariableDeclaration", 771 | "scope": 1540, 772 | "src": "784:14:7", 773 | "stateVariable": false, 774 | "storageLocation": "default", 775 | "typeDescriptions": { 776 | "typeIdentifier": "t_string_memory_ptr", 777 | "typeString": "string" 778 | }, 779 | "typeName": { 780 | "id": 1537, 781 | "name": "string", 782 | "nodeType": "ElementaryTypeName", 783 | "src": "784:6:7", 784 | "typeDescriptions": { 785 | "typeIdentifier": "t_string_storage_ptr", 786 | "typeString": "string" 787 | } 788 | }, 789 | "value": null, 790 | "visibility": "internal" 791 | } 792 | ], 793 | "src": "783:16:7" 794 | }, 795 | "scope": 1548, 796 | "src": "745:55:7", 797 | "stateMutability": "view", 798 | "superFunction": null, 799 | "visibility": "public" 800 | }, 801 | { 802 | "body": null, 803 | "documentation": null, 804 | "id": 1547, 805 | "implemented": false, 806 | "isConstructor": false, 807 | "isDeclaredConst": true, 808 | "modifiers": [], 809 | "name": "tokenURI", 810 | "nodeType": "FunctionDefinition", 811 | "parameters": { 812 | "id": 1543, 813 | "nodeType": "ParameterList", 814 | "parameters": [ 815 | { 816 | "constant": false, 817 | "id": 1542, 818 | "name": "_tokenId", 819 | "nodeType": "VariableDeclaration", 820 | "scope": 1547, 821 | "src": "821:16:7", 822 | "stateVariable": false, 823 | "storageLocation": "default", 824 | "typeDescriptions": { 825 | "typeIdentifier": "t_uint256", 826 | "typeString": "uint256" 827 | }, 828 | "typeName": { 829 | "id": 1541, 830 | "name": "uint256", 831 | "nodeType": "ElementaryTypeName", 832 | "src": "821:7:7", 833 | "typeDescriptions": { 834 | "typeIdentifier": "t_uint256", 835 | "typeString": "uint256" 836 | } 837 | }, 838 | "value": null, 839 | "visibility": "internal" 840 | } 841 | ], 842 | "src": "820:18:7" 843 | }, 844 | "payable": false, 845 | "returnParameters": { 846 | "id": 1546, 847 | "nodeType": "ParameterList", 848 | "parameters": [ 849 | { 850 | "constant": false, 851 | "id": 1545, 852 | "name": "", 853 | "nodeType": "VariableDeclaration", 854 | "scope": 1547, 855 | "src": "860:6:7", 856 | "stateVariable": false, 857 | "storageLocation": "default", 858 | "typeDescriptions": { 859 | "typeIdentifier": "t_string_memory_ptr", 860 | "typeString": "string" 861 | }, 862 | "typeName": { 863 | "id": 1544, 864 | "name": "string", 865 | "nodeType": "ElementaryTypeName", 866 | "src": "860:6:7", 867 | "typeDescriptions": { 868 | "typeIdentifier": "t_string_storage_ptr", 869 | "typeString": "string" 870 | } 871 | }, 872 | "value": null, 873 | "visibility": "internal" 874 | } 875 | ], 876 | "src": "859:8:7" 877 | }, 878 | "scope": 1548, 879 | "src": "803:65:7", 880 | "stateMutability": "view", 881 | "superFunction": null, 882 | "visibility": "public" 883 | } 884 | ], 885 | "scope": 1556, 886 | "src": "648:222:7" 887 | }, 888 | { 889 | "baseContracts": [ 890 | { 891 | "arguments": null, 892 | "baseName": { 893 | "contractScope": null, 894 | "id": 1549, 895 | "name": "ERC721Basic", 896 | "nodeType": "UserDefinedTypeName", 897 | "referencedDeclaration": 1662, 898 | "src": "1050:11:7", 899 | "typeDescriptions": { 900 | "typeIdentifier": "t_contract$_ERC721Basic_$1662", 901 | "typeString": "contract ERC721Basic" 902 | } 903 | }, 904 | "id": 1550, 905 | "nodeType": "InheritanceSpecifier", 906 | "src": "1050:11:7" 907 | }, 908 | { 909 | "arguments": null, 910 | "baseName": { 911 | "contractScope": null, 912 | "id": 1551, 913 | "name": "ERC721Enumerable", 914 | "nodeType": "UserDefinedTypeName", 915 | "referencedDeclaration": 1528, 916 | "src": "1063:16:7", 917 | "typeDescriptions": { 918 | "typeIdentifier": "t_contract$_ERC721Enumerable_$1528", 919 | "typeString": "contract ERC721Enumerable" 920 | } 921 | }, 922 | "id": 1552, 923 | "nodeType": "InheritanceSpecifier", 924 | "src": "1063:16:7" 925 | }, 926 | { 927 | "arguments": null, 928 | "baseName": { 929 | "contractScope": null, 930 | "id": 1553, 931 | "name": "ERC721Metadata", 932 | "nodeType": "UserDefinedTypeName", 933 | "referencedDeclaration": 1548, 934 | "src": "1081:14:7", 935 | "typeDescriptions": { 936 | "typeIdentifier": "t_contract$_ERC721Metadata_$1548", 937 | "typeString": "contract ERC721Metadata" 938 | } 939 | }, 940 | "id": 1554, 941 | "nodeType": "InheritanceSpecifier", 942 | "src": "1081:14:7" 943 | } 944 | ], 945 | "contractDependencies": [ 946 | 1528, 947 | 1548, 948 | 1662 949 | ], 950 | "contractKind": "contract", 951 | "documentation": "@title ERC-721 Non-Fungible Token Standard, full implementation interface\n@dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md", 952 | "fullyImplemented": false, 953 | "id": 1555, 954 | "linearizedBaseContracts": [ 955 | 1555, 956 | 1548, 957 | 1528, 958 | 1662 959 | ], 960 | "name": "ERC721", 961 | "nodeType": "ContractDefinition", 962 | "nodes": [], 963 | "scope": 1556, 964 | "src": "1031:68:7" 965 | } 966 | ], 967 | "src": "0:1100:7" 968 | }, 969 | "legacyAST": { 970 | "absolutePath": "zeppelin-solidity/contracts/token/ERC721/ERC721.sol", 971 | "exportedSymbols": { 972 | "ERC721": [ 973 | 1555 974 | ], 975 | "ERC721Enumerable": [ 976 | 1528 977 | ], 978 | "ERC721Metadata": [ 979 | 1548 980 | ] 981 | }, 982 | "id": 1556, 983 | "nodeType": "SourceUnit", 984 | "nodes": [ 985 | { 986 | "id": 1503, 987 | "literals": [ 988 | "solidity", 989 | "^", 990 | "0.4", 991 | ".21" 992 | ], 993 | "nodeType": "PragmaDirective", 994 | "src": "0:24:7" 995 | }, 996 | { 997 | "absolutePath": "zeppelin-solidity/contracts/token/ERC721/ERC721Basic.sol", 998 | "file": "./ERC721Basic.sol", 999 | "id": 1504, 1000 | "nodeType": "ImportDirective", 1001 | "scope": 1556, 1002 | "sourceUnit": 1663, 1003 | "src": "26:27:7", 1004 | "symbolAliases": [], 1005 | "unitAlias": "" 1006 | }, 1007 | { 1008 | "baseContracts": [ 1009 | { 1010 | "arguments": null, 1011 | "baseName": { 1012 | "contractScope": null, 1013 | "id": 1505, 1014 | "name": "ERC721Basic", 1015 | "nodeType": "UserDefinedTypeName", 1016 | "referencedDeclaration": 1662, 1017 | "src": "244:11:7", 1018 | "typeDescriptions": { 1019 | "typeIdentifier": "t_contract$_ERC721Basic_$1662", 1020 | "typeString": "contract ERC721Basic" 1021 | } 1022 | }, 1023 | "id": 1506, 1024 | "nodeType": "InheritanceSpecifier", 1025 | "src": "244:11:7" 1026 | } 1027 | ], 1028 | "contractDependencies": [ 1029 | 1662 1030 | ], 1031 | "contractKind": "contract", 1032 | "documentation": "@title ERC-721 Non-Fungible Token Standard, optional enumeration extension\n@dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md", 1033 | "fullyImplemented": false, 1034 | "id": 1528, 1035 | "linearizedBaseContracts": [ 1036 | 1528, 1037 | 1662 1038 | ], 1039 | "name": "ERC721Enumerable", 1040 | "nodeType": "ContractDefinition", 1041 | "nodes": [ 1042 | { 1043 | "body": null, 1044 | "documentation": null, 1045 | "id": 1511, 1046 | "implemented": false, 1047 | "isConstructor": false, 1048 | "isDeclaredConst": true, 1049 | "modifiers": [], 1050 | "name": "totalSupply", 1051 | "nodeType": "FunctionDefinition", 1052 | "parameters": { 1053 | "id": 1507, 1054 | "nodeType": "ParameterList", 1055 | "parameters": [], 1056 | "src": "280:2:7" 1057 | }, 1058 | "payable": false, 1059 | "returnParameters": { 1060 | "id": 1510, 1061 | "nodeType": "ParameterList", 1062 | "parameters": [ 1063 | { 1064 | "constant": false, 1065 | "id": 1509, 1066 | "name": "", 1067 | "nodeType": "VariableDeclaration", 1068 | "scope": 1511, 1069 | "src": "304:7:7", 1070 | "stateVariable": false, 1071 | "storageLocation": "default", 1072 | "typeDescriptions": { 1073 | "typeIdentifier": "t_uint256", 1074 | "typeString": "uint256" 1075 | }, 1076 | "typeName": { 1077 | "id": 1508, 1078 | "name": "uint256", 1079 | "nodeType": "ElementaryTypeName", 1080 | "src": "304:7:7", 1081 | "typeDescriptions": { 1082 | "typeIdentifier": "t_uint256", 1083 | "typeString": "uint256" 1084 | } 1085 | }, 1086 | "value": null, 1087 | "visibility": "internal" 1088 | } 1089 | ], 1090 | "src": "303:9:7" 1091 | }, 1092 | "scope": 1528, 1093 | "src": "260:53:7", 1094 | "stateMutability": "view", 1095 | "superFunction": null, 1096 | "visibility": "public" 1097 | }, 1098 | { 1099 | "body": null, 1100 | "documentation": null, 1101 | "id": 1520, 1102 | "implemented": false, 1103 | "isConstructor": false, 1104 | "isDeclaredConst": true, 1105 | "modifiers": [], 1106 | "name": "tokenOfOwnerByIndex", 1107 | "nodeType": "FunctionDefinition", 1108 | "parameters": { 1109 | "id": 1516, 1110 | "nodeType": "ParameterList", 1111 | "parameters": [ 1112 | { 1113 | "constant": false, 1114 | "id": 1513, 1115 | "name": "_owner", 1116 | "nodeType": "VariableDeclaration", 1117 | "scope": 1520, 1118 | "src": "345:14:7", 1119 | "stateVariable": false, 1120 | "storageLocation": "default", 1121 | "typeDescriptions": { 1122 | "typeIdentifier": "t_address", 1123 | "typeString": "address" 1124 | }, 1125 | "typeName": { 1126 | "id": 1512, 1127 | "name": "address", 1128 | "nodeType": "ElementaryTypeName", 1129 | "src": "345:7:7", 1130 | "typeDescriptions": { 1131 | "typeIdentifier": "t_address", 1132 | "typeString": "address" 1133 | } 1134 | }, 1135 | "value": null, 1136 | "visibility": "internal" 1137 | }, 1138 | { 1139 | "constant": false, 1140 | "id": 1515, 1141 | "name": "_index", 1142 | "nodeType": "VariableDeclaration", 1143 | "scope": 1520, 1144 | "src": "361:14:7", 1145 | "stateVariable": false, 1146 | "storageLocation": "default", 1147 | "typeDescriptions": { 1148 | "typeIdentifier": "t_uint256", 1149 | "typeString": "uint256" 1150 | }, 1151 | "typeName": { 1152 | "id": 1514, 1153 | "name": "uint256", 1154 | "nodeType": "ElementaryTypeName", 1155 | "src": "361:7:7", 1156 | "typeDescriptions": { 1157 | "typeIdentifier": "t_uint256", 1158 | "typeString": "uint256" 1159 | } 1160 | }, 1161 | "value": null, 1162 | "visibility": "internal" 1163 | } 1164 | ], 1165 | "src": "344:32:7" 1166 | }, 1167 | "payable": false, 1168 | "returnParameters": { 1169 | "id": 1519, 1170 | "nodeType": "ParameterList", 1171 | "parameters": [ 1172 | { 1173 | "constant": false, 1174 | "id": 1518, 1175 | "name": "_tokenId", 1176 | "nodeType": "VariableDeclaration", 1177 | "scope": 1520, 1178 | "src": "398:16:7", 1179 | "stateVariable": false, 1180 | "storageLocation": "default", 1181 | "typeDescriptions": { 1182 | "typeIdentifier": "t_uint256", 1183 | "typeString": "uint256" 1184 | }, 1185 | "typeName": { 1186 | "id": 1517, 1187 | "name": "uint256", 1188 | "nodeType": "ElementaryTypeName", 1189 | "src": "398:7:7", 1190 | "typeDescriptions": { 1191 | "typeIdentifier": "t_uint256", 1192 | "typeString": "uint256" 1193 | } 1194 | }, 1195 | "value": null, 1196 | "visibility": "internal" 1197 | } 1198 | ], 1199 | "src": "397:18:7" 1200 | }, 1201 | "scope": 1528, 1202 | "src": "316:100:7", 1203 | "stateMutability": "view", 1204 | "superFunction": null, 1205 | "visibility": "public" 1206 | }, 1207 | { 1208 | "body": null, 1209 | "documentation": null, 1210 | "id": 1527, 1211 | "implemented": false, 1212 | "isConstructor": false, 1213 | "isDeclaredConst": true, 1214 | "modifiers": [], 1215 | "name": "tokenByIndex", 1216 | "nodeType": "FunctionDefinition", 1217 | "parameters": { 1218 | "id": 1523, 1219 | "nodeType": "ParameterList", 1220 | "parameters": [ 1221 | { 1222 | "constant": false, 1223 | "id": 1522, 1224 | "name": "_index", 1225 | "nodeType": "VariableDeclaration", 1226 | "scope": 1527, 1227 | "src": "441:14:7", 1228 | "stateVariable": false, 1229 | "storageLocation": "default", 1230 | "typeDescriptions": { 1231 | "typeIdentifier": "t_uint256", 1232 | "typeString": "uint256" 1233 | }, 1234 | "typeName": { 1235 | "id": 1521, 1236 | "name": "uint256", 1237 | "nodeType": "ElementaryTypeName", 1238 | "src": "441:7:7", 1239 | "typeDescriptions": { 1240 | "typeIdentifier": "t_uint256", 1241 | "typeString": "uint256" 1242 | } 1243 | }, 1244 | "value": null, 1245 | "visibility": "internal" 1246 | } 1247 | ], 1248 | "src": "440:16:7" 1249 | }, 1250 | "payable": false, 1251 | "returnParameters": { 1252 | "id": 1526, 1253 | "nodeType": "ParameterList", 1254 | "parameters": [ 1255 | { 1256 | "constant": false, 1257 | "id": 1525, 1258 | "name": "", 1259 | "nodeType": "VariableDeclaration", 1260 | "scope": 1527, 1261 | "src": "478:7:7", 1262 | "stateVariable": false, 1263 | "storageLocation": "default", 1264 | "typeDescriptions": { 1265 | "typeIdentifier": "t_uint256", 1266 | "typeString": "uint256" 1267 | }, 1268 | "typeName": { 1269 | "id": 1524, 1270 | "name": "uint256", 1271 | "nodeType": "ElementaryTypeName", 1272 | "src": "478:7:7", 1273 | "typeDescriptions": { 1274 | "typeIdentifier": "t_uint256", 1275 | "typeString": "uint256" 1276 | } 1277 | }, 1278 | "value": null, 1279 | "visibility": "internal" 1280 | } 1281 | ], 1282 | "src": "477:9:7" 1283 | }, 1284 | "scope": 1528, 1285 | "src": "419:68:7", 1286 | "stateMutability": "view", 1287 | "superFunction": null, 1288 | "visibility": "public" 1289 | } 1290 | ], 1291 | "scope": 1556, 1292 | "src": "215:274:7" 1293 | }, 1294 | { 1295 | "baseContracts": [ 1296 | { 1297 | "arguments": null, 1298 | "baseName": { 1299 | "contractScope": null, 1300 | "id": 1529, 1301 | "name": "ERC721Basic", 1302 | "nodeType": "UserDefinedTypeName", 1303 | "referencedDeclaration": 1662, 1304 | "src": "675:11:7", 1305 | "typeDescriptions": { 1306 | "typeIdentifier": "t_contract$_ERC721Basic_$1662", 1307 | "typeString": "contract ERC721Basic" 1308 | } 1309 | }, 1310 | "id": 1530, 1311 | "nodeType": "InheritanceSpecifier", 1312 | "src": "675:11:7" 1313 | } 1314 | ], 1315 | "contractDependencies": [ 1316 | 1662 1317 | ], 1318 | "contractKind": "contract", 1319 | "documentation": "@title ERC-721 Non-Fungible Token Standard, optional metadata extension\n@dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md", 1320 | "fullyImplemented": false, 1321 | "id": 1548, 1322 | "linearizedBaseContracts": [ 1323 | 1548, 1324 | 1662 1325 | ], 1326 | "name": "ERC721Metadata", 1327 | "nodeType": "ContractDefinition", 1328 | "nodes": [ 1329 | { 1330 | "body": null, 1331 | "documentation": null, 1332 | "id": 1535, 1333 | "implemented": false, 1334 | "isConstructor": false, 1335 | "isDeclaredConst": true, 1336 | "modifiers": [], 1337 | "name": "name", 1338 | "nodeType": "FunctionDefinition", 1339 | "parameters": { 1340 | "id": 1531, 1341 | "nodeType": "ParameterList", 1342 | "parameters": [], 1343 | "src": "704:2:7" 1344 | }, 1345 | "payable": false, 1346 | "returnParameters": { 1347 | "id": 1534, 1348 | "nodeType": "ParameterList", 1349 | "parameters": [ 1350 | { 1351 | "constant": false, 1352 | "id": 1533, 1353 | "name": "_name", 1354 | "nodeType": "VariableDeclaration", 1355 | "scope": 1535, 1356 | "src": "728:12:7", 1357 | "stateVariable": false, 1358 | "storageLocation": "default", 1359 | "typeDescriptions": { 1360 | "typeIdentifier": "t_string_memory_ptr", 1361 | "typeString": "string" 1362 | }, 1363 | "typeName": { 1364 | "id": 1532, 1365 | "name": "string", 1366 | "nodeType": "ElementaryTypeName", 1367 | "src": "728:6:7", 1368 | "typeDescriptions": { 1369 | "typeIdentifier": "t_string_storage_ptr", 1370 | "typeString": "string" 1371 | } 1372 | }, 1373 | "value": null, 1374 | "visibility": "internal" 1375 | } 1376 | ], 1377 | "src": "727:14:7" 1378 | }, 1379 | "scope": 1548, 1380 | "src": "691:51:7", 1381 | "stateMutability": "view", 1382 | "superFunction": null, 1383 | "visibility": "public" 1384 | }, 1385 | { 1386 | "body": null, 1387 | "documentation": null, 1388 | "id": 1540, 1389 | "implemented": false, 1390 | "isConstructor": false, 1391 | "isDeclaredConst": true, 1392 | "modifiers": [], 1393 | "name": "symbol", 1394 | "nodeType": "FunctionDefinition", 1395 | "parameters": { 1396 | "id": 1536, 1397 | "nodeType": "ParameterList", 1398 | "parameters": [], 1399 | "src": "760:2:7" 1400 | }, 1401 | "payable": false, 1402 | "returnParameters": { 1403 | "id": 1539, 1404 | "nodeType": "ParameterList", 1405 | "parameters": [ 1406 | { 1407 | "constant": false, 1408 | "id": 1538, 1409 | "name": "_symbol", 1410 | "nodeType": "VariableDeclaration", 1411 | "scope": 1540, 1412 | "src": "784:14:7", 1413 | "stateVariable": false, 1414 | "storageLocation": "default", 1415 | "typeDescriptions": { 1416 | "typeIdentifier": "t_string_memory_ptr", 1417 | "typeString": "string" 1418 | }, 1419 | "typeName": { 1420 | "id": 1537, 1421 | "name": "string", 1422 | "nodeType": "ElementaryTypeName", 1423 | "src": "784:6:7", 1424 | "typeDescriptions": { 1425 | "typeIdentifier": "t_string_storage_ptr", 1426 | "typeString": "string" 1427 | } 1428 | }, 1429 | "value": null, 1430 | "visibility": "internal" 1431 | } 1432 | ], 1433 | "src": "783:16:7" 1434 | }, 1435 | "scope": 1548, 1436 | "src": "745:55:7", 1437 | "stateMutability": "view", 1438 | "superFunction": null, 1439 | "visibility": "public" 1440 | }, 1441 | { 1442 | "body": null, 1443 | "documentation": null, 1444 | "id": 1547, 1445 | "implemented": false, 1446 | "isConstructor": false, 1447 | "isDeclaredConst": true, 1448 | "modifiers": [], 1449 | "name": "tokenURI", 1450 | "nodeType": "FunctionDefinition", 1451 | "parameters": { 1452 | "id": 1543, 1453 | "nodeType": "ParameterList", 1454 | "parameters": [ 1455 | { 1456 | "constant": false, 1457 | "id": 1542, 1458 | "name": "_tokenId", 1459 | "nodeType": "VariableDeclaration", 1460 | "scope": 1547, 1461 | "src": "821:16:7", 1462 | "stateVariable": false, 1463 | "storageLocation": "default", 1464 | "typeDescriptions": { 1465 | "typeIdentifier": "t_uint256", 1466 | "typeString": "uint256" 1467 | }, 1468 | "typeName": { 1469 | "id": 1541, 1470 | "name": "uint256", 1471 | "nodeType": "ElementaryTypeName", 1472 | "src": "821:7:7", 1473 | "typeDescriptions": { 1474 | "typeIdentifier": "t_uint256", 1475 | "typeString": "uint256" 1476 | } 1477 | }, 1478 | "value": null, 1479 | "visibility": "internal" 1480 | } 1481 | ], 1482 | "src": "820:18:7" 1483 | }, 1484 | "payable": false, 1485 | "returnParameters": { 1486 | "id": 1546, 1487 | "nodeType": "ParameterList", 1488 | "parameters": [ 1489 | { 1490 | "constant": false, 1491 | "id": 1545, 1492 | "name": "", 1493 | "nodeType": "VariableDeclaration", 1494 | "scope": 1547, 1495 | "src": "860:6:7", 1496 | "stateVariable": false, 1497 | "storageLocation": "default", 1498 | "typeDescriptions": { 1499 | "typeIdentifier": "t_string_memory_ptr", 1500 | "typeString": "string" 1501 | }, 1502 | "typeName": { 1503 | "id": 1544, 1504 | "name": "string", 1505 | "nodeType": "ElementaryTypeName", 1506 | "src": "860:6:7", 1507 | "typeDescriptions": { 1508 | "typeIdentifier": "t_string_storage_ptr", 1509 | "typeString": "string" 1510 | } 1511 | }, 1512 | "value": null, 1513 | "visibility": "internal" 1514 | } 1515 | ], 1516 | "src": "859:8:7" 1517 | }, 1518 | "scope": 1548, 1519 | "src": "803:65:7", 1520 | "stateMutability": "view", 1521 | "superFunction": null, 1522 | "visibility": "public" 1523 | } 1524 | ], 1525 | "scope": 1556, 1526 | "src": "648:222:7" 1527 | }, 1528 | { 1529 | "baseContracts": [ 1530 | { 1531 | "arguments": null, 1532 | "baseName": { 1533 | "contractScope": null, 1534 | "id": 1549, 1535 | "name": "ERC721Basic", 1536 | "nodeType": "UserDefinedTypeName", 1537 | "referencedDeclaration": 1662, 1538 | "src": "1050:11:7", 1539 | "typeDescriptions": { 1540 | "typeIdentifier": "t_contract$_ERC721Basic_$1662", 1541 | "typeString": "contract ERC721Basic" 1542 | } 1543 | }, 1544 | "id": 1550, 1545 | "nodeType": "InheritanceSpecifier", 1546 | "src": "1050:11:7" 1547 | }, 1548 | { 1549 | "arguments": null, 1550 | "baseName": { 1551 | "contractScope": null, 1552 | "id": 1551, 1553 | "name": "ERC721Enumerable", 1554 | "nodeType": "UserDefinedTypeName", 1555 | "referencedDeclaration": 1528, 1556 | "src": "1063:16:7", 1557 | "typeDescriptions": { 1558 | "typeIdentifier": "t_contract$_ERC721Enumerable_$1528", 1559 | "typeString": "contract ERC721Enumerable" 1560 | } 1561 | }, 1562 | "id": 1552, 1563 | "nodeType": "InheritanceSpecifier", 1564 | "src": "1063:16:7" 1565 | }, 1566 | { 1567 | "arguments": null, 1568 | "baseName": { 1569 | "contractScope": null, 1570 | "id": 1553, 1571 | "name": "ERC721Metadata", 1572 | "nodeType": "UserDefinedTypeName", 1573 | "referencedDeclaration": 1548, 1574 | "src": "1081:14:7", 1575 | "typeDescriptions": { 1576 | "typeIdentifier": "t_contract$_ERC721Metadata_$1548", 1577 | "typeString": "contract ERC721Metadata" 1578 | } 1579 | }, 1580 | "id": 1554, 1581 | "nodeType": "InheritanceSpecifier", 1582 | "src": "1081:14:7" 1583 | } 1584 | ], 1585 | "contractDependencies": [ 1586 | 1528, 1587 | 1548, 1588 | 1662 1589 | ], 1590 | "contractKind": "contract", 1591 | "documentation": "@title ERC-721 Non-Fungible Token Standard, full implementation interface\n@dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md", 1592 | "fullyImplemented": false, 1593 | "id": 1555, 1594 | "linearizedBaseContracts": [ 1595 | 1555, 1596 | 1548, 1597 | 1528, 1598 | 1662 1599 | ], 1600 | "name": "ERC721", 1601 | "nodeType": "ContractDefinition", 1602 | "nodes": [], 1603 | "scope": 1556, 1604 | "src": "1031:68:7" 1605 | } 1606 | ], 1607 | "src": "0:1100:7" 1608 | }, 1609 | "compiler": { 1610 | "name": "solc", 1611 | "version": "0.4.23+commit.124ca40d.Emscripten.clang" 1612 | }, 1613 | "networks": {}, 1614 | "schemaVersion": "2.0.0", 1615 | "updatedAt": "2018-05-13T21:06:29.993Z" 1616 | } -------------------------------------------------------------------------------- /build/contracts/ERC721Receiver.json: -------------------------------------------------------------------------------- 1 | { 2 | "contractName": "ERC721Receiver", 3 | "abi": [ 4 | { 5 | "constant": false, 6 | "inputs": [ 7 | { 8 | "name": "_from", 9 | "type": "address" 10 | }, 11 | { 12 | "name": "_tokenId", 13 | "type": "uint256" 14 | }, 15 | { 16 | "name": "_data", 17 | "type": "bytes" 18 | } 19 | ], 20 | "name": "onERC721Received", 21 | "outputs": [ 22 | { 23 | "name": "", 24 | "type": "bytes4" 25 | } 26 | ], 27 | "payable": false, 28 | "stateMutability": "nonpayable", 29 | "type": "function" 30 | } 31 | ], 32 | "bytecode": "0x", 33 | "deployedBytecode": "0x", 34 | "sourceMap": "", 35 | "deployedSourceMap": "", 36 | "source": "pragma solidity ^0.4.21;\n\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ncontract ERC721Receiver {\n /**\n * @dev Magic value to be returned upon successful reception of an NFT\n * Equals to `bytes4(keccak256(\"onERC721Received(address,uint256,bytes)\"))`,\n * which can be also obtained as `ERC721Receiver(0).onERC721Received.selector`\n */\n bytes4 constant ERC721_RECEIVED = 0xf0b9e5ba;\n\n /**\n * @notice Handle the receipt of an NFT\n * @dev The ERC721 smart contract calls this function on the recipient\n * after a `safetransfer`. This function MAY throw to revert and reject the\n * transfer. This function MUST use 50,000 gas or less. Return of other\n * than the magic value MUST result in the transaction being reverted.\n * Note: the contract address is always the message sender.\n * @param _from The sending address\n * @param _tokenId The NFT identifier which is being transfered\n * @param _data Additional data with no specified format\n * @return `bytes4(keccak256(\"onERC721Received(address,uint256,bytes)\"))`\n */\n function onERC721Received(address _from, uint256 _tokenId, bytes _data) public returns(bytes4);\n}\n", 37 | "sourcePath": "zeppelin-solidity/contracts/token/ERC721/ERC721Receiver.sol", 38 | "ast": { 39 | "absolutePath": "zeppelin-solidity/contracts/token/ERC721/ERC721Receiver.sol", 40 | "exportedSymbols": { 41 | "ERC721Receiver": [ 42 | 2262 43 | ] 44 | }, 45 | "id": 2263, 46 | "nodeType": "SourceUnit", 47 | "nodes": [ 48 | { 49 | "id": 2247, 50 | "literals": [ 51 | "solidity", 52 | "^", 53 | "0.4", 54 | ".21" 55 | ], 56 | "nodeType": "PragmaDirective", 57 | "src": "0:24:10" 58 | }, 59 | { 60 | "baseContracts": [], 61 | "contractDependencies": [], 62 | "contractKind": "contract", 63 | "documentation": "@title ERC721 token receiver interface\n@dev Interface for any contract that wants to support safeTransfers\n from ERC721 asset contracts.", 64 | "fullyImplemented": false, 65 | "id": 2262, 66 | "linearizedBaseContracts": [ 67 | 2262 68 | ], 69 | "name": "ERC721Receiver", 70 | "nodeType": "ContractDefinition", 71 | "nodes": [ 72 | { 73 | "constant": true, 74 | "id": 2250, 75 | "name": "ERC721_RECEIVED", 76 | "nodeType": "VariableDeclaration", 77 | "scope": 2262, 78 | "src": "456:44:10", 79 | "stateVariable": true, 80 | "storageLocation": "default", 81 | "typeDescriptions": { 82 | "typeIdentifier": "t_bytes4", 83 | "typeString": "bytes4" 84 | }, 85 | "typeName": { 86 | "id": 2248, 87 | "name": "bytes4", 88 | "nodeType": "ElementaryTypeName", 89 | "src": "456:6:10", 90 | "typeDescriptions": { 91 | "typeIdentifier": "t_bytes4", 92 | "typeString": "bytes4" 93 | } 94 | }, 95 | "value": { 96 | "argumentTypes": null, 97 | "hexValue": "30786630623965356261", 98 | "id": 2249, 99 | "isConstant": false, 100 | "isLValue": false, 101 | "isPure": true, 102 | "kind": "number", 103 | "lValueRequested": false, 104 | "nodeType": "Literal", 105 | "src": "490:10:10", 106 | "subdenomination": null, 107 | "typeDescriptions": { 108 | "typeIdentifier": "t_rational_4038714810_by_1", 109 | "typeString": "int_const 4038714810" 110 | }, 111 | "value": "0xf0b9e5ba" 112 | }, 113 | "visibility": "internal" 114 | }, 115 | { 116 | "body": null, 117 | "documentation": "@notice Handle the receipt of an NFT\n@dev The ERC721 smart contract calls this function on the recipient\n after a `safetransfer`. This function MAY throw to revert and reject the\n transfer. This function MUST use 50,000 gas or less. Return of other\n than the magic value MUST result in the transaction being reverted.\n Note: the contract address is always the message sender.\n@param _from The sending address\n@param _tokenId The NFT identifier which is being transfered\n@param _data Additional data with no specified format\n@return `bytes4(keccak256(\"onERC721Received(address,uint256,bytes)\"))`", 118 | "id": 2261, 119 | "implemented": false, 120 | "isConstructor": false, 121 | "isDeclaredConst": false, 122 | "modifiers": [], 123 | "name": "onERC721Received", 124 | "nodeType": "FunctionDefinition", 125 | "parameters": { 126 | "id": 2257, 127 | "nodeType": "ParameterList", 128 | "parameters": [ 129 | { 130 | "constant": false, 131 | "id": 2252, 132 | "name": "_from", 133 | "nodeType": "VariableDeclaration", 134 | "scope": 2261, 135 | "src": "1188:13:10", 136 | "stateVariable": false, 137 | "storageLocation": "default", 138 | "typeDescriptions": { 139 | "typeIdentifier": "t_address", 140 | "typeString": "address" 141 | }, 142 | "typeName": { 143 | "id": 2251, 144 | "name": "address", 145 | "nodeType": "ElementaryTypeName", 146 | "src": "1188:7:10", 147 | "typeDescriptions": { 148 | "typeIdentifier": "t_address", 149 | "typeString": "address" 150 | } 151 | }, 152 | "value": null, 153 | "visibility": "internal" 154 | }, 155 | { 156 | "constant": false, 157 | "id": 2254, 158 | "name": "_tokenId", 159 | "nodeType": "VariableDeclaration", 160 | "scope": 2261, 161 | "src": "1203:16:10", 162 | "stateVariable": false, 163 | "storageLocation": "default", 164 | "typeDescriptions": { 165 | "typeIdentifier": "t_uint256", 166 | "typeString": "uint256" 167 | }, 168 | "typeName": { 169 | "id": 2253, 170 | "name": "uint256", 171 | "nodeType": "ElementaryTypeName", 172 | "src": "1203:7:10", 173 | "typeDescriptions": { 174 | "typeIdentifier": "t_uint256", 175 | "typeString": "uint256" 176 | } 177 | }, 178 | "value": null, 179 | "visibility": "internal" 180 | }, 181 | { 182 | "constant": false, 183 | "id": 2256, 184 | "name": "_data", 185 | "nodeType": "VariableDeclaration", 186 | "scope": 2261, 187 | "src": "1221:11:10", 188 | "stateVariable": false, 189 | "storageLocation": "default", 190 | "typeDescriptions": { 191 | "typeIdentifier": "t_bytes_memory_ptr", 192 | "typeString": "bytes" 193 | }, 194 | "typeName": { 195 | "id": 2255, 196 | "name": "bytes", 197 | "nodeType": "ElementaryTypeName", 198 | "src": "1221:5:10", 199 | "typeDescriptions": { 200 | "typeIdentifier": "t_bytes_storage_ptr", 201 | "typeString": "bytes" 202 | } 203 | }, 204 | "value": null, 205 | "visibility": "internal" 206 | } 207 | ], 208 | "src": "1187:46:10" 209 | }, 210 | "payable": false, 211 | "returnParameters": { 212 | "id": 2260, 213 | "nodeType": "ParameterList", 214 | "parameters": [ 215 | { 216 | "constant": false, 217 | "id": 2259, 218 | "name": "", 219 | "nodeType": "VariableDeclaration", 220 | "scope": 2261, 221 | "src": "1249:6:10", 222 | "stateVariable": false, 223 | "storageLocation": "default", 224 | "typeDescriptions": { 225 | "typeIdentifier": "t_bytes4", 226 | "typeString": "bytes4" 227 | }, 228 | "typeName": { 229 | "id": 2258, 230 | "name": "bytes4", 231 | "nodeType": "ElementaryTypeName", 232 | "src": "1249:6:10", 233 | "typeDescriptions": { 234 | "typeIdentifier": "t_bytes4", 235 | "typeString": "bytes4" 236 | } 237 | }, 238 | "value": null, 239 | "visibility": "internal" 240 | } 241 | ], 242 | "src": "1248:8:10" 243 | }, 244 | "scope": 2262, 245 | "src": "1162:95:10", 246 | "stateMutability": "nonpayable", 247 | "superFunction": null, 248 | "visibility": "public" 249 | } 250 | ], 251 | "scope": 2263, 252 | "src": "181:1078:10" 253 | } 254 | ], 255 | "src": "0:1260:10" 256 | }, 257 | "legacyAST": { 258 | "absolutePath": "zeppelin-solidity/contracts/token/ERC721/ERC721Receiver.sol", 259 | "exportedSymbols": { 260 | "ERC721Receiver": [ 261 | 2262 262 | ] 263 | }, 264 | "id": 2263, 265 | "nodeType": "SourceUnit", 266 | "nodes": [ 267 | { 268 | "id": 2247, 269 | "literals": [ 270 | "solidity", 271 | "^", 272 | "0.4", 273 | ".21" 274 | ], 275 | "nodeType": "PragmaDirective", 276 | "src": "0:24:10" 277 | }, 278 | { 279 | "baseContracts": [], 280 | "contractDependencies": [], 281 | "contractKind": "contract", 282 | "documentation": "@title ERC721 token receiver interface\n@dev Interface for any contract that wants to support safeTransfers\n from ERC721 asset contracts.", 283 | "fullyImplemented": false, 284 | "id": 2262, 285 | "linearizedBaseContracts": [ 286 | 2262 287 | ], 288 | "name": "ERC721Receiver", 289 | "nodeType": "ContractDefinition", 290 | "nodes": [ 291 | { 292 | "constant": true, 293 | "id": 2250, 294 | "name": "ERC721_RECEIVED", 295 | "nodeType": "VariableDeclaration", 296 | "scope": 2262, 297 | "src": "456:44:10", 298 | "stateVariable": true, 299 | "storageLocation": "default", 300 | "typeDescriptions": { 301 | "typeIdentifier": "t_bytes4", 302 | "typeString": "bytes4" 303 | }, 304 | "typeName": { 305 | "id": 2248, 306 | "name": "bytes4", 307 | "nodeType": "ElementaryTypeName", 308 | "src": "456:6:10", 309 | "typeDescriptions": { 310 | "typeIdentifier": "t_bytes4", 311 | "typeString": "bytes4" 312 | } 313 | }, 314 | "value": { 315 | "argumentTypes": null, 316 | "hexValue": "30786630623965356261", 317 | "id": 2249, 318 | "isConstant": false, 319 | "isLValue": false, 320 | "isPure": true, 321 | "kind": "number", 322 | "lValueRequested": false, 323 | "nodeType": "Literal", 324 | "src": "490:10:10", 325 | "subdenomination": null, 326 | "typeDescriptions": { 327 | "typeIdentifier": "t_rational_4038714810_by_1", 328 | "typeString": "int_const 4038714810" 329 | }, 330 | "value": "0xf0b9e5ba" 331 | }, 332 | "visibility": "internal" 333 | }, 334 | { 335 | "body": null, 336 | "documentation": "@notice Handle the receipt of an NFT\n@dev The ERC721 smart contract calls this function on the recipient\n after a `safetransfer`. This function MAY throw to revert and reject the\n transfer. This function MUST use 50,000 gas or less. Return of other\n than the magic value MUST result in the transaction being reverted.\n Note: the contract address is always the message sender.\n@param _from The sending address\n@param _tokenId The NFT identifier which is being transfered\n@param _data Additional data with no specified format\n@return `bytes4(keccak256(\"onERC721Received(address,uint256,bytes)\"))`", 337 | "id": 2261, 338 | "implemented": false, 339 | "isConstructor": false, 340 | "isDeclaredConst": false, 341 | "modifiers": [], 342 | "name": "onERC721Received", 343 | "nodeType": "FunctionDefinition", 344 | "parameters": { 345 | "id": 2257, 346 | "nodeType": "ParameterList", 347 | "parameters": [ 348 | { 349 | "constant": false, 350 | "id": 2252, 351 | "name": "_from", 352 | "nodeType": "VariableDeclaration", 353 | "scope": 2261, 354 | "src": "1188:13:10", 355 | "stateVariable": false, 356 | "storageLocation": "default", 357 | "typeDescriptions": { 358 | "typeIdentifier": "t_address", 359 | "typeString": "address" 360 | }, 361 | "typeName": { 362 | "id": 2251, 363 | "name": "address", 364 | "nodeType": "ElementaryTypeName", 365 | "src": "1188:7:10", 366 | "typeDescriptions": { 367 | "typeIdentifier": "t_address", 368 | "typeString": "address" 369 | } 370 | }, 371 | "value": null, 372 | "visibility": "internal" 373 | }, 374 | { 375 | "constant": false, 376 | "id": 2254, 377 | "name": "_tokenId", 378 | "nodeType": "VariableDeclaration", 379 | "scope": 2261, 380 | "src": "1203:16:10", 381 | "stateVariable": false, 382 | "storageLocation": "default", 383 | "typeDescriptions": { 384 | "typeIdentifier": "t_uint256", 385 | "typeString": "uint256" 386 | }, 387 | "typeName": { 388 | "id": 2253, 389 | "name": "uint256", 390 | "nodeType": "ElementaryTypeName", 391 | "src": "1203:7:10", 392 | "typeDescriptions": { 393 | "typeIdentifier": "t_uint256", 394 | "typeString": "uint256" 395 | } 396 | }, 397 | "value": null, 398 | "visibility": "internal" 399 | }, 400 | { 401 | "constant": false, 402 | "id": 2256, 403 | "name": "_data", 404 | "nodeType": "VariableDeclaration", 405 | "scope": 2261, 406 | "src": "1221:11:10", 407 | "stateVariable": false, 408 | "storageLocation": "default", 409 | "typeDescriptions": { 410 | "typeIdentifier": "t_bytes_memory_ptr", 411 | "typeString": "bytes" 412 | }, 413 | "typeName": { 414 | "id": 2255, 415 | "name": "bytes", 416 | "nodeType": "ElementaryTypeName", 417 | "src": "1221:5:10", 418 | "typeDescriptions": { 419 | "typeIdentifier": "t_bytes_storage_ptr", 420 | "typeString": "bytes" 421 | } 422 | }, 423 | "value": null, 424 | "visibility": "internal" 425 | } 426 | ], 427 | "src": "1187:46:10" 428 | }, 429 | "payable": false, 430 | "returnParameters": { 431 | "id": 2260, 432 | "nodeType": "ParameterList", 433 | "parameters": [ 434 | { 435 | "constant": false, 436 | "id": 2259, 437 | "name": "", 438 | "nodeType": "VariableDeclaration", 439 | "scope": 2261, 440 | "src": "1249:6:10", 441 | "stateVariable": false, 442 | "storageLocation": "default", 443 | "typeDescriptions": { 444 | "typeIdentifier": "t_bytes4", 445 | "typeString": "bytes4" 446 | }, 447 | "typeName": { 448 | "id": 2258, 449 | "name": "bytes4", 450 | "nodeType": "ElementaryTypeName", 451 | "src": "1249:6:10", 452 | "typeDescriptions": { 453 | "typeIdentifier": "t_bytes4", 454 | "typeString": "bytes4" 455 | } 456 | }, 457 | "value": null, 458 | "visibility": "internal" 459 | } 460 | ], 461 | "src": "1248:8:10" 462 | }, 463 | "scope": 2262, 464 | "src": "1162:95:10", 465 | "stateMutability": "nonpayable", 466 | "superFunction": null, 467 | "visibility": "public" 468 | } 469 | ], 470 | "scope": 2263, 471 | "src": "181:1078:10" 472 | } 473 | ], 474 | "src": "0:1260:10" 475 | }, 476 | "compiler": { 477 | "name": "solc", 478 | "version": "0.4.23+commit.124ca40d.Emscripten.clang" 479 | }, 480 | "networks": {}, 481 | "schemaVersion": "2.0.0", 482 | "updatedAt": "2018-05-13T21:06:29.996Z" 483 | } -------------------------------------------------------------------------------- /build/contracts/Proxy.json: -------------------------------------------------------------------------------- 1 | { 2 | "contractName": "Proxy", 3 | "abi": [ 4 | { 5 | "payable": true, 6 | "stateMutability": "payable", 7 | "type": "fallback" 8 | }, 9 | { 10 | "constant": true, 11 | "inputs": [], 12 | "name": "implementation", 13 | "outputs": [ 14 | { 15 | "name": "", 16 | "type": "address" 17 | } 18 | ], 19 | "payable": false, 20 | "stateMutability": "view", 21 | "type": "function" 22 | } 23 | ], 24 | "bytecode": "0x", 25 | "deployedBytecode": "0x", 26 | "sourceMap": "", 27 | "deployedSourceMap": "", 28 | "source": "pragma solidity ^0.4.21;\n\n/**\n * @title Proxy\n * @dev Gives the possibility to delegate any call to a foreign implementation.\n */\ncontract Proxy {\n /**\n * @dev Tells the address of the implementation where every call will be delegated.\n * @return address of the implementation to which it will be delegated\n */\n function implementation() public view returns (address);\n\n /**\n * @dev Fallback function allowing to perform a delegatecall to the given implementation.\n * This function will return whatever the implementation call returns\n */\n function () payable public {\n address _impl = implementation();\n require(_impl != address(0));\n\n assembly {\n let ptr := mload(0x40)\n calldatacopy(ptr, 0, calldatasize)\n let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0)\n let size := returndatasize\n returndatacopy(ptr, 0, size)\n\n switch result\n case 0 { revert(ptr, size) }\n default { return(ptr, size) }\n }\n }\n}\n", 29 | "sourcePath": "/Users/devin/code/blockchain/ethmoji/ethmoji-contracts/contracts/Proxy.sol", 30 | "ast": { 31 | "absolutePath": "/Users/devin/code/blockchain/ethmoji/ethmoji-contracts/contracts/Proxy.sol", 32 | "exportedSymbols": { 33 | "Proxy": [ 34 | 1605 35 | ] 36 | }, 37 | "id": 1606, 38 | "nodeType": "SourceUnit", 39 | "nodes": [ 40 | { 41 | "id": 1581, 42 | "literals": [ 43 | "solidity", 44 | "^", 45 | "0.4", 46 | ".21" 47 | ], 48 | "nodeType": "PragmaDirective", 49 | "src": "0:24:6" 50 | }, 51 | { 52 | "baseContracts": [], 53 | "contractDependencies": [], 54 | "contractKind": "contract", 55 | "documentation": "@title Proxy\n@dev Gives the possibility to delegate any call to a foreign implementation.", 56 | "fullyImplemented": false, 57 | "id": 1605, 58 | "linearizedBaseContracts": [ 59 | 1605 60 | ], 61 | "name": "Proxy", 62 | "nodeType": "ContractDefinition", 63 | "nodes": [ 64 | { 65 | "body": null, 66 | "documentation": "@dev Tells the address of the implementation where every call will be delegated.\n@return address of the implementation to which it will be delegated", 67 | "id": 1586, 68 | "implemented": false, 69 | "isConstructor": false, 70 | "isDeclaredConst": true, 71 | "modifiers": [], 72 | "name": "implementation", 73 | "nodeType": "FunctionDefinition", 74 | "parameters": { 75 | "id": 1582, 76 | "nodeType": "ParameterList", 77 | "parameters": [], 78 | "src": "340:2:6" 79 | }, 80 | "payable": false, 81 | "returnParameters": { 82 | "id": 1585, 83 | "nodeType": "ParameterList", 84 | "parameters": [ 85 | { 86 | "constant": false, 87 | "id": 1584, 88 | "name": "", 89 | "nodeType": "VariableDeclaration", 90 | "scope": 1586, 91 | "src": "364:7:6", 92 | "stateVariable": false, 93 | "storageLocation": "default", 94 | "typeDescriptions": { 95 | "typeIdentifier": "t_address", 96 | "typeString": "address" 97 | }, 98 | "typeName": { 99 | "id": 1583, 100 | "name": "address", 101 | "nodeType": "ElementaryTypeName", 102 | "src": "364:7:6", 103 | "typeDescriptions": { 104 | "typeIdentifier": "t_address", 105 | "typeString": "address" 106 | } 107 | }, 108 | "value": null, 109 | "visibility": "internal" 110 | } 111 | ], 112 | "src": "363:9:6" 113 | }, 114 | "scope": 1605, 115 | "src": "317:56:6", 116 | "stateMutability": "view", 117 | "superFunction": null, 118 | "visibility": "public" 119 | }, 120 | { 121 | "body": { 122 | "id": 1603, 123 | "nodeType": "Block", 124 | "src": "577:399:6", 125 | "statements": [ 126 | { 127 | "assignments": [ 128 | 1590 129 | ], 130 | "declarations": [ 131 | { 132 | "constant": false, 133 | "id": 1590, 134 | "name": "_impl", 135 | "nodeType": "VariableDeclaration", 136 | "scope": 1604, 137 | "src": "583:13:6", 138 | "stateVariable": false, 139 | "storageLocation": "default", 140 | "typeDescriptions": { 141 | "typeIdentifier": "t_address", 142 | "typeString": "address" 143 | }, 144 | "typeName": { 145 | "id": 1589, 146 | "name": "address", 147 | "nodeType": "ElementaryTypeName", 148 | "src": "583:7:6", 149 | "typeDescriptions": { 150 | "typeIdentifier": "t_address", 151 | "typeString": "address" 152 | } 153 | }, 154 | "value": null, 155 | "visibility": "internal" 156 | } 157 | ], 158 | "id": 1593, 159 | "initialValue": { 160 | "argumentTypes": null, 161 | "arguments": [], 162 | "expression": { 163 | "argumentTypes": [], 164 | "id": 1591, 165 | "name": "implementation", 166 | "nodeType": "Identifier", 167 | "overloadedDeclarations": [], 168 | "referencedDeclaration": 1586, 169 | "src": "599:14:6", 170 | "typeDescriptions": { 171 | "typeIdentifier": "t_function_internal_view$__$returns$_t_address_$", 172 | "typeString": "function () view returns (address)" 173 | } 174 | }, 175 | "id": 1592, 176 | "isConstant": false, 177 | "isLValue": false, 178 | "isPure": false, 179 | "kind": "functionCall", 180 | "lValueRequested": false, 181 | "names": [], 182 | "nodeType": "FunctionCall", 183 | "src": "599:16:6", 184 | "typeDescriptions": { 185 | "typeIdentifier": "t_address", 186 | "typeString": "address" 187 | } 188 | }, 189 | "nodeType": "VariableDeclarationStatement", 190 | "src": "583:32:6" 191 | }, 192 | { 193 | "expression": { 194 | "argumentTypes": null, 195 | "arguments": [ 196 | { 197 | "argumentTypes": null, 198 | "commonType": { 199 | "typeIdentifier": "t_address", 200 | "typeString": "address" 201 | }, 202 | "id": 1599, 203 | "isConstant": false, 204 | "isLValue": false, 205 | "isPure": false, 206 | "lValueRequested": false, 207 | "leftExpression": { 208 | "argumentTypes": null, 209 | "id": 1595, 210 | "name": "_impl", 211 | "nodeType": "Identifier", 212 | "overloadedDeclarations": [], 213 | "referencedDeclaration": 1590, 214 | "src": "629:5:6", 215 | "typeDescriptions": { 216 | "typeIdentifier": "t_address", 217 | "typeString": "address" 218 | } 219 | }, 220 | "nodeType": "BinaryOperation", 221 | "operator": "!=", 222 | "rightExpression": { 223 | "argumentTypes": null, 224 | "arguments": [ 225 | { 226 | "argumentTypes": null, 227 | "hexValue": "30", 228 | "id": 1597, 229 | "isConstant": false, 230 | "isLValue": false, 231 | "isPure": true, 232 | "kind": "number", 233 | "lValueRequested": false, 234 | "nodeType": "Literal", 235 | "src": "646:1:6", 236 | "subdenomination": null, 237 | "typeDescriptions": { 238 | "typeIdentifier": "t_rational_0_by_1", 239 | "typeString": "int_const 0" 240 | }, 241 | "value": "0" 242 | } 243 | ], 244 | "expression": { 245 | "argumentTypes": [ 246 | { 247 | "typeIdentifier": "t_rational_0_by_1", 248 | "typeString": "int_const 0" 249 | } 250 | ], 251 | "id": 1596, 252 | "isConstant": false, 253 | "isLValue": false, 254 | "isPure": true, 255 | "lValueRequested": false, 256 | "nodeType": "ElementaryTypeNameExpression", 257 | "src": "638:7:6", 258 | "typeDescriptions": { 259 | "typeIdentifier": "t_type$_t_address_$", 260 | "typeString": "type(address)" 261 | }, 262 | "typeName": "address" 263 | }, 264 | "id": 1598, 265 | "isConstant": false, 266 | "isLValue": false, 267 | "isPure": true, 268 | "kind": "typeConversion", 269 | "lValueRequested": false, 270 | "names": [], 271 | "nodeType": "FunctionCall", 272 | "src": "638:10:6", 273 | "typeDescriptions": { 274 | "typeIdentifier": "t_address", 275 | "typeString": "address" 276 | } 277 | }, 278 | "src": "629:19:6", 279 | "typeDescriptions": { 280 | "typeIdentifier": "t_bool", 281 | "typeString": "bool" 282 | } 283 | } 284 | ], 285 | "expression": { 286 | "argumentTypes": [ 287 | { 288 | "typeIdentifier": "t_bool", 289 | "typeString": "bool" 290 | } 291 | ], 292 | "id": 1594, 293 | "name": "require", 294 | "nodeType": "Identifier", 295 | "overloadedDeclarations": [ 296 | 2474, 297 | 2475 298 | ], 299 | "referencedDeclaration": 2474, 300 | "src": "621:7:6", 301 | "typeDescriptions": { 302 | "typeIdentifier": "t_function_require_pure$_t_bool_$returns$__$", 303 | "typeString": "function (bool) pure" 304 | } 305 | }, 306 | "id": 1600, 307 | "isConstant": false, 308 | "isLValue": false, 309 | "isPure": false, 310 | "kind": "functionCall", 311 | "lValueRequested": false, 312 | "names": [], 313 | "nodeType": "FunctionCall", 314 | "src": "621:28:6", 315 | "typeDescriptions": { 316 | "typeIdentifier": "t_tuple$__$", 317 | "typeString": "tuple()" 318 | } 319 | }, 320 | "id": 1601, 321 | "nodeType": "ExpressionStatement", 322 | "src": "621:28:6" 323 | }, 324 | { 325 | "externalReferences": [ 326 | { 327 | "_impl": { 328 | "declaration": 1590, 329 | "isOffset": false, 330 | "isSlot": false, 331 | "src": "775:5:6", 332 | "valueSize": 1 333 | } 334 | } 335 | ], 336 | "id": 1602, 337 | "nodeType": "InlineAssembly", 338 | "operations": "{\n let ptr := mload(0x40)\n calldatacopy(ptr, 0, calldatasize())\n let result := delegatecall(gas(), _impl, ptr, calldatasize(), 0, 0)\n let size := returndatasize()\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n}", 339 | "src": "656:320:6" 340 | } 341 | ] 342 | }, 343 | "documentation": "@dev Fallback function allowing to perform a delegatecall to the given implementation.\nThis function will return whatever the implementation call returns", 344 | "id": 1604, 345 | "implemented": true, 346 | "isConstructor": false, 347 | "isDeclaredConst": false, 348 | "modifiers": [], 349 | "name": "", 350 | "nodeType": "FunctionDefinition", 351 | "parameters": { 352 | "id": 1587, 353 | "nodeType": "ParameterList", 354 | "parameters": [], 355 | "src": "559:2:6" 356 | }, 357 | "payable": true, 358 | "returnParameters": { 359 | "id": 1588, 360 | "nodeType": "ParameterList", 361 | "parameters": [], 362 | "src": "577:0:6" 363 | }, 364 | "scope": 1605, 365 | "src": "550:426:6", 366 | "stateMutability": "payable", 367 | "superFunction": null, 368 | "visibility": "public" 369 | } 370 | ], 371 | "scope": 1606, 372 | "src": "130:848:6" 373 | } 374 | ], 375 | "src": "0:979:6" 376 | }, 377 | "legacyAST": { 378 | "absolutePath": "/Users/devin/code/blockchain/ethmoji/ethmoji-contracts/contracts/Proxy.sol", 379 | "exportedSymbols": { 380 | "Proxy": [ 381 | 1605 382 | ] 383 | }, 384 | "id": 1606, 385 | "nodeType": "SourceUnit", 386 | "nodes": [ 387 | { 388 | "id": 1581, 389 | "literals": [ 390 | "solidity", 391 | "^", 392 | "0.4", 393 | ".21" 394 | ], 395 | "nodeType": "PragmaDirective", 396 | "src": "0:24:6" 397 | }, 398 | { 399 | "baseContracts": [], 400 | "contractDependencies": [], 401 | "contractKind": "contract", 402 | "documentation": "@title Proxy\n@dev Gives the possibility to delegate any call to a foreign implementation.", 403 | "fullyImplemented": false, 404 | "id": 1605, 405 | "linearizedBaseContracts": [ 406 | 1605 407 | ], 408 | "name": "Proxy", 409 | "nodeType": "ContractDefinition", 410 | "nodes": [ 411 | { 412 | "body": null, 413 | "documentation": "@dev Tells the address of the implementation where every call will be delegated.\n@return address of the implementation to which it will be delegated", 414 | "id": 1586, 415 | "implemented": false, 416 | "isConstructor": false, 417 | "isDeclaredConst": true, 418 | "modifiers": [], 419 | "name": "implementation", 420 | "nodeType": "FunctionDefinition", 421 | "parameters": { 422 | "id": 1582, 423 | "nodeType": "ParameterList", 424 | "parameters": [], 425 | "src": "340:2:6" 426 | }, 427 | "payable": false, 428 | "returnParameters": { 429 | "id": 1585, 430 | "nodeType": "ParameterList", 431 | "parameters": [ 432 | { 433 | "constant": false, 434 | "id": 1584, 435 | "name": "", 436 | "nodeType": "VariableDeclaration", 437 | "scope": 1586, 438 | "src": "364:7:6", 439 | "stateVariable": false, 440 | "storageLocation": "default", 441 | "typeDescriptions": { 442 | "typeIdentifier": "t_address", 443 | "typeString": "address" 444 | }, 445 | "typeName": { 446 | "id": 1583, 447 | "name": "address", 448 | "nodeType": "ElementaryTypeName", 449 | "src": "364:7:6", 450 | "typeDescriptions": { 451 | "typeIdentifier": "t_address", 452 | "typeString": "address" 453 | } 454 | }, 455 | "value": null, 456 | "visibility": "internal" 457 | } 458 | ], 459 | "src": "363:9:6" 460 | }, 461 | "scope": 1605, 462 | "src": "317:56:6", 463 | "stateMutability": "view", 464 | "superFunction": null, 465 | "visibility": "public" 466 | }, 467 | { 468 | "body": { 469 | "id": 1603, 470 | "nodeType": "Block", 471 | "src": "577:399:6", 472 | "statements": [ 473 | { 474 | "assignments": [ 475 | 1590 476 | ], 477 | "declarations": [ 478 | { 479 | "constant": false, 480 | "id": 1590, 481 | "name": "_impl", 482 | "nodeType": "VariableDeclaration", 483 | "scope": 1604, 484 | "src": "583:13:6", 485 | "stateVariable": false, 486 | "storageLocation": "default", 487 | "typeDescriptions": { 488 | "typeIdentifier": "t_address", 489 | "typeString": "address" 490 | }, 491 | "typeName": { 492 | "id": 1589, 493 | "name": "address", 494 | "nodeType": "ElementaryTypeName", 495 | "src": "583:7:6", 496 | "typeDescriptions": { 497 | "typeIdentifier": "t_address", 498 | "typeString": "address" 499 | } 500 | }, 501 | "value": null, 502 | "visibility": "internal" 503 | } 504 | ], 505 | "id": 1593, 506 | "initialValue": { 507 | "argumentTypes": null, 508 | "arguments": [], 509 | "expression": { 510 | "argumentTypes": [], 511 | "id": 1591, 512 | "name": "implementation", 513 | "nodeType": "Identifier", 514 | "overloadedDeclarations": [], 515 | "referencedDeclaration": 1586, 516 | "src": "599:14:6", 517 | "typeDescriptions": { 518 | "typeIdentifier": "t_function_internal_view$__$returns$_t_address_$", 519 | "typeString": "function () view returns (address)" 520 | } 521 | }, 522 | "id": 1592, 523 | "isConstant": false, 524 | "isLValue": false, 525 | "isPure": false, 526 | "kind": "functionCall", 527 | "lValueRequested": false, 528 | "names": [], 529 | "nodeType": "FunctionCall", 530 | "src": "599:16:6", 531 | "typeDescriptions": { 532 | "typeIdentifier": "t_address", 533 | "typeString": "address" 534 | } 535 | }, 536 | "nodeType": "VariableDeclarationStatement", 537 | "src": "583:32:6" 538 | }, 539 | { 540 | "expression": { 541 | "argumentTypes": null, 542 | "arguments": [ 543 | { 544 | "argumentTypes": null, 545 | "commonType": { 546 | "typeIdentifier": "t_address", 547 | "typeString": "address" 548 | }, 549 | "id": 1599, 550 | "isConstant": false, 551 | "isLValue": false, 552 | "isPure": false, 553 | "lValueRequested": false, 554 | "leftExpression": { 555 | "argumentTypes": null, 556 | "id": 1595, 557 | "name": "_impl", 558 | "nodeType": "Identifier", 559 | "overloadedDeclarations": [], 560 | "referencedDeclaration": 1590, 561 | "src": "629:5:6", 562 | "typeDescriptions": { 563 | "typeIdentifier": "t_address", 564 | "typeString": "address" 565 | } 566 | }, 567 | "nodeType": "BinaryOperation", 568 | "operator": "!=", 569 | "rightExpression": { 570 | "argumentTypes": null, 571 | "arguments": [ 572 | { 573 | "argumentTypes": null, 574 | "hexValue": "30", 575 | "id": 1597, 576 | "isConstant": false, 577 | "isLValue": false, 578 | "isPure": true, 579 | "kind": "number", 580 | "lValueRequested": false, 581 | "nodeType": "Literal", 582 | "src": "646:1:6", 583 | "subdenomination": null, 584 | "typeDescriptions": { 585 | "typeIdentifier": "t_rational_0_by_1", 586 | "typeString": "int_const 0" 587 | }, 588 | "value": "0" 589 | } 590 | ], 591 | "expression": { 592 | "argumentTypes": [ 593 | { 594 | "typeIdentifier": "t_rational_0_by_1", 595 | "typeString": "int_const 0" 596 | } 597 | ], 598 | "id": 1596, 599 | "isConstant": false, 600 | "isLValue": false, 601 | "isPure": true, 602 | "lValueRequested": false, 603 | "nodeType": "ElementaryTypeNameExpression", 604 | "src": "638:7:6", 605 | "typeDescriptions": { 606 | "typeIdentifier": "t_type$_t_address_$", 607 | "typeString": "type(address)" 608 | }, 609 | "typeName": "address" 610 | }, 611 | "id": 1598, 612 | "isConstant": false, 613 | "isLValue": false, 614 | "isPure": true, 615 | "kind": "typeConversion", 616 | "lValueRequested": false, 617 | "names": [], 618 | "nodeType": "FunctionCall", 619 | "src": "638:10:6", 620 | "typeDescriptions": { 621 | "typeIdentifier": "t_address", 622 | "typeString": "address" 623 | } 624 | }, 625 | "src": "629:19:6", 626 | "typeDescriptions": { 627 | "typeIdentifier": "t_bool", 628 | "typeString": "bool" 629 | } 630 | } 631 | ], 632 | "expression": { 633 | "argumentTypes": [ 634 | { 635 | "typeIdentifier": "t_bool", 636 | "typeString": "bool" 637 | } 638 | ], 639 | "id": 1594, 640 | "name": "require", 641 | "nodeType": "Identifier", 642 | "overloadedDeclarations": [ 643 | 2474, 644 | 2475 645 | ], 646 | "referencedDeclaration": 2474, 647 | "src": "621:7:6", 648 | "typeDescriptions": { 649 | "typeIdentifier": "t_function_require_pure$_t_bool_$returns$__$", 650 | "typeString": "function (bool) pure" 651 | } 652 | }, 653 | "id": 1600, 654 | "isConstant": false, 655 | "isLValue": false, 656 | "isPure": false, 657 | "kind": "functionCall", 658 | "lValueRequested": false, 659 | "names": [], 660 | "nodeType": "FunctionCall", 661 | "src": "621:28:6", 662 | "typeDescriptions": { 663 | "typeIdentifier": "t_tuple$__$", 664 | "typeString": "tuple()" 665 | } 666 | }, 667 | "id": 1601, 668 | "nodeType": "ExpressionStatement", 669 | "src": "621:28:6" 670 | }, 671 | { 672 | "externalReferences": [ 673 | { 674 | "_impl": { 675 | "declaration": 1590, 676 | "isOffset": false, 677 | "isSlot": false, 678 | "src": "775:5:6", 679 | "valueSize": 1 680 | } 681 | } 682 | ], 683 | "id": 1602, 684 | "nodeType": "InlineAssembly", 685 | "operations": "{\n let ptr := mload(0x40)\n calldatacopy(ptr, 0, calldatasize())\n let result := delegatecall(gas(), _impl, ptr, calldatasize(), 0, 0)\n let size := returndatasize()\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n}", 686 | "src": "656:320:6" 687 | } 688 | ] 689 | }, 690 | "documentation": "@dev Fallback function allowing to perform a delegatecall to the given implementation.\nThis function will return whatever the implementation call returns", 691 | "id": 1604, 692 | "implemented": true, 693 | "isConstructor": false, 694 | "isDeclaredConst": false, 695 | "modifiers": [], 696 | "name": "", 697 | "nodeType": "FunctionDefinition", 698 | "parameters": { 699 | "id": 1587, 700 | "nodeType": "ParameterList", 701 | "parameters": [], 702 | "src": "559:2:6" 703 | }, 704 | "payable": true, 705 | "returnParameters": { 706 | "id": 1588, 707 | "nodeType": "ParameterList", 708 | "parameters": [], 709 | "src": "577:0:6" 710 | }, 711 | "scope": 1605, 712 | "src": "550:426:6", 713 | "stateMutability": "payable", 714 | "superFunction": null, 715 | "visibility": "public" 716 | } 717 | ], 718 | "scope": 1606, 719 | "src": "130:848:6" 720 | } 721 | ], 722 | "src": "0:979:6" 723 | }, 724 | "compiler": { 725 | "name": "solc", 726 | "version": "0.4.23+commit.124ca40d.Emscripten.clang" 727 | }, 728 | "networks": {}, 729 | "schemaVersion": "2.0.0", 730 | "updatedAt": "2018-04-22T21:25:08.090Z" 731 | } -------------------------------------------------------------------------------- /contracts/Avatar.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.21; 2 | 3 | import "zeppelin-solidity/contracts/ownership/Ownable.sol"; 4 | 5 | contract Avatar is Ownable { 6 | struct AvatarToken { 7 | address contractAddress; 8 | uint id; 9 | } 10 | 11 | mapping(address => AvatarToken) avatars; 12 | 13 | mapping(address => bool) validAvatarContracts; 14 | 15 | function getAvatar(address avatarOwner) public view returns (uint id, address contractAddress) { 16 | AvatarToken memory token = avatars[avatarOwner]; 17 | require(token.contractAddress != 0); 18 | require(ERC721(token.contractAddress).ownerOf(token.id) == avatarOwner); 19 | 20 | return (token.id, token.contractAddress); 21 | } 22 | 23 | function setAvatar(address contractAddress, uint id) public { 24 | require(ERC721(contractAddress).ownerOf(id) == msg.sender); 25 | require(validAvatarContracts[contractAddress] == true); 26 | 27 | AvatarToken memory token; 28 | token.contractAddress = contractAddress; 29 | token.id = id; 30 | 31 | avatars[msg.sender] = token; 32 | } 33 | 34 | function setValidContractForAvatar(address contractAddress) public onlyOwner { 35 | validAvatarContracts[contractAddress] = true; 36 | } 37 | 38 | function removeValidContractForAvatar(address contractAddress) public onlyOwner { 39 | validAvatarContracts[contractAddress] = false; 40 | } 41 | 42 | function isValidContractForAvatar(address contractAddress) public view returns(bool) { 43 | return validAvatarContracts[contractAddress]; 44 | } 45 | } 46 | 47 | contract ERC721 { 48 | function ownerOf(uint256 _tokenId) public view returns (address); 49 | } -------------------------------------------------------------------------------- /contracts/Composable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.21; 2 | 3 | import "zeppelin-solidity/contracts/token/ERC721/ERC721Token.sol"; 4 | import "zeppelin-solidity/contracts/math/SafeMath.sol"; 5 | import "zeppelin-solidity/contracts/ownership/Ownable.sol"; 6 | import "zeppelin-solidity/contracts/payment/PullPayment.sol"; 7 | import "zeppelin-solidity/contracts/lifecycle/Pausable.sol"; 8 | 9 | 10 | /** 11 | * @title Composable 12 | * Composable - a contract to mint compositions 13 | */ 14 | 15 | contract Composable is ERC721Token, Ownable, PullPayment, Pausable { 16 | // Max number of layers for a composition token 17 | uint public constant MAX_LAYERS = 100; 18 | 19 | // The minimum composition fee for an ethmoji 20 | uint256 public minCompositionFee; 21 | 22 | // Mapping from token ID to composition price 23 | mapping (uint256 => uint256) public tokenIdToCompositionPrice; 24 | 25 | // Mapping from token ID to composition price increase 26 | mapping (uint256 => uint256) public tokenIdToCompositionPriceChangeRate; 27 | 28 | // Mapping from token ID to owner ability of changing composition price increase 29 | mapping (uint256 => bool) public tokenIdToCompPricePermission; 30 | 31 | // Mapping from token ID to layers representing it 32 | mapping (uint256 => uint256[]) public tokenIdToLayers; 33 | 34 | // Hash of all layers to track uniqueness of ethmojis 35 | mapping (bytes32 => bool) public compositions; 36 | 37 | // Image hashes to track uniquenes of ethmoji images. 38 | mapping (uint256 => uint256) public imageHashes; 39 | 40 | // Reverse mapping of token ID to image hash. 41 | mapping (uint256 => uint256) public tokenIdToImageHash; 42 | 43 | // Event for emitting new base token created 44 | event BaseTokenCreated(uint256 tokenId); 45 | 46 | // Event for emitting new composition token created 47 | event CompositionTokenCreated(uint256 tokenId, uint256[] layers, address indexed owner); 48 | 49 | // Event for emitting composition price changing for a token 50 | event CompositionPriceChanged(uint256 tokenId, uint256 price, address indexed owner); 51 | 52 | // Event for emitting composition price changing for a token 53 | event RoyaltiesPaid(uint256 tokenId, uint256 amount, address indexed owner); 54 | 55 | // Whether or not this contract accepts making compositions with other compositions 56 | bool public isCompositionOnlyWithBaseLayers; 57 | 58 | // ----- EXPOSED METHODS -------------------------------------------------------------------------- 59 | 60 | /** 61 | * @dev Mints a base token to an address with a given composition price 62 | * @param _to address of the future owner of the token 63 | * @param _compositionPrice uint256 composition price for the new token 64 | * @param _changeRate uint256 the rate at which comp price increases after every use 65 | * @param _changeableCompPrice bool whether or not the comp price can be changed 66 | * @param _imageHash uint256 hash of the resulting image 67 | */ 68 | function mintTo(address _to, uint256 _compositionPrice, uint256 _changeRate, bool _changeableCompPrice, uint256 _imageHash) public onlyOwner { 69 | uint256 newTokenIndex = _getNextTokenId(); 70 | _mint(_to, newTokenIndex); 71 | tokenIdToLayers[newTokenIndex] = [newTokenIndex]; 72 | require(_isUnique(tokenIdToLayers[newTokenIndex], _imageHash)); 73 | compositions[keccak256([newTokenIndex])] = true; 74 | imageHashes[_imageHash] = newTokenIndex; 75 | tokenIdToImageHash[newTokenIndex] = _imageHash; 76 | emit BaseTokenCreated(newTokenIndex); 77 | _setCompositionPrice(newTokenIndex, _compositionPrice); 78 | _setCompositionPriceChangeRate(newTokenIndex, _changeRate); 79 | _setCompositionPriceChangePermission(newTokenIndex, _changeableCompPrice); 80 | } 81 | 82 | /** 83 | * @dev Mints a composition emoji 84 | * @param _tokenIds uint256[] the array of layers that will make up the composition 85 | */ 86 | function compose(uint256[] _tokenIds, uint256 _imageHash) public payable whenNotPaused { 87 | require(_tokenIds.length > 1); 88 | uint256 price = getTotalCompositionPrice(_tokenIds); 89 | require(msg.sender != address(0) && msg.value >= price); 90 | require(_tokenIds.length <= MAX_LAYERS); 91 | 92 | uint256[] memory layers = new uint256[](MAX_LAYERS); 93 | uint actualSize = 0; 94 | 95 | for (uint i = 0; i < _tokenIds.length; i++) { 96 | uint256 compositionLayerId = _tokenIds[i]; 97 | require(_tokenLayersExist(compositionLayerId)); 98 | uint256[] memory inheritedLayers = tokenIdToLayers[compositionLayerId]; 99 | if (isCompositionOnlyWithBaseLayers) { 100 | require(inheritedLayers.length == 1); 101 | } 102 | require(inheritedLayers.length < MAX_LAYERS); 103 | for (uint j = 0; j < inheritedLayers.length; j++) { 104 | require(actualSize < MAX_LAYERS); 105 | for (uint k = 0; k < layers.length; k++) { 106 | require(layers[k] != inheritedLayers[j]); 107 | if (layers[k] == 0) { 108 | break; 109 | } 110 | } 111 | layers[actualSize] = inheritedLayers[j]; 112 | actualSize += 1; 113 | } 114 | require(ownerOf(compositionLayerId) != address(0)); 115 | asyncSend(ownerOf(compositionLayerId), tokenIdToCompositionPrice[compositionLayerId]); 116 | emit RoyaltiesPaid(compositionLayerId, tokenIdToCompositionPrice[compositionLayerId], ownerOf(compositionLayerId)); 117 | tokenIdToCompositionPrice[compositionLayerId] = tokenIdToCompositionPrice[compositionLayerId].add(tokenIdToCompositionPriceChangeRate[compositionLayerId]); 118 | } 119 | 120 | uint256 newTokenIndex = _getNextTokenId(); 121 | 122 | tokenIdToLayers[newTokenIndex] = _trim(layers, actualSize); 123 | require(_isUnique(tokenIdToLayers[newTokenIndex], _imageHash)); 124 | compositions[keccak256(tokenIdToLayers[newTokenIndex])] = true; 125 | imageHashes[_imageHash] = newTokenIndex; 126 | tokenIdToImageHash[newTokenIndex] = _imageHash; 127 | 128 | _mint(msg.sender, newTokenIndex); 129 | 130 | if (msg.value > price) { 131 | uint256 purchaseExcess = SafeMath.sub(msg.value, price); 132 | msg.sender.transfer(purchaseExcess); 133 | } 134 | 135 | if (!isCompositionOnlyWithBaseLayers) { 136 | _setCompositionPrice(newTokenIndex, minCompositionFee); 137 | } 138 | 139 | emit CompositionTokenCreated(newTokenIndex, tokenIdToLayers[newTokenIndex], msg.sender); 140 | } 141 | 142 | /** 143 | * @dev allows an address to withdraw its balance in the contract 144 | * @param _tokenId uint256 the token ID 145 | * @return uint256[] list of layers for a token 146 | */ 147 | function getTokenLayers(uint256 _tokenId) public view returns(uint256[]) { 148 | return tokenIdToLayers[_tokenId]; 149 | } 150 | 151 | /** 152 | * @dev given an array of ids, returns whether or not this composition is valid and unique 153 | * does not assume the layers array is flattened 154 | * @param _tokenIds uint256[] an array of token IDs 155 | * @return bool whether or not the composition is unique 156 | */ 157 | function isValidComposition(uint256[] _tokenIds, uint256 _imageHash) public view returns (bool) { 158 | if (isCompositionOnlyWithBaseLayers) { 159 | return _isValidBaseLayersOnly(_tokenIds, _imageHash); 160 | } else { 161 | return _isValidWithCompositions(_tokenIds, _imageHash); 162 | } 163 | } 164 | 165 | /** 166 | * @dev returns composition price of a given token ID 167 | * @param _tokenId uint256 token ID 168 | * @return uint256 composition price 169 | */ 170 | function getCompositionPrice(uint256 _tokenId) public view returns(uint256) { 171 | return tokenIdToCompositionPrice[_tokenId]; 172 | } 173 | 174 | /** 175 | * @dev get total price for minting a composition given the array of desired layers 176 | * @param _tokenIds uint256[] an array of token IDs 177 | * @return uint256 price for minting a composition with the desired layers 178 | */ 179 | function getTotalCompositionPrice(uint256[] _tokenIds) public view returns(uint256) { 180 | uint256 totalCompositionPrice = 0; 181 | for (uint i = 0; i < _tokenIds.length; i++) { 182 | require(_tokenLayersExist(_tokenIds[i])); 183 | totalCompositionPrice = SafeMath.add(totalCompositionPrice, tokenIdToCompositionPrice[_tokenIds[i]]); 184 | } 185 | 186 | totalCompositionPrice = SafeMath.div(SafeMath.mul(totalCompositionPrice, 105), 100); 187 | 188 | return totalCompositionPrice; 189 | } 190 | 191 | /** 192 | * @dev sets the composition price for a token ID. 193 | * Cannot be lower than the current composition fee 194 | * @param _tokenId uint256 the token ID 195 | * @param _price uint256 the new composition price 196 | */ 197 | function setCompositionPrice(uint256 _tokenId, uint256 _price) public onlyOwnerOf(_tokenId) { 198 | require(tokenIdToCompPricePermission[_tokenId] == true); 199 | _setCompositionPrice(_tokenId, _price); 200 | } 201 | 202 | // ----- PRIVATE FUNCTIONS ------------------------------------------------------------------------ 203 | 204 | /** 205 | * @dev given an array of ids, returns whether or not this composition is valid and unique 206 | * for when only base layers are allowed 207 | * does not assume the layers array is flattened 208 | * @param _tokenIds uint256[] an array of token IDs 209 | * @return bool whether or not the composition is unique 210 | */ 211 | function _isValidBaseLayersOnly(uint256[] _tokenIds, uint256 _imageHash) private view returns (bool) { 212 | require(_tokenIds.length <= MAX_LAYERS); 213 | uint256[] memory layers = new uint256[](_tokenIds.length); 214 | 215 | for (uint i = 0; i < _tokenIds.length; i++) { 216 | if (!_tokenLayersExist(_tokenIds[i])) { 217 | return false; 218 | } 219 | 220 | if (tokenIdToLayers[_tokenIds[i]].length != 1) { 221 | return false; 222 | } 223 | 224 | for (uint k = 0; k < layers.length; k++) { 225 | if (layers[k] == tokenIdToLayers[_tokenIds[i]][0]) { 226 | return false; 227 | } 228 | if (layers[k] == 0) { 229 | layers[k] = tokenIdToLayers[_tokenIds[i]][0]; 230 | break; 231 | } 232 | } 233 | } 234 | 235 | return _isUnique(layers, _imageHash); 236 | } 237 | 238 | /** 239 | * @dev given an array of ids, returns whether or not this composition is valid and unique 240 | * when compositions are allowed 241 | * does not assume the layers array is flattened 242 | * @param _tokenIds uint256[] an array of token IDs 243 | * @return bool whether or not the composition is unique 244 | */ 245 | function _isValidWithCompositions(uint256[] _tokenIds, uint256 _imageHash) private view returns (bool) { 246 | uint256[] memory layers = new uint256[](MAX_LAYERS); 247 | uint actualSize = 0; 248 | if (_tokenIds.length > MAX_LAYERS) { 249 | return false; 250 | } 251 | 252 | for (uint i = 0; i < _tokenIds.length; i++) { 253 | uint256 compositionLayerId = _tokenIds[i]; 254 | if (!_tokenLayersExist(compositionLayerId)) { 255 | return false; 256 | } 257 | uint256[] memory inheritedLayers = tokenIdToLayers[compositionLayerId]; 258 | require(inheritedLayers.length < MAX_LAYERS); 259 | for (uint j = 0; j < inheritedLayers.length; j++) { 260 | require(actualSize < MAX_LAYERS); 261 | for (uint k = 0; k < layers.length; k++) { 262 | if (layers[k] == inheritedLayers[j]) { 263 | return false; 264 | } 265 | if (layers[k] == 0) { 266 | break; 267 | } 268 | } 269 | layers[actualSize] = inheritedLayers[j]; 270 | actualSize += 1; 271 | } 272 | } 273 | return _isUnique(_trim(layers, actualSize), _imageHash); 274 | } 275 | 276 | /** 277 | * @dev trims the given array to a given size 278 | * @param _layers uint256[] the array of layers that will make up the composition 279 | * @param _size uint the array of layers that will make up the composition 280 | * @return uint256[] array trimmed to given size 281 | */ 282 | function _trim(uint256[] _layers, uint _size) private pure returns(uint256[]) { 283 | uint256[] memory trimmedLayers = new uint256[](_size); 284 | for (uint i = 0; i < _size; i++) { 285 | trimmedLayers[i] = _layers[i]; 286 | } 287 | 288 | return trimmedLayers; 289 | } 290 | 291 | /** 292 | * @dev checks if a token is an existing token by checking if it has non-zero layers 293 | * @param _tokenId uint256 token ID 294 | * @return bool whether or not the given tokenId exists according to its layers 295 | */ 296 | function _tokenLayersExist(uint256 _tokenId) private view returns (bool) { 297 | return tokenIdToLayers[_tokenId].length != 0; 298 | } 299 | 300 | /** 301 | * @dev set composition price for a token 302 | * @param _tokenId uint256 token ID 303 | * @param _price uint256 new composition price 304 | */ 305 | function _setCompositionPrice(uint256 _tokenId, uint256 _price) private { 306 | require(_price >= minCompositionFee); 307 | tokenIdToCompositionPrice[_tokenId] = _price; 308 | emit CompositionPriceChanged(_tokenId, _price, msg.sender); 309 | } 310 | 311 | /** 312 | * @dev set composition price increase rate a token 313 | * @param _tokenId uint256 token ID 314 | * @param _changeRate uint256 composition price change rate 315 | */ 316 | function _setCompositionPriceChangeRate(uint256 _tokenId, uint256 _changeRate) private { 317 | tokenIdToCompositionPriceChangeRate[_tokenId] = _changeRate; 318 | } 319 | 320 | /** 321 | * @dev set permission to change comp price in the future 322 | * @param _tokenId uint256 token ID 323 | * @param _canChange bool whether or not the composition price can be manually changed 324 | */ 325 | function _setCompositionPriceChangePermission(uint256 _tokenId, bool _canChange) private { 326 | tokenIdToCompPricePermission[_tokenId] = _canChange; 327 | } 328 | 329 | /** 330 | * @dev calculates the next token ID based on totalSupply 331 | * @return uint256 for the next token ID 332 | */ 333 | function _getNextTokenId() private view returns (uint256) { 334 | return totalSupply().add(1); 335 | } 336 | 337 | /** 338 | * @dev given an array of ids, returns whether or not this composition is unique 339 | * assumes the layers are all base layers (flattened) 340 | * @param _layers uint256[] an array of token IDs 341 | * @param _imageHash uint256 image hash for the composition 342 | * @return bool whether or not the composition is unique 343 | */ 344 | function _isUnique(uint256[] _layers, uint256 _imageHash) private view returns (bool) { 345 | return compositions[keccak256(_layers)] == false && imageHashes[_imageHash] == 0; 346 | } 347 | 348 | // ----- ONLY OWNER FUNCTIONS --------------------------------------------------------------------- 349 | 350 | /** 351 | * @dev payout method for the contract owner to payout contract profits to a given address 352 | * @param _to address for the payout 353 | */ 354 | function payout (address _to) public onlyOwner { 355 | totalPayments = 0; 356 | address(_to).transfer(address(this).balance); 357 | } 358 | 359 | /** 360 | * @dev sets global default composition fee for all new tokens 361 | * @param _price uint256 new default composition price 362 | */ 363 | function setMinCompositionFee(uint256 _price) public onlyOwner { 364 | minCompositionFee = _price; 365 | } 366 | } -------------------------------------------------------------------------------- /contracts/Ethmoji.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.21; 2 | 3 | import "./Composable.sol"; 4 | import "zeppelin-solidity/contracts/math/SafeMath.sol"; 5 | 6 | /** 7 | * @title Ethmoji 8 | * Ethmoji - a contract to mint and compose original emojis 9 | */ 10 | contract Ethmoji is Composable { 11 | using SafeMath for uint256; 12 | 13 | // set proxy as the owner 14 | bool internal _initialized; 15 | 16 | string public constant NAME = "Ethmoji"; 17 | string public constant SYMBOL = "EMJ"; 18 | 19 | function Ethmoji() ERC721Token("Ethmoji", "EMJ") public { } 20 | 21 | function initialize(address newOwner) public { 22 | require(!_initialized); 23 | isCompositionOnlyWithBaseLayers = true; 24 | minCompositionFee = .001 ether; 25 | owner = newOwner; 26 | _initialized = true; 27 | } 28 | 29 | /** 30 | * @dev Mints a composition emoji 31 | * @param _tokenIds uint256[] the array of layers that will make up the composition 32 | */ 33 | function compose(uint256[] _tokenIds, uint256 _imageHash) public payable whenNotPaused { 34 | Composable.compose(_tokenIds, _imageHash); 35 | 36 | // Immediately pay out to layer owners 37 | for (uint256 i = 0; i < _tokenIds.length; i++) { 38 | _withdrawTo(ownerOf(_tokenIds[i])); 39 | } 40 | } 41 | 42 | // ----- PRIVATE FUNCTIONS ------------------------------------------------------------------------ 43 | 44 | /** 45 | * @dev withdraw accumulated balance to the payee 46 | * @param _payee address to which to withdraw to 47 | */ 48 | function _withdrawTo(address _payee) private { 49 | uint256 payment = payments[_payee]; 50 | 51 | if (payment != 0 && address(this).balance >= payment) { 52 | totalPayments = totalPayments.sub(payment); 53 | payments[_payee] = 0; 54 | _payee.transfer(payment); 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /contracts/EthmojiProxy.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.21; 2 | 3 | import "./Proxy.sol"; 4 | import "./OwnableProxy.sol"; 5 | 6 | contract EthmojiProxy is Proxy, OwnableProxy { 7 | 8 | /** 9 | * @dev This event will be emitted every time the implementation gets upgraded 10 | * @param implementation representing the address of the upgraded implementation 11 | */ 12 | event Upgraded(address indexed implementation); 13 | 14 | // Storage position of the address of the current implementation 15 | bytes32 private constant implementationPosition = keccak256("ethmoji.io.super.duper.awesome.proxy.implementation"); 16 | 17 | /** 18 | * @dev Tells the address of the current implementation 19 | * @return address of the current implementation 20 | */ 21 | function implementation() public view returns (address impl) { 22 | bytes32 position = implementationPosition; 23 | assembly { 24 | impl := sload(position) 25 | } 26 | } 27 | 28 | /** 29 | * @dev Sets the address of the current implementation 30 | * @param newImplementation address representing the new implementation to be set 31 | */ 32 | function setImplementation(address newImplementation) internal { 33 | bytes32 position = implementationPosition; 34 | assembly { 35 | sstore(position, newImplementation) 36 | } 37 | } 38 | 39 | /** 40 | * @dev Allows the proxy owner to upgrade the current version of the proxy. 41 | * @param newImplementation representing the address of the new implementation to be set. 42 | */ 43 | function upgradeTo(address newImplementation) public onlyProxyOwner { 44 | _upgradeTo(newImplementation); 45 | } 46 | 47 | /** 48 | * @dev Allows the proxy owner to upgrade the current version of the proxy and call the new implementation 49 | * to initialize whatever is needed through a low level call. 50 | * @param newImplementation representing the address of the new implementation to be set. 51 | * @param data represents the msg.data to bet sent in the low level call. This parameter may include the function 52 | * signature of the implementation to be called with the needed payload 53 | */ 54 | function upgradeToAndCall(address newImplementation, bytes data) payable public onlyProxyOwner { 55 | upgradeTo(newImplementation); 56 | require(address(this).call.value(msg.value)(data)); 57 | } 58 | 59 | /** 60 | * @dev Upgrades the implementation address 61 | * @param newImplementation representing the address of the new implementation to be set 62 | */ 63 | function _upgradeTo(address newImplementation) internal { 64 | address currentImplementation = implementation(); 65 | require(currentImplementation != newImplementation); 66 | setImplementation(newImplementation); 67 | emit Upgraded(newImplementation); 68 | } 69 | } 70 | 71 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.21; 2 | 3 | 4 | contract Migrations { 5 | address public owner; 6 | uint public lastCompletedMigration; 7 | 8 | modifier restricted() { 9 | if (msg.sender == owner) _; 10 | } 11 | 12 | function Migrations() public { 13 | owner = msg.sender; 14 | } 15 | 16 | function setCompleted(uint completed) public restricted { 17 | lastCompletedMigration = completed; 18 | } 19 | 20 | function upgrade(address newAddress) public restricted { 21 | Migrations upgraded = Migrations(newAddress); 22 | upgraded.setCompleted(lastCompletedMigration); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contracts/OwnableProxy.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.21; 2 | 3 | contract OwnableProxy { 4 | /** 5 | * @dev Event to show ownership has been transferred 6 | * @param previousOwner representing the address of the previous owner 7 | * @param newOwner representing the address of the new owner 8 | */ 9 | event ProxyOwnershipTransferred(address previousOwner, address newOwner); 10 | 11 | // Storage position of the owner of the contract 12 | bytes32 private constant ownerPosition = keccak256("ethmoji.io.super.duper.awesome.proxy.owner"); 13 | 14 | /** 15 | * @dev the constructor sets the original owner of the contract to the sender account. 16 | */ 17 | function OwnableProxy() public { 18 | setUpgradeabilityOwner(msg.sender); 19 | } 20 | 21 | /** 22 | * @dev Throws if called by any account other than the owner. 23 | */ 24 | modifier onlyProxyOwner() { 25 | require(msg.sender == proxyOwner()); 26 | _; 27 | } 28 | 29 | /** 30 | * @dev Tells the address of the owner 31 | * @return the address of the owner 32 | */ 33 | function proxyOwner() public view returns (address owner) { 34 | bytes32 position = ownerPosition; 35 | assembly { 36 | owner := sload(position) 37 | } 38 | } 39 | 40 | /** 41 | * @dev Sets the address of the owner 42 | */ 43 | function setUpgradeabilityOwner(address newProxyOwner) internal { 44 | bytes32 position = ownerPosition; 45 | assembly { 46 | sstore(position, newProxyOwner) 47 | } 48 | } 49 | 50 | /** 51 | * @dev Allows the current owner to transfer control of the contract to a newOwner. 52 | * @param newOwner The address to transfer ownership to. 53 | */ 54 | function transferProxyOwnership(address newOwner) public onlyProxyOwner { 55 | require(newOwner != address(0)); 56 | emit ProxyOwnershipTransferred(proxyOwner(), newOwner); 57 | setUpgradeabilityOwner(newOwner); 58 | } 59 | } -------------------------------------------------------------------------------- /contracts/Proxy.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.21; 2 | 3 | /** 4 | * @title Proxy 5 | * @dev Gives the possibility to delegate any call to a foreign implementation. 6 | */ 7 | contract Proxy { 8 | /** 9 | * @dev Tells the address of the implementation where every call will be delegated. 10 | * @return address of the implementation to which it will be delegated 11 | */ 12 | function implementation() public view returns (address); 13 | 14 | /** 15 | * @dev Fallback function allowing to perform a delegatecall to the given implementation. 16 | * This function will return whatever the implementation call returns 17 | */ 18 | function () payable public { 19 | address _impl = implementation(); 20 | require(_impl != address(0)); 21 | 22 | assembly { 23 | let ptr := mload(0x40) 24 | calldatacopy(ptr, 0, calldatasize) 25 | let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0) 26 | let size := returndatasize 27 | returndatacopy(ptr, 0, size) 28 | 29 | switch result 30 | case 0 { revert(ptr, size) } 31 | default { return(ptr, size) } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const Ethmoji = require("./build/contracts/Ethmoji.json"); 2 | 3 | module.exports.Ethmoji = Ethmoji; 4 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | const Migrations = artifacts.require("../node_modules/zeppelin-solidity/contracts/lifecycle/Migrations.sol"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | const Ethmoji = artifacts.require("./ethmoji/Ethmoji.sol"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Ethmoji, {gas: 6721975}); 5 | }; 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ethmoji-contracts", 3 | "version": "1.0.4", 4 | "description": "Contracts for Ethmoji composable art blockchain game", 5 | "main": "index.js", 6 | "scripts": { 7 | "truffle": "truffle", 8 | "test": "truffle test", 9 | "deploy:rinkeby": "rm -rf build/ && truffle migrate --network rinkeby", 10 | "build": "rm -rf build/ && truffle compile" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/ProjectOpenSea/opensea-contracts.git" 15 | }, 16 | "author": "Open Sea", 17 | "contributors": [ 18 | "Elena Nadolinski (https://github.com/leanthebean)", 19 | "Devin Finzer (https://github.com/dfinzer)", 20 | "Feridun Mert Celebi (https://github.com/mertcelebi)" 21 | ], 22 | "dependencies": { 23 | "chai-as-promised": "^7.1.1", 24 | "chai-bignumber": "^2.0.2", 25 | "debug": "3.0.1", 26 | "eth-gas-reporter": "^0.1.1", 27 | "ethereumjs-abi": "^0.6.5", 28 | "keccak": "^1.4.0", 29 | "sha256": "^0.2.0", 30 | "truffle": "4.0.1", 31 | "truffle-hdwallet-provider": "^0.0.3", 32 | "web3": "0.20.1", 33 | "zeppelin-solidity": "^1.8.0" 34 | }, 35 | "homepage": "https://ethmoji.io" 36 | } 37 | -------------------------------------------------------------------------------- /test/ethmoji/AvatarTest.js: -------------------------------------------------------------------------------- 1 | var abi = require('ethereumjs-abi') 2 | 3 | var contractDefinition = artifacts.require('Avatar') 4 | var ethmojiContractDefinition = artifacts.require('Ethmoji') 5 | var ethmojiProxyContractDefinition = artifacts.require('EthmojiProxy') 6 | const BigNumber = web3.BigNumber 7 | 8 | require('chai') 9 | .use(require('chai-as-promised')) 10 | .use(require('chai-bignumber')(BigNumber)) 11 | .should() 12 | 13 | contract("Avatar", accounts => { 14 | var owner = accounts[0] 15 | var secondUser = accounts[1] 16 | var avatar 17 | var ethmojiProxy 18 | 19 | beforeEach(async function () { 20 | avatar = await contractDefinition.new({from: owner}) 21 | let ethmoji = await ethmojiContractDefinition.new({from: owner}) 22 | ethmojiProxy = await ethmojiProxyContractDefinition.new({ from: owner }) 23 | 24 | const initializeData = encodeCall('initialize', ['address'], [owner]) 25 | await ethmojiProxy.upgradeToAndCall(ethmoji.address, initializeData, { from: owner }) 26 | 27 | ethmojiProxy = await ethmojiContractDefinition.at(ethmojiProxy.address) 28 | }) 29 | 30 | describe('setValidContractForAvatar', () => { 31 | it('sets ethmoji as a valid avatar contract', async function () { 32 | await avatar.setValidContractForAvatar(ethmojiProxy.address, {from: owner}) 33 | 34 | let res = await avatar.isValidContractForAvatar(ethmojiProxy.address) 35 | res.should.be.true 36 | }) 37 | }) 38 | 39 | describe('avatar', () => { 40 | beforeEach(async function () { 41 | await avatar.setValidContractForAvatar(ethmojiProxy.address, {from: owner}) 42 | }) 43 | 44 | it('owner can set an avatar', async function () { 45 | let compositionFee = await ethmojiProxy.minCompositionFee() 46 | let compPriceIncrease = compositionFee 47 | 48 | await ethmojiProxy.mintTo(owner, compositionFee, compPriceIncrease, false, 1, { from: owner }) //mints token 1 49 | let tokenOwner = await ethmojiProxy.ownerOf(1) 50 | tokenOwner.should.be.equal(owner) 51 | 52 | await avatar.setAvatar(ethmojiProxy.address, 1, {from: owner}) 53 | 54 | let storedAvatarInfo = await avatar.getAvatar(owner) 55 | 56 | storedAvatarInfo[0].should.bignumber.be.equal(1) 57 | storedAvatarInfo[1].should.be.equal(ethmojiProxy.address) 58 | }) 59 | 60 | it('not owner can not set an avatar', async function () { 61 | let compositionFee = await ethmojiProxy.minCompositionFee() 62 | let compPriceIncrease = compositionFee 63 | 64 | await ethmojiProxy.mintTo(owner, compositionFee, compPriceIncrease, false, 1, { from: owner }) //mints token 1 65 | let tokenOwner = await ethmojiProxy.ownerOf(1) 66 | tokenOwner.should.be.equal(owner) 67 | 68 | await expectThrow(avatar.setAvatar(ethmojiProxy.address, 1, {from: secondUser})) 69 | }) 70 | 71 | it('owner loses avatar after transfer', async function () { 72 | let compositionFee = await ethmojiProxy.minCompositionFee() 73 | let compPriceIncrease = compositionFee 74 | 75 | await ethmojiProxy.mintTo(owner, compositionFee, compPriceIncrease, false, 1, { from: owner }) //mints token 1 76 | let tokenOwner = await ethmojiProxy.ownerOf(1) 77 | tokenOwner.should.be.equal(owner) 78 | 79 | await avatar.setAvatar(ethmojiProxy.address, 1, {from: owner}) 80 | 81 | let storedAvatarInfo = await avatar.getAvatar(owner) 82 | 83 | storedAvatarInfo[0].should.bignumber.be.equal(1) 84 | storedAvatarInfo[1].should.be.equal(ethmojiProxy.address) 85 | 86 | await ethmojiProxy.transfer(secondUser, 1, { from: owner }) 87 | 88 | await expectThrow(avatar.getAvatar(owner)) 89 | }) 90 | }) 91 | }) 92 | 93 | var expectThrow = async promise => { 94 | try { 95 | await promise 96 | } catch (error) { 97 | // TODO: Check jump destination to destinguish between a throw 98 | // and an actual invalid jump. 99 | const invalidOpcode = error.message.search('invalid opcode') >= 0 100 | // TODO: When we contract A calls contract B, and B throws, instead 101 | // of an 'invalid jump', we get an 'out of gas' error. How do 102 | // we distinguish this from an actual out of gas event? (The 103 | // testrpc log actually show an 'invalid jump' event.) 104 | const outOfGas = error.message.search('out of gas') >= 0 105 | const revert = error.message.search('revert') >= 0 106 | assert( 107 | invalidOpcode || outOfGas || revert, 108 | 'Expected throw, got \'' + error + '\' instead', 109 | ) 110 | return 111 | } 112 | assert.fail('Expected throw not received') 113 | } 114 | 115 | var encodeCall = function(name, arguments, values) { 116 | const methodId = abi.methodID(name, arguments).toString('hex'); 117 | const params = abi.rawEncode(arguments, values).toString('hex'); 118 | return '0x' + methodId + params; 119 | } -------------------------------------------------------------------------------- /test/ethmoji/EthmojiProxyTest.js: -------------------------------------------------------------------------------- 1 | var abi = require('ethereumjs-abi') 2 | 3 | var ethmojiContractDefinition = artifacts.require('Ethmoji') 4 | var ethmojiProxyContractDefinition = artifacts.require('EthmojiProxy') 5 | const BigNumber = web3.BigNumber 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | contract("EthmojiProxy", accounts => { 13 | var owner = accounts[0] 14 | var secondUser = accounts[1] 15 | var ethmojiProxy 16 | var ethmoji 17 | 18 | beforeEach(async function () { 19 | ethmoji = await ethmojiContractDefinition.new({from: owner}) 20 | ethmojiProxy = await ethmojiProxyContractDefinition.new({ from: owner }) 21 | 22 | const initializeData = encodeCall('initialize', ['address'], [owner]) 23 | await ethmojiProxy.upgradeToAndCall(ethmoji.address, initializeData, { from: owner }) 24 | 25 | ethmojiProxy = await ethmojiContractDefinition.at(ethmojiProxy.address) 26 | }) 27 | 28 | it('can upgrade', async function () { 29 | let ethmojiV2 = await ethmojiContractDefinition.new({from: owner}) 30 | 31 | ethmojiProxy = await ethmojiProxyContractDefinition.at(ethmojiProxy.address) 32 | 33 | let currentImplementationAddress = await ethmojiProxy.implementation() 34 | 35 | let ethmojiV1Address = ethmoji.address 36 | let ethmojiV2Address = ethmojiV2.address 37 | 38 | expect(currentImplementationAddress).to.equal(ethmojiV1Address); 39 | 40 | await ethmojiProxy.upgradeTo(ethmojiV2.address, { from: owner }) 41 | 42 | currentImplementationAddress = await ethmojiProxy.implementation() 43 | 44 | expect(currentImplementationAddress).to.not.equal(ethmojiV1Address); 45 | expect(currentImplementationAddress).to.equal(ethmojiV2Address); 46 | 47 | ethmojiProxy = await ethmojiContractDefinition.at(ethmojiProxy.address) 48 | 49 | let ethmojiOwner = await ethmojiProxy.owner() 50 | ethmojiOwner.should.be.equal.owner 51 | 52 | }) 53 | 54 | it('not owner can not upgrade', async function () { 55 | let ethmojiV2 = await ethmojiContractDefinition.new({from: owner}) 56 | 57 | ethmojiProxy = await ethmojiProxyContractDefinition.at(ethmojiProxy.address) 58 | 59 | let currentImplementationAddress = await ethmojiProxy.implementation() 60 | 61 | let ethmojiV1Address = ethmoji.address 62 | let ethmojiV2Address = ethmojiV2.address 63 | 64 | expect(currentImplementationAddress).to.equal(ethmojiV1Address); 65 | 66 | await expectThrow(ethmojiProxy.upgradeTo(ethmojiV2.address, { from: secondUser })) 67 | }) 68 | }) 69 | 70 | var expectThrow = async promise => { 71 | try { 72 | await promise 73 | } catch (error) { 74 | // TODO: Check jump destination to destinguish between a throw 75 | // and an actual invalid jump. 76 | const invalidOpcode = error.message.search('invalid opcode') >= 0 77 | // TODO: When we contract A calls contract B, and B throws, instead 78 | // of an 'invalid jump', we get an 'out of gas' error. How do 79 | // we distinguish this from an actual out of gas event? (The 80 | // testrpc log actually show an 'invalid jump' event.) 81 | const outOfGas = error.message.search('out of gas') >= 0 82 | const revert = error.message.search('revert') >= 0 83 | assert( 84 | invalidOpcode || outOfGas || revert, 85 | 'Expected throw, got \'' + error + '\' instead', 86 | ) 87 | return 88 | } 89 | assert.fail('Expected throw not received') 90 | } 91 | 92 | var encodeCall = function(name, arguments, values) { 93 | const methodId = abi.methodID(name, arguments).toString('hex'); 94 | const params = abi.rawEncode(arguments, values).toString('hex'); 95 | return '0x' + methodId + params; 96 | } -------------------------------------------------------------------------------- /test/ethmoji/EthmojiTest.js: -------------------------------------------------------------------------------- 1 | // FYI: methods in the beforeEach do not get reported in eth-gas-reporter, hence the lack of useful beforeEach methods :( 2 | var contractDeclaration = artifacts.require("Ethmoji") 3 | var proxyContractDeclaration = artifacts.require("EthmojiProxy") 4 | var abi = require('ethereumjs-abi') 5 | 6 | const createKeccakHash = require('keccak') 7 | const BigNumber = web3.BigNumber 8 | require('chai') 9 | .use(require('chai-as-promised')) 10 | .use(require('chai-bignumber')(BigNumber)) 11 | .should() 12 | 13 | contract('Ethmoji', accounts => { 14 | var owner = accounts[0] 15 | var purchaser = accounts[1] 16 | var contractInstance; 17 | let tx1; 18 | let tx2; 19 | let compositionFee 20 | let compPriceIncrease 21 | let imageHash 22 | let imageHashTwo 23 | let imageHashThree 24 | let developerFee = 1.05 25 | 26 | beforeEach(async function() { 27 | var ethmojiContractInstance = await contractDeclaration.new({ from: owner }) 28 | var proxy = await proxyContractDeclaration.new({ from: owner }) 29 | 30 | const initializeData = encodeCall('initialize', ['address'], [owner]) 31 | await proxy.upgradeToAndCall(ethmojiContractInstance.address, initializeData, { from: owner }) 32 | 33 | contractInstance = await contractDeclaration.at(proxy.address) 34 | 35 | compositionFee = await contractInstance.minCompositionFee() 36 | 37 | compPriceIncrease = new BigNumber(web3.toWei(.001, "ether")) 38 | imageHash = 12345 39 | imageHashTwo = 45678 40 | imageHashThree = 891 41 | }) 42 | 43 | describe('initial state', () => { 44 | it('initial state', async function () { 45 | const name = await contractInstance.name() 46 | const symbol = await contractInstance.symbol() 47 | 48 | name.should.be.equal('Ethmoji') 49 | symbol.should.be.equal('EMJ') 50 | }) 51 | }) 52 | 53 | describe('prices', () => { 54 | it('for minting a composition with default prices', async function () { 55 | await contractInstance.mintTo(owner, compositionFee, compPriceIncrease, false, imageHash, { from: owner }) //mints token 1 56 | await contractInstance.mintTo(owner, compositionFee, compPriceIncrease, false, imageHashTwo, { from: owner }) //mints token 2 57 | 58 | let price = await contractInstance.getTotalCompositionPrice([1, 2]) 59 | let expectedMintingPrice = compositionFee.add(compositionFee).mul(developerFee) 60 | 61 | price.should.bignumber.be.equal(expectedMintingPrice) 62 | }) 63 | 64 | it('for minting a composition with set prices', async function () { 65 | let newCompositionPriceForToken1 = 1 66 | let newCompositionPriceForToken2 = 2 67 | 68 | let compPrice1 = new BigNumber(web3.toWei(newCompositionPriceForToken1, "ether")) 69 | let compPrice2 = new BigNumber(web3.toWei(newCompositionPriceForToken2, "ether")) 70 | 71 | await contractInstance.mintTo(owner, compPrice1, compPriceIncrease, false, imageHash, { from: owner }) //mints token 1 72 | await contractInstance.mintTo(owner, compPrice2, compPriceIncrease, false, imageHashTwo, { from: owner }) //mints token 2 73 | 74 | let price = await contractInstance.getTotalCompositionPrice([1, 2]) 75 | let expectedMintingPrice = (((newCompositionPriceForToken1 + newCompositionPriceForToken2) * developerFee ) / 100) * 100 //floating number math.. 76 | 77 | price.toString().should.be.equal(web3.toWei(expectedMintingPrice, "ether")) 78 | }) 79 | 80 | it('after setting global composition fee', async function () { 81 | await contractInstance.setMinCompositionFee(new BigNumber(web3.toWei(5, "ether")), { from: owner }) 82 | 83 | let newCompositionFee = await contractInstance.minCompositionFee() 84 | await contractInstance.mintTo(owner, newCompositionFee, compPriceIncrease, false, imageHash, { from: owner }) //mints token 1 85 | await contractInstance.mintTo(owner, newCompositionFee, compPriceIncrease, false, imageHashTwo, { from: owner }) //mints token 2 86 | 87 | let expectedMintingPrice = (((5 + 5) * developerFee ) / 100) * 100 //floating number math.. 88 | 89 | let price = await contractInstance.getTotalCompositionPrice([1, 2]) 90 | price.toString().should.be.equal(web3.toWei(expectedMintingPrice, "ether")) 91 | }) 92 | 93 | it('same base costs more after previous uses', async function () { 94 | await contractInstance.mintTo(owner, compositionFee, compPriceIncrease, false, imageHash, { from: owner }) //mints token 1 95 | await contractInstance.mintTo(owner, compositionFee, compPriceIncrease, false, imageHashTwo, { from: owner }) //mints token 2 96 | await contractInstance.mintTo(owner, compositionFee, compPriceIncrease, false, 3, { from: owner }) //mints token 3 97 | 98 | let mintingPrice = await contractInstance.getTotalCompositionPrice([1, 2]) 99 | 100 | await contractInstance.compose([1, 2], imageHashThree, { from: owner, value: mintingPrice, gasPrice: 0 }) // mints token 3 101 | 102 | let price = await contractInstance.getTotalCompositionPrice([1, 3]) 103 | 104 | let expectedMintingPrice = compositionFee.add(compositionFee).add(compPriceIncrease).mul(developerFee) 105 | 106 | price.should.bignumber.be.equal(expectedMintingPrice) 107 | }) 108 | }) 109 | 110 | describe('minting a base token', () => { 111 | let tx; 112 | let tokenId; 113 | let compositionPrice; 114 | 115 | it('emits correct log', async function () { 116 | tx = await contractInstance.mintTo(owner, compositionFee, compPriceIncrease, false, imageHash, { from: owner }) 117 | tx.logs[0].event.should.be.equal('Transfer') 118 | 119 | tx.logs[1].event.should.be.equal('BaseTokenCreated') 120 | tx.logs[2].event.should.be.equal('CompositionPriceChanged') 121 | }) 122 | 123 | it('sets one layer (itself)', async function () { 124 | tx = await contractInstance.mintTo(owner, compositionFee, compPriceIncrease, false, imageHash, { from: owner }) 125 | tokenId = tx.logs[0].args._tokenId; 126 | 127 | const layers = await contractInstance.getTokenLayers(tokenId) 128 | layers.length.should.be.equal(1) 129 | layers[0].should.be.bignumber.equal(tokenId) 130 | }) 131 | 132 | it('sets correct owner (owner)', async function () { 133 | tx = await contractInstance.mintTo(owner, compositionFee, compPriceIncrease, false, imageHash, { from: owner }) 134 | tokenId = tx.logs[0].args._tokenId; 135 | 136 | const tokenOwner = await contractInstance.ownerOf(tokenId) 137 | tokenOwner.should.be.equal(owner) 138 | }) 139 | 140 | it('sets correct initial composition price', async function () { 141 | tx = await contractInstance.mintTo(owner, compositionFee, compPriceIncrease, false, imageHash, { from: owner }) 142 | tokenId = tx.logs[0].args._tokenId; 143 | 144 | const compositionPrice = await contractInstance.getCompositionPrice(tokenId) 145 | compositionPrice.should.bignumber.be.equal(compositionPrice) 146 | }) 147 | 148 | it('updates uniqueness', async function () { 149 | tx = await contractInstance.mintTo(owner, compositionFee, compPriceIncrease, false, imageHash, { from: owner }) 150 | tokenId = tx.logs[0].args._tokenId; 151 | 152 | var isValidComposition = await contractInstance.isValidComposition([tokenId], imageHash) 153 | isValidComposition.should.be.false 154 | }) 155 | }) 156 | 157 | describe('uniqueness', () => { 158 | let tx 159 | let mintingPrice 160 | 161 | beforeEach(async function () { 162 | for(let i = 1; i <= 10; i ++ ) { 163 | await contractInstance.mintTo(owner, compositionFee, compPriceIncrease, false, i, { from: owner }) 164 | } 165 | }) 166 | 167 | it('checks uniqueness with existing hashes layers', async function () { 168 | let isUnique = await contractInstance.isValidComposition([2, 3], imageHash) 169 | isUnique.should.be.equal(true) 170 | 171 | mintingPrice = await contractInstance.getTotalCompositionPrice([2, 3]) 172 | await contractInstance.compose([2, 3], imageHash, { from: owner, value: mintingPrice, gasPrice: 0 }) 173 | 174 | isUnique = await contractInstance.isValidComposition([1, 2], imageHash) 175 | isUnique.should.be.equal(false) 176 | 177 | isUnique = await contractInstance.isValidComposition([1, 3], imageHashTwo) 178 | isUnique.should.be.equal(true) 179 | }) 180 | 181 | it('using composition emoji to create an exisitng emoji breaks uniqueness', async function () { 182 | mintingPrice = await contractInstance.getTotalCompositionPrice([1, 2, 3]) 183 | 184 | let tx = await contractInstance.compose([1, 2], imageHash, { from: owner, value: mintingPrice, gasPrice: 0 }) // mints token 11 185 | let tokenId = tx.logs.filter(t => t.event == 'Transfer')[0].args._tokenId 186 | tokenId.should.bignumber.be.equal(11) 187 | 188 | mintingPrice = await contractInstance.getTotalCompositionPrice([1, 2, 3]) 189 | await contractInstance.compose([1, 2, 3], imageHashTwo, { from: owner, value: mintingPrice, gasPrice: 0 }) // mints token 12 190 | isUnique = await contractInstance.isValidComposition([11, 3], imageHashThree) 191 | isUnique.should.be.equal(false) 192 | 193 | await expectThrow(contractInstance.compose([11, 3], imageHashThree, { from: owner, value: mintingPrice, gasPrice: 0 })) 194 | }) 195 | 196 | it('checks uniqueness with duplicate layers', async function () { 197 | let isUnique = await contractInstance.isValidComposition([1, 1, 2], imageHash) 198 | isUnique.should.be.equal(false) 199 | }) 200 | 201 | it('checks that uniqueness fails on compositions with more than 100 layers', async function () { 202 | for(let i = 1; i <= 101; i ++ ) { 203 | let imageHash = i+10; 204 | await contractInstance.mintTo(owner, compositionFee, compPriceIncrease, false, imageHash, { from: owner }) 205 | } 206 | let compLayers = Array.apply(null, Array(102)).map(function (_, i) { return i+1; }); 207 | let isCompositionOnlyWithBaseLayers = await contractInstance.isCompositionOnlyWithBaseLayers() 208 | await expectThrow(contractInstance.isValidComposition(compLayers, 100000000)) 209 | }) 210 | 211 | it('checks that uniqueness is true on compositions with 100 layers', async function () { 212 | for(let i = 1; i <= 91; i ++ ) { 213 | let imageHash = i+10; 214 | await contractInstance.mintTo(owner, compositionFee, compPriceIncrease, false, imageHash, { from: owner }) 215 | } 216 | 217 | let compLayers = Array.apply(null, Array(100)).map(function (_, i) { return i+1; }); 218 | let isUnique = await contractInstance.isValidComposition(compLayers, imageHashTwo) 219 | isUnique.should.be.equal(true) 220 | }) 221 | 222 | it('checks that uniqueness when large number is used', async function () { 223 | let bigLayerId = new web3.BigNumber("9".repeat(32)) 224 | let isUnique = await contractInstance.isValidComposition([bigLayerId, bigLayerId.plus(1), bigLayerId.plus(2)], imageHash) 225 | isUnique.should.be.equal(false) 226 | }) 227 | }) 228 | 229 | describe('minting a composition', () => { 230 | let tx 231 | let mintingPrice 232 | 233 | beforeEach(async function () { 234 | // mints token 1-10 235 | for(let i = 1; i <= 10; i ++ ) { 236 | let imageHash = i; 237 | await contractInstance.mintTo(owner, compositionFee, compPriceIncrease, false, imageHash, { from: owner }) 238 | } 239 | mintingPrice = await contractInstance.getTotalCompositionPrice([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 240 | }) 241 | 242 | it('emits correct logs', async function () { 243 | let isUnique = await contractInstance.isValidComposition([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], imageHash) 244 | isUnique.should.be.equal(true) 245 | 246 | tx = await contractInstance.compose([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], imageHash, { from: purchaser, value: mintingPrice, gasPrice: 0 }) 247 | 248 | isUnique = await contractInstance.isValidComposition([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], imageHashTwo) 249 | isUnique.should.be.equal(false) 250 | 251 | tx.logs[0].event.should.be.equal('RoyaltiesPaid') 252 | tx.logs[1].event.should.be.equal('RoyaltiesPaid') 253 | tx.logs[2].event.should.be.equal('RoyaltiesPaid') 254 | tx.logs[3].event.should.be.equal('RoyaltiesPaid') 255 | tx.logs[4].event.should.be.equal('RoyaltiesPaid') 256 | tx.logs[5].event.should.be.equal('RoyaltiesPaid') 257 | tx.logs[6].event.should.be.equal('RoyaltiesPaid') 258 | tx.logs[7].event.should.be.equal('RoyaltiesPaid') 259 | tx.logs[8].event.should.be.equal('RoyaltiesPaid') 260 | tx.logs[9].event.should.be.equal('RoyaltiesPaid') 261 | tx.logs[10].event.should.be.equal('Transfer') 262 | tx.logs[11].event.should.be.equal('CompositionTokenCreated') 263 | }) 264 | 265 | it('caller overpays and gets the excess back', async function () { 266 | let balanceBeforeTransaction = web3.eth.getBalance(purchaser) 267 | let price = new BigNumber(web3.toWei(10, "ether")) 268 | tx = await contractInstance.compose([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], imageHash, { from: purchaser, value: price, gasPrice: 0 }) 269 | 270 | tx.logs[0].event.should.be.equal('RoyaltiesPaid') 271 | tx.logs[1].event.should.be.equal('RoyaltiesPaid') 272 | tx.logs[2].event.should.be.equal('RoyaltiesPaid') 273 | tx.logs[3].event.should.be.equal('RoyaltiesPaid') 274 | tx.logs[4].event.should.be.equal('RoyaltiesPaid') 275 | tx.logs[5].event.should.be.equal('RoyaltiesPaid') 276 | tx.logs[6].event.should.be.equal('RoyaltiesPaid') 277 | tx.logs[7].event.should.be.equal('RoyaltiesPaid') 278 | tx.logs[8].event.should.be.equal('RoyaltiesPaid') 279 | tx.logs[9].event.should.be.equal('RoyaltiesPaid') 280 | tx.logs[10].event.should.be.equal('Transfer') 281 | tx.logs[11].event.should.be.equal('CompositionTokenCreated') 282 | 283 | let balanceAfterTransaction = web3.eth.getBalance(purchaser) 284 | 285 | balanceAfterTransaction.should.bignumber.be.equal(balanceBeforeTransaction.minus(mintingPrice)) 286 | }) 287 | 288 | it('composes with 100 layers', async function() { 289 | for(let i = 1; i <= 65; i ++ ) { 290 | let imageHash = i + 10 291 | await contractInstance.mintTo(owner, compositionFee, compPriceIncrease, false, imageHash, { from: owner }) 292 | } 293 | let compLayers = Array.apply(null, Array(65)).map(function (_, i) { return i + 1; }); 294 | mintingPrice = await contractInstance.getTotalCompositionPrice(compLayers) 295 | tx = await contractInstance.compose(compLayers, imageHashTwo, { from: owner, value: mintingPrice, gasPrice: 0 }) 296 | }) 297 | 298 | it('has correct id', async function () { 299 | tx = await contractInstance.compose([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], imageHash, { from: owner, value: mintingPrice, gasPrice: 0 }) 300 | 301 | let tokenId = tx.logs.filter(t => t.event == 'Transfer')[0].args._tokenId 302 | tokenId.should.bignumber.be.equal(11) 303 | }) 304 | 305 | it('has correct layers when using base emojis', async function () { 306 | tx = await contractInstance.compose([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], imageHash, { from: owner, value: mintingPrice, gasPrice: 0 }) 307 | let tokenId = tx.logs.filter(t => t.event == 'Transfer')[0].args._tokenId 308 | tokenId.should.be.bignumber.be.equal(11) 309 | 310 | let layers = await contractInstance.getTokenLayers(tokenId) 311 | layers.length.should.be.equal(10) 312 | layers[0].should.bignumber.be.equal(1) 313 | layers[1].should.bignumber.be.equal(2) 314 | layers[2].should.bignumber.be.equal(3) 315 | layers[3].should.bignumber.be.equal(4) 316 | layers[4].should.bignumber.be.equal(5) 317 | layers[5].should.bignumber.be.equal(6) 318 | layers[6].should.bignumber.be.equal(7) 319 | layers[7].should.bignumber.be.equal(8) 320 | layers[8].should.bignumber.be.equal(9) 321 | layers[9].should.bignumber.be.equal(10) 322 | }) 323 | 324 | it('throws when using composition emoji and base emojis', async function () { 325 | tx = await contractInstance.compose([1, 2], imageHash, { from: owner, value: mintingPrice, gasPrice: 0}) //token 11 326 | let tokenId = tx.logs.filter(t => t.event == 'Transfer')[0].args._tokenId 327 | tokenId.should.bignumber.be.equal(11) 328 | 329 | await expectThrow(contractInstance.compose([11, 3], imageHashTwo, { from: owner, value: mintingPrice, gasPrice: 0})) 330 | }) 331 | 332 | it('throws when using two composition emojis', async function () { 333 | tx = await contractInstance.compose([1, 2], imageHash, { from: owner, value: mintingPrice, gasPrice: 0}) //token 11 334 | let tokenId = tx.logs.filter(t => t.event == 'Transfer')[0].args._tokenId 335 | tokenId.should.bignumber.be.equal(11) 336 | 337 | tx = await contractInstance.compose([3, 4], imageHashTwo, { from: owner, value: mintingPrice, gasPrice: 0}) //token 12 338 | tokenId = tx.logs[2].args._tokenId 339 | tokenId.should.bignumber.be.equal(12) 340 | 341 | await expectThrow(contractInstance.compose([11, 12], imageHashThree, { from: owner, value: mintingPrice, gasPrice: 0})) 342 | }) 343 | 344 | it('throws when trying to make a composite emoji with duplicate', async function () { 345 | tx = await contractInstance.compose([1, 2], imageHash, { from: owner, value: mintingPrice, gasPrice: 0}) //token 11 346 | let tokenId = tx.logs.filter(t => t.event == 'Transfer')[0].args._tokenId 347 | tokenId.should.bignumber.be.equal(11) 348 | 349 | await expectThrow(contractInstance.compose([1, 2], imageHash, { from: owner, value: mintingPrice, gasPrice: 0})) //token 11 350 | }) 351 | }) 352 | 353 | describe('profits', () => { 354 | it('gives owner of emoji profits from compostion emojis', async function () { 355 | //owner owns token id 1 and gets paid for compositions that use token id 1 356 | 357 | await contractInstance.mintTo(purchaser, compositionFee, compPriceIncrease, false, imageHash, { from: owner }) //mints token 1 358 | await contractInstance.mintTo(owner, compositionFee, compPriceIncrease, false, imageHashTwo, { from: owner }) //mints token 2 359 | 360 | let balanceOfOwnerPreTransaction = web3.eth.getBalance(owner); 361 | 362 | let mintingPrice = await contractInstance.getTotalCompositionPrice([1, 2]) 363 | await contractInstance.compose([1, 2], compositionFee, { from: purchaser, value: mintingPrice, gasPrice: 0 }) 364 | 365 | let balanceOfOwnerAfterTransaction = web3.eth.getBalance(owner); 366 | 367 | balanceOfOwnerAfterTransaction.should.bignumber.be.equal(balanceOfOwnerPreTransaction.add(compositionFee)) 368 | }) 369 | 370 | it('gives owner of emoji profits from compostion emojis with set composition price', async function () { 371 | //owner owns token id 1 and gets paid for compositions that use token id 1 372 | await contractInstance.mintTo(owner, compositionFee, compPriceIncrease, true, imageHash, { from: owner }) //mints token 1 373 | await contractInstance.mintTo(purchaser, compositionFee, compPriceIncrease, false, imageHashTwo, { from: owner }) //mints token 2 374 | 375 | let newCompositionPriceForToken1 = new BigNumber(web3.toWei(.005, "ether")) 376 | await contractInstance.setCompositionPrice(1, newCompositionPriceForToken1, { from: owner }) 377 | 378 | let balanceOfOwnerPreTransaction = web3.eth.getBalance(owner); 379 | 380 | let mintingPrice = await contractInstance.getTotalCompositionPrice([1, 2]) 381 | await contractInstance.compose([1, 2], imageHashThree, { from: purchaser, value: mintingPrice, gasPrice: 0 }) 382 | 383 | let balanceOfOwnerAfterTransaction = web3.eth.getBalance(owner); 384 | 385 | balanceOfOwnerAfterTransaction.should.bignumber.be.equal(balanceOfOwnerPreTransaction.add(newCompositionPriceForToken1)) 386 | }) 387 | }) 388 | 389 | describe('payout', () => { 390 | it('gives developer fee collected by the contract to specified address', async function () { 391 | await contractInstance.mintTo(owner, compositionFee, compPriceIncrease, false, imageHash, { from: owner }) //mints token 1 392 | await contractInstance.mintTo(owner, compositionFee, compPriceIncrease, false, imageHashTwo, { from: owner }) //mints token 2 393 | 394 | let balanceOfContractPreTransaction = web3.eth.getBalance(contractInstance.address); 395 | let balanceOfOwnerPreTransaction = web3.eth.getBalance(owner); 396 | 397 | let mintingPrice = await contractInstance.getTotalCompositionPrice([1, 2], { from: owner, gasPrice: 0 }) 398 | mintingPrice.should.bignumber.be.equal(compositionFee.add(compositionFee).mul(developerFee)) 399 | await contractInstance.compose([1, 2], imageHashThree, { from: purchaser, value: mintingPrice, gasPrice: 0 }) 400 | 401 | let balanceOfOwnerPostWithdrawTransaction = web3.eth.getBalance(owner); 402 | balanceOfOwnerPostWithdrawTransaction.should.bignumber.be.equal(balanceOfOwnerPreTransaction.add(compositionFee.add(compositionFee))) 403 | 404 | let balanceOfContractAfterMinting = web3.eth.getBalance(contractInstance.address); 405 | balanceOfContractAfterMinting.should.bignumber.be.equal(compositionFee.add(compositionFee).mul(developerFee).minus(compositionFee.add(compositionFee))) 406 | 407 | await contractInstance.payout(owner, { from: owner, gasPrice: 0 }) 408 | 409 | let balanceOfContractAfterTransaction = web3.eth.getBalance(contractInstance.address); 410 | let balanceOfOwnerAfterTransaction = web3.eth.getBalance(owner); 411 | 412 | balanceOfOwnerAfterTransaction.should.bignumber.be.equal(balanceOfOwnerPostWithdrawTransaction.add(balanceOfContractAfterMinting)) 413 | balanceOfContractAfterTransaction.should.bignumber.be.equal(balanceOfContractPreTransaction) 414 | }) 415 | }) 416 | 417 | describe('transfer ownership', () => { 418 | let newAddress 419 | beforeEach(async function () { 420 | newAddress = accounts[2]; 421 | }) 422 | 423 | it('account does not have access to contract owner only functions', async function () { 424 | await expectThrow(contractInstance.payout(newAddress, {from : newAddress})) 425 | }) 426 | 427 | it('non contract owner cannot set contract owners', async function () { 428 | await expectThrow(contractInstance.transferOwnership(newAddress, {from : newAddress})) 429 | }) 430 | 431 | it('account does have access to contract owner only functions after it is set as owner', async function () { 432 | await contractInstance.transferOwnership(newAddress, { from: owner }) 433 | let tx = await contractInstance.payout(newAddress, {from : newAddress}) 434 | tx.should.be.not.null 435 | }) 436 | }) 437 | }) 438 | 439 | var expectThrow = async promise => { 440 | try { 441 | await promise 442 | } catch (error) { 443 | // TODO: Check jump destination to destinguish between a throw 444 | // and an actual invalid jump. 445 | const invalidOpcode = error.message.search('invalid opcode') >= 0 446 | // TODO: When we contract A calls contract B, and B throws, instead 447 | // of an 'invalid jump', we get an 'out of gas' error. How do 448 | // we distinguish this from an actual out of gas event? (The 449 | // testrpc log actually show an 'invalid jump' event.) 450 | const outOfGas = error.message.search('out of gas') >= 0 451 | const revert = error.message.search('revert') >= 0 452 | assert( 453 | invalidOpcode || outOfGas || revert, 454 | 'Expected throw, got \'' + error + '\' instead', 455 | ) 456 | return 457 | } 458 | assert.fail('Expected throw not received') 459 | } 460 | 461 | var encodeCall = function(name, arguments, values) { 462 | const methodId = abi.methodID(name, arguments).toString('hex'); 463 | const params = abi.rawEncode(arguments, values).toString('hex'); 464 | return '0x' + methodId + params; 465 | } 466 | -------------------------------------------------------------------------------- /truffle.js: -------------------------------------------------------------------------------- 1 | const HDWalletProvider = require("truffle-hdwallet-provider"); 2 | const MNEMONIC = process.env.MNEMONIC 3 | const INFURA_KEY = process.env.INFURA_KEY 4 | 5 | if (!MNEMONIC || !INFURA_KEY) { 6 | console.error("Please set a mnemonic and infura key.") 7 | return 8 | } 9 | 10 | module.exports = { 11 | networks: { 12 | development: { 13 | host: "localhost", 14 | port: 8545, 15 | gas: 4600000, 16 | network_id: "*" // Match any network id 17 | }, 18 | rinkeby: { 19 | provider: function() { 20 | return new HDWalletProvider( 21 | MNEMONIC, 22 | "https://rinkeby.infura.io/" + INFURA_KEY 23 | ); 24 | }, 25 | network_id: "*", 26 | gas: 4000000 27 | }, 28 | live: { 29 | network_id: 1, 30 | provider: function() { 31 | return new HDWalletProvider( 32 | MNEMONIC, 33 | "https://mainnet.infura.io/" + INFURA_KEY 34 | ); 35 | }, 36 | gas: 4000000, 37 | gasPrice: 50000000000 38 | }, 39 | mocha: { 40 | reporter: 'eth-gas-reporter', 41 | reporterOptions : { 42 | currency: 'USD', 43 | gasPrice: 2 44 | } 45 | } 46 | } 47 | }; 48 | --------------------------------------------------------------------------------