Merge pull request #642 from embark-framework/features/ens-register
ENS pre-register domains in development
This commit is contained in:
commit
2192347631
|
@ -183,7 +183,7 @@ class Blockchain {
|
|||
const self = this;
|
||||
|
||||
this.events.setCommandHandler("blockchain:defaultAccount:get", function(cb) {
|
||||
cb(self.defaultAccount);
|
||||
cb(self.defaultAccount());
|
||||
});
|
||||
|
||||
this.events.setCommandHandler("blockchain:defaultAccount:set", function(account, cb) {
|
||||
|
@ -199,6 +199,9 @@ class Blockchain {
|
|||
self.getGasPrice(cb);
|
||||
});
|
||||
|
||||
this.events.setCommandHandler("blockchain:contract:create", function(params, cb) {
|
||||
cb(self.ContractObject(params));
|
||||
});
|
||||
}
|
||||
|
||||
defaultAccount() {
|
||||
|
@ -226,7 +229,7 @@ class Blockchain {
|
|||
}
|
||||
|
||||
ContractObject(params) {
|
||||
return new this.web3.eth.Contract(params.abi);
|
||||
return new this.web3.eth.Contract(params.abi, params.address);
|
||||
}
|
||||
|
||||
deployContractObject(contractObject, params) {
|
||||
|
|
|
@ -282,10 +282,7 @@ Config.prototype.loadNameSystemConfigFile = function() {
|
|||
"default": {
|
||||
"available_providers": ["ens"],
|
||||
"provider": "ens",
|
||||
"enabled": true,
|
||||
"register": {
|
||||
"rootDomain": "embark"
|
||||
}
|
||||
"enabled": true
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@ contract ENSRegistry is ENS {
|
|||
mapping (bytes32 => Record) records;
|
||||
|
||||
// Permits modifications only by the owner of the specified node.
|
||||
modifier only_owner(bytes32 node) {
|
||||
require(records[node].owner == msg.sender);
|
||||
modifier only_owner(bytes32 node, address owner) {
|
||||
require(records[node].owner == 0 || records[node].owner == msg.sender || records[node].owner == owner);
|
||||
_;
|
||||
}
|
||||
|
||||
|
@ -32,19 +32,19 @@ contract ENSRegistry is ENS {
|
|||
* @param node The node to transfer ownership of.
|
||||
* @param owner The address of the new owner.
|
||||
*/
|
||||
function setOwner(bytes32 node, address owner) public only_owner(node) {
|
||||
function setOwner(bytes32 node, address owner) public only_owner(node, owner) {
|
||||
Transfer(node, owner);
|
||||
records[node].owner = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Transfers ownership of a subnode keccak256(node, label) to a new address. May only be called by the owner of the parent node.
|
||||
* @dev Transfers ownership of a subnode sha3(node, label) to a new address. May only be called by the owner of the parent node.
|
||||
* @param node The parent node.
|
||||
* @param label The hash of the label specifying the subnode.
|
||||
* @param owner The address of the new owner.
|
||||
*/
|
||||
function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public only_owner(node) {
|
||||
var subnode = keccak256(node, label);
|
||||
function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public only_owner(node, owner) {
|
||||
var subnode = sha3(node, label);
|
||||
NewOwner(node, label, owner);
|
||||
records[subnode].owner = owner;
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ contract ENSRegistry is ENS {
|
|||
* @param node The node to update.
|
||||
* @param resolver The address of the resolver.
|
||||
*/
|
||||
function setResolver(bytes32 node, address resolver) public only_owner(node) {
|
||||
function setResolver(bytes32 node, address resolver) public only_owner(node, 0x0) {
|
||||
NewResolver(node, resolver);
|
||||
records[node].resolver = resolver;
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ contract ENSRegistry is ENS {
|
|||
* @param node The node to update.
|
||||
* @param ttl The TTL in seconds.
|
||||
*/
|
||||
function setTTL(bytes32 node, uint64 ttl) public only_owner(node) {
|
||||
function setTTL(bytes32 node, uint64 ttl) public only_owner(node, 0x0) {
|
||||
NewTTL(node, ttl);
|
||||
records[node].ttl = ttl;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
pragma solidity ^0.4.18;
|
||||
|
||||
import './ENS.sol';
|
||||
import './Resolver.sol';
|
||||
|
||||
/**
|
||||
* A registrar that allocates subdomains to the first person to claim them.
|
||||
|
@ -10,7 +11,8 @@ contract FIFSRegistrar {
|
|||
bytes32 rootNode;
|
||||
|
||||
modifier only_owner(bytes32 subnode) {
|
||||
address currentOwner = ens.owner(keccak256(rootNode, subnode));
|
||||
bytes32 node = sha3(rootNode, subnode);
|
||||
address currentOwner = ens.owner(node);
|
||||
require(currentOwner == 0 || currentOwner == msg.sender);
|
||||
_;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
pragma solidity ^0.4.23;
|
||||
|
||||
import "./ENS.sol";
|
||||
|
||||
/**
|
||||
* A simple resolver anyone can use; only allows the owner of a node to set its
|
||||
* address.
|
||||
*/
|
||||
contract Resolver {
|
||||
event AddrChanged(bytes32 indexed node, address a);
|
||||
event ContentChanged(bytes32 indexed node, bytes32 hash);
|
||||
event NameChanged(bytes32 indexed node, string name);
|
||||
event ABIChanged(bytes32 indexed node, uint256 indexed contentType);
|
||||
event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y);
|
||||
event TextChanged(bytes32 indexed node, string indexedKey, string key);
|
||||
|
||||
struct PublicKey {
|
||||
bytes32 x;
|
||||
bytes32 y;
|
||||
}
|
||||
|
||||
struct Record {
|
||||
address addr;
|
||||
bytes32 content;
|
||||
string name;
|
||||
PublicKey pubkey;
|
||||
mapping(string=>string) text;
|
||||
mapping(uint256=>bytes) abis;
|
||||
}
|
||||
|
||||
ENS ens;
|
||||
|
||||
mapping (bytes32 => Record) records;
|
||||
|
||||
modifier only_owner(bytes32 node) {
|
||||
address currentOwner = ens.owner(node);
|
||||
require(currentOwner == 0 || currentOwner == msg.sender);
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param ensAddr The ENS registrar contract.
|
||||
*/
|
||||
constructor(ENS ensAddr) public {
|
||||
ens = ensAddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the address associated with an ENS node.
|
||||
* May only be called by the owner of that node in the ENS registry.
|
||||
* @param node The node to update.
|
||||
* @param addr The address to set.
|
||||
*/
|
||||
function setAddr(bytes32 node, address addr) public only_owner(node) {
|
||||
records[node].addr = addr;
|
||||
emit AddrChanged(node, addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the content hash associated with an ENS node.
|
||||
* May only be called by the owner of that node in the ENS registry.
|
||||
* Note that this resource type is not standardized, and will likely change
|
||||
* in future to a resource type based on multihash.
|
||||
* @param node The node to update.
|
||||
* @param hash The content hash to set
|
||||
*/
|
||||
function setContent(bytes32 node, bytes32 hash) public only_owner(node) {
|
||||
records[node].content = hash;
|
||||
emit ContentChanged(node, hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name associated with an ENS node, for reverse records.
|
||||
* May only be called by the owner of that node in the ENS registry.
|
||||
* @param node The node to update.
|
||||
* @param name The name to set.
|
||||
*/
|
||||
function setName(bytes32 node, string name) public only_owner(node) {
|
||||
records[node].name = name;
|
||||
emit NameChanged(node, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ABI associated with an ENS node.
|
||||
* Nodes may have one ABI of each content type. To remove an ABI, set it to
|
||||
* the empty string.
|
||||
* @param node The node to update.
|
||||
* @param contentType The content type of the ABI
|
||||
* @param data The ABI data.
|
||||
*/
|
||||
function setABI(bytes32 node, uint256 contentType, bytes data) public only_owner(node) {
|
||||
// Content types must be powers of 2
|
||||
require(((contentType - 1) & contentType) == 0);
|
||||
|
||||
records[node].abis[contentType] = data;
|
||||
emit ABIChanged(node, contentType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SECP256k1 public key associated with an ENS node.
|
||||
* @param node The ENS node to query
|
||||
* @param x the X coordinate of the curve point for the public key.
|
||||
* @param y the Y coordinate of the curve point for the public key.
|
||||
*/
|
||||
function setPubkey(bytes32 node, bytes32 x, bytes32 y) public only_owner(node) {
|
||||
records[node].pubkey = PublicKey(x, y);
|
||||
emit PubkeyChanged(node, x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the text data associated with an ENS node and key.
|
||||
* May only be called by the owner of that node in the ENS registry.
|
||||
* @param node The node to update.
|
||||
* @param key The key to set.
|
||||
* @param value The text data value to set.
|
||||
*/
|
||||
function setText(bytes32 node, string key, string value) public only_owner(node) {
|
||||
records[node].text[key] = value;
|
||||
emit TextChanged(node, key, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text data associated with an ENS node and key.
|
||||
* @param node The ENS node to query.
|
||||
* @param key The text data key to query.
|
||||
* @return The associated text data.
|
||||
*/
|
||||
function text(bytes32 node, string key) public view returns (string) {
|
||||
return records[node].text[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SECP256k1 public key associated with an ENS node.
|
||||
* Defined in EIP 619.
|
||||
* @param node The ENS node to query
|
||||
* @return x, y the X and Y coordinates of the curve point for the public key.
|
||||
*/
|
||||
function pubkey(bytes32 node) public view returns (bytes32 x, bytes32 y) {
|
||||
return (records[node].pubkey.x, records[node].pubkey.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ABI associated with an ENS node.
|
||||
* Defined in EIP205.
|
||||
* @param node The ENS node to query
|
||||
* @param contentTypes A bitwise OR of the ABI formats accepted by the caller.
|
||||
* @return contentType The content type of the return value
|
||||
* @return data The ABI data
|
||||
*/
|
||||
function ABI(bytes32 node, uint256 contentTypes) public view returns (uint256 contentType, bytes data) {
|
||||
Record storage record = records[node];
|
||||
for (contentType = 1; contentType <= contentTypes; contentType <<= 1) {
|
||||
if ((contentType & contentTypes) != 0 && record.abis[contentType].length > 0) {
|
||||
data = record.abis[contentType];
|
||||
return;
|
||||
}
|
||||
}
|
||||
contentType = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name associated with an ENS node, for reverse records.
|
||||
* Defined in EIP181.
|
||||
* @param node The ENS node to query.
|
||||
* @return The associated name.
|
||||
*/
|
||||
function name(bytes32 node) public view returns (string) {
|
||||
return records[node].name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content hash associated with an ENS node.
|
||||
* Note that this resource type is not standardized, and will likely change
|
||||
* in future to a resource type based on multihash.
|
||||
* @param node The ENS node to query.
|
||||
* @return The associated content hash.
|
||||
*/
|
||||
function content(bytes32 node) public view returns (bytes32) {
|
||||
return records[node].content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address associated with an ENS node.
|
||||
* @param node The ENS node to query.
|
||||
* @return The associated address.
|
||||
*/
|
||||
function addr(bytes32 node) public view returns (address) {
|
||||
return records[node].addr;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,4 @@
|
|||
/*global EmbarkJS, web3*/
|
||||
|
||||
import namehash from 'eth-ens-namehash';
|
||||
/*global EmbarkJS, web3, registerSubDomain, namehash*/
|
||||
|
||||
let __embarkENS = {};
|
||||
|
||||
|
@ -57,27 +55,6 @@ __embarkENS.resolverInterface = [
|
|||
],
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "node",
|
||||
"type": "bytes32"
|
||||
},
|
||||
{
|
||||
"name": "kind",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"name": "has",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
|
@ -157,6 +134,8 @@ __embarkENS.resolverInterface = [
|
|||
const providerNotSetError = 'ENS provider not set';
|
||||
const NoDecodeAddrError = 'Error: Couldn\'t decode address from ABI: 0x';
|
||||
const NoDecodeStringError = 'ERROR: The returned value is not a convertible string: 0x0';
|
||||
const reverseAddrSuffix = '.addr.reverse';
|
||||
const voidAddress = '0x0000000000000000000000000000000000000000';
|
||||
|
||||
__embarkENS.registryAddresses = {
|
||||
// Mainnet
|
||||
|
@ -170,23 +149,25 @@ __embarkENS.registryAddresses = {
|
|||
__embarkENS.setProvider = function (config) {
|
||||
const self = this;
|
||||
const ERROR_MESSAGE = 'ENS is not available in this chain';
|
||||
self.registration = config.registration;
|
||||
self.env = config.env;
|
||||
|
||||
EmbarkJS.onReady(() => {
|
||||
web3.eth.net.getId((err, id) => {
|
||||
if (err) {
|
||||
web3.eth.net.getId()
|
||||
.then((id) => {
|
||||
const registryAddress = self.registryAddresses[id] || config.registryAddress;
|
||||
self.isAvailable = true;
|
||||
self.ens = new EmbarkJS.Contract({abi: config.registryAbi, address: registryAddress});
|
||||
self.registrar = new EmbarkJS.Contract({abi: config.registrarAbi, address: config.registrarAddress});
|
||||
self.resolver = new EmbarkJS.Contract({abi: config.resolverAbi, address: config.resolverAddress});
|
||||
})
|
||||
.catch(err => {
|
||||
if (err.message.indexOf('Provider not set or invalid') > -1) {
|
||||
console.warn(ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
if (!self.registryAddresses[id]) {
|
||||
console.warn(ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
self.isAvailable = true;
|
||||
self.ens = new EmbarkJS.Contract({abi: config.abi, address: self.registryAddresses[id]});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -208,6 +189,9 @@ __embarkENS.resolve = function (name, callback) {
|
|||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
if (resolverAddress === voidAddress) {
|
||||
return cb('Name not yet registered');
|
||||
}
|
||||
let resolverContract = new EmbarkJS.Contract({abi: this.resolverInterface, address: resolverAddress});
|
||||
resolverContract.methods.addr(node).call(cb);
|
||||
});
|
||||
|
@ -221,7 +205,7 @@ __embarkENS.lookup = function (address, callback) {
|
|||
if (address.startsWith("0x")) {
|
||||
address = address.slice(2);
|
||||
}
|
||||
let node = namehash.hash(address.toLowerCase() + ".addr.reverse");
|
||||
let node = web3.utils.soliditySha3(address.toLowerCase() + reverseAddrSuffix);
|
||||
|
||||
function cb(err, name) {
|
||||
if (err === NoDecodeStringError || err === NoDecodeAddrError) {
|
||||
|
@ -234,11 +218,32 @@ __embarkENS.lookup = function (address, callback) {
|
|||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
if (resolverAddress === voidAddress) {
|
||||
return cb('Address not associated to a resolver');
|
||||
}
|
||||
let resolverContract = new EmbarkJS.Contract({abi: this.resolverInterface, address: resolverAddress});
|
||||
resolverContract.methods.name(node).call(cb);
|
||||
});
|
||||
};
|
||||
|
||||
__embarkENS.registerSubDomain = function (name, address, callback) {
|
||||
callback = callback || function () {};
|
||||
|
||||
if (this.env !== 'development') {
|
||||
return callback('Sub-domain registration is only available in development mode');
|
||||
}
|
||||
if (!this.registration || !this.registration.rootDomain) {
|
||||
return callback('No rootDomain is declared in config/namesystem.js (register.rootDomain). Unable to register a subdomain until then.');
|
||||
}
|
||||
if (!address || !web3.utils.isAddress(address)) {
|
||||
return callback('You need to specify a valid address for the subdomain');
|
||||
}
|
||||
|
||||
// Register function generated by the index
|
||||
registerSubDomain(this.ens, this.registrar, this.resolver, web3.eth.defaultAccount, name, this.registration.rootDomain,
|
||||
web3.utils.soliditySha3(address.toLowerCase().substr(2) + reverseAddrSuffix), address, console, callback);
|
||||
};
|
||||
|
||||
__embarkENS.isAvailable = function () {
|
||||
return Boolean(this.isAvailable);
|
||||
};
|
||||
|
|
|
@ -1,28 +1,104 @@
|
|||
const fs = require('../../core/fs.js');
|
||||
const utils = require('../../utils/utils.js');
|
||||
const namehash = require('eth-ens-namehash');
|
||||
const async = require('async');
|
||||
|
||||
const reverseAddrSuffix = '.addr.reverse';
|
||||
|
||||
class ENS {
|
||||
constructor(embark, _options) {
|
||||
const self = this;
|
||||
this.env = embark.env;
|
||||
this.logger = embark.logger;
|
||||
this.events = embark.events;
|
||||
this.namesConfig = embark.config.namesystemConfig;
|
||||
this.registration = this.namesConfig.register;
|
||||
this.registration = this.namesConfig.register || {};
|
||||
this.embark = embark;
|
||||
|
||||
this.addENSToEmbarkJS();
|
||||
this.configureENSRegistry();
|
||||
this.configureRootRegistrar();
|
||||
this.configureContracts();
|
||||
this.registerEvents();
|
||||
}
|
||||
|
||||
self.embark.registerActionForEvent("contracts:deploy:afterAll", (cb) => {
|
||||
self.events.request('contracts:contract', "ENSRegistry", (contract) => {
|
||||
registerEvents() {
|
||||
const self = this;
|
||||
self.embark.registerActionForEvent("contracts:deploy:afterAll", (cb) => {
|
||||
async.parallel([
|
||||
function getENSRegistry(paraCb) {
|
||||
self.events.request('contracts:contract', "ENSRegistry", (contract) => {
|
||||
paraCb(null, contract);
|
||||
});
|
||||
},
|
||||
function getRegistrar(paraCb) {
|
||||
self.events.request('contracts:contract', "FIFSRegistrar", (contract) => {
|
||||
paraCb(null, contract);
|
||||
});
|
||||
},
|
||||
function getResolver(paraCb) {
|
||||
self.events.request('contracts:contract', "Resolver", (contract) => {
|
||||
paraCb(null, contract);
|
||||
});
|
||||
}
|
||||
], (err, results) => {
|
||||
// result[0] => ENSRegistry; result[1] => FIFSRegistrar; result[2] => FIFSRegistrar
|
||||
let config = {
|
||||
abi: contract.abiDefinition,
|
||||
address: contract.deployedAddress
|
||||
env: self.env,
|
||||
registration: self.registration,
|
||||
registryAbi: results[0].abiDefinition,
|
||||
registryAddress: results[0].deployedAddress,
|
||||
registrarAbi: results[1].abiDefinition,
|
||||
registrarAddress: results[1].deployedAddress,
|
||||
resolverAbi: results[2].abiDefinition,
|
||||
resolverAddress: results[2].deployedAddress
|
||||
};
|
||||
self.addSetProvider(config);
|
||||
cb();
|
||||
|
||||
if (!self.env === 'development' || !self.registration || !self.registration.subdomains || !Object.keys(self.registration.subdomains).length) {
|
||||
return cb();
|
||||
}
|
||||
self.registerConfigDomains(config, cb);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
registerConfigDomains(config, cb) {
|
||||
const self = this;
|
||||
const register = require('./register');
|
||||
self.events.request("blockchain:defaultAccount:get", (defaultAccount) => {
|
||||
async.parallel([
|
||||
function createRegistryContract(paraCb) {
|
||||
self.events.request("blockchain:contract:create",
|
||||
{abi: config.registryAbi, address: config.registryAddress},
|
||||
(registry) => {
|
||||
paraCb(null, registry);
|
||||
});
|
||||
},
|
||||
function createRegistrarContract(paraCb) {
|
||||
self.events.request("blockchain:contract:create",
|
||||
{abi: config.registrarAbi, address: config.registrarAddress},
|
||||
(registrar) => {
|
||||
paraCb(null, registrar);
|
||||
});
|
||||
},
|
||||
function createResolverContract(paraCb) {
|
||||
self.events.request("blockchain:contract:create",
|
||||
{abi: config.resolverAbi, address: config.resolverAddress},
|
||||
(resolver) => {
|
||||
paraCb(null, resolver);
|
||||
});
|
||||
}
|
||||
], function (err, contracts) {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
const [ens, registrar, resolver] = contracts;
|
||||
|
||||
async.each(Object.keys(self.registration.subdomains), (subDomainName, eachCb) => {
|
||||
const address = self.registration.subdomains[subDomainName];
|
||||
const reverseNode = utils.soliditySha3(address.toLowerCase().substr(2) + reverseAddrSuffix);
|
||||
register(ens, registrar, resolver, defaultAccount, subDomainName, self.registration.rootDomain,
|
||||
reverseNode, address, self.logger, eachCb);
|
||||
}, cb);
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -39,32 +115,39 @@ class ENS {
|
|||
}
|
||||
|
||||
// get namehash, import it into file
|
||||
self.events.request("version:get:eth-ens-namehash", function(EnsNamehashVersion) {
|
||||
self.events.request("version:get:eth-ens-namehash", function (EnsNamehashVersion) {
|
||||
let currentEnsNamehashVersion = require('../../../package.json').dependencies["eth-ens-namehash"];
|
||||
if (EnsNamehashVersion !== currentEnsNamehashVersion) {
|
||||
self.events.request("version:getPackageLocation", "eth-ens-namehash", EnsNamehashVersion, function(err, location) {
|
||||
self.events.request("version:getPackageLocation", "eth-ens-namehash", EnsNamehashVersion, function (err, location) {
|
||||
self.embark.registerImportFile("eth-ens-namehash", fs.dappPath(location));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let code = "";
|
||||
let code = fs.readFileSync(utils.joinPath(__dirname, 'register.js')).toString();
|
||||
code += "\n" + fs.readFileSync(utils.joinPath(__dirname, 'embarkjs.js')).toString();
|
||||
code += "\nEmbarkJS.Names.registerProvider('ens', __embarkENS);";
|
||||
|
||||
this.embark.addCodeToEmbarkJS(code);
|
||||
}
|
||||
|
||||
configureENSRegistry() {
|
||||
const self = this;
|
||||
|
||||
self.embark.registerContractConfiguration({
|
||||
configureContracts() {
|
||||
const config = {
|
||||
"default": {
|
||||
"gas": "auto",
|
||||
"gas": "auto"
|
||||
},
|
||||
"development": {
|
||||
"contracts": {
|
||||
"ENSRegistry": {
|
||||
"deploy": true,
|
||||
"args": []
|
||||
},
|
||||
"Resolver": {
|
||||
"deploy": true,
|
||||
"args": ["$ENSRegistry"]
|
||||
},
|
||||
"FIFSRegistrar": {
|
||||
"deploy": false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -72,6 +155,12 @@ class ENS {
|
|||
"contracts": {
|
||||
"ENSRegistry": {
|
||||
"address": "0x112234455c3a32fd11230c42e7bccd4a84e02010"
|
||||
},
|
||||
"Resolver": {
|
||||
"deploy": false
|
||||
},
|
||||
"FIFSRegistrar": {
|
||||
"deploy": false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -79,6 +168,12 @@ class ENS {
|
|||
"contracts": {
|
||||
"ENSRegistry": {
|
||||
"address": "0xe7410170f87102DF0055eB195163A03B7F2Bff4A"
|
||||
},
|
||||
"Resolver": {
|
||||
"deploy": false
|
||||
},
|
||||
"FIFSRegistrar": {
|
||||
"deploy": false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -86,51 +181,40 @@ class ENS {
|
|||
"contracts": {
|
||||
"ENSRegistry": {
|
||||
"address": "0x314159265dd8dbb310642f98f50c066173c1259b"
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
self.embark.events.request("config:contractsFiles:add", self.embark.pathToFile('./contracts/ENSRegistry.sol'));
|
||||
}
|
||||
|
||||
configureRootRegistrar() {
|
||||
const self = this;
|
||||
let rootNode = namehash.hash(self.registration.rootDomain);
|
||||
self.embark.registerContractConfiguration({
|
||||
"default": {
|
||||
"gas": "auto",
|
||||
"contracts": {
|
||||
"FIFSRegistrar": {
|
||||
"deploy": true,
|
||||
"args": ["$ENSRegistry", rootNode],
|
||||
"onDeploy": ["ENSRegistry.methods.setOwner(0, FIFSRegistrar.options.address).send()"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ropsten": {
|
||||
"contracts": {
|
||||
"FIFSRegistrar": {
|
||||
},
|
||||
"Resolver": {
|
||||
"deploy": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"rinkeby": {
|
||||
"contracts": {
|
||||
"FIFSRegistrar": {
|
||||
"deploy": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"livenet": {
|
||||
"contracts": {
|
||||
},
|
||||
"FIFSRegistrar": {
|
||||
"deploy": false
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
self.embark.events.request("config:contractsFiles:add", self.embark.pathToFile('./contracts/FIFSRegistrar.sol'));
|
||||
};
|
||||
|
||||
if (this.registration && this.registration.rootDomain) {
|
||||
// Register root domain if it is defined
|
||||
const rootNode = namehash.hash(this.registration.rootDomain);
|
||||
config.development.contracts['FIFSRegistrar'] = {
|
||||
"deploy": true,
|
||||
"args": ["$ENSRegistry", rootNode],
|
||||
"onDeploy": [
|
||||
`ENSRegistry.methods.setOwner('${rootNode}', web3.eth.defaultAccount).send().then(() => {
|
||||
ENSRegistry.methods.setResolver('${rootNode}', "$Resolver").send();
|
||||
var reverseNode = web3.utils.soliditySha3(web3.eth.defaultAccount.toLowerCase().substr(2) + '${reverseAddrSuffix}');
|
||||
ENSRegistry.methods.setResolver(reverseNode, "$Resolver").send();
|
||||
Resolver.methods.setAddr('${rootNode}', web3.eth.defaultAccount).send();
|
||||
Resolver.methods.setName(reverseNode, '${this.registration.rootDomain}').send();
|
||||
})`
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
this.embark.registerContractConfiguration(config);
|
||||
|
||||
this.embark.events.request("config:contractsFiles:add", this.embark.pathToFile('./contracts/ENSRegistry.sol'));
|
||||
this.embark.events.request("config:contractsFiles:add", this.embark.pathToFile('./contracts/FIFSRegistrar.sol'));
|
||||
this.embark.events.request("config:contractsFiles:add", this.embark.pathToFile('./contracts/Resolver.sol'));
|
||||
}
|
||||
|
||||
addSetProvider(config) {
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
const namehash = require('eth-ens-namehash');
|
||||
|
||||
function registerSubDomain(ens, registrar, resolver, defaultAccount, subdomain, rootDomain, reverseNode, address, logger, callback) {
|
||||
const subnode = namehash.hash(subdomain);
|
||||
const node = namehash.hash(`${subdomain}.${rootDomain}`);
|
||||
const toSend = registrar.methods.register(subnode, defaultAccount);
|
||||
let transaction;
|
||||
|
||||
toSend.estimateGas()
|
||||
// Register domain
|
||||
.then(gasEstimated => {
|
||||
return toSend.send({gas: gasEstimated + 1000, from: defaultAccount});
|
||||
})
|
||||
// Set resolver for the node
|
||||
.then(transac => {
|
||||
if (transac.status !== "0x1" && transac.status !== "0x01" && transac.status !== true) {
|
||||
logger.warn('Failed transaction', transac);
|
||||
return callback('Failed to register. Check gas cost.');
|
||||
}
|
||||
transaction = transac;
|
||||
return ens.methods.setResolver(node, resolver.options.address).send({from: defaultAccount});
|
||||
})
|
||||
// Set address for node
|
||||
.then(_result => {
|
||||
return resolver.methods.setAddr(node, address).send({from: defaultAccount});
|
||||
})
|
||||
// Set resolver for the reverse node
|
||||
.then(_result => {
|
||||
return ens.methods.setResolver(reverseNode, resolver.options.address).send({from: defaultAccount});
|
||||
})
|
||||
// Set name for reverse node
|
||||
.then(_result => {
|
||||
return resolver.methods.setName(reverseNode, subdomain + '.embark.eth').send({from: defaultAccount});
|
||||
})
|
||||
.then(_result => {
|
||||
callback(null, transaction);
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error(err);
|
||||
callback('Failed to register with error: ' + (err.message || err));
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = registerSubDomain;
|
||||
}
|
|
@ -268,6 +268,11 @@ function sha3(arg) {
|
|||
return Web3.utils.sha3(arg);
|
||||
}
|
||||
|
||||
function soliditySha3(arg) {
|
||||
const Web3 = require('web3');
|
||||
return Web3.utils.soliditySha3(arg);
|
||||
}
|
||||
|
||||
function normalizeInput(input) {
|
||||
let args = Object.values(input);
|
||||
if (args.length === 0) {
|
||||
|
@ -364,6 +369,7 @@ module.exports = {
|
|||
getExternalContractUrl,
|
||||
toChecksumAddress,
|
||||
sha3,
|
||||
soliditySha3,
|
||||
normalizeInput,
|
||||
buildUrl,
|
||||
buildUrlFromConfig,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -38,7 +38,7 @@
|
|||
"decompress": "^4.2.0",
|
||||
"deep-equal": "^1.0.1",
|
||||
"ejs": "^2.5.8",
|
||||
"embarkjs": "^0.2.0",
|
||||
"embarkjs": "^0.3.0",
|
||||
"eth-ens-namehash": "^2.0.8",
|
||||
"eth-lib": "^0.2.8",
|
||||
"ethereumjs-wallet": "^0.6.0",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*global web3*/
|
||||
import EmbarkJS from 'Embark/EmbarkJS';
|
||||
import React from 'react';
|
||||
import {Alert, Form, FormGroup, FormControl, Button} from 'react-bootstrap';
|
||||
import { Alert, Form, FormGroup, FormControl, Button } from 'react-bootstrap';
|
||||
|
||||
window.EmbarkJS = EmbarkJS;
|
||||
|
||||
|
@ -10,18 +11,49 @@ class ENS extends React.Component {
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
valueResolve: 'ethereumfoundation.eth',
|
||||
valueResolve: 'embark.eth',
|
||||
responseResolve: null,
|
||||
isResolveError: false,
|
||||
valueLookup: '0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359',
|
||||
valueLookup: '',
|
||||
responseLookup: null,
|
||||
isLookupError: false,
|
||||
valueRegister: '',
|
||||
addressRegister: '',
|
||||
responseRegister: null,
|
||||
isRegisterError: false,
|
||||
embarkLogs: []
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
EmbarkJS.onReady(() => {
|
||||
this.setState({
|
||||
addressRegister: web3.eth.defaultAccount,
|
||||
valueLookup: web3.eth.defaultAccount
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
handleChange(stateName, e) {
|
||||
this.setState({[stateName]: e.target.value});
|
||||
this.setState({ [stateName]: e.target.value });
|
||||
}
|
||||
|
||||
registerSubDomain(e) {
|
||||
e.preventDefault();
|
||||
const self = this;
|
||||
const embarkLogs = this.state.embarkLogs;
|
||||
embarkLogs.push(`EmbarkJS.Names.registerSubDomain('${this.state.valueRegister}', '${this.state.addressRegister}', console.log)`);
|
||||
this.setState({
|
||||
embarkLogs: embarkLogs
|
||||
});
|
||||
|
||||
EmbarkJS.Names.registerSubDomain(this.state.valueRegister, this.state.addressRegister, (err, transaction) => {
|
||||
const message = err ? err : `Successfully registered "${this.state.valueRegister}" with ${transaction.gasUsed} gas`;
|
||||
self.setState({
|
||||
responseRegister: message,
|
||||
isRegisterError: !!err
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
resolveName(e) {
|
||||
|
@ -35,7 +67,7 @@ class ENS extends React.Component {
|
|||
EmbarkJS.Names.resolve(this.state.valueResolve, (err, result) => {
|
||||
if (err) {
|
||||
return this.setState({
|
||||
responseResolve: err,
|
||||
responseResolve: err.message || err,
|
||||
isResolveError: true
|
||||
});
|
||||
}
|
||||
|
@ -57,7 +89,7 @@ class ENS extends React.Component {
|
|||
EmbarkJS.Names.lookup(this.state.valueLookup, (err, result) => {
|
||||
if (err) {
|
||||
return this.setState({
|
||||
responseLookup: err,
|
||||
responseLookup: err.message || err,
|
||||
isLookupError: true
|
||||
});
|
||||
}
|
||||
|
@ -70,12 +102,6 @@ class ENS extends React.Component {
|
|||
|
||||
render() {
|
||||
return (<React.Fragment>
|
||||
{
|
||||
!this.props.enabled ?
|
||||
<React.Fragment>
|
||||
<Alert bsStyle="warning">ENS provider might not be set</Alert>
|
||||
</React.Fragment> : ''
|
||||
}
|
||||
<h3>Resolve a name</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
|
@ -106,6 +132,25 @@ class ENS extends React.Component {
|
|||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3>Register subdomain for embark</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
{this.state.responseRegister &&
|
||||
<Alert className="alert-result" bsStyle={this.state.isRegisterError ? 'danger' : 'success'}>
|
||||
<span className="value">{this.state.responseRegister}</span>
|
||||
</Alert>}
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.valueRegister}
|
||||
onChange={(e) => this.handleChange('valueRegister', e)}/>
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.addressRegister}
|
||||
onChange={(e) => this.handleChange('addressRegister', e)}/>
|
||||
<Button bsStyle="primary" onClick={(e) => this.registerSubDomain(e)}>Register subdomain</Button>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3>Embark Calls </h3>
|
||||
<p>Javascript calls being made: </p>
|
||||
<div className="logs">
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
module.exports = {
|
||||
default: {
|
||||
available_providers: ["ens"],
|
||||
provider: "ens"
|
||||
provider: "ens",
|
||||
register: {
|
||||
rootDomain: "embark.eth",
|
||||
subdomains: {
|
||||
'status': '0x1a2f3b98e434c02363f3dac3174af93c1d690914'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
pragma solidity ^0.4.18;
|
||||
|
||||
interface ENS {
|
||||
|
||||
// Logged when the owner of a node assigns a new owner to a subnode.
|
||||
event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
|
||||
|
||||
// Logged when the owner of a node transfers ownership to a new account.
|
||||
event Transfer(bytes32 indexed node, address owner);
|
||||
|
||||
// Logged when the resolver for a node changes.
|
||||
event NewResolver(bytes32 indexed node, address resolver);
|
||||
|
||||
// Logged when the TTL of a node changes
|
||||
event NewTTL(bytes32 indexed node, uint64 ttl);
|
||||
|
||||
|
||||
function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public;
|
||||
function setResolver(bytes32 node, address resolver) public;
|
||||
function setOwner(bytes32 node, address owner) public;
|
||||
function setTTL(bytes32 node, uint64 ttl) public;
|
||||
function owner(bytes32 node) public view returns (address);
|
||||
function resolver(bytes32 node) public view returns (address);
|
||||
function ttl(bytes32 node) public view returns (uint64);
|
||||
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
pragma solidity ^0.4.18;
|
||||
|
||||
import './ENS.sol';
|
||||
|
||||
/**
|
||||
* The ENS registry contract.
|
||||
*/
|
||||
contract ENSRegistry is ENS {
|
||||
struct Record {
|
||||
address owner;
|
||||
address resolver;
|
||||
uint64 ttl;
|
||||
}
|
||||
|
||||
mapping (bytes32 => Record) records;
|
||||
|
||||
// Permits modifications only by the owner of the specified node.
|
||||
modifier only_owner(bytes32 node, address owner) {
|
||||
require(records[node].owner == 0 || records[node].owner == msg.sender || records[node].owner == owner);
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Constructs a new ENS registrar.
|
||||
*/
|
||||
function ENSRegistry() public {
|
||||
records[0x0].owner = msg.sender;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Transfers ownership of a node to a new address. May only be called by the current owner of the node.
|
||||
* @param node The node to transfer ownership of.
|
||||
* @param owner The address of the new owner.
|
||||
*/
|
||||
function setOwner(bytes32 node, address owner) public only_owner(node, owner) {
|
||||
Transfer(node, owner);
|
||||
records[node].owner = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Transfers ownership of a subnode sha3(node, label) to a new address. May only be called by the owner of the parent node.
|
||||
* @param node The parent node.
|
||||
* @param label The hash of the label specifying the subnode.
|
||||
* @param owner The address of the new owner.
|
||||
*/
|
||||
function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public only_owner(node, owner) {
|
||||
var subnode = keccak256(node, label);
|
||||
NewOwner(node, label, owner);
|
||||
records[subnode].owner = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets the resolver address for the specified node.
|
||||
* @param node The node to update.
|
||||
* @param resolver The address of the resolver.
|
||||
*/
|
||||
function setResolver(bytes32 node, address resolver) public only_owner(node, 0x0) {
|
||||
NewResolver(node, resolver);
|
||||
records[node].resolver = resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets the TTL for the specified node.
|
||||
* @param node The node to update.
|
||||
* @param ttl The TTL in seconds.
|
||||
*/
|
||||
function setTTL(bytes32 node, uint64 ttl) public only_owner(node, 0x0) {
|
||||
NewTTL(node, ttl);
|
||||
records[node].ttl = ttl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the address that owns the specified node.
|
||||
* @param node The specified node.
|
||||
* @return address of the owner.
|
||||
*/
|
||||
function owner(bytes32 node) public view returns (address) {
|
||||
return records[node].owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the address of the resolver for the specified node.
|
||||
* @param node The specified node.
|
||||
* @return address of the resolver.
|
||||
*/
|
||||
function resolver(bytes32 node) public view returns (address) {
|
||||
return records[node].resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the TTL of a node, and any records associated with it.
|
||||
* @param node The specified node.
|
||||
* @return ttl of the node.
|
||||
*/
|
||||
function ttl(bytes32 node) public view returns (uint64) {
|
||||
return records[node].ttl;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
pragma solidity ^0.4.18;
|
||||
|
||||
import './ENS.sol';
|
||||
import './Resolver.sol';
|
||||
|
||||
/**
|
||||
* A registrar that allocates subdomains to the first person to claim them.
|
||||
*/
|
||||
contract FIFSRegistrar {
|
||||
ENS ens;
|
||||
bytes32 rootNode;
|
||||
|
||||
modifier only_owner(bytes32 subnode) {
|
||||
bytes32 node = sha3(rootNode, subnode);
|
||||
address currentOwner = ens.owner(node);
|
||||
require(currentOwner == 0 || currentOwner == msg.sender);
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param ensAddr The address of the ENS registry.
|
||||
* @param node The node that this registrar administers.
|
||||
*/
|
||||
function FIFSRegistrar(ENS ensAddr, bytes32 node) public {
|
||||
ens = ensAddr;
|
||||
rootNode = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a name, or change the owner of an existing registration.
|
||||
* @param subnode The hash of the label to register.
|
||||
* @param owner The address of the new owner.
|
||||
*/
|
||||
function register(bytes32 subnode, address owner) public only_owner(subnode) {
|
||||
ens.setSubnodeOwner(rootNode, subnode, owner);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
pragma solidity ^0.4.23;
|
||||
|
||||
import "./ENS.sol";
|
||||
|
||||
/**
|
||||
* A simple resolver anyone can use; only allows the owner of a node to set its
|
||||
* address.
|
||||
*/
|
||||
contract Resolver {
|
||||
event AddrChanged(bytes32 indexed node, address a);
|
||||
event ContentChanged(bytes32 indexed node, bytes32 hash);
|
||||
event NameChanged(bytes32 indexed node, string name);
|
||||
event ABIChanged(bytes32 indexed node, uint256 indexed contentType);
|
||||
event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y);
|
||||
event TextChanged(bytes32 indexed node, string indexedKey, string key);
|
||||
|
||||
struct PublicKey {
|
||||
bytes32 x;
|
||||
bytes32 y;
|
||||
}
|
||||
|
||||
struct Record {
|
||||
address addr;
|
||||
bytes32 content;
|
||||
string name;
|
||||
PublicKey pubkey;
|
||||
mapping(string=>string) text;
|
||||
mapping(uint256=>bytes) abis;
|
||||
}
|
||||
|
||||
ENS ens;
|
||||
|
||||
mapping (bytes32 => Record) records;
|
||||
|
||||
modifier only_owner(bytes32 node) {
|
||||
address currentOwner = ens.owner(node);
|
||||
require(currentOwner == 0 || currentOwner == msg.sender);
|
||||
_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param ensAddr The ENS registrar contract.
|
||||
*/
|
||||
constructor(ENS ensAddr) public {
|
||||
ens = ensAddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the address associated with an ENS node.
|
||||
* May only be called by the owner of that node in the ENS registry.
|
||||
* @param node The node to update.
|
||||
* @param addr The address to set.
|
||||
*/
|
||||
function setAddr(bytes32 node, address addr) public only_owner(node) {
|
||||
records[node].addr = addr;
|
||||
emit AddrChanged(node, addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the content hash associated with an ENS node.
|
||||
* May only be called by the owner of that node in the ENS registry.
|
||||
* Note that this resource type is not standardized, and will likely change
|
||||
* in future to a resource type based on multihash.
|
||||
* @param node The node to update.
|
||||
* @param hash The content hash to set
|
||||
*/
|
||||
function setContent(bytes32 node, bytes32 hash) public only_owner(node) {
|
||||
records[node].content = hash;
|
||||
emit ContentChanged(node, hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name associated with an ENS node, for reverse records.
|
||||
* May only be called by the owner of that node in the ENS registry.
|
||||
* @param node The node to update.
|
||||
* @param name The name to set.
|
||||
*/
|
||||
function setName(bytes32 node, string name) public only_owner(node) {
|
||||
records[node].name = name;
|
||||
emit NameChanged(node, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ABI associated with an ENS node.
|
||||
* Nodes may have one ABI of each content type. To remove an ABI, set it to
|
||||
* the empty string.
|
||||
* @param node The node to update.
|
||||
* @param contentType The content type of the ABI
|
||||
* @param data The ABI data.
|
||||
*/
|
||||
function setABI(bytes32 node, uint256 contentType, bytes data) public only_owner(node) {
|
||||
// Content types must be powers of 2
|
||||
require(((contentType - 1) & contentType) == 0);
|
||||
|
||||
records[node].abis[contentType] = data;
|
||||
emit ABIChanged(node, contentType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SECP256k1 public key associated with an ENS node.
|
||||
* @param node The ENS node to query
|
||||
* @param x the X coordinate of the curve point for the public key.
|
||||
* @param y the Y coordinate of the curve point for the public key.
|
||||
*/
|
||||
function setPubkey(bytes32 node, bytes32 x, bytes32 y) public only_owner(node) {
|
||||
records[node].pubkey = PublicKey(x, y);
|
||||
emit PubkeyChanged(node, x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the text data associated with an ENS node and key.
|
||||
* May only be called by the owner of that node in the ENS registry.
|
||||
* @param node The node to update.
|
||||
* @param key The key to set.
|
||||
* @param value The text data value to set.
|
||||
*/
|
||||
function setText(bytes32 node, string key, string value) public only_owner(node) {
|
||||
records[node].text[key] = value;
|
||||
emit TextChanged(node, key, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text data associated with an ENS node and key.
|
||||
* @param node The ENS node to query.
|
||||
* @param key The text data key to query.
|
||||
* @return The associated text data.
|
||||
*/
|
||||
function text(bytes32 node, string key) public view returns (string) {
|
||||
return records[node].text[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SECP256k1 public key associated with an ENS node.
|
||||
* Defined in EIP 619.
|
||||
* @param node The ENS node to query
|
||||
* @return x, y the X and Y coordinates of the curve point for the public key.
|
||||
*/
|
||||
function pubkey(bytes32 node) public view returns (bytes32 x, bytes32 y) {
|
||||
return (records[node].pubkey.x, records[node].pubkey.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ABI associated with an ENS node.
|
||||
* Defined in EIP205.
|
||||
* @param node The ENS node to query
|
||||
* @param contentTypes A bitwise OR of the ABI formats accepted by the caller.
|
||||
* @return contentType The content type of the return value
|
||||
* @return data The ABI data
|
||||
*/
|
||||
function ABI(bytes32 node, uint256 contentTypes) public view returns (uint256 contentType, bytes data) {
|
||||
Record storage record = records[node];
|
||||
for (contentType = 1; contentType <= contentTypes; contentType <<= 1) {
|
||||
if ((contentType & contentTypes) != 0 && record.abis[contentType].length > 0) {
|
||||
data = record.abis[contentType];
|
||||
return;
|
||||
}
|
||||
}
|
||||
contentType = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name associated with an ENS node, for reverse records.
|
||||
* Defined in EIP181.
|
||||
* @param node The ENS node to query.
|
||||
* @return The associated name.
|
||||
*/
|
||||
function name(bytes32 node) public view returns (string) {
|
||||
return records[node].name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content hash associated with an ENS node.
|
||||
* Note that this resource type is not standardized, and will likely change
|
||||
* in future to a resource type based on multihash.
|
||||
* @param node The ENS node to query.
|
||||
* @return The associated content hash.
|
||||
*/
|
||||
function content(bytes32 node) public view returns (bytes32) {
|
||||
return records[node].content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address associated with an ENS node.
|
||||
* @param node The ENS node to query.
|
||||
* @return The associated address.
|
||||
*/
|
||||
function addr(bytes32 node) public view returns (address) {
|
||||
return records[node].addr;
|
||||
}
|
||||
}
|
|
@ -19,26 +19,18 @@ module.exports = {
|
|||
},
|
||||
SimpleStorage: {
|
||||
fromIndex: 0,
|
||||
args: [
|
||||
100
|
||||
],
|
||||
onDeploy: [
|
||||
"SimpleStorage.methods.setRegistar(web3.eth.defaultAccount).send()"
|
||||
]
|
||||
args: [100],
|
||||
onDeploy: ["SimpleStorage.methods.setRegistar(web3.eth.defaultAccount).send()"]
|
||||
},
|
||||
AnotherStorage: {
|
||||
args: [
|
||||
"$SimpleStorage"
|
||||
]
|
||||
args: ["$SimpleStorage"]
|
||||
},
|
||||
Token: {
|
||||
deploy: false,
|
||||
args: [1000]
|
||||
},
|
||||
Test: {
|
||||
onDeploy: [
|
||||
"Test.methods.changeAddress('$MyToken')"
|
||||
]
|
||||
onDeploy: ["Test.methods.changeAddress('$MyToken')"]
|
||||
},
|
||||
MyToken: {
|
||||
instanceOf: "Token"
|
||||
|
@ -71,18 +63,23 @@ module.exports = {
|
|||
},
|
||||
SimpleStorageTest: {
|
||||
file: "./some_folder/test_contract.sol",
|
||||
args: [
|
||||
1000
|
||||
]
|
||||
args: [1000]
|
||||
},
|
||||
Identity: {
|
||||
file: "https://github.com/status-im/contracts/blob/master/contracts/identity/Identity.sol"
|
||||
},
|
||||
SimpleStorageWithHttpImport: {
|
||||
fromIndex: 0,
|
||||
args: [
|
||||
100
|
||||
]
|
||||
args: [100]
|
||||
},
|
||||
ENSRegistry: {
|
||||
"deploy": false
|
||||
},
|
||||
Resolver: {
|
||||
"deploy": false
|
||||
},
|
||||
FIFSRegistrar: {
|
||||
"deploy": false
|
||||
}
|
||||
},
|
||||
afterDeploy: [
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
{
|
||||
"default": {
|
||||
"enabled": true,
|
||||
"available_providers": ["ens"],
|
||||
"available_providers": [
|
||||
"ens"
|
||||
],
|
||||
"provider": "ens",
|
||||
"register": {
|
||||
"rootDomain": "embark"
|
||||
"rootDomain": "embark.eth",
|
||||
"subdomains": {
|
||||
"status": "0x4a17f35f0a9927fb4141aa91cbbc72c1b31598de"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*global contract, config, it, assert, before*/
|
||||
const Resolver = require('Embark/contracts/Resolver');
|
||||
|
||||
const namehash = require('eth-ens-namehash');
|
||||
const address = '0x38ac14a9B6a7c8F9C46e4804074186c9F201D0A0';
|
||||
const rootNode = namehash.hash('embark.eth');
|
||||
|
||||
config({
|
||||
contracts: {
|
||||
"ENSRegistry": {
|
||||
"args": []
|
||||
},
|
||||
"Resolver": {
|
||||
"args": ["$ENSRegistry"]
|
||||
},
|
||||
"FIFSRegistrar": {
|
||||
"args": ["$ENSRegistry", rootNode],
|
||||
"onDeploy": [
|
||||
`ENSRegistry.methods.setOwner('${rootNode}', web3.eth.defaultAccount).send().then(() => {
|
||||
ENSRegistry.methods.setResolver('${rootNode}', "$Resolver").send();
|
||||
Resolver.methods.setAddr('${rootNode}', '${address}').send().then(() => {
|
||||
global.ensTestReady = true;
|
||||
});
|
||||
});`
|
||||
]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
contract("ENS", function () {
|
||||
this.timeout(1000);
|
||||
|
||||
before(function (done) {
|
||||
// Wait for onDeploy to finish
|
||||
const wait = setInterval(() => {
|
||||
if (!global.ensTestReady) {
|
||||
return;
|
||||
}
|
||||
clearInterval(wait);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should have registered embark.eth", async function () {
|
||||
const domainAddress = await Resolver.methods.addr(rootNode).call();
|
||||
assert.strictEqual(domainAddress, address);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue