diff --git a/.gitignore b/.gitignore index b512c09..cee5989 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -node_modules \ No newline at end of file +node_modules +/dist/ diff --git a/.urbitrc b/.urbitrc index b53c38e..e41200d 100644 --- a/.urbitrc +++ b/.urbitrc @@ -1,5 +1,5 @@ module.exports = { URBIT_PIERS: [ - "%URBITPIER%", + "/home/do7ze5/urbit/dus/home", ] }; diff --git a/README.md b/README.md index 6ffa183..927cd63 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ -Get started building a simple application for Landscape on your [Urbit](http://urbit.org) ship with a few commands. +Implementation of the urbit bounty Display ETH Data +Link: https://grants.urbit.org/bounties/831044524-display-eth-data -This tool is experimental and primarily used internally to develop front-end applications. While Tlon does not officially support this tool, you can always get general programming help for Urbit in the `~dopzod/urbit-help` chat. +It is an ethereum event viewer gall + landscape app which can be used to listen for ethereum contract events. ## Installation @@ -12,10 +13,6 @@ In order to run your application on your ship, you will need Urbit v.0.10.0 or h Once you're up and running, your tile lives in `tile/tile.js`, which uses [React](https://reactjs.org) to render itself -- you'll want a basic foothold with it first. When you make changes, the `urbit` directory will update with the compiled application and, if you're running `npm run serve`, it will automatically copy itself to your Urbit ship when you save your changes (more information on that below). -### `npm start` - -This runs the wizard. Give it an application name and the location of your Urbit ship's desk and it will customise the files so your new application will run on your ship. - ### `npm run build` This builds your application and copies it into your Urbit ship's desk. In your Urbit (v.0.8.0 or higher) `|commit %home` (or `%your-desk-name`) to synchronise your changes. @@ -26,25 +23,3 @@ If this is the first time you're running your application on your Urbit ship, do Builds the application and copies it into your Urbit ship's desk, watching for changes. In your Urbit (v.0.8.0 or higher) `|commit %home` (or `%your-desk-name`) to synchronise your changes. -## FAQ - -### What is a "tile" vs. "full" app? - -When you run `npm run start`, the wizard will ask you to specify which you want: - -- **tile**: A tile that exists on the Landscape launch screen. A pre-existing example is the "Weather" tile or the "Clock" tile in Landscape. -- **full**: A tile that links to a full-screen application: this means that you will work in both `tile.js` (for the tile interface) and `root.js` (and beyond) in the `src` folder. - -No matter which option you specify, the wizard will customise the Hoon boilerplate for you and provide a basic example accordingly. - -### How can I ensure my app fits Landscape design? - -Landscape makes use of the [Indigo](https://urbit.github.io/indigo-react/) CSS framework. The template tile and full application both make use of it as an example for you to get going fast. - -### What if I want to communicate with my ship / provide more functionality besides a front-end? - -By default, your app will provide an example of passing state from ship to front-end with the `peer-[yourappname]tile` arm in the app's .hoon file -- in this case, just sending your ship's name as a data prop. The code is well-commented if you don't want to pass state, or if you want to know how to pass almost anything else from your ship to the Landscape interface. - -In order to do anything substantial, of course, you'll want to know [Hoon](https://urbit.org/docs/tutorials/hoon/). If this is intimidating, don't panic: `create-landscape-app` is a fantastic way to start learning by leveraging your strengths. This repository is intended to be a boilerplate for rapid front-end development; it's also a gradual, incremental introduction to Hoon for web developers by allowing for rapid prototyping and experimentation with the Landscape interface. - -Happy hacking! diff --git a/full/gulpfile.js b/full/gulpfile.js deleted file mode 100644 index eb8b6a3..0000000 --- a/full/gulpfile.js +++ /dev/null @@ -1,164 +0,0 @@ -var gulp = require('gulp'); -var cssimport = require('gulp-cssimport'); -var rollup = require('gulp-better-rollup'); -var cssnano = require('cssnano'); -var postcss = require('gulp-postcss'); -var sucrase = require('@sucrase/gulp-plugin'); -var minify = require('gulp-minify'); - -var resolve = require('rollup-plugin-node-resolve'); -var commonjs = require('rollup-plugin-commonjs'); -var rootImport = require('rollup-plugin-root-import'); -var globals = require('rollup-plugin-node-globals'); - -/*** - Main config options -***/ - -var urbitrc = require('./.urbitrc'); - -/*** - End main config options -***/ - -gulp.task('css-bundle', function() { - let plugins = [ - cssnano() - ]; - return gulp - .src('src/index.css') - .pipe(cssimport()) - .pipe(postcss(plugins)) - .pipe(gulp.dest('./urbit/app/%APPNAME%/css')); -}); - -gulp.task('jsx-transform', function(cb) { - return gulp.src('src/**/*.js') - .pipe(sucrase({ - transforms: ['jsx'] - })) - .pipe(gulp.dest('dist')); -}); - -gulp.task('tile-jsx-transform', function(cb) { - return gulp.src('tile/**/*.js') - .pipe(sucrase({ - transforms: ['jsx'] - })) - .pipe(gulp.dest('dist')); -}); - -gulp.task('js-imports', function(cb) { - return gulp.src('dist/index.js') - .pipe(rollup({ - plugins: [ - commonjs({ - namedExports: { - 'node_modules/react/index.js': [ 'Component' ], - 'node_modules/react-is/index.js': [ 'isValidElementType' ], - } - }), - rootImport({ - root: `${__dirname}/dist/js`, - useEntry: 'prepend', - extensions: '.js' - }), - globals(), - resolve() - ] - }, 'umd')) - .on('error', function(e){ - console.log(e); - cb(); - }) - .pipe(gulp.dest('./urbit/app/%APPNAME%/js/')) - .on('end', cb); -}); - -gulp.task('tile-js-imports', function(cb) { - return gulp.src('dist/tile.js') - .pipe(rollup({ - plugins: [ - commonjs({ - namedExports: { - 'node_modules/react/index.js': [ 'Component' ], - } - }), - rootImport({ - root: `${__dirname}/dist/js`, - useEntry: 'prepend', - extensions: '.js' - }), - globals(), - resolve() - ] - }, 'umd')) - .on('error', function(e){ - console.log(e); - cb(); - }) - .pipe(gulp.dest('./urbit/app/%APPNAME%/js/')) - .on('end', cb); -}); - - -gulp.task('js-minify', function () { - return gulp.src('./urbit/app/%APPNAME%/js/index.js') - .pipe(minify()) - .pipe(gulp.dest('./urbit/app/%APPNAME%/js/')); -}); - -gulp.task('tile-js-minify', function () { - return gulp.src('./urbit/app/%APPNAME%/js/tile.js') - .pipe(minify()) - .pipe(gulp.dest('./urbit/app/%APPNAME%/js/')); -}); - -gulp.task('urbit-copy', function () { - let ret = gulp.src('urbit/**/*'); - - urbitrc.URBIT_PIERS.forEach(function(pier) { - ret = ret.pipe(gulp.dest(pier)); - }); - - return ret; -}); - -gulp.task('js-bundle-dev', gulp.series('jsx-transform', 'js-imports')); -gulp.task('tile-js-bundle-dev', gulp.series('tile-jsx-transform', 'tile-js-imports')); -gulp.task('js-bundle-prod', gulp.series('jsx-transform', 'js-imports', 'js-minify')) -gulp.task('tile-js-bundle-prod', - gulp.series('tile-jsx-transform', 'tile-js-imports', 'tile-js-minify')); - -gulp.task('bundle-dev', - gulp.series( - gulp.parallel( - 'css-bundle', - 'js-bundle-dev', - 'tile-js-bundle-dev' - ), - 'urbit-copy' - ) -); - -gulp.task('bundle-prod', - gulp.series( - gulp.parallel( - 'css-bundle', - 'js-bundle-prod', - 'tile-js-bundle-prod', - ), - 'urbit-copy' - ) -); - -gulp.task('default', gulp.series('bundle-dev')); - -gulp.task('watch', gulp.series('default', function() { - gulp.watch('tile/**/*.js', gulp.parallel('tile-js-bundle-dev')); - - gulp.watch('src/**/*.js', gulp.parallel('js-bundle-dev')); - gulp.watch('src/**/*.css', gulp.parallel('css-bundle')); - - gulp.watch('urbit/**/*', gulp.parallel('urbit-copy')); -})); diff --git a/full/src/css/custom.css b/full/src/css/custom.css deleted file mode 100644 index fd29b29..0000000 --- a/full/src/css/custom.css +++ /dev/null @@ -1,139 +0,0 @@ -p, h1, h2, h3, h4, h5, h6, a, input, textarea, button { - margin-block-end: unset; - margin-block-start: unset; - -webkit-margin-before: unset; - -webkit-margin-after: unset; - font-family: Inter, sans-serif; -} - -a { - color: #000; - text-decoration: none; -} - -textarea, select, input, button { - outline: none; - -webkit-appearance: none; - border: none; - background-color: #fff; -} - - -h2 { - font-size: 32px; - line-height: 48px; - font-weight: bold; -} - -.body-regular { - font-size: 16px; - line-height: 24px; - font-weight: 600; -} - -.body-large { - font-size: 20px; - line-height: 24px; -} - -.label-regular { - font-size: 14px; - line-height: 24px; -} - -.label-small-mono { - font-size: 12px; - line-height: 24px; - font-family: "Source Code Pro", monospace; -} - -.body-regular-400 { - font-size: 16px; - line-height: 24px; - font-weight: 400; -} - -.plus-font { - font-size: 48px; - line-height: 24px; -} - -.btn-font { - font-size: 14px; - line-height: 16px; - font-weight: 600; -} -.mono { - font-family: "Source Code Pro", monospace; -} - -.inter { - font-family: Inter, sans-serif; -} - -.mix-blend-diff { - mix-blend-mode: difference; -} - -/* dark */ - -@media (prefers-color-scheme: dark) { - body { - background-color: #333; - } - .bg-black-d { - background-color: black; - } - .white-d { - color: white; - } - .gray1-d { - color: #4d4d4d; - } - .gray2-d { - color: #7f7f7f; - } - .gray3-d { - color: #b1b2b3; - } - .gray4-d { - color: #e6e6e6; - } - .bg-gray0-d { - background-color: #333; - } - .bg-gray1-d { - background-color: #4d4d4d; - } - .b--gray0-d { - border-color: #333; - } - .b--gray1-d { - border-color: #4d4d4d; - } - .b--gray2-d { - border-color: #7f7f7f; - } - .b--white-d { - border-color: #fff; - } - .bb-d { - border-bottom-width: 1px; - border-bottom-style: solid; - } - .invert-d { - filter: invert(1); - } - .o-80-d { - opacity: .8; - } - .focus-b--white-d:focus { - border-color: #fff; - } - a { - color: #fff; - } - .hover-bg-gray1-d:hover { - color: #4d4d4d; - } -} diff --git a/full/src/index.css b/full/src/index.css deleted file mode 100644 index 8208efd..0000000 --- a/full/src/index.css +++ /dev/null @@ -1,4 +0,0 @@ -@import 'css/indigo-static.css'; -@import 'css/fonts.css'; -@import 'css/custom.css'; - diff --git a/full/src/js/api.js b/full/src/js/api.js deleted file mode 100644 index 317d454..0000000 --- a/full/src/js/api.js +++ /dev/null @@ -1,49 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import _ from 'lodash'; - -class UrbitApi { - setAuthTokens(authTokens) { - this.authTokens = authTokens; - this.bindPaths = []; - } - - bind(path, method, ship = this.authTokens.ship, appl = "%APPNAME%", success, fail) { - this.bindPaths = _.uniq([...this.bindPaths, path]); - - window.subscriptionId = window.urb.subscribe(ship, appl, path, - (err) => { - fail(err); - }, - (event) => { - success({ - data: event, - from: { - ship, - path - } - }); - }, - (err) => { - fail(err); - }); - } - - %APPNAME%(data) { - this.action("%APPNAME%", "json", data); - } - - action(appl, mark, data) { - return new Promise((resolve, reject) => { - window.urb.poke(ship, appl, mark, data, - (json) => { - resolve(json); - }, - (err) => { - reject(err); - }); - }); - } -} -export let api = new UrbitApi(); -window.api = api; diff --git a/full/src/js/components/root.js b/full/src/js/components/root.js deleted file mode 100644 index f55bc92..0000000 --- a/full/src/js/components/root.js +++ /dev/null @@ -1,33 +0,0 @@ -import React, { Component } from 'react'; -import { BrowserRouter, Route } from "react-router-dom"; -import _ from 'lodash'; -import { HeaderBar } from "./lib/header-bar.js" - - -export class Root extends Component { - constructor(props) { - super(props); - } - - render() { - - return ( - -
- - { - return ( -
-

%APPNAME%

-

Welcome to your Landscape application.

-

To get started, edit src/index.js or %APPNAME%.hoon and |commit %home on your Urbit ship to see your changes.

- -> Read the docs -
- )}} - /> -
-
- ) - } -} - diff --git a/full/tile/tile.js b/full/tile/tile.js deleted file mode 100644 index 17b185e..0000000 --- a/full/tile/tile.js +++ /dev/null @@ -1,19 +0,0 @@ -import React, { Component } from 'react'; -import _ from 'lodash'; - - -export default class %APPNAME%Tile extends Component { - - render() { - return ( -
- -

%APPNAME%

-
-
- ); - } - -} - -window.%APPNAME%Tile = %APPNAME%Tile; diff --git a/full/urbit/app/smol.hoon b/full/urbit/app/smol.hoon deleted file mode 100644 index c852b27..0000000 --- a/full/urbit/app/smol.hoon +++ /dev/null @@ -1,113 +0,0 @@ -/+ *server, default-agent -/= index - /^ octs - /; as-octs:mimes:html - /: /===/app/%APPNAME%/index - /| /html/ - /~ ~ - == -/= tile-js - /^ octs - /; as-octs:mimes:html - /: /===/app/%APPNAME%/js/tile - /| /js/ - /~ ~ - == -/= script - /^ octs - /; as-octs:mimes:html - /: /===/app/%APPNAME%/js/index - /| /js/ - /~ ~ - == -/= style - /^ octs - /; as-octs:mimes:html - /: /===/app/%APPNAME%/css/index - /| /css/ - /~ ~ - == -/= %APPNAME%-png - /^ (map knot @) - /: /===/app/%APPNAME%/img /_ /png/ -:: -|% -+$ card card:agent:gall --- -^- agent:gall -=< - |_ bol=bowl:gall - +* this . - %APPNAME%-core +> - cc ~(. %APPNAME%-core bol) - def ~(. (default-agent this %|) bol) - :: - ++ on-init - ^- (quip card _this) - =/ launcha [%launch-action !>([%%APPNAME% / '/~%APPNAME%/js/tile.js'])] - :_ this - :~ [%pass / %arvo %e %connect [~ /'~%APPNAME%'] %%APPNAME%] - [%pass /%APPNAME% %agent [our.bol %launch] %poke launcha] - == - ++ on-poke - |= [=mark =vase] - ^- (quip card _this) - ?> (team:title our.bol src.bol) - ?+ mark (on-poke:def mark vase) - %handle-http-request - =+ !<([eyre-id=@ta =inbound-request:eyre] vase) - :_ this - %+ give-simple-payload:app eyre-id - %+ require-authorization:app inbound-request - poke-handle-http-request:cc - :: - == - :: - ++ on-watch - |= =path - ^- (quip card:agent:gall _this) - ?: ?=([%http-response *] path) - `this - ?. =(/ path) - (on-watch:def path) - [[%give %fact ~ %json !>(*json)]~ this] - :: - ++ on-agent on-agent:def - :: - ++ on-arvo - |= [=wire =sign-arvo] - ^- (quip card _this) - ?. ?=(%bound +<.sign-arvo) - (on-arvo:def wire sign-arvo) - [~ this] - :: - ++ on-save on-save:def - ++ on-load on-load:def - ++ on-leave on-leave:def - ++ on-peek on-peek:def - ++ on-fail on-fail:def - -- -:: -:: -|_ bol=bowl:gall -:: -++ poke-handle-http-request - |= =inbound-request:eyre - ^- simple-payload:http - =+ url=(parse-request-line url.request.inbound-request) - ?+ site.url not-found:gen - [%'~%APPNAME%' %css %index ~] (css-response:gen style) - [%'~%APPNAME%' %js %tile ~] (js-response:gen tile-js) - [%'~%APPNAME%' %js %index ~] (js-response:gen script) - :: - [%'~%APPNAME%' %img @t *] - =/ name=@t i.t.t.site.url - =/ img (~(get by %APPNAME%-png) name) - ?~ img - not-found:gen - (png-response:gen (as-octs:mimes:html u.img)) - :: - [%'~%APPNAME%' *] (html-response:gen index) - == -:: --- \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 32eaa0f..53aaafe 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,5 +1,8 @@ var gulp = require('gulp'); +var cssimport = require('gulp-cssimport'); var rollup = require('gulp-better-rollup'); +var cssnano = require('cssnano'); +var postcss = require('gulp-postcss'); var sucrase = require('@sucrase/gulp-plugin'); var minify = require('gulp-minify'); @@ -18,6 +21,25 @@ var urbitrc = require('./.urbitrc'); End main config options ***/ +gulp.task('css-bundle', function() { + let plugins = [ + cssnano() + ]; + return gulp + .src('src/index.css') + .pipe(cssimport()) + .pipe(postcss(plugins)) + .pipe(gulp.dest('./urbit/app/eth-event-viewer/css')); +}); + +gulp.task('jsx-transform', function(cb) { + return gulp.src('src/**/*.js') + .pipe(sucrase({ + transforms: ['jsx'] + })) + .pipe(gulp.dest('dist')); +}); + gulp.task('tile-jsx-transform', function(cb) { return gulp.src('tile/**/*.js') .pipe(sucrase({ @@ -26,6 +48,32 @@ gulp.task('tile-jsx-transform', function(cb) { .pipe(gulp.dest('dist')); }); +gulp.task('js-imports', function(cb) { + return gulp.src('dist/index.js') + .pipe(rollup({ + plugins: [ + commonjs({ + namedExports: { + 'node_modules/react/index.js': [ 'Component' ], + 'node_modules/react-is/index.js': [ 'isValidElementType' ], + } + }), + rootImport({ + root: `${__dirname}/dist/js`, + useEntry: 'prepend', + extensions: '.js' + }), + globals(), + resolve() + ] + }, 'umd')) + .on('error', function(e){ + console.log(e); + cb(); + }) + .pipe(gulp.dest('./urbit/app/eth-event-viewer/js/')) + .on('end', cb); +}); gulp.task('tile-js-imports', function(cb) { return gulp.src('dist/tile.js') @@ -49,14 +97,21 @@ gulp.task('tile-js-imports', function(cb) { console.log(e); cb(); }) - .pipe(gulp.dest('./urbit/app/%APPNAME%/js/')) + .pipe(gulp.dest('./urbit/app/eth-event-viewer/js/')) .on('end', cb); }); + +gulp.task('js-minify', function () { + return gulp.src('./urbit/app/eth-event-viewer/js/index.js') + .pipe(minify()) + .pipe(gulp.dest('./urbit/app/eth-event-viewer/js/')); +}); + gulp.task('tile-js-minify', function () { - return gulp.src('./urbit/app/%APPNAME%/js/tile.js') + return gulp.src('./urbit/app/eth-event-viewer/js/tile.js') .pipe(minify()) - .pipe(gulp.dest('./urbit/app/%APPNAME%/js/')); + .pipe(gulp.dest('./urbit/app/eth-event-viewer/js/')); }); gulp.task('urbit-copy', function () { @@ -69,14 +124,41 @@ gulp.task('urbit-copy', function () { return ret; }); +gulp.task('js-bundle-dev', gulp.series('jsx-transform', 'js-imports')); gulp.task('tile-js-bundle-dev', gulp.series('tile-jsx-transform', 'tile-js-imports')); -gulp.task('tile-js-bundle-prod', +gulp.task('js-bundle-prod', gulp.series('jsx-transform', 'js-imports', 'js-minify')) +gulp.task('tile-js-bundle-prod', gulp.series('tile-jsx-transform', 'tile-js-imports', 'tile-js-minify')); -gulp.task('bundle-prod', gulp.series('tile-js-bundle-prod', 'urbit-copy')); +gulp.task('bundle-dev', + gulp.series( + gulp.parallel( + 'css-bundle', + 'js-bundle-dev', + 'tile-js-bundle-dev' + ), + 'urbit-copy' + ) +); + +gulp.task('bundle-prod', + gulp.series( + gulp.parallel( + 'css-bundle', + 'js-bundle-prod', + 'tile-js-bundle-prod', + ), + 'urbit-copy' + ) +); + +gulp.task('default', gulp.series('bundle-dev')); -gulp.task('default', gulp.series('tile-js-bundle-dev', 'urbit-copy')); gulp.task('watch', gulp.series('default', function() { gulp.watch('tile/**/*.js', gulp.parallel('tile-js-bundle-dev')); + + gulp.watch('src/**/*.js', gulp.parallel('js-bundle-dev')); + gulp.watch('src/**/*.css', gulp.parallel('css-bundle')); + gulp.watch('urbit/**/*', gulp.parallel('urbit-copy')); })); diff --git a/package-lock.json b/package-lock.json index eb1a54c..ed4f1dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "create-landscape-app", - "version": "2.0.0", + "version": "3.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -401,7 +401,8 @@ }, "kind-of": { "version": "6.0.2", - "resolved": "", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true } } @@ -461,6 +462,11 @@ } } }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, "browserslist": { "version": "4.6.6", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.6.tgz", @@ -490,6 +496,11 @@ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, + "buffer-to-arraybuffer": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", + "integrity": "sha1-YGSkD6dutDxyOrqe+PbhIW0QURo=" + }, "builtin-modules": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", @@ -1047,8 +1058,15 @@ "decode-uri-component": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "requires": { + "mimic-response": "^1.0.0" + } }, "deep-equal": { "version": "0.2.2", @@ -1183,6 +1201,11 @@ } } }, + "dom-walk": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", + "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=" + }, "domelementtype": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", @@ -1236,6 +1259,20 @@ "integrity": "sha512-SU9yyql6uA0Fc8bWR7sCYNGBtxkC+tQb6UaC7ReaadN42Kx7Ka+dzx3lAIm9Ock+ULEawJuTFcVB2x34uOCg0Q==", "dev": true }, + "elliptic": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", + "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", @@ -1351,6 +1388,40 @@ "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", "dev": true }, + "eth-lib": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", + "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "ethereum-bloom-filters": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.6.tgz", + "integrity": "sha512-dE9CGNzgOOsdh7msZirvv8qjHtnHpvBlKe2647kM8v+yeF71IRso55jpojemvHV+jMjr48irPWxMRaHuOWzAFA==", + "requires": { + "js-sha3": "^0.8.0" + } + }, + "ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha1-xmWSHkduh7ziqdWIpv4EBbLEFpk=", + "requires": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" + } + } + }, "eventemitter3": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz", @@ -1480,7 +1551,8 @@ }, "kind-of": { "version": "6.0.2", - "resolved": "", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true } } @@ -1643,7 +1715,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -1664,12 +1737,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1684,17 +1759,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -1811,7 +1889,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -1823,6 +1902,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -1837,6 +1917,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -1844,12 +1925,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -1868,6 +1951,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -1948,7 +2032,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -1960,6 +2045,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -2045,7 +2131,8 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -2081,6 +2168,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -2100,6 +2188,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -2143,12 +2232,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, @@ -2249,6 +2340,15 @@ "object.defaults": "^1.1.0" } }, + "global": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz", + "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", + "requires": { + "min-document": "^2.19.0", + "process": "~0.5.1" + } + }, "global-modules": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", @@ -2673,6 +2773,15 @@ } } }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, "hex-color-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", @@ -2692,6 +2801,16 @@ "value-equal": "^0.4.0" } }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "hoist-non-react-statics": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz", @@ -2965,6 +3084,11 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, + "is-function": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.1.tgz", + "integrity": "sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU=" + }, "is-glob": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", @@ -2974,6 +3098,11 @@ "is-extglob": "^2.1.1" } }, + "is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha1-fY035q135dEnFIkTxXPggtd39VQ=" + }, "is-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", @@ -3110,6 +3239,11 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, + "js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3487,6 +3621,19 @@ } } }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, + "min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", + "requires": { + "dom-walk": "^0.1.0" + } + }, "mini-create-react-context": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.3.2.tgz", @@ -3497,6 +3644,16 @@ "tiny-warning": "^1.0.2" } }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -3723,6 +3880,22 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, + "number-to-bn": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", + "integrity": "sha1-uzYjWS9+X54AMLGXe9QaDFP+HqA=", + "requires": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" + } + } + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -3965,6 +4138,11 @@ "path-root": "^0.1.1" } }, + "parse-headers": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.3.tgz", + "integrity": "sha512-QhhZ+DCCit2Coi2vmAKbq5RGTRcQUOE2+REgv8vdyu7MnYx2eZztegqtTx99TZ86GTIwqiy3+4nQTWZ2tgmdCA==" + }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -4486,6 +4664,11 @@ "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", "dev": true }, + "process": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", + "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=" + }, "process-es6": { "version": "0.11.6", "resolved": "https://registry.npmjs.org/process-es6/-/process-es6-0.11.6.tgz", @@ -4556,6 +4739,24 @@ "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", "dev": true }, + "query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "requires": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, "react": { "version": "16.8.6", "resolved": "https://registry.npmjs.org/react/-/react-16.8.6.tgz", @@ -5005,8 +5206,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safe-regex": { "version": "1.1.0", @@ -5075,6 +5275,21 @@ } } }, + "simple-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", + "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=" + }, + "simple-get": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz", + "integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==", + "requires": { + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", @@ -5185,7 +5400,8 @@ }, "kind-of": { "version": "6.0.2", - "resolved": "", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true } } @@ -5369,6 +5585,11 @@ "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", "dev": true }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -5405,6 +5626,14 @@ "is-utf8": "^0.2.0" } }, + "strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha1-DF8VX+8RUTczd96du1iNoFUA428=", + "requires": { + "is-hex-prefixed": "1.0.0" + } + }, "stylehacks": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", @@ -5545,6 +5774,11 @@ "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", "dev": true }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" + }, "timsort": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", @@ -5666,6 +5900,11 @@ "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", "dev": true }, + "underscore": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", + "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" + }, "undertaker": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.1.tgz", @@ -5821,12 +6060,22 @@ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", "dev": true }, + "url-set-query": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", + "integrity": "sha1-AW6M/Xwg7gXK/neV6JK9BwL6ozk=" + }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, + "utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==" + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -5976,6 +6225,21 @@ "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==", "dev": true }, + "web3-utils": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.6.tgz", + "integrity": "sha512-8/HnqG/l7dGmKMgEL9JeKPTtjScxOePTzopv5aaKFExPfaBrYRkgoMqhoowCiAl/s16QaTn4DoIF1QC4YsT7Mg==", + "requires": { + "bn.js": "4.11.8", + "eth-lib": "0.2.7", + "ethereum-bloom-filters": "^1.0.6", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "underscore": "1.9.1", + "utf8": "3.0.0" + } + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -6036,6 +6300,39 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "xhr": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.5.0.tgz", + "integrity": "sha512-4nlO/14t3BNUZRXIXfXe+3N6w3s1KoxcJUUURctd64BLRe67E4gRwp4PjywtDY72fXpZ1y6Ch0VZQRY/gMPzzQ==", + "requires": { + "global": "~4.3.0", + "is-function": "^1.0.1", + "parse-headers": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "xhr-request": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz", + "integrity": "sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==", + "requires": { + "buffer-to-arraybuffer": "^0.0.5", + "object-assign": "^4.1.1", + "query-string": "^5.0.1", + "simple-get": "^2.7.0", + "timed-out": "^4.0.1", + "url-set-query": "^1.0.0", + "xhr": "^2.0.4" + } + }, + "xhr-request-promise": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.2.tgz", + "integrity": "sha1-NDxE0e53JrhkgGloLQ+EDIO0Jh0=", + "requires": { + "xhr-request": "^1.0.1" + } + }, "xml-lexer": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/xml-lexer/-/xml-lexer-0.2.2.tgz", @@ -6056,8 +6353,7 @@ "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" }, "y18n": { "version": "4.0.0", diff --git a/package.json b/package.json index 85d40cf..dc966f9 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,8 @@ "react-router-dom": "^5.0.0", "replace-in-file": "^4.1.1", "urbit-ob": "^4.1.2", - "urbit-sigil-js": "^1.3.13" + "urbit-sigil-js": "^1.3.13", + "web3-utils": "^1.2.6" }, "resolutions": { "natives": "1.1.3" diff --git a/src/css/custom.css b/src/css/custom.css new file mode 100644 index 0000000..94a3d81 --- /dev/null +++ b/src/css/custom.css @@ -0,0 +1,282 @@ +* { + -webkit-font-smoothing: antialiased; + -webkit-touch-callout: none; +} + +html, body { + height: 100%; + width: 100%; +} + +p, h1, h2, h3, h4, h5, h6, a, input, textarea, button { + margin-block-end: unset; + margin-block-start: unset; + -webkit-margin-before: unset; + -webkit-margin-after: unset; + font-family: Inter, sans-serif; + padding: 0; +} + +textarea, input, button { + outline: none; + -webkit-appearance: none; + border: none; + background-color: #fff; +} + +a { + color: #000; + font-weight: 400; + text-decoration: none; +} + +h2 { + font-weight: 400; +} + +.body-large { + font-size: 20px; + line-height: 24px; +} + +.body-medium { + font-size: 16px; + line-height: 19px; +} + +.body-small { + font-size: 12px; + line-height: 16px; + color: #7f7f7f; +} + +.label-regular { + font-size: 14px; +} + +.inter { + font-family: Inter, sans-serif; +} + +.clamp-3 { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +.clamp-message { + max-width: calc(100% - 36px - 1.5rem); +} + +.clamp-attachment { + overflow: scroll; + max-height: 10em; + max-width: 100%; +} + +.lh-16 { + line-height: 16px; +} + +.mono { + font-family: "Source Code Pro", monospace; +} + +.list-ship { + line-height: 2.2; +} + +.c-default { + cursor: default; +} + +.word-break-all { + word-break: break-all; +} + +.focus-b--black:focus { + border-color: #000; +} + +.mix-blend-diff { + mix-blend-mode: difference; +} + +.placeholder-inter::placeholder { + font-family: "Inter", sans-serif; +} + +/* spinner */ + +.spin-active { + animation: spin 2s infinite; +} + +@keyframes spin { + 0% {transform: rotate(0deg);} + 25% {transform: rotate(90deg);} + 50% {transform: rotate(180deg);} + 75% {transform: rotate(270deg);} + 100% {transform: rotate(360deg);} +} + +/* embeds */ +.embed-container { + position: relative; + height: 0; + overflow: hidden; + padding-bottom: 28.125%; +} + +.embed-container iframe, .embed-container object, .embed-container embed { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.mh-16 { + max-height: 16rem; +} + +/* toggler checkbox */ +.toggle::after { + content: ""; + height: 12px; + width: 12px; + background: white; + position: absolute; + top: 2px; + left: 2px; + border-radius: 100%; +} + +.toggle.checked::after { + content: ""; + height: 12px; + width: 12px; + background: white; + position: absolute; + top: 2px; + left: 14px; + border-radius: 100%; +} + +/* responsive */ + +@media all and (max-width: 34.375em) { + .dn-s { + display: none; + } + .flex-basis-full-s { + flex-basis: 100%; + } + .h-100-minus-40-s { + height: calc(100% - 40px); + } + .h-100-minus-96-s { + height: calc(100% - 96px); + } + .embed-container { + padding-bottom: 56.25%; + } +} + +@media all and (min-width: 34.375em) and (max-width: 46.875em) { + .flex-basis-300-m { + flex-basis: 300px; + } + .h-100-minus-40-m { + height: calc(100% - 40px); + } + .embed-container { + padding-bottom: 56.25%; + } +} + +@media all and (min-width: 46.875em) and (max-width: 60em) { + .flex-basis-300-l { + flex-basis: 300px; + } + .h-100-minus-40-l { + height: calc(100% - 40px); + } + .embed-container { + padding-bottom: 37.5%; + } +} + +@media all and (min-width: 60em) { + .flex-basis-300-xl { + flex-basis: 300px; + } + .h-100-minus-40-xl { + height: calc(100% - 40px); + } +} + +/* dark */ + +@media (prefers-color-scheme: dark) { + body { + background-color: #333; + } + .bg-black-d { + background-color: black; + } + .white-d { + color: white; + } + .gray1-d { + color: #4d4d4d; + } + .gray2-d { + color: #7f7f7f; + } + .gray3-d { + color: #b1b2b3; + } + .gray4-d { + color: #e6e6e6; + } + .bg-gray0-d { + background-color: #333; + } + .bg-gray1-d { + background-color: #4d4d4d; + } + .b--gray0-d { + border-color: #333; + } + .b--gray1-d { + border-color: #4d4d4d; + } + .b--gray2-d { + border-color: #7f7f7f; + } + .b--white-d { + border-color: #fff; + } + .bb-d { + border-bottom-width: 1px; + border-bottom-style: solid; + } + .invert-d { + filter: invert(1); + } + .o-80-d { + opacity: .8; + } + .focus-b--white-d:focus { + border-color: #fff; + } + a { + color: #fff; + } + .hover-bg-gray1-d:hover { + color: #4d4d4d; + } +} diff --git a/full/src/css/fonts.css b/src/css/fonts.css similarity index 100% rename from full/src/css/fonts.css rename to src/css/fonts.css diff --git a/full/src/css/indigo-static.css b/src/css/indigo-static.css similarity index 100% rename from full/src/css/indigo-static.css rename to src/css/indigo-static.css diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..c75970c --- /dev/null +++ b/src/index.css @@ -0,0 +1,83 @@ +@import "css/indigo-static.css"; +@import "css/fonts.css"; +@import "css/custom.css"; + +.h-100-minus-56 { + height: calc(100% - 56px); +} + +.h-100-minus-60 { + height: calc(100% - 60px); +} + +.h-100-minus-2 { + height: calc(100% - 2px); +} + +.w-100-minus-320 { + width: calc(100% - 320px); +} + +.h-100-minus-40 { + height: calc(100% - 40px); +} + +.w-320-px { + width: 320px; +} + +.mw-180-px { + min-width: 180px; + max-width: 180px; +} + +.mw-310-px { + min-width: 310px; + max-width: 310px; +} + +.w-382-px { + width: 382px; +} + +p, +div { + font-family: "Inter", sans-serif; +} + +.pointer-none { + pointer-events: none; +} +.text-center { + text-align: center; +} + +/* responsive */ + +@media all and (max-width: 34.375em) { + .mr-2-s { + margin-right: .5rem; + } + .ml-2-s { + margin-left: .5rem; + } + .h-100-minus-200-s { + height: calc(100% - 200px); + } + .ba-0-s { + border: none; + } + .w-100-s { + width: 100%; + } + .w-auto-s { + width: 100%; + } + .ml0-s { + margin-left: 0; + } + .mh-134-s { + max-height: 134px; + overflow: auto; + } +} diff --git a/full/src/index.js b/src/index.js similarity index 100% rename from full/src/index.js rename to src/index.js diff --git a/src/js/api.js b/src/js/api.js new file mode 100644 index 0000000..4e094e3 --- /dev/null +++ b/src/js/api.js @@ -0,0 +1,120 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import _ from 'lodash'; + +class UrbitApi { + setAuthTokens(authTokens) { + this.authTokens = authTokens; + this.bindPaths = []; + } + + bind(path, method, ship = this.authTokens.ship, appl = "eth-event-viewer", success, fail) { + this.bindPaths = _.uniq([...this.bindPaths, path]); + + window.subscriptionId = window.urb.subscribe(ship, appl, path, + (err) => { + fail(err); + }, + (event) => { + success({ + data: event, + from: { + ship, + path + } + }); + }, + (err) => { + fail(err); + }); + } + + etheventviewer(data) { + this.action("eth-event-viewer", "json", data); + } + + action(appl, mark, data) { + return new Promise((resolve, reject) => { + window.urb.poke(ship, appl, mark, data, + (json) => { + resolve(json); + }, + (err) => { + reject(err); + }); + }); + } + + getAbi(address) { + api.action('eth-event-viewer', 'json', { + 'get-abi': { + address + } + }) + } + + getBlockNumber(timestamp) { + api.action('eth-event-viewer', 'json', { + 'get-block-number': { + timestamp + } + }) + } + + removeContract(address) { + api.action('eth-event-viewer', 'json', { + 'remove-contract': { + address + } + }) + } + + newContract(contract) { + api.action('eth-event-viewer', 'json', { + 'add-contract': { + address: contract.address, + name: contract.name, + 'block-number': contract.blockNumber, + 'specific-events': contract.specificEvents, + 'abi-events': contract.abiEvents ? JSON.stringify(contract.abiEvents) : null, + 'event-logs': null, + } + }) + } + + setShowAllEvents(address, value) { + const currFilter = store.state.eventFilters.find(filter => filter.address === address) || {address, showAllEvents:true, filters:[]}; + store.handleEvent({ + data: { + local: { + 'eventFilters': [ + ...store.state.eventFilters.filter(filter => filter.address !== address), + { + ...currFilter, + showAllEvents: value, + } + ] + } + } + }); + } + + setEventFilters(address, value) { + const currFilter = store.state.eventFilters.find(filter => filter.address === address) || {address, showAllEvents:true, filters:[]}; + store.handleEvent({ + data: { + local: { + 'eventFilters': [ + ...store.state.eventFilters.filter(filter => filter.address !== address), + { + ...currFilter, + filters: value, + } + ] + } + } + }); + } +} +export let api = new UrbitApi(); +window.api = api; diff --git a/src/js/components/lib/checkbox.js b/src/js/components/lib/checkbox.js new file mode 100644 index 0000000..1904c69 --- /dev/null +++ b/src/js/components/lib/checkbox.js @@ -0,0 +1,23 @@ +import React, { Component } from 'react'; + +export class Checkbox extends Component { + render() { + const { label, isActive, toggle } = this.props; + return ( +
toggle()}> +
+
+ {isActive && '✓'} +
+ {label} +
+
); + } +} diff --git a/src/js/components/lib/contracts-sidebar.js b/src/js/components/lib/contracts-sidebar.js new file mode 100644 index 0000000..103bd80 --- /dev/null +++ b/src/js/components/lib/contracts-sidebar.js @@ -0,0 +1,59 @@ +import React, { Component } from 'react'; +import { Link } from 'react-router-dom'; + +export class ContractsSidebar extends Component { + render() { + return ( +
+
+ +

New Contract

+ +
+ {this.renderContractsList()} +
+ ); + } + + renderContractsList() { + const { contracts } = this.props; + + if (!contracts) { + return null; + } + return ( + + ); + } + + renderListItem(contract) { + const { selectedContract } = this.props; + return ( +
  • +
    + {contract.name &&

    {contract.name}

    } +

    {contract.address}

    +
    +
  • + ); + } +} diff --git a/src/js/components/lib/events-selection.js b/src/js/components/lib/events-selection.js new file mode 100644 index 0000000..dc7c916 --- /dev/null +++ b/src/js/components/lib/events-selection.js @@ -0,0 +1,95 @@ +import React, { Component } from 'react'; +import { Checkbox } from './checkbox'; +import {getEventStructureByName} from '../../lib/events'; + +export class EventsSelection extends Component { + constructor(props) { + super(props); + this.state = { + selectedEvents: [], + listenToAllEvents: true, + } + } + + render() { + const { abi } = this.props; + const { selectedEvents, listenToAllEvents } = this.state; + if (!abi || abi.length === 0) { + return <> +

    No Events found!

    +

    Please insert a valid contract address...

    + ; + } + return (
    +
    +
    +

    Select contract events:

    +
    + { + abi + .filter(topics => topics.type === 'event') + .map(event => { + return ( this.toggleFromEvents(event.name)} + isActive={selectedEvents.some(eventName => eventName === event.name)}/>) + }) + } +
    +
    +
    + this.toggleEventListDisabled()} + isActive={listenToAllEvents}/> +
    ); + } + + toggleEventListDisabled() { + this.setState({ listenToAllEvents: !this.state.listenToAllEvents }, this.toggleEventChanged); + } + + selectAllEvents() { + const { abi } = this.props; + this.setState({ + selectedEvents: abi.filter(topics => topics.type === 'event').map(event => event.name) + }, this.toggleEventChanged); + } + + toggleFromEvents(eventName) { + const { selectedEvents } = this.state; + if (selectedEvents.some(event => event === eventName)) { + this.remove(selectedEvents, eventName); + } else { + this.add(selectedEvents, eventName); + } + } + + add(selectedEvents, eventName) { + this.setState({ + selectedEvents: [...selectedEvents, eventName], + }, this.toggleEventChanged); + } + + remove(selectedEvents, eventName) { + this.setState({ + selectedEvents: selectedEvents.filter(event => event !== eventName), + }, this.toggleEventChanged); + } + + toggleEventChanged() { + const { abi, onEventsChanged } = this.props; + const { selectedEvents, listenToAllEvents } = this.state; + + if (onEventsChanged) { + if(listenToAllEvents) { + onEventsChanged([]); + } else { + const structuredEvents = selectedEvents + .map(eventName => getEventStructureByName(abi, eventName)); + onEventsChanged(structuredEvents); + } + } + } +} diff --git a/src/js/components/lib/filter.js b/src/js/components/lib/filter.js new file mode 100644 index 0000000..afcbf93 --- /dev/null +++ b/src/js/components/lib/filter.js @@ -0,0 +1,10 @@ +import React, { Component } from 'react'; + +export class Filter extends Component { + render() { + const { label, isActive, onClick } = this.props; + return ({label}); + } +} diff --git a/full/src/js/components/lib/header-bar.js b/src/js/components/lib/header-bar.js similarity index 89% rename from full/src/js/components/lib/header-bar.js rename to src/js/components/lib/header-bar.js index f46d873..ee621c1 100644 --- a/full/src/js/components/lib/header-bar.js +++ b/src/js/components/lib/header-bar.js @@ -15,7 +15,7 @@ export class HeaderBar extends Component { } style={{ height: 40 }}> @@ -33,7 +33,7 @@ export class HeaderBar extends Component { }}> {title} -
    +
    diff --git a/full/src/js/components/lib/icons/icon-spinner.js b/src/js/components/lib/icons/icon-spinner.js similarity index 100% rename from full/src/js/components/lib/icons/icon-spinner.js rename to src/js/components/lib/icons/icon-spinner.js diff --git a/full/src/js/components/lib/icons/sigil.js b/src/js/components/lib/icons/sigil.js similarity index 100% rename from full/src/js/components/lib/icons/sigil.js rename to src/js/components/lib/icons/sigil.js diff --git a/src/js/components/log.js b/src/js/components/log.js new file mode 100644 index 0000000..b967acb --- /dev/null +++ b/src/js/components/log.js @@ -0,0 +1,205 @@ +import React, { Component } from 'react'; +import { getEventHashPairs } from '../lib/events'; +import { Filter } from './lib/filter'; +import _ from 'lodash'; +import { api } from '/api'; +import { getUniqueOrderedLogs } from '../reducers/utils'; +import { Link } from 'react-router-dom'; + +export class EventLogs extends Component { + constructor(props) { + super(props); + this.state = { + contract: props.contract, + } + this.updateContractWithUniqueEventsBound = this.updateContractWithUniqueEvents.bind(this); + this.updateContractEventsDebounce = _.debounce(this.updateContractWithUniqueEventsBound, 300); + } + + componentDidUpdate(prevProps) { + const prevContract = prevProps.contract; + const { contract } = this.props; + if (prevContract && contract) { + if (prevContract.address !== contract.address) { + this.setState({ contract}); + } + if (prevContract.eventLogs.length !== contract.eventLogs.length) { + // render only after received a bulk of new events, not every new event + // furthermore events are checked for uniqueness since it might be possible to receive them twice + this.updateContractEventsDebounce(contract); + } + } else if (contract) { + this.setState({ contract }) + } + } + + render() { + const { filterOptions } = this.props; + const { contract } = this.state; + if (!contract) { + return this.renderNoDataAvailable(); + } + + let { showAllEvents, filters } = filterOptions || { filters: [], showAllEvents: true }; + const hashPairs = getEventHashPairs(contract.abiEvents); + + let logs = contract.eventLogs || []; + + if (!showAllEvents && filters.length > 0) { + logs = this.filterLogs(logs, hashPairs, filters); + } + + // show max 200 entries + logs = _.take(logs, 200); + + return (
    + {this.renderFilterBar(contract.address, showAllEvents, hashPairs, filters)} + { + logs.length > 0 ? this.renderLog(logs, hashPairs, contract) : this.renderNoDataAvailable() + } +
    + ) + } + + renderFilterBar(address, showAllEvents, hashPairs, filters) { + return
    +
    + { + api.setShowAllEvents(address, !showAllEvents); + }}/> + { + showAllEvents || (hashPairs && hashPairs.length > 0 && this.renderFilters(hashPairs, filters)) + } +
    +
    + +
    api.removeContract(address)}> + remove +
    + +
    +
    + } + + renderLog(logs, hashPairs, contract) { + return
    + +
    ; + } + + renderFilters(hashPairs, filters) { + const { contract } = this.state; + const specificEvents = contract.specificEvents.map(event => { + const name = event.split('('); + return name ? name[0] : null; + }).filter(name => name); + + return hashPairs + .filter(p => specificEvents.length > 0 ? specificEvents.some(ev => ev === p.name) : true) + .map(pair => { + return ( + filter === pair.name)} + label={pair.name} + onClick={() => this.toggleFilter(pair.name, filters)}/> + ) + }) + } + + renderListItem(eventLog, hashPairs) { + const hashPair = hashPairs.find(hash => hash.hash === eventLog.topics[0]); + + return ( +
  • +
    +
    +

    {hashPair ? hashPair.name : eventLog.topics[0]}

    +

    Block No. {eventLog.mined['block-number']}

    +
    + { + this.renderEventTopics(eventLog, hashPair) + } +
    +
  • + ); + } + + renderEventTopics(eventLog, hashPair) { + return eventLog.topics.map((topic, index) => { + // first index is hash of topics + if (index === 0) { + return null; + } + const topicIndex = index - 1; + const topicName = hashPair && hashPair.inputs[topicIndex] && hashPair.inputs[topicIndex].name; + return (
    +

    {topicName ? topicName : topic}

    +

    {topic}

    +
    ) + }) + } + + renderNoDataAvailable() { + return
    +
    +

    No contract data available.

    +

    It might need some time, take a coffee and lean back.

    +
    +
    ; + } + + filterLogs(logs, hashPairs, filters) { + return logs.filter(log => { + const filterHash = filter => hashPairs.find(pair => pair.name === filter) || { hash: null }; + return !filters.some(filter => filterHash(filter).hash === log.topics[0]) + }); + } + + toggleFilter(eventName, filters) { + if (filters.some(filter => filter === eventName)) { + this.removeFilter(eventName, filters); + } else { + this.addFilter(eventName, filters); + } + } + + addFilter(eventName, filters) { + api.setEventFilters(this.state.contract.address, [...filters, eventName]); + } + + removeFilter(eventName, filters) { + api.setEventFilters(this.state.contract.address, filters.filter(filter => filter !== eventName)); + } + + updateContractWithUniqueEvents(contract) { + const newContract = { + ...contract, + eventLog: { + ...getUniqueOrderedLogs(contract) + } + } + this.setState({ contract: newContract }); + } +} diff --git a/src/js/components/new.js b/src/js/components/new.js new file mode 100644 index 0000000..7c21aa3 --- /dev/null +++ b/src/js/components/new.js @@ -0,0 +1,180 @@ +import React, { Component } from 'react'; +import { EventsSelection } from './lib/events-selection'; +import { Link } from 'react-router-dom'; +import _ from 'lodash'; +import web3Utils from 'web3-utils'; +import { api } from '/api'; + +const initialState = { + address: '', + name: '', + abiEvents: '', + blockNumber: undefined, + specificEvents: [], + validAddress: false, +}; + +export class NewContract extends Component { + constructor(props) { + super(props); + const blockNumber = isNaN(+props.blockNumber) ? undefined : +props.blockNumber; + this.state = { + ...initialState, + blockNumber, + }; + this.handleContractChangeBound = this.handleContractChange.bind(this); + this.handleNameChangeBound = this.handleNameChange.bind(this); + this.handleBlockNumberChangeBound = this.handleBlockNumberChange.bind(this); + } + + componentDidUpdate(prevProps) { + const {abi, blockNumber} = this.props; + if(abi && abi !== prevProps.abi) { + this.setState({abiEvents: abi.filter(topics => topics.type === 'event')}); + } else if((blockNumber !== prevProps.blockNumber || !this.state.blockNumber) && !isNaN(+blockNumber)) { + this.setState({blockNumber: +blockNumber}); + } + } + + getPreviousWeek() { + const today = new Date(); + const previousWeek = new Date(today.getFullYear(), today.getMonth(), + today.getDate() - 7, today.getHours(), today.getMinutes()); + return _.round(previousWeek.getTime() / 1000).toString(); + } + + render() { + const { address, abiEvents, name, blockNumber } = this.state; + return (
    +
    +
    +

    Contract Address

    +