initial commit
Add init, deposit, send console commands to interact with the Plasma chain Add plasma exit command and function working in embark and browser Remove browser codeAll browser code is now required through embarkjs-omg
This commit is contained in:
commit
2a8f0bd937
|
@ -0,0 +1,31 @@
|
|||
/* global module require */
|
||||
|
||||
const cloneDeep = require('lodash.clonedeep');
|
||||
|
||||
module.exports = (api) => {
|
||||
const env = api.env();
|
||||
|
||||
const base = {};
|
||||
|
||||
const browser = cloneDeep(base);
|
||||
Object.assign(browser, {
|
||||
ignore: [
|
||||
'**/node.js'
|
||||
]
|
||||
});
|
||||
|
||||
const node = cloneDeep(base);
|
||||
|
||||
const nodeTest = cloneDeep(base);
|
||||
|
||||
switch (env) {
|
||||
case 'browser':
|
||||
return browser;
|
||||
case 'node':
|
||||
return node;
|
||||
// case 'node:test':
|
||||
// return nodeTest;
|
||||
default:
|
||||
return base;
|
||||
}
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
# Dependency directory
|
||||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
||||
node_modules
|
||||
|
||||
dist
|
||||
package
|
||||
|
||||
.idea
|
||||
.vscode
|
||||
.eslintrc.json
|
||||
|
||||
embark-omg-*.tgz
|
||||
NOTES
|
||||
npm-debug.log
|
||||
TODO
|
||||
|
||||
yarn-error.log
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 Iuri Matias
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,4 @@
|
|||
# Embark-Omg Setup
|
||||
Embark-omg is a plugin for [Embark](https://github.com/embark-framework/embark) that ...
|
||||
|
||||
#### Please report any other issues you find, thank you!
|
|
@ -0,0 +1,62 @@
|
|||
/* global module require */
|
||||
|
||||
const cloneDeep = require('lodash.clonedeep');
|
||||
|
||||
module.exports = (api) => {
|
||||
const env = api.env();
|
||||
|
||||
const base = {
|
||||
babelrcRoots: [
|
||||
'.',
|
||||
'packages/*'
|
||||
],
|
||||
plugins: [
|
||||
'babel-plugin-macros',
|
||||
['@babel/plugin-proposal-decorators', {
|
||||
legacy: true
|
||||
}],
|
||||
'@babel/plugin-syntax-dynamic-import',
|
||||
['@babel/plugin-proposal-class-properties', {
|
||||
loose: true
|
||||
}],
|
||||
'@babel/plugin-proposal-optional-chaining',
|
||||
['@babel/plugin-transform-runtime', {
|
||||
corejs: 2
|
||||
}]
|
||||
],
|
||||
presets: [
|
||||
'@babel/preset-env'
|
||||
]
|
||||
};
|
||||
|
||||
if (env === 'base' || env.startsWith('base:')) {
|
||||
return base;
|
||||
}
|
||||
|
||||
const browser = cloneDeep(base);
|
||||
browser.plugins[browser.plugins.length - 1][1].useESModules = true;
|
||||
browser.presets[0] = [browser.presets[0], {
|
||||
modules: false,
|
||||
targets: { browsers: ['last 1 version', 'not dead', '> 0.2%'] }
|
||||
}];
|
||||
|
||||
if (env === 'browser' || env.startsWith('browser:')) {
|
||||
return browser;
|
||||
}
|
||||
|
||||
const node = cloneDeep(base);
|
||||
node.plugins.splice(
|
||||
node.plugins.indexOf('@babel/plugin-syntax-dynamic-import') + 1,
|
||||
0,
|
||||
'babel-plugin-dynamic-import-node'
|
||||
);
|
||||
node.presets[0] = [node.presets[0], {
|
||||
targets: { node: '8.11.3' }
|
||||
}];
|
||||
|
||||
if (env === 'node' || env.startsWith('node:')) {
|
||||
return node;
|
||||
}
|
||||
|
||||
return {};
|
||||
};
|
|
@ -0,0 +1,75 @@
|
|||
{
|
||||
"name": "embark-omg",
|
||||
"version": "1.0.0",
|
||||
"description": "OmiseGO plugin for Embark",
|
||||
"main": "dist/index.js",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"lint": "./node_modules/.bin/eslint src/",
|
||||
"babel": "cross-env BABEL_ENV=node babel --out-dir dist src --source-maps",
|
||||
"build": "npm-run-all build:**",
|
||||
"build:node": "cross-env BABEL_ENV=node babel src --extensions \".js\" --out-dir dist --source-maps",
|
||||
"// build:node:test": "cross-env BABEL_ENV=node:test babel test --extensions \".js\" --out-dir build-test --source-maps",
|
||||
"ci": "npm run qa",
|
||||
"clean": "npm run reset",
|
||||
"package": "npm pack",
|
||||
"qa": "npm-run-all build test package",
|
||||
"reset": "npx rimraf .nyc_output build-test coverage dist embark-omg-*.tgz package",
|
||||
"start": "npm run watch",
|
||||
"// test": "nyc --reporter=html --reporter=json mocha \"build-test/**/*.js\" --exit --no-timeouts --require source-map-support/register",
|
||||
"watch": "run-p \"build:** -- --verbose --watch\""
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/emizzle/embark-omg.git"
|
||||
},
|
||||
"keywords": [
|
||||
"Embark",
|
||||
"OmiseGO",
|
||||
"blockchain",
|
||||
"Ethereum"
|
||||
],
|
||||
"author": "eric.mastro@gmail.com",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/emizzle/embark-omg/issues"
|
||||
},
|
||||
"homepage": "https://github.com/emizzle/embark-omg#readme",
|
||||
"dependencies": {
|
||||
"@babel/plugin-proposal-optional-chaining": "7.2.0",
|
||||
"@babel/runtime-corejs2": "7.3.1",
|
||||
"@omisego/omg-js": "1.2.2",
|
||||
"@omisego/omg-js-childchain": "1.2.1",
|
||||
"@omisego/omg-js-rootchain": "1.2.2",
|
||||
"@omisego/omg-js-util": "1.2.1",
|
||||
"async": "3.0.1",
|
||||
"axios": "0.19.0",
|
||||
"date-fns": "2.0.0-alpha.27",
|
||||
"embark-utils": "^4.1.0-beta.2",
|
||||
"embarkjs-omg": "1.0.0",
|
||||
"ethers": "4.0.28"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.2.3",
|
||||
"@babel/core": "7.2.2",
|
||||
"@babel/plugin-proposal-class-properties": "7.4.4",
|
||||
"@babel/plugin-proposal-decorators": "7.4.4",
|
||||
"@babel/plugin-syntax-dynamic-import": "7.2.0",
|
||||
"@babel/plugin-transform-runtime": "7.4.0",
|
||||
"@babel/preset-env": "7.4.1",
|
||||
"babel-plugin-dynamic-import-node": "2.2.0",
|
||||
"babel-plugin-macros": "2.6.0",
|
||||
"cross-env": "5.2.0",
|
||||
"eslint": "4.19.1",
|
||||
"lodash.clonedeep": "4.5.0",
|
||||
"npm-run-all": "4.1.5",
|
||||
"rimraf": "2.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.12.0 <12.0.0",
|
||||
"npm": ">=6.4.1",
|
||||
"yarn": ">=1.12.3"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,276 @@
|
|||
import EmbarkJSOmg from "embarkjs-omg";
|
||||
import EmbarkUtils from "./utils/embark";
|
||||
import { dappPath } from "embark-utils";
|
||||
import { formatDate } from "./utils";
|
||||
import { getWatcherStatus } from "./utils/plasma";
|
||||
import { waterfall } from "async";
|
||||
|
||||
// Service check constants
|
||||
const SERVICE_CHECK_ON = 'on';
|
||||
const SERVICE_CHECK_OFF = 'off';
|
||||
|
||||
/**
|
||||
* Plugin that allows Embark to connect to and interact with an existing Plama chain,
|
||||
* and provides an EmbarkJS.Plasma API to allow the DApp to interact with the chain.
|
||||
*/
|
||||
class EmbarkOmg extends EmbarkJSOmg {
|
||||
constructor(embark) {
|
||||
super(embark);
|
||||
|
||||
this.embark = embark;
|
||||
this.events = embark.events;
|
||||
this.pluginConfig = embark.pluginConfig;
|
||||
this.accounts = [];
|
||||
|
||||
// gets hydrated blockchain config from embark, use it to init
|
||||
this.events.once('config:load:blockchain', (blockchainConfig) => {
|
||||
this.logger.info("blockchain config loaded...");
|
||||
this.embarkUtils = new EmbarkUtils({ events: this.events, logger: this.logger, blockchainConfig });
|
||||
|
||||
this.init().then(() => {
|
||||
this.addCodeToEmbarkJs();
|
||||
});
|
||||
});
|
||||
|
||||
this.registerServiceCheck();
|
||||
this.registerConsoleCommands();
|
||||
}
|
||||
|
||||
async init() {
|
||||
// init account used for root and child chains
|
||||
try {
|
||||
const accounts = await this.embarkUtils.accounts;
|
||||
this.accounts = accounts;
|
||||
} catch (e) {
|
||||
return this.logger.error(`Error getting accounts from Embark's config: ${e}`);
|
||||
}
|
||||
try {
|
||||
this.web3Path = await this.embarkUtils.web3Path;
|
||||
}
|
||||
catch (e) {
|
||||
this.logger.error(`Error getting web3 from Embark: ${e}`);
|
||||
}
|
||||
try {
|
||||
await super.init(this.accounts, this.web3Path);
|
||||
this.events.emit("embark-omg:init");
|
||||
}
|
||||
catch (e) {
|
||||
this.logger.error(`Error initializing EmbarkOmg: ${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
generateSymlink(varName, location) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.events.request('code-generator:symlink:generate', location, varName, (err, symlinkDest) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
resolve(symlinkDest);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
codeGeneratorReady() {
|
||||
return new Promise((resolve, _reject) => {
|
||||
this.events.request('code-generator:ready', () => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async addCodeToEmbarkJs() {
|
||||
const nodePath = dappPath('node_modules');
|
||||
const embarkjsOmgPath = require.resolve("embarkjs-omg", { paths: [nodePath] });
|
||||
let web3SymlinkPath, embarkJsOmgSymlinkPath;
|
||||
|
||||
await this.codeGeneratorReady();
|
||||
|
||||
// create a symlink to web3 - this is currently the job of the web3 connector, so either this will run
|
||||
// first or the connector will overwrite it.
|
||||
try {
|
||||
web3SymlinkPath = await this.generateSymlink('web3', this.web3Path);
|
||||
}
|
||||
catch (err) {
|
||||
this.logger.error(__('Error creating a symlink to web3'));
|
||||
return this.logger.error(err.message || err);
|
||||
}
|
||||
try {
|
||||
embarkJsOmgSymlinkPath = await this.generateSymlink('embarkjs-omg', embarkjsOmgPath);
|
||||
}
|
||||
catch (err) {
|
||||
this.logger.error(__('Error creating a symlink to embarkjs-omg'));
|
||||
return this.logger.error(err.message || err);
|
||||
}
|
||||
|
||||
this.events.emit('runcode:register', 'embarkjsOmg', require('embarkjs-omg'), () => {
|
||||
let code = "";
|
||||
code += `\nlet __embarkPlasma = global.embarkjsOmg || require('${embarkJsOmgSymlinkPath}').default;`;
|
||||
//code += `\nWeb3 = global.embarkjsOmg || require('${embarkJsOmgSymlinkPath}').default;`;
|
||||
code += `\nconst opts = {
|
||||
logger: {
|
||||
info: console.log,
|
||||
error: console.error,
|
||||
trace: console.trace
|
||||
},
|
||||
pluginConfig: ${JSON.stringify(this.pluginConfig)}
|
||||
};`;
|
||||
code += "\nEmbarkJS.onReady(() => {";
|
||||
code += "\n EmbarkJS.Plasma = new __embarkPlasma(opts);";
|
||||
// code += `\n EmbarkJS.Plasma.init(${JSON.stringify(this.accounts)}, "${web3SymlinkPath}");`;
|
||||
code += `\n EmbarkJS.Plasma.init(${JSON.stringify(this.accounts)}, global.embarkjsOmg ? "${web3SymlinkPath}" : null);`; // pass the symlink path ONLY when we are in the node (VM) context
|
||||
code += "\n});";
|
||||
|
||||
this.embark.addCodeToEmbarkJS(code);
|
||||
});
|
||||
}
|
||||
|
||||
registerConsoleCommands() {
|
||||
this.embark.registerConsoleCommand({
|
||||
description: `Initialises the Plasma chain using the account configured in the DApp's blockchain configuration. All transactions on the child chain will use this as the 'from' account.`,
|
||||
matches: ["plasma init", "plasma init --force"],
|
||||
usage: "plasma init [--force]",
|
||||
process: (cmd, callback) => {
|
||||
const force = cmd.endsWith("--force");
|
||||
if (this.inited && !force) {
|
||||
return callback("The Plasma chain is already initialized. If you'd like to reinitialize the chain, use the --force option ('plasma init --force')."); // passes a message back to cockpit console
|
||||
}
|
||||
this.init()
|
||||
.then((message) => {
|
||||
callback(null, message);
|
||||
})
|
||||
.catch(callback);
|
||||
}
|
||||
});
|
||||
|
||||
const depositRegex = /^plasma[\s]+deposit[\s]+([0-9]+)$/;
|
||||
this.embark.registerConsoleCommand({
|
||||
description: "Deposits ETH from the root chain (Rinkeby) to the Plasma chain to be used for transacting on the Plasma chain.",
|
||||
matches: (cmd) => {
|
||||
return depositRegex.test(cmd);
|
||||
},
|
||||
usage: "plasma deposit [amount]",
|
||||
process: (cmd, callback) => {
|
||||
if (!this.inited) {
|
||||
return callback("The Plasma chain has not been initialized. Please initialize the Plamsa chain using 'plasma init' before continuting."); // passes a message back to cockpit console
|
||||
}
|
||||
const matches = cmd.match(depositRegex) || [];
|
||||
if (matches.length <= 1) {
|
||||
return callback("Invalid command format, please use the format 'plasma deposit [amount]', ie 'plasma deposit 100000'");
|
||||
}
|
||||
this.deposit(matches[1])
|
||||
.then((message) => {
|
||||
callback(null, message);
|
||||
})
|
||||
.catch(callback);
|
||||
}
|
||||
});
|
||||
|
||||
const sendRegex = /^plasma[\s]+send[\s]+(0x[0-9,a-f,A-F]{40,40})[\s]+([0-9]+)$/;
|
||||
this.embark.registerConsoleCommand({
|
||||
description: "Sends an ETH tx on the Plasma chain from the account configured in the DApp's blockchain configuration to any other account on the Plasma chain.",
|
||||
matches: (cmd) => {
|
||||
return sendRegex.test(cmd);
|
||||
},
|
||||
usage: "plasma send [to_address] [amount]",
|
||||
process: (cmd, callback) => {
|
||||
if (!this.inited) {
|
||||
return callback("The Plasma chain has not been initialized. Please initialize the Plamsa chain using 'plasma init' before continuting."); // passes a message back to cockpit console
|
||||
}
|
||||
const matches = cmd.match(sendRegex) || [];
|
||||
if (matches.length <= 2) {
|
||||
return callback("Invalid command format, please use the format 'plasma send [to_address] [amount]', ie 'plasma send 0x38d5beb778b6e62d82e3ba4633e08987e6d0f990 555'");
|
||||
}
|
||||
this.send(matches[1], matches[2])
|
||||
.then((message) => {
|
||||
callback(null, message);
|
||||
})
|
||||
.catch(callback);
|
||||
}
|
||||
});
|
||||
|
||||
const exitRegex = /^plasma[\s]+exit[\s]+(0x[0-9,a-f,A-F]{40,40})$/;
|
||||
this.embark.registerConsoleCommand({
|
||||
description: "Exits the ETH from the Plasma chain to the Rinkeby chain.",
|
||||
matches: (cmd) => {
|
||||
return exitRegex.test(cmd);
|
||||
},
|
||||
usage: "plasma exit [plasma_chain_address]",
|
||||
process: (cmd, callback) => {
|
||||
if (!this.inited) {
|
||||
return callback("The Plasma chain has not been initialized. Please initialize the Plamsa chain using 'plasma init' before continuting."); // passes a message back to cockpit console
|
||||
}
|
||||
const matches = cmd.match(exitRegex) || [];
|
||||
if (matches.length <= 1) {
|
||||
return callback("Invalid command format, please use the format 'plasma exit [plasma_chain_address]', ie 'plasma exit 0x38d5beb778b6e62d82e3ba4633e08987e6d0f990'");
|
||||
}
|
||||
this.exit(matches[1]).then((message) => {
|
||||
callback(null, message);
|
||||
}).catch((e) => {
|
||||
callback(e.message);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.embark.registerConsoleCommand({
|
||||
description: "Gets the status of the Plasma chain.",
|
||||
matches: ["plasma status"],
|
||||
process: (cmd, callback) => {
|
||||
getWatcherStatus(this.pluginConfig.WATCHER_URL).then((status) => {
|
||||
callback(null, JSON.stringify(status));
|
||||
}).catch((e) => {
|
||||
callback(e.message);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this plugin for Embark service checks and sets up log messages for
|
||||
* connection and disconnection events. The service check pings the Status app.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
registerServiceCheck() {
|
||||
const name = "OMG Plasma Chain";
|
||||
|
||||
this.events.request("services:register", name, (cb) => {
|
||||
|
||||
waterfall([
|
||||
(next) => {
|
||||
if (this.inited) {
|
||||
return next();
|
||||
}
|
||||
this.events.once("embark-omg:init", next);
|
||||
},
|
||||
(next) => {
|
||||
// TODO: web3_clientVersion method is currently not implemented in web3.js 1.0
|
||||
getWatcherStatus(this.pluginConfig.WATCHER_URL)
|
||||
.then((status) => {
|
||||
const serviceStatus = `Last block: ${formatDate(status.last_mined_child_block_timestamp)}`;
|
||||
next(null, { name: serviceStatus, status: status ? SERVICE_CHECK_ON : SERVICE_CHECK_OFF });
|
||||
})
|
||||
.catch(next);
|
||||
}
|
||||
], (err, statusObj) => {
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
cb(statusObj);
|
||||
});
|
||||
}, 5000, 'off');
|
||||
|
||||
this.events.on('check:backOnline:OmiseGO', () => {
|
||||
this.logger.info("------------------");
|
||||
this.logger.info("Connected to the Plama chain!");
|
||||
this.logger.info("------------------");
|
||||
});
|
||||
|
||||
this.events.on('check:wentOffline:OmiseGO', () => {
|
||||
this.logger.error("------------------");
|
||||
this.logger.error("Couldn't connect or lost connection to the Plasma chain...");
|
||||
this.logger.error("------------------");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default EmbarkOmg;
|
|
@ -0,0 +1,42 @@
|
|||
import { AccountParser, dappPath, embarkPath } from "embark-utils";
|
||||
|
||||
export default class EmbarkUtils {
|
||||
constructor({ events, logger, blockchainConfig }) {
|
||||
this.events = events;
|
||||
this.logger = logger;
|
||||
this.blockchainConfig = blockchainConfig;
|
||||
}
|
||||
get accounts() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.events.request("blockchain:ready", () => {
|
||||
this.events.request("blockchain:get", (embarkWeb3) => {
|
||||
try {
|
||||
const accountsParsed = AccountParser.parseAccountsConfig(this.blockchainConfig.accounts, embarkWeb3, dappPath(), this.logger, []);
|
||||
resolve(accountsParsed);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
get web3Path() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.events.request("version:get:web3", (web3Version) => {
|
||||
if (web3Version === "1.0.0-beta") {
|
||||
const nodePath = embarkPath('node_modules');
|
||||
const web3Path = require.resolve("web3", { paths: [nodePath] });
|
||||
return resolve(web3Path);
|
||||
}
|
||||
this.events.request("version:getPackageLocation", "web3", web3Version, (err, location) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
const locationPath = embarkPath(location).replace(/\\/g, '/');
|
||||
resolve(locationPath);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import { formatDistance } from 'date-fns';
|
||||
|
||||
/**
|
||||
* Formats an int date into a displayable date
|
||||
* @param {Number} intDate - date in seconds
|
||||
* @returns {String} prettyfied date
|
||||
*/
|
||||
export function formatDate(intDate) {
|
||||
const padZeros = 13 - intDate.toString().length;
|
||||
if (padZeros > 0) {
|
||||
intDate *= Math.pow(10, padZeros);
|
||||
}
|
||||
return formatDistance(new Date(intDate), new Date()) + ' ago';
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import { post } from "axios";
|
||||
|
||||
export async function getWatcherStatus(watcherUrl) {
|
||||
const response = await post(`${watcherUrl}/status.get`);
|
||||
if (!(response.status === 200 && response.data && response.data.success)) {
|
||||
throw new Error(`Error getting status of the Plasma watcher`);
|
||||
}
|
||||
return response.data.data;
|
||||
}
|
Loading…
Reference in New Issue