mirror of https://github.com/embarklabs/embark.git
fixes due to bad rebase
This commit is contained in:
parent
6fac1f297d
commit
95df68e67c
|
@ -1,4 +1,4 @@
|
||||||
process.on('uncaughtException', function(e) {
|
process.on('uncaughtException', function(e){
|
||||||
process.send({error: e.stack});
|
process.send({error: e.stack});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
const Web3 = require('web3');
|
const Web3 = require('web3');
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
const Provider = require('./provider.js');
|
const Provider = require('./provider.js');
|
||||||
const utils = require('../utils/utils');
|
const utils = require('../../utils/utils');
|
||||||
|
const constants = require('../../constants');
|
||||||
|
const embarkJsUtils = require('embarkjs').Utils;
|
||||||
|
|
||||||
const WEB3_READY = 'blockchain:ready';
|
const WEB3_READY = 'blockchain:ready';
|
||||||
|
|
||||||
class Blockchain {
|
// TODO: consider another name, this is the blockchain connector
|
||||||
constructor(options) {
|
class BlockchainConnector {
|
||||||
|
constructor(embark, options) {
|
||||||
const self = this;
|
const self = this;
|
||||||
this.plugins = options.plugins;
|
this.plugins = options.plugins;
|
||||||
this.logger = embark.logger;
|
this.logger = embark.logger;
|
||||||
|
@ -22,6 +25,10 @@ class Blockchain {
|
||||||
cb(self.isWeb3Ready);
|
cb(self.isWeb3Ready);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
self.events.setCommandHandler("blockchain:object", (cb) => {
|
||||||
|
cb(self);
|
||||||
|
});
|
||||||
|
|
||||||
if (!this.web3) {
|
if (!this.web3) {
|
||||||
this.initWeb3();
|
this.initWeb3();
|
||||||
} else {
|
} else {
|
||||||
|
@ -32,6 +39,7 @@ class Blockchain {
|
||||||
this.registerRequests();
|
this.registerRequests();
|
||||||
this.registerWeb3Object();
|
this.registerWeb3Object();
|
||||||
this.registerEvents();
|
this.registerEvents();
|
||||||
|
this.subscribeToPendingTransactions();
|
||||||
}
|
}
|
||||||
|
|
||||||
initWeb3(cb) {
|
initWeb3(cb) {
|
||||||
|
@ -328,60 +336,14 @@ class Blockchain {
|
||||||
}
|
}
|
||||||
|
|
||||||
deployContractFromObject(deployContractObject, params, cb) {
|
deployContractFromObject(deployContractObject, params, cb) {
|
||||||
const self = this;
|
embarkJsUtils.secureSend(this.web3, deployContractObject, {
|
||||||
let hash;
|
|
||||||
let calledBacked = false;
|
|
||||||
|
|
||||||
function callback(err, receipt) {
|
|
||||||
if (calledBacked) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!err && !receipt.contractAddress) {
|
|
||||||
return; // Not deployed yet. Need to wait
|
|
||||||
}
|
|
||||||
if (interval) {
|
|
||||||
clearInterval(interval);
|
|
||||||
}
|
|
||||||
calledBacked = true;
|
|
||||||
cb(err, receipt);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This interval is there to compensate for the event that sometimes doesn't get triggered when using WebSocket
|
|
||||||
// FIXME The issue somehow only happens when the blockchain node is started in the same terminal
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
if (!hash) {
|
|
||||||
return; // Wait until we receive the hash
|
|
||||||
}
|
|
||||||
self.web3.eth.getTransactionReceipt(hash, (err, receipt) => {
|
|
||||||
if (!err && !receipt) {
|
|
||||||
return; // Transaction is not yet complete
|
|
||||||
}
|
|
||||||
callback(err, receipt);
|
|
||||||
});
|
|
||||||
}, 500);
|
|
||||||
|
|
||||||
deployContractObject.send({
|
|
||||||
from: params.from, gas: params.gas, gasPrice: params.gasPrice
|
from: params.from, gas: params.gas, gasPrice: params.gasPrice
|
||||||
}, function (err, transactionHash) {
|
}, true, cb);
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
hash = transactionHash;
|
|
||||||
}).on('receipt', function (receipt) {
|
|
||||||
if (receipt.contractAddress !== undefined) {
|
|
||||||
callback(null, receipt);
|
|
||||||
}
|
|
||||||
}).then(function (_contract) {
|
|
||||||
if (!hash) {
|
|
||||||
return; // Somehow we didn't get the receipt yet... Interval will catch it
|
|
||||||
}
|
|
||||||
self.web3.eth.getTransactionReceipt(hash, callback);
|
|
||||||
}).catch(callback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
determineDefaultAccount(cb) {
|
determineDefaultAccount(cb) {
|
||||||
const self = this;
|
const self = this;
|
||||||
self.getAccounts(function (err, accounts) {
|
self.getAccounts(function(err, accounts) {
|
||||||
if (err) {
|
if (err) {
|
||||||
self.logger.error(err);
|
self.logger.error(err);
|
||||||
return cb(new Error(err));
|
return cb(new Error(err));
|
||||||
|
@ -399,8 +361,21 @@ class Blockchain {
|
||||||
// can just be a command without a callback
|
// can just be a command without a callback
|
||||||
this.events.emit("runcode:register", "web3", this.web3, false);
|
this.events.emit("runcode:register", "web3", this.web3, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
subscribeToPendingTransactions() {
|
||||||
|
const self = this;
|
||||||
|
this.onReady(() => {
|
||||||
|
if (self.logsSubscription) {
|
||||||
|
self.logsSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
self.logsSubscription = self.web3.eth
|
||||||
|
.subscribe('newBlockHeaders', () => {})
|
||||||
|
.on("data", function (blockHeader) {
|
||||||
|
self.events.emit('block:header', blockHeader);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockchainConnector.ACCEPTED_TYPES = ['rpc', 'ws', 'vm'];
|
BlockchainConnector.ACCEPTED_TYPES = ['rpc', 'ws', 'vm'];
|
||||||
|
|
||||||
module.exports = BlockchainConnector;
|
module.exports = BlockchainConnector;
|
||||||
|
|
|
@ -11,17 +11,13 @@ class Provider {
|
||||||
this.web3Endpoint = options.web3Endpoint;
|
this.web3Endpoint = options.web3Endpoint;
|
||||||
this.logger = options.logger;
|
this.logger = options.logger;
|
||||||
this.isDev = options.isDev;
|
this.isDev = options.isDev;
|
||||||
this.engine = new ProviderEngine();
|
|
||||||
this.asyncMethods = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
startWeb3Provider(callback) {
|
startWeb3Provider(callback) {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
if (this.type === 'rpc') {
|
if (this.type === 'rpc') {
|
||||||
self.engine.addProvider(new RpcSubprovider({
|
self.provider = new this.web3.providers.HttpProvider(self.web3Endpoint);
|
||||||
rpcUrl: self.web3Endpoint
|
|
||||||
}));
|
|
||||||
} else if (this.type === 'ws') {
|
} else if (this.type === 'ws') {
|
||||||
// Note: don't pass to the provider things like {headers: {Origin: "embark"}}. Origin header is for browser to fill
|
// Note: don't pass to the provider things like {headers: {Origin: "embark"}}. Origin header is for browser to fill
|
||||||
// to protect user, it has no meaning if it is used server-side. See here for more details: https://github.com/ethereum/go-ethereum/issues/16608
|
// to protect user, it has no meaning if it is used server-side. See here for more details: https://github.com/ethereum/go-ethereum/issues/16608
|
||||||
|
@ -36,26 +32,7 @@ class Provider {
|
||||||
return callback(__("contracts config error: unknown deployment type %s", this.type));
|
return callback(__("contracts config error: unknown deployment type %s", this.type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.web3.setProvider(self.provider);
|
||||||
// network connectivity error
|
|
||||||
self.engine.on('error', (err) => {
|
|
||||||
// report connectivity errors
|
|
||||||
self.logger.error(err);
|
|
||||||
});
|
|
||||||
|
|
||||||
self.engine.start();
|
|
||||||
//self.on('error', (err) => {
|
|
||||||
// console.log('ERR', JSON.stringify(err));
|
|
||||||
// // report connectivity errors as trace due to polling
|
|
||||||
// self.logger.trace('web3 provider error: ', err);
|
|
||||||
// self.logger.trace('stopping web3 provider due to error');
|
|
||||||
|
|
||||||
// // prevent continuous polling errors
|
|
||||||
// self.stop();
|
|
||||||
//});
|
|
||||||
|
|
||||||
//self.web3.setProvider(self);
|
|
||||||
//self.start();
|
|
||||||
|
|
||||||
self.web3.eth.getAccounts((err, accounts) => {
|
self.web3.eth.getAccounts((err, accounts) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -125,36 +102,10 @@ class Provider {
|
||||||
if (!self.isDev) {
|
if (!self.isDev) {
|
||||||
return callback();
|
return callback();
|
||||||
}
|
}
|
||||||
async.each(self.accounts, (account, eachCb) => {
|
async.eachLimit(self.accounts, 1, (account, eachCb) => {
|
||||||
fundAccount(self.web3, account.address, account.hexBalance, eachCb);
|
fundAccount(self.web3, account.address, account.hexBalance, eachCb);
|
||||||
}, callback);
|
}, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
stop() {
|
|
||||||
this.engine.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
eth_accounts(payload, cb) {
|
|
||||||
return cb(null, this.addresses);
|
|
||||||
}
|
|
||||||
|
|
||||||
sendAsync(payload, callback) {
|
|
||||||
let method = this.asyncMethods[payload.method];
|
|
||||||
if (method) {
|
|
||||||
return method.call(method, payload, (err, result) => {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
let response = {'id': payload.id, 'jsonrpc': '2.0', 'result': result};
|
|
||||||
callback(null, response);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.engine.sendAsync.apply(this.engine, arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
send() {
|
|
||||||
return this.engine.send.apply(this.engine, arguments);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Provider;
|
module.exports = Provider;
|
||||||
|
|
|
@ -1,82 +0,0 @@
|
||||||
const async = require('async');
|
|
||||||
const AccountParser = require('../../utils/accountParser');
|
|
||||||
const fundAccount = require('./fundAccount');
|
|
||||||
|
|
||||||
class Provider {
|
|
||||||
constructor(options) {
|
|
||||||
this.web3 = options.web3;
|
|
||||||
this.accountsConfig = options.accountsConfig;
|
|
||||||
this.blockchainConfig = options.blockchainConfig;
|
|
||||||
this.type = options.type;
|
|
||||||
this.web3Endpoint = options.web3Endpoint;
|
|
||||||
this.logger = options.logger;
|
|
||||||
this.isDev = options.isDev;
|
|
||||||
}
|
|
||||||
|
|
||||||
startWeb3Provider(callback) {
|
|
||||||
const self = this;
|
|
||||||
|
|
||||||
if (this.type === 'rpc') {
|
|
||||||
self.provider = new this.web3.providers.HttpProvider(self.web3Endpoint);
|
|
||||||
} else if (this.type === 'ws') {
|
|
||||||
self.provider = new this.web3.providers.WebsocketProvider(self.web3Endpoint, {headers: {Origin: "embark"}});
|
|
||||||
} else {
|
|
||||||
return callback(__("contracts config error: unknown deployment type %s", this.type));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.web3.setProvider(self.provider);
|
|
||||||
|
|
||||||
self.accounts = AccountParser.parseAccountsConfig(self.accountsConfig, self.web3, self.logger);
|
|
||||||
self.addresses = [];
|
|
||||||
|
|
||||||
if (!self.accounts.length) {
|
|
||||||
return callback();
|
|
||||||
}
|
|
||||||
self.accounts.forEach(account => {
|
|
||||||
self.addresses.push(account.address);
|
|
||||||
self.web3.eth.accounts.wallet.add(account);
|
|
||||||
});
|
|
||||||
self.web3.eth.defaultAccount = self.addresses[0];
|
|
||||||
const realSend = self.provider.send.bind(self.provider);
|
|
||||||
self.provider.send = function (payload, cb) {
|
|
||||||
if (payload.method === 'eth_accounts') {
|
|
||||||
return realSend(payload, function (err, result) {
|
|
||||||
if (err) {
|
|
||||||
return cb(err);
|
|
||||||
}
|
|
||||||
result.result = result.result.concat(self.addresses);
|
|
||||||
cb(null, result);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
realSend(payload, cb);
|
|
||||||
};
|
|
||||||
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
if (this.provider && this.provider.removeAllListeners) {
|
|
||||||
this.provider.removeAllListeners('connect');
|
|
||||||
this.provider.removeAllListeners('error');
|
|
||||||
this.provider.removeAllListeners('end');
|
|
||||||
this.provider.removeAllListeners('data');
|
|
||||||
this.provider.responseCallbacks = {};
|
|
||||||
this.provider = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fundAccounts(callback) {
|
|
||||||
const self = this;
|
|
||||||
if (!self.accounts.length) {
|
|
||||||
return callback();
|
|
||||||
}
|
|
||||||
if (!self.isDev) {
|
|
||||||
return callback();
|
|
||||||
}
|
|
||||||
async.eachLimit(self.accounts, 1, (account, eachCb) => {
|
|
||||||
fundAccount(self.web3, account.address, account.hexBalance, eachCb);
|
|
||||||
}, callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = Provider;
|
|
|
@ -14,8 +14,6 @@ const Ipc = require('../../core/ipc');
|
||||||
|
|
||||||
const {defaultHost, dockerHostSwap} = require('../../utils/host');
|
const {defaultHost, dockerHostSwap} = require('../../utils/host');
|
||||||
|
|
||||||
const {defaultHost, dockerHostSwap} = require('../../utils/host');
|
|
||||||
|
|
||||||
/*eslint complexity: ["error", 36]*/
|
/*eslint complexity: ["error", 36]*/
|
||||||
var Blockchain = function(userConfig, clientClass) {
|
var Blockchain = function(userConfig, clientClass) {
|
||||||
this.userConfig = userConfig;
|
this.userConfig = userConfig;
|
||||||
|
|
|
@ -2,7 +2,6 @@ const async = require('async');
|
||||||
const Viz = require('viz.js');
|
const Viz = require('viz.js');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
// TODO: refactor this class to use the plugin api and not refeneences directly
|
|
||||||
class GraphGenerator {
|
class GraphGenerator {
|
||||||
constructor(embark, _options) {
|
constructor(embark, _options) {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
|
@ -39,7 +39,6 @@ class NpmTimer{
|
||||||
else{
|
else{
|
||||||
// otherwise, find our download complete measurement
|
// otherwise, find our download complete measurement
|
||||||
entry = utils.last(items.getEntries().filter(entry => entry.name === this._downloadComplete));
|
entry = utils.last(items.getEntries().filter(entry => entry.name === this._downloadComplete));
|
||||||
|
|
||||||
if(entry){
|
if(entry){
|
||||||
strDuration = __('Finished downloading and installing {{packageName}} {{version}} in {{duration}}ms', {packageName: this._packageName, version: this._version, duration: entry.duration});
|
strDuration = __('Finished downloading and installing {{packageName}} {{version}} in {{duration}}ms', {packageName: this._packageName, version: this._version, duration: entry.duration});
|
||||||
performance.clearMarks();
|
performance.clearMarks();
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
/* global EmbarkJS */
|
|
||||||
|
|
||||||
import {detectSeries} from 'async';
|
|
||||||
|
|
||||||
let __embarkStorage = {};
|
|
||||||
|
|
||||||
__embarkStorage.setProviders = async function (dappConnOptions) {
|
|
||||||
try {
|
|
||||||
await detectSeries(dappConnOptions, async (dappConn, callback) => {
|
|
||||||
if(dappConn === '$BZZ' || dappConn.provider === 'swarm'){
|
|
||||||
let options = dappConn;
|
|
||||||
if(dappConn === '$BZZ') options = {"useOnlyGivenProvider": true};
|
|
||||||
try{
|
|
||||||
await EmbarkJS.Storage.setProvider('swarm', options);
|
|
||||||
let isAvailable = await EmbarkJS.Storage.isAvailable();
|
|
||||||
callback(null, isAvailable);
|
|
||||||
}catch(err){
|
|
||||||
callback(null, false); // catch errors for when bzz object not initialised but config has requested it to be used
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(dappConn.provider === 'ipfs') {
|
|
||||||
// set the provider then check the connection, if true, use that provider, else, check next provider
|
|
||||||
try{
|
|
||||||
await EmbarkJS.Storage.setProvider('ipfs', dappConn);
|
|
||||||
let isAvailable = await EmbarkJS.Storage.isAvailable();
|
|
||||||
callback(null, isAvailable);
|
|
||||||
} catch(err) {
|
|
||||||
callback(null, false); // catch but keep looping by not passing err to callback
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, function(err, result){
|
|
||||||
if(!result) throw new Error('Could not connect to a storage provider using any of the dappConnections in the storage config');
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
throw new Error('Failed to connect to a storage provider: ' + err.message);
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,39 +0,0 @@
|
||||||
|
|
||||||
class ProcessManager {
|
|
||||||
constructor(options) {
|
|
||||||
const self = this;
|
|
||||||
this.logger = options.logger;
|
|
||||||
this.events = options.events;
|
|
||||||
this.plugins = options.plugins;
|
|
||||||
this.processes = {};
|
|
||||||
|
|
||||||
self.events.setCommandHandler('processes:register', (name, cb) => {
|
|
||||||
console.dir("=====> registering " + name);
|
|
||||||
this.processes[name] = {
|
|
||||||
state: 'unstarted',
|
|
||||||
cb: cb
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
self.events.setCommandHandler('processes:launch', (name, cb) => {
|
|
||||||
let process = self.processes[name];
|
|
||||||
// TODO: should make distinction between starting and running
|
|
||||||
if (process.state != 'unstarted') {
|
|
||||||
console.dir("=====> already started " + name);
|
|
||||||
return cb();
|
|
||||||
}
|
|
||||||
console.dir("=====> launching " + name);
|
|
||||||
process.state = 'starting';
|
|
||||||
//let pry = require('pryjs');
|
|
||||||
//eval(pry.it);
|
|
||||||
process.cb.apply(process.cb, [() => {
|
|
||||||
process.state = 'running';
|
|
||||||
console.dir("=====> launched " + name);
|
|
||||||
cb();
|
|
||||||
}]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = ProcessManager;
|
|
|
@ -54,7 +54,6 @@
|
||||||
"eth-ens-namehash": "2.0.8",
|
"eth-ens-namehash": "2.0.8",
|
||||||
"eth-lib": "0.2.8",
|
"eth-lib": "0.2.8",
|
||||||
"babel-plugin-webpack-aliases": "^1.1.3",
|
"babel-plugin-webpack-aliases": "^1.1.3",
|
||||||
"embarkjs": "^0.3.4",
|
|
||||||
"ethereumjs-wallet": "0.6.0",
|
"ethereumjs-wallet": "0.6.0",
|
||||||
"express": "4.16.3",
|
"express": "4.16.3",
|
||||||
"express-ws": "4.0.0",
|
"express-ws": "4.0.0",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
|
{
|
||||||
"default": {
|
"default": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"rpcHost": "localhost",
|
"rpcHost": "localhost",
|
||||||
|
@ -13,7 +13,6 @@
|
||||||
"networkType": "custom",
|
"networkType": "custom",
|
||||||
"networkId": "1337",
|
"networkId": "1337",
|
||||||
"isDev": true,
|
"isDev": true,
|
||||||
"genesisBlock": "config/development/genesis.json",
|
|
||||||
"datadir": ".embark/development/datadir",
|
"datadir": ".embark/development/datadir",
|
||||||
"mineWhenNeeded": true,
|
"mineWhenNeeded": true,
|
||||||
"nodiscover": true,
|
"nodiscover": true,
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"config": "config/",
|
"config": "config/",
|
||||||
"versions": {
|
"versions": {
|
||||||
"solc": "0.4.24",
|
"solc": "0.4.24",
|
||||||
"web3": "1.0.0-beta.34",
|
"web3": "1.0.0-beta",
|
||||||
"ipfs-api": "17.2.7"
|
"ipfs-api": "17.2.7"
|
||||||
},
|
},
|
||||||
"plugins": {
|
"plugins": {
|
||||||
|
|
|
@ -18,21 +18,27 @@ config({
|
||||||
"onDeploy": [
|
"onDeploy": [
|
||||||
`ENSRegistry.methods.setOwner('${rootNode}', web3.eth.defaultAccount).send().then(() => {
|
`ENSRegistry.methods.setOwner('${rootNode}', web3.eth.defaultAccount).send().then(() => {
|
||||||
ENSRegistry.methods.setResolver('${rootNode}', "$Resolver").send();
|
ENSRegistry.methods.setResolver('${rootNode}', "$Resolver").send();
|
||||||
Resolver.methods.setAddr('${rootNode}', '${address}').send();
|
Resolver.methods.setAddr('${rootNode}', '${address}').send().then(() => {
|
||||||
})`
|
global.ensTestReady = true;
|
||||||
|
});
|
||||||
|
});`
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
contract("ENS", function () {
|
contract("ENS", function () {
|
||||||
this.timeout(0);
|
this.timeout(1000);
|
||||||
|
|
||||||
before(function (done) {
|
before(function (done) {
|
||||||
// Wait for onDeploy to finish
|
// Wait for onDeploy to finish
|
||||||
setTimeout(function () {
|
const wait = setInterval(() => {
|
||||||
|
if (!global.ensTestReady) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
clearInterval(wait);
|
||||||
done();
|
done();
|
||||||
}, 500);
|
}, 50);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should have registered embark.eth", async function () {
|
it("should have registered embark.eth", async function () {
|
||||||
|
|
Loading…
Reference in New Issue