├── .gitignore ├── build └── contracts │ ├── Migrations.sol.js │ └── SimpleNameRegistry.sol.js ├── contracts ├── Migrations.sol └── SimpleNameRegistry.sol ├── deploy_mnemonic.key ├── index.js ├── migrations ├── 1_initial_migration.js └── 2_deploy_contracts.js ├── package.json ├── test ├── interface.js └── simplenameregistry.js └── truffle.js /.gitignore: -------------------------------------------------------------------------------- 1 | deploy_mnemonic.key 2 | node_modules 3 | -------------------------------------------------------------------------------- /build/contracts/Migrations.sol.js: -------------------------------------------------------------------------------- 1 | var Web3 = require("web3"); 2 | var SolidityEvent = require("web3/lib/web3/event.js"); 3 | 4 | (function() { 5 | // Planned for future features, logging, etc. 6 | function Provider(provider) { 7 | this.provider = provider; 8 | } 9 | 10 | Provider.prototype.send = function() { 11 | this.provider.send.apply(this.provider, arguments); 12 | }; 13 | 14 | Provider.prototype.sendAsync = function() { 15 | this.provider.sendAsync.apply(this.provider, arguments); 16 | }; 17 | 18 | var BigNumber = (new Web3()).toBigNumber(0).constructor; 19 | 20 | var Utils = { 21 | is_object: function(val) { 22 | return typeof val == "object" && !Array.isArray(val); 23 | }, 24 | is_big_number: function(val) { 25 | if (typeof val != "object") return false; 26 | 27 | // Instanceof won't work because we have multiple versions of Web3. 28 | try { 29 | new BigNumber(val); 30 | return true; 31 | } catch (e) { 32 | return false; 33 | } 34 | }, 35 | merge: function() { 36 | var merged = {}; 37 | var args = Array.prototype.slice.call(arguments); 38 | 39 | for (var i = 0; i < args.length; i++) { 40 | var object = args[i]; 41 | var keys = Object.keys(object); 42 | for (var j = 0; j < keys.length; j++) { 43 | var key = keys[j]; 44 | var value = object[key]; 45 | merged[key] = value; 46 | } 47 | } 48 | 49 | return merged; 50 | }, 51 | promisifyFunction: function(fn, C) { 52 | var self = this; 53 | return function() { 54 | var instance = this; 55 | 56 | var args = Array.prototype.slice.call(arguments); 57 | var tx_params = {}; 58 | var last_arg = args[args.length - 1]; 59 | 60 | // It's only tx_params if it's an object and not a BigNumber. 61 | if (Utils.is_object(last_arg) && !Utils.is_big_number(last_arg)) { 62 | tx_params = args.pop(); 63 | } 64 | 65 | tx_params = Utils.merge(C.class_defaults, tx_params); 66 | 67 | return new Promise(function(accept, reject) { 68 | var callback = function(error, result) { 69 | if (error != null) { 70 | reject(error); 71 | } else { 72 | accept(result); 73 | } 74 | }; 75 | args.push(tx_params, callback); 76 | fn.apply(instance.contract, args); 77 | }); 78 | }; 79 | }, 80 | synchronizeFunction: function(fn, instance, C) { 81 | var self = this; 82 | return function() { 83 | var args = Array.prototype.slice.call(arguments); 84 | var tx_params = {}; 85 | var last_arg = args[args.length - 1]; 86 | 87 | // It's only tx_params if it's an object and not a BigNumber. 88 | if (Utils.is_object(last_arg) && !Utils.is_big_number(last_arg)) { 89 | tx_params = args.pop(); 90 | } 91 | 92 | tx_params = Utils.merge(C.class_defaults, tx_params); 93 | 94 | return new Promise(function(accept, reject) { 95 | 96 | var decodeLogs = function(logs) { 97 | return logs.map(function(log) { 98 | var logABI = C.events[log.topics[0]]; 99 | 100 | if (logABI == null) { 101 | return null; 102 | } 103 | 104 | var decoder = new SolidityEvent(null, logABI, instance.address); 105 | return decoder.decode(log); 106 | }).filter(function(log) { 107 | return log != null; 108 | }); 109 | }; 110 | 111 | var callback = function(error, tx) { 112 | if (error != null) { 113 | reject(error); 114 | return; 115 | } 116 | 117 | var timeout = C.synchronization_timeout || 240000; 118 | var start = new Date().getTime(); 119 | 120 | var make_attempt = function() { 121 | C.web3.eth.getTransactionReceipt(tx, function(err, receipt) { 122 | if (err) return reject(err); 123 | 124 | if (receipt != null) { 125 | // If they've opted into next gen, return more information. 126 | if (C.next_gen == true) { 127 | return accept({ 128 | tx: tx, 129 | receipt: receipt, 130 | logs: decodeLogs(receipt.logs) 131 | }); 132 | } else { 133 | return accept(tx); 134 | } 135 | } 136 | 137 | if (timeout > 0 && new Date().getTime() - start > timeout) { 138 | return reject(new Error("Transaction " + tx + " wasn't processed in " + (timeout / 1000) + " seconds!")); 139 | } 140 | 141 | setTimeout(make_attempt, 1000); 142 | }); 143 | }; 144 | 145 | make_attempt(); 146 | }; 147 | 148 | args.push(tx_params, callback); 149 | fn.apply(self, args); 150 | }); 151 | }; 152 | } 153 | }; 154 | 155 | function instantiate(instance, contract) { 156 | instance.contract = contract; 157 | var constructor = instance.constructor; 158 | 159 | // Provision our functions. 160 | for (var i = 0; i < instance.abi.length; i++) { 161 | var item = instance.abi[i]; 162 | if (item.type == "function") { 163 | if (item.constant == true) { 164 | instance[item.name] = Utils.promisifyFunction(contract[item.name], constructor); 165 | } else { 166 | instance[item.name] = Utils.synchronizeFunction(contract[item.name], instance, constructor); 167 | } 168 | 169 | instance[item.name].call = Utils.promisifyFunction(contract[item.name].call, constructor); 170 | instance[item.name].sendTransaction = Utils.promisifyFunction(contract[item.name].sendTransaction, constructor); 171 | instance[item.name].request = contract[item.name].request; 172 | instance[item.name].estimateGas = Utils.promisifyFunction(contract[item.name].estimateGas, constructor); 173 | } 174 | 175 | if (item.type == "event") { 176 | instance[item.name] = contract[item.name]; 177 | } 178 | } 179 | 180 | instance.allEvents = contract.allEvents; 181 | instance.address = contract.address; 182 | instance.transactionHash = contract.transactionHash; 183 | }; 184 | 185 | // Use inheritance to create a clone of this contract, 186 | // and copy over contract's static functions. 187 | function mutate(fn) { 188 | var temp = function Clone() { return fn.apply(this, arguments); }; 189 | 190 | Object.keys(fn).forEach(function(key) { 191 | temp[key] = fn[key]; 192 | }); 193 | 194 | temp.prototype = Object.create(fn.prototype); 195 | bootstrap(temp); 196 | return temp; 197 | }; 198 | 199 | function bootstrap(fn) { 200 | fn.web3 = new Web3(); 201 | fn.class_defaults = fn.prototype.defaults || {}; 202 | 203 | // Set the network iniitally to make default data available and re-use code. 204 | // Then remove the saved network id so the network will be auto-detected on first use. 205 | fn.setNetwork("default"); 206 | fn.network_id = null; 207 | return fn; 208 | }; 209 | 210 | // Accepts a contract object created with web3.eth.contract. 211 | // Optionally, if called without `new`, accepts a network_id and will 212 | // create a new version of the contract abstraction with that network_id set. 213 | function Contract() { 214 | if (this instanceof Contract) { 215 | instantiate(this, arguments[0]); 216 | } else { 217 | var C = mutate(Contract); 218 | var network_id = arguments.length > 0 ? arguments[0] : "default"; 219 | C.setNetwork(network_id); 220 | return C; 221 | } 222 | }; 223 | 224 | Contract.currentProvider = null; 225 | 226 | Contract.setProvider = function(provider) { 227 | var wrapped = new Provider(provider); 228 | this.web3.setProvider(wrapped); 229 | this.currentProvider = provider; 230 | }; 231 | 232 | Contract.new = function() { 233 | if (this.currentProvider == null) { 234 | throw new Error("Migrations error: Please call setProvider() first before calling new()."); 235 | } 236 | 237 | var args = Array.prototype.slice.call(arguments); 238 | 239 | if (!this.unlinked_binary) { 240 | throw new Error("Migrations error: contract binary not set. Can't deploy new instance."); 241 | } 242 | 243 | var regex = /__[^_]+_+/g; 244 | var unlinked_libraries = this.binary.match(regex); 245 | 246 | if (unlinked_libraries != null) { 247 | unlinked_libraries = unlinked_libraries.map(function(name) { 248 | // Remove underscores 249 | return name.replace(/_/g, ""); 250 | }).sort().filter(function(name, index, arr) { 251 | // Remove duplicates 252 | if (index + 1 >= arr.length) { 253 | return true; 254 | } 255 | 256 | return name != arr[index + 1]; 257 | }).join(", "); 258 | 259 | throw new Error("Migrations contains unresolved libraries. You must deploy and link the following libraries before you can deploy a new version of Migrations: " + unlinked_libraries); 260 | } 261 | 262 | var self = this; 263 | 264 | return new Promise(function(accept, reject) { 265 | var contract_class = self.web3.eth.contract(self.abi); 266 | var tx_params = {}; 267 | var last_arg = args[args.length - 1]; 268 | 269 | // It's only tx_params if it's an object and not a BigNumber. 270 | if (Utils.is_object(last_arg) && !Utils.is_big_number(last_arg)) { 271 | tx_params = args.pop(); 272 | } 273 | 274 | tx_params = Utils.merge(self.class_defaults, tx_params); 275 | 276 | if (tx_params.data == null) { 277 | tx_params.data = self.binary; 278 | } 279 | 280 | // web3 0.9.0 and above calls new twice this callback twice. 281 | // Why, I have no idea... 282 | var intermediary = function(err, web3_instance) { 283 | if (err != null) { 284 | reject(err); 285 | return; 286 | } 287 | 288 | if (err == null && web3_instance != null && web3_instance.address != null) { 289 | accept(new self(web3_instance)); 290 | } 291 | }; 292 | 293 | args.push(tx_params, intermediary); 294 | contract_class.new.apply(contract_class, args); 295 | }); 296 | }; 297 | 298 | Contract.at = function(address) { 299 | if (address == null || typeof address != "string" || address.length != 42) { 300 | throw new Error("Invalid address passed to Migrations.at(): " + address); 301 | } 302 | 303 | var contract_class = this.web3.eth.contract(this.abi); 304 | var contract = contract_class.at(address); 305 | 306 | return new this(contract); 307 | }; 308 | 309 | Contract.deployed = function() { 310 | if (!this.address) { 311 | throw new Error("Cannot find deployed address: Migrations not deployed or address not set."); 312 | } 313 | 314 | return this.at(this.address); 315 | }; 316 | 317 | Contract.defaults = function(class_defaults) { 318 | if (this.class_defaults == null) { 319 | this.class_defaults = {}; 320 | } 321 | 322 | if (class_defaults == null) { 323 | class_defaults = {}; 324 | } 325 | 326 | var self = this; 327 | Object.keys(class_defaults).forEach(function(key) { 328 | var value = class_defaults[key]; 329 | self.class_defaults[key] = value; 330 | }); 331 | 332 | return this.class_defaults; 333 | }; 334 | 335 | Contract.extend = function() { 336 | var args = Array.prototype.slice.call(arguments); 337 | 338 | for (var i = 0; i < arguments.length; i++) { 339 | var object = arguments[i]; 340 | var keys = Object.keys(object); 341 | for (var j = 0; j < keys.length; j++) { 342 | var key = keys[j]; 343 | var value = object[key]; 344 | this.prototype[key] = value; 345 | } 346 | } 347 | }; 348 | 349 | Contract.all_networks = { 350 | "2": { 351 | "abi": [ 352 | { 353 | "constant": false, 354 | "inputs": [ 355 | { 356 | "name": "new_address", 357 | "type": "address" 358 | } 359 | ], 360 | "name": "upgrade", 361 | "outputs": [], 362 | "type": "function" 363 | }, 364 | { 365 | "constant": true, 366 | "inputs": [], 367 | "name": "last_completed_migration", 368 | "outputs": [ 369 | { 370 | "name": "", 371 | "type": "uint256" 372 | } 373 | ], 374 | "type": "function" 375 | }, 376 | { 377 | "constant": true, 378 | "inputs": [], 379 | "name": "owner", 380 | "outputs": [ 381 | { 382 | "name": "", 383 | "type": "address" 384 | } 385 | ], 386 | "type": "function" 387 | }, 388 | { 389 | "constant": false, 390 | "inputs": [ 391 | { 392 | "name": "completed", 393 | "type": "uint256" 394 | } 395 | ], 396 | "name": "setCompleted", 397 | "outputs": [], 398 | "type": "function" 399 | }, 400 | { 401 | "inputs": [], 402 | "type": "constructor" 403 | } 404 | ], 405 | "unlinked_binary": "0x606060405260008054600160a060020a03191633179055610130806100246000396000f3606060405260e060020a60003504630900f010811461003c578063445df0ac146100c05780638da5cb5b146100c9578063fdacd576146100db575b005b61003a60043560008054600160a060020a039081163390911614156100bc57604080516001547ffdacd576000000000000000000000000000000000000000000000000000000008252600482015290518392600160a060020a0384169263fdacd5769260248281019392829003018183876161da5a03f115610002575050505b5050565b61010160015481565b610113600054600160a060020a031681565b61003a60043560005433600160a060020a03908116911614156100fe5760018190555b50565b60408051918252519081900360200190f35b60408051600160a060020a03929092168252519081900360200190f3", 406 | "events": {}, 407 | "updated_at": 1473288757560, 408 | "address": "0x13cedc9b746ece8031b5f4066eaf34adda5c104b", 409 | "links": {} 410 | }, 411 | "default": { 412 | "abi": [ 413 | { 414 | "constant": false, 415 | "inputs": [ 416 | { 417 | "name": "new_address", 418 | "type": "address" 419 | } 420 | ], 421 | "name": "upgrade", 422 | "outputs": [], 423 | "type": "function" 424 | }, 425 | { 426 | "constant": true, 427 | "inputs": [], 428 | "name": "last_completed_migration", 429 | "outputs": [ 430 | { 431 | "name": "", 432 | "type": "uint256" 433 | } 434 | ], 435 | "type": "function" 436 | }, 437 | { 438 | "constant": true, 439 | "inputs": [], 440 | "name": "owner", 441 | "outputs": [ 442 | { 443 | "name": "", 444 | "type": "address" 445 | } 446 | ], 447 | "type": "function" 448 | }, 449 | { 450 | "constant": false, 451 | "inputs": [ 452 | { 453 | "name": "completed", 454 | "type": "uint256" 455 | } 456 | ], 457 | "name": "setCompleted", 458 | "outputs": [], 459 | "type": "function" 460 | }, 461 | { 462 | "inputs": [], 463 | "type": "constructor" 464 | } 465 | ], 466 | "unlinked_binary": "0x606060405260008054600160a060020a03191633179055610130806100246000396000f3606060405260e060020a60003504630900f010811461003c578063445df0ac146100c05780638da5cb5b146100c9578063fdacd576146100db575b005b61003a60043560008054600160a060020a039081163390911614156100bc57604080516001547ffdacd576000000000000000000000000000000000000000000000000000000008252600482015290518392600160a060020a0384169263fdacd5769260248281019392829003018183876161da5a03f115610002575050505b5050565b61010160015481565b610113600054600160a060020a031681565b61003a60043560005433600160a060020a03908116911614156100fe5760018190555b50565b60408051918252519081900360200190f35b60408051600160a060020a03929092168252519081900360200190f3", 467 | "events": {}, 468 | "updated_at": 1473286321140, 469 | "address": "0xbeadef152c07e2352f9539e9261e96e7392c0952", 470 | "links": {} 471 | } 472 | }; 473 | 474 | Contract.checkNetwork = function(callback) { 475 | var self = this; 476 | 477 | if (this.network_id != null) { 478 | return callback(); 479 | } 480 | 481 | this.web3.version.network(function(err, result) { 482 | if (err) return callback(err); 483 | 484 | var network_id = result.toString(); 485 | 486 | // If we have the main network, 487 | if (network_id == "1") { 488 | var possible_ids = ["1", "live", "default"]; 489 | 490 | for (var i = 0; i < possible_ids.length; i++) { 491 | var id = possible_ids[i]; 492 | if (Contract.all_networks[id] != null) { 493 | network_id = id; 494 | break; 495 | } 496 | } 497 | } 498 | 499 | if (self.all_networks[network_id] == null) { 500 | return callback(new Error(self.name + " error: Can't find artifacts for network id '" + network_id + "'")); 501 | } 502 | 503 | self.setNetwork(network_id); 504 | callback(); 505 | }) 506 | }; 507 | 508 | Contract.setNetwork = function(network_id) { 509 | var network = this.all_networks[network_id] || {}; 510 | 511 | this.abi = this.prototype.abi = network.abi; 512 | this.unlinked_binary = this.prototype.unlinked_binary = network.unlinked_binary; 513 | this.address = this.prototype.address = network.address; 514 | this.updated_at = this.prototype.updated_at = network.updated_at; 515 | this.links = this.prototype.links = network.links || {}; 516 | this.events = this.prototype.events = network.events || {}; 517 | 518 | this.network_id = network_id; 519 | }; 520 | 521 | Contract.networks = function() { 522 | return Object.keys(this.all_networks); 523 | }; 524 | 525 | Contract.link = function(name, address) { 526 | if (typeof name == "function") { 527 | var contract = name; 528 | 529 | if (contract.address == null) { 530 | throw new Error("Cannot link contract without an address."); 531 | } 532 | 533 | Contract.link(contract.contract_name, contract.address); 534 | 535 | // Merge events so this contract knows about library's events 536 | Object.keys(contract.events).forEach(function(topic) { 537 | Contract.events[topic] = contract.events[topic]; 538 | }); 539 | 540 | return; 541 | } 542 | 543 | if (typeof name == "object") { 544 | var obj = name; 545 | Object.keys(obj).forEach(function(name) { 546 | var a = obj[name]; 547 | Contract.link(name, a); 548 | }); 549 | return; 550 | } 551 | 552 | Contract.links[name] = address; 553 | }; 554 | 555 | Contract.contract_name = Contract.prototype.contract_name = "Migrations"; 556 | Contract.generated_with = Contract.prototype.generated_with = "3.2.0"; 557 | 558 | // Allow people to opt-in to breaking changes now. 559 | Contract.next_gen = false; 560 | 561 | var properties = { 562 | binary: function() { 563 | var binary = Contract.unlinked_binary; 564 | 565 | Object.keys(Contract.links).forEach(function(library_name) { 566 | var library_address = Contract.links[library_name]; 567 | var regex = new RegExp("__" + library_name + "_*", "g"); 568 | 569 | binary = binary.replace(regex, library_address.replace("0x", "")); 570 | }); 571 | 572 | return binary; 573 | } 574 | }; 575 | 576 | Object.keys(properties).forEach(function(key) { 577 | var getter = properties[key]; 578 | 579 | var definition = {}; 580 | definition.enumerable = true; 581 | definition.configurable = false; 582 | definition.get = getter; 583 | 584 | Object.defineProperty(Contract, key, definition); 585 | Object.defineProperty(Contract.prototype, key, definition); 586 | }); 587 | 588 | bootstrap(Contract); 589 | 590 | if (typeof module != "undefined" && typeof module.exports != "undefined") { 591 | module.exports = Contract; 592 | } else { 593 | // There will only be one version of this contract in the browser, 594 | // and we can use that. 595 | window.Migrations = Contract; 596 | } 597 | })(); 598 | -------------------------------------------------------------------------------- /build/contracts/SimpleNameRegistry.sol.js: -------------------------------------------------------------------------------- 1 | var Web3 = require("web3"); 2 | var SolidityEvent = require("web3/lib/web3/event.js"); 3 | 4 | (function() { 5 | // Planned for future features, logging, etc. 6 | function Provider(provider) { 7 | this.provider = provider; 8 | } 9 | 10 | Provider.prototype.send = function() { 11 | this.provider.send.apply(this.provider, arguments); 12 | }; 13 | 14 | Provider.prototype.sendAsync = function() { 15 | this.provider.sendAsync.apply(this.provider, arguments); 16 | }; 17 | 18 | var BigNumber = (new Web3()).toBigNumber(0).constructor; 19 | 20 | var Utils = { 21 | is_object: function(val) { 22 | return typeof val == "object" && !Array.isArray(val); 23 | }, 24 | is_big_number: function(val) { 25 | if (typeof val != "object") return false; 26 | 27 | // Instanceof won't work because we have multiple versions of Web3. 28 | try { 29 | new BigNumber(val); 30 | return true; 31 | } catch (e) { 32 | return false; 33 | } 34 | }, 35 | merge: function() { 36 | var merged = {}; 37 | var args = Array.prototype.slice.call(arguments); 38 | 39 | for (var i = 0; i < args.length; i++) { 40 | var object = args[i]; 41 | var keys = Object.keys(object); 42 | for (var j = 0; j < keys.length; j++) { 43 | var key = keys[j]; 44 | var value = object[key]; 45 | merged[key] = value; 46 | } 47 | } 48 | 49 | return merged; 50 | }, 51 | promisifyFunction: function(fn, C) { 52 | var self = this; 53 | return function() { 54 | var instance = this; 55 | 56 | var args = Array.prototype.slice.call(arguments); 57 | var tx_params = {}; 58 | var last_arg = args[args.length - 1]; 59 | 60 | // It's only tx_params if it's an object and not a BigNumber. 61 | if (Utils.is_object(last_arg) && !Utils.is_big_number(last_arg)) { 62 | tx_params = args.pop(); 63 | } 64 | 65 | tx_params = Utils.merge(C.class_defaults, tx_params); 66 | 67 | return new Promise(function(accept, reject) { 68 | var callback = function(error, result) { 69 | if (error != null) { 70 | reject(error); 71 | } else { 72 | accept(result); 73 | } 74 | }; 75 | args.push(tx_params, callback); 76 | fn.apply(instance.contract, args); 77 | }); 78 | }; 79 | }, 80 | synchronizeFunction: function(fn, instance, C) { 81 | var self = this; 82 | return function() { 83 | var args = Array.prototype.slice.call(arguments); 84 | var tx_params = {}; 85 | var last_arg = args[args.length - 1]; 86 | 87 | // It's only tx_params if it's an object and not a BigNumber. 88 | if (Utils.is_object(last_arg) && !Utils.is_big_number(last_arg)) { 89 | tx_params = args.pop(); 90 | } 91 | 92 | tx_params = Utils.merge(C.class_defaults, tx_params); 93 | 94 | return new Promise(function(accept, reject) { 95 | 96 | var decodeLogs = function(logs) { 97 | return logs.map(function(log) { 98 | var logABI = C.events[log.topics[0]]; 99 | 100 | if (logABI == null) { 101 | return null; 102 | } 103 | 104 | var decoder = new SolidityEvent(null, logABI, instance.address); 105 | return decoder.decode(log); 106 | }).filter(function(log) { 107 | return log != null; 108 | }); 109 | }; 110 | 111 | var callback = function(error, tx) { 112 | if (error != null) { 113 | reject(error); 114 | return; 115 | } 116 | 117 | var timeout = C.synchronization_timeout || 240000; 118 | var start = new Date().getTime(); 119 | 120 | var make_attempt = function() { 121 | C.web3.eth.getTransactionReceipt(tx, function(err, receipt) { 122 | if (err) return reject(err); 123 | 124 | if (receipt != null) { 125 | // If they've opted into next gen, return more information. 126 | if (C.next_gen == true) { 127 | return accept({ 128 | tx: tx, 129 | receipt: receipt, 130 | logs: decodeLogs(receipt.logs) 131 | }); 132 | } else { 133 | return accept(tx); 134 | } 135 | } 136 | 137 | if (timeout > 0 && new Date().getTime() - start > timeout) { 138 | return reject(new Error("Transaction " + tx + " wasn't processed in " + (timeout / 1000) + " seconds!")); 139 | } 140 | 141 | setTimeout(make_attempt, 1000); 142 | }); 143 | }; 144 | 145 | make_attempt(); 146 | }; 147 | 148 | args.push(tx_params, callback); 149 | fn.apply(self, args); 150 | }); 151 | }; 152 | } 153 | }; 154 | 155 | function instantiate(instance, contract) { 156 | instance.contract = contract; 157 | var constructor = instance.constructor; 158 | 159 | // Provision our functions. 160 | for (var i = 0; i < instance.abi.length; i++) { 161 | var item = instance.abi[i]; 162 | if (item.type == "function") { 163 | if (item.constant == true) { 164 | instance[item.name] = Utils.promisifyFunction(contract[item.name], constructor); 165 | } else { 166 | instance[item.name] = Utils.synchronizeFunction(contract[item.name], instance, constructor); 167 | } 168 | 169 | instance[item.name].call = Utils.promisifyFunction(contract[item.name].call, constructor); 170 | instance[item.name].sendTransaction = Utils.promisifyFunction(contract[item.name].sendTransaction, constructor); 171 | instance[item.name].request = contract[item.name].request; 172 | instance[item.name].estimateGas = Utils.promisifyFunction(contract[item.name].estimateGas, constructor); 173 | } 174 | 175 | if (item.type == "event") { 176 | instance[item.name] = contract[item.name]; 177 | } 178 | } 179 | 180 | instance.allEvents = contract.allEvents; 181 | instance.address = contract.address; 182 | instance.transactionHash = contract.transactionHash; 183 | }; 184 | 185 | // Use inheritance to create a clone of this contract, 186 | // and copy over contract's static functions. 187 | function mutate(fn) { 188 | var temp = function Clone() { return fn.apply(this, arguments); }; 189 | 190 | Object.keys(fn).forEach(function(key) { 191 | temp[key] = fn[key]; 192 | }); 193 | 194 | temp.prototype = Object.create(fn.prototype); 195 | bootstrap(temp); 196 | return temp; 197 | }; 198 | 199 | function bootstrap(fn) { 200 | fn.web3 = new Web3(); 201 | fn.class_defaults = fn.prototype.defaults || {}; 202 | 203 | // Set the network iniitally to make default data available and re-use code. 204 | // Then remove the saved network id so the network will be auto-detected on first use. 205 | fn.setNetwork("default"); 206 | fn.network_id = null; 207 | return fn; 208 | }; 209 | 210 | // Accepts a contract object created with web3.eth.contract. 211 | // Optionally, if called without `new`, accepts a network_id and will 212 | // create a new version of the contract abstraction with that network_id set. 213 | function Contract() { 214 | if (this instanceof Contract) { 215 | instantiate(this, arguments[0]); 216 | } else { 217 | var C = mutate(Contract); 218 | var network_id = arguments.length > 0 ? arguments[0] : "default"; 219 | C.setNetwork(network_id); 220 | return C; 221 | } 222 | }; 223 | 224 | Contract.currentProvider = null; 225 | 226 | Contract.setProvider = function(provider) { 227 | var wrapped = new Provider(provider); 228 | this.web3.setProvider(wrapped); 229 | this.currentProvider = provider; 230 | }; 231 | 232 | Contract.new = function() { 233 | if (this.currentProvider == null) { 234 | throw new Error("SimpleNameRegistry error: Please call setProvider() first before calling new()."); 235 | } 236 | 237 | var args = Array.prototype.slice.call(arguments); 238 | 239 | if (!this.unlinked_binary) { 240 | throw new Error("SimpleNameRegistry error: contract binary not set. Can't deploy new instance."); 241 | } 242 | 243 | var regex = /__[^_]+_+/g; 244 | var unlinked_libraries = this.binary.match(regex); 245 | 246 | if (unlinked_libraries != null) { 247 | unlinked_libraries = unlinked_libraries.map(function(name) { 248 | // Remove underscores 249 | return name.replace(/_/g, ""); 250 | }).sort().filter(function(name, index, arr) { 251 | // Remove duplicates 252 | if (index + 1 >= arr.length) { 253 | return true; 254 | } 255 | 256 | return name != arr[index + 1]; 257 | }).join(", "); 258 | 259 | throw new Error("SimpleNameRegistry contains unresolved libraries. You must deploy and link the following libraries before you can deploy a new version of SimpleNameRegistry: " + unlinked_libraries); 260 | } 261 | 262 | var self = this; 263 | 264 | return new Promise(function(accept, reject) { 265 | var contract_class = self.web3.eth.contract(self.abi); 266 | var tx_params = {}; 267 | var last_arg = args[args.length - 1]; 268 | 269 | // It's only tx_params if it's an object and not a BigNumber. 270 | if (Utils.is_object(last_arg) && !Utils.is_big_number(last_arg)) { 271 | tx_params = args.pop(); 272 | } 273 | 274 | tx_params = Utils.merge(self.class_defaults, tx_params); 275 | 276 | if (tx_params.data == null) { 277 | tx_params.data = self.binary; 278 | } 279 | 280 | // web3 0.9.0 and above calls new twice this callback twice. 281 | // Why, I have no idea... 282 | var intermediary = function(err, web3_instance) { 283 | if (err != null) { 284 | reject(err); 285 | return; 286 | } 287 | 288 | if (err == null && web3_instance != null && web3_instance.address != null) { 289 | accept(new self(web3_instance)); 290 | } 291 | }; 292 | 293 | args.push(tx_params, intermediary); 294 | contract_class.new.apply(contract_class, args); 295 | }); 296 | }; 297 | 298 | Contract.at = function(address) { 299 | if (address == null || typeof address != "string" || address.length != 42) { 300 | throw new Error("Invalid address passed to SimpleNameRegistry.at(): " + address); 301 | } 302 | 303 | var contract_class = this.web3.eth.contract(this.abi); 304 | var contract = contract_class.at(address); 305 | 306 | return new this(contract); 307 | }; 308 | 309 | Contract.deployed = function() { 310 | if (!this.address) { 311 | throw new Error("Cannot find deployed address: SimpleNameRegistry not deployed or address not set."); 312 | } 313 | 314 | return this.at(this.address); 315 | }; 316 | 317 | Contract.defaults = function(class_defaults) { 318 | if (this.class_defaults == null) { 319 | this.class_defaults = {}; 320 | } 321 | 322 | if (class_defaults == null) { 323 | class_defaults = {}; 324 | } 325 | 326 | var self = this; 327 | Object.keys(class_defaults).forEach(function(key) { 328 | var value = class_defaults[key]; 329 | self.class_defaults[key] = value; 330 | }); 331 | 332 | return this.class_defaults; 333 | }; 334 | 335 | Contract.extend = function() { 336 | var args = Array.prototype.slice.call(arguments); 337 | 338 | for (var i = 0; i < arguments.length; i++) { 339 | var object = arguments[i]; 340 | var keys = Object.keys(object); 341 | for (var j = 0; j < keys.length; j++) { 342 | var key = keys[j]; 343 | var value = object[key]; 344 | this.prototype[key] = value; 345 | } 346 | } 347 | }; 348 | 349 | Contract.all_networks = { 350 | "2": { 351 | "abi": [ 352 | { 353 | "constant": true, 354 | "inputs": [ 355 | { 356 | "name": "", 357 | "type": "bytes32" 358 | } 359 | ], 360 | "name": "names", 361 | "outputs": [ 362 | { 363 | "name": "", 364 | "type": "address" 365 | } 366 | ], 367 | "type": "function" 368 | }, 369 | { 370 | "constant": false, 371 | "inputs": [ 372 | { 373 | "name": "name", 374 | "type": "bytes32" 375 | }, 376 | { 377 | "name": "addr", 378 | "type": "address" 379 | } 380 | ], 381 | "name": "register", 382 | "outputs": [], 383 | "type": "function" 384 | }, 385 | { 386 | "inputs": [], 387 | "type": "constructor" 388 | } 389 | ], 390 | "unlinked_binary": "0x60606040527f646f6e617465000000000000000000000000000000000000000000000000000060009081526020527fc725da53770b15d4bbf7cbd8dbf8474581242173379045f6d4cc668f4d71b90c8054600160a060020a0319163317905560b88061006b6000396000f3606060405260e060020a600035046320c38e2b81146024578063d22057a9146044575b005b609b600435600060208190529081526040902054600160a060020a031681565b6022600435602435600082815260208190526040812054600160a060020a0316141560975760406000908120838252602091909152805473ffffffffffffffffffffffffffffffffffffffff1916821790555b5050565b60408051600160a060020a03929092168252519081900360200190f3", 391 | "events": {}, 392 | "updated_at": 1473288757564, 393 | "links": {}, 394 | "address": "0x284bdb561b5d8983f91d63264f40ab97c272dc7b" 395 | }, 396 | "default": { 397 | "abi": [ 398 | { 399 | "constant": true, 400 | "inputs": [ 401 | { 402 | "name": "", 403 | "type": "bytes32" 404 | } 405 | ], 406 | "name": "names", 407 | "outputs": [ 408 | { 409 | "name": "", 410 | "type": "address" 411 | } 412 | ], 413 | "type": "function" 414 | }, 415 | { 416 | "constant": false, 417 | "inputs": [ 418 | { 419 | "name": "name", 420 | "type": "bytes32" 421 | }, 422 | { 423 | "name": "addr", 424 | "type": "address" 425 | } 426 | ], 427 | "name": "register", 428 | "outputs": [], 429 | "type": "function" 430 | }, 431 | { 432 | "inputs": [], 433 | "type": "constructor" 434 | } 435 | ], 436 | "unlinked_binary": "0x60606040527f646f6e617465000000000000000000000000000000000000000000000000000060009081526020527fc725da53770b15d4bbf7cbd8dbf8474581242173379045f6d4cc668f4d71b90c8054600160a060020a0319163317905560b88061006b6000396000f3606060405260e060020a600035046320c38e2b81146024578063d22057a9146044575b005b609b600435600060208190529081526040902054600160a060020a031681565b6022600435602435600082815260208190526040812054600160a060020a0316141560975760406000908120838252602091909152805473ffffffffffffffffffffffffffffffffffffffff1916821790555b5050565b60408051600160a060020a03929092168252519081900360200190f3", 437 | "events": {}, 438 | "updated_at": 1473286321143, 439 | "links": {}, 440 | "address": "0xa7dc0333bae5d57bf64cf8558df23c74d6944d4e" 441 | } 442 | }; 443 | 444 | Contract.checkNetwork = function(callback) { 445 | var self = this; 446 | 447 | if (this.network_id != null) { 448 | return callback(); 449 | } 450 | 451 | this.web3.version.network(function(err, result) { 452 | if (err) return callback(err); 453 | 454 | var network_id = result.toString(); 455 | 456 | // If we have the main network, 457 | if (network_id == "1") { 458 | var possible_ids = ["1", "live", "default"]; 459 | 460 | for (var i = 0; i < possible_ids.length; i++) { 461 | var id = possible_ids[i]; 462 | if (Contract.all_networks[id] != null) { 463 | network_id = id; 464 | break; 465 | } 466 | } 467 | } 468 | 469 | if (self.all_networks[network_id] == null) { 470 | return callback(new Error(self.name + " error: Can't find artifacts for network id '" + network_id + "'")); 471 | } 472 | 473 | self.setNetwork(network_id); 474 | callback(); 475 | }) 476 | }; 477 | 478 | Contract.setNetwork = function(network_id) { 479 | var network = this.all_networks[network_id] || {}; 480 | 481 | this.abi = this.prototype.abi = network.abi; 482 | this.unlinked_binary = this.prototype.unlinked_binary = network.unlinked_binary; 483 | this.address = this.prototype.address = network.address; 484 | this.updated_at = this.prototype.updated_at = network.updated_at; 485 | this.links = this.prototype.links = network.links || {}; 486 | this.events = this.prototype.events = network.events || {}; 487 | 488 | this.network_id = network_id; 489 | }; 490 | 491 | Contract.networks = function() { 492 | return Object.keys(this.all_networks); 493 | }; 494 | 495 | Contract.link = function(name, address) { 496 | if (typeof name == "function") { 497 | var contract = name; 498 | 499 | if (contract.address == null) { 500 | throw new Error("Cannot link contract without an address."); 501 | } 502 | 503 | Contract.link(contract.contract_name, contract.address); 504 | 505 | // Merge events so this contract knows about library's events 506 | Object.keys(contract.events).forEach(function(topic) { 507 | Contract.events[topic] = contract.events[topic]; 508 | }); 509 | 510 | return; 511 | } 512 | 513 | if (typeof name == "object") { 514 | var obj = name; 515 | Object.keys(obj).forEach(function(name) { 516 | var a = obj[name]; 517 | Contract.link(name, a); 518 | }); 519 | return; 520 | } 521 | 522 | Contract.links[name] = address; 523 | }; 524 | 525 | Contract.contract_name = Contract.prototype.contract_name = "SimpleNameRegistry"; 526 | Contract.generated_with = Contract.prototype.generated_with = "3.2.0"; 527 | 528 | // Allow people to opt-in to breaking changes now. 529 | Contract.next_gen = false; 530 | 531 | var properties = { 532 | binary: function() { 533 | var binary = Contract.unlinked_binary; 534 | 535 | Object.keys(Contract.links).forEach(function(library_name) { 536 | var library_address = Contract.links[library_name]; 537 | var regex = new RegExp("__" + library_name + "_*", "g"); 538 | 539 | binary = binary.replace(regex, library_address.replace("0x", "")); 540 | }); 541 | 542 | return binary; 543 | } 544 | }; 545 | 546 | Object.keys(properties).forEach(function(key) { 547 | var getter = properties[key]; 548 | 549 | var definition = {}; 550 | definition.enumerable = true; 551 | definition.configurable = false; 552 | definition.get = getter; 553 | 554 | Object.defineProperty(Contract, key, definition); 555 | Object.defineProperty(Contract.prototype, key, definition); 556 | }); 557 | 558 | bootstrap(Contract); 559 | 560 | if (typeof module != "undefined" && typeof module.exports != "undefined") { 561 | module.exports = Contract; 562 | } else { 563 | // There will only be one version of this contract in the browser, 564 | // and we can use that. 565 | window.SimpleNameRegistry = Contract; 566 | } 567 | })(); 568 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | contract Migrations { 2 | address public owner; 3 | uint public last_completed_migration; 4 | 5 | modifier restricted() { 6 | if (msg.sender == owner) _ 7 | } 8 | 9 | function Migrations() { 10 | owner = msg.sender; 11 | } 12 | 13 | function setCompleted(uint completed) restricted { 14 | last_completed_migration = completed; 15 | } 16 | 17 | function upgrade(address new_address) restricted { 18 | Migrations upgraded = Migrations(new_address); 19 | upgraded.setCompleted(last_completed_migration); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /contracts/SimpleNameRegistry.sol: -------------------------------------------------------------------------------- 1 | contract SimpleNameRegistry { 2 | mapping (bytes32 => address) public names; 3 | 4 | function SimpleNameRegistry() { 5 | names["donate"] = msg.sender; 6 | } 7 | 8 | function register(bytes32 name, address addr) { 9 | if (names[name] == 0) { 10 | names[name] = addr; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /deploy_mnemonic.key: -------------------------------------------------------------------------------- 1 | REPLACE WITH YOUR OWN 12 WORD MNEMONIC 2 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // This simple library abstracts out all of Ethereum, using 2 | // Infura to get network data, making this very accessible 3 | // to other JS projects. 4 | 5 | var SimpleNameRegistry = require("./build/contracts/SimpleNameRegistry.sol.js"); 6 | 7 | var Web3 = require("web3"); 8 | var provider = new Web3.providers.HttpProvider("https://morden.infura.io:8545/") 9 | var web3 = new Web3(provider); 10 | 11 | SimpleNameRegistry.setProvider(provider); 12 | SimpleNameRegistry.setNetwork(2); // Enforce morden 13 | 14 | module.exports = { 15 | get: function(name, callback) { 16 | SimpleNameRegistry.deployed().names.call(name).then(function(address) { 17 | callback(null, address); 18 | }).catch(callback); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | module.exports = function(deployer) { 2 | deployer.deploy(Migrations); 3 | }; 4 | -------------------------------------------------------------------------------- /migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | module.exports = function(deployer) { 2 | deployer.deploy(SimpleNameRegistry); 3 | }; 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example-truffle-library", 3 | "version": "1.0.0", 4 | "description": "Example project showing how to use Truffle to build libraries", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Tim Coulter (http://timothyjcoulter.com)", 10 | "license": "MIT", 11 | "dependencies": { 12 | "web3": "^0.16.0" 13 | }, 14 | "devDependencies": { 15 | "bip39": "^2.2.0", 16 | "ethereumjs-wallet": "^0.6.0", 17 | "web3-provider-engine": "^8.0.4" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/interface.js: -------------------------------------------------------------------------------- 1 | var SimpleNameRegistry = require("../build/contracts/SimpleNameRegistry.sol.js"); 2 | 3 | var NameReg = require("../index"); 4 | 5 | // Note: This uses describe(), instead of contract(), which means this is 6 | // a normal javascript test and doesn't have the state provided by contract(). 7 | describe("library interface", function() { 8 | it("should have a donation address", function(done) { 9 | NameReg.get("donate", function(err, address) { 10 | assert.equal(address, "0xc3d2a1629d3990d8b9d9799c8675ec18c6f00247"); 11 | done(); 12 | }) 13 | }) 14 | }); 15 | -------------------------------------------------------------------------------- /test/simplenameregistry.js: -------------------------------------------------------------------------------- 1 | contract('SimpleNameRegistry', function(accounts) { 2 | it("should set the donate address as the first name", function() { 3 | var namereg = SimpleNameRegistry.deployed(); 4 | 5 | return namereg.names.call("donate").then(function(addr) { 6 | assert.equal(addr, accounts[0]); 7 | }); 8 | }); 9 | 10 | it("registers new names", function() { 11 | var namereg = SimpleNameRegistry.deployed(); 12 | 13 | return namereg.register("newname", "0x1234567890123456789012345678901234567890").then(function() { 14 | return namereg.names.call("newname"); 15 | }).then(function(addr) { 16 | assert.equal(addr, "0x1234567890123456789012345678901234567890"); 17 | }); 18 | }); 19 | 20 | it("won't override pre-registered names", function() { 21 | var namereg = SimpleNameRegistry.deployed(); 22 | 23 | return namereg.register("newname", "0x1111111111111111111111111111111111111111").then(function() { 24 | return namereg.names.call("newname"); 25 | }).then(function(addr) { 26 | assert.equal(addr, "0x1234567890123456789012345678901234567890"); 27 | }); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /truffle.js: -------------------------------------------------------------------------------- 1 | // This is a bit unruly, and needs to be put in its own package. 2 | // But all this preamble tells Truffle how to sign transactions on 3 | // its own from a bip39 mnemonic (which creates addresses and private keys). 4 | // This allows Truffle deployment to work with infura. Note we do 5 | // this specifically when deploying to the morden network. 6 | 7 | var hdkey = require('ethereumjs-wallet/hdkey'); 8 | var bip39 = require("bip39"); 9 | var ProviderEngine = require("web3-provider-engine"); 10 | var WalletSubprovider = require('web3-provider-engine/subproviders/wallet.js'); 11 | var Web3Subprovider = require("web3-provider-engine/subproviders/web3.js"); 12 | var Web3 = require("web3"); 13 | var fs = require("fs"); 14 | var path = require("path") 15 | 16 | // Read the mnemonic from a file that's not committed to github, for security. 17 | var mnemonic = fs.readFileSync(path.join(__dirname, "deploy_mnemonic.key"), {encoding: "utf8"}).trim(); 18 | 19 | var wallet_hdpath = "m/44'/60'/0'/0/"; 20 | var hd = hdkey.fromMasterSeed(bip39.mnemonicToSeed(mnemonic)); 21 | 22 | // Get the first account 23 | var account = hd.derivePath(wallet_hdpath + "0") 24 | var wallet = account.getWallet(); 25 | var address = "0x" + wallet.getAddress().toString("hex"); 26 | 27 | var providerUrl = "https://morden.infura.io:8545"; 28 | 29 | var engine = new ProviderEngine(); 30 | engine.addProvider(new WalletSubprovider(wallet, {})); 31 | engine.addProvider(new Web3Subprovider(new Web3.providers.HttpProvider(providerUrl))); 32 | engine.start(engine); 33 | 34 | module.exports = { 35 | // Specifically for morden 36 | networks: { 37 | morden: { 38 | network_id: 2, 39 | provider: engine, 40 | from: address 41 | } 42 | }, 43 | // Default configuration 44 | rpc: { 45 | host: "localhost", 46 | port: 8545 47 | } 48 | }; 49 | --------------------------------------------------------------------------------