├── .babelrc ├── .editorconfig ├── .eslintrc.js ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── .travis.yml ├── AUTHORS ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── build └── main.js ├── fonts └── fontawesome-webfont.woff ├── formatSolc.js ├── index.js ├── keymaps └── atom-solidity.cson ├── lib ├── actions │ ├── AccountActions.js │ ├── ClientActions.js │ ├── ContractActions.js │ ├── ErrorActions.js │ ├── EventActions.js │ ├── FilesActions.js │ ├── NodeActions.js │ ├── index.js │ └── types.js ├── components │ ├── CoinbaseView │ │ └── index.js │ ├── CompileBtn │ │ └── index.js │ ├── ContractCompiled │ │ └── index.js │ ├── ContractExecution │ │ └── index.js │ ├── Contracts │ │ └── index.js │ ├── CreateButton │ │ └── index.js │ ├── ErrorView │ │ └── index.js │ ├── EventItem │ │ └── index.js │ ├── Events │ │ └── index.js │ ├── FunctionABI │ │ └── index.js │ ├── GasInput │ │ └── index.js │ ├── InputsForm │ │ └── index.js │ ├── LoaderView │ │ └── index.js │ ├── NodeControl │ │ └── index.js │ ├── RemixDebugger │ │ └── index.js │ ├── RemixTests │ │ └── index.js │ ├── StaticAnalysis │ │ └── index.js │ ├── TabView │ │ └── index.js │ ├── TxAnalyzer │ │ └── index.js │ └── VersionSelector │ │ └── index.js ├── ethereum-interface-view.js ├── ethereum-interface.js ├── helpers │ ├── compiler-imports.js │ ├── configureStore.js │ └── uiHelpers.js ├── reducers │ ├── AccountReducer.js │ ├── ClientReducer.js │ ├── ContractReducer.js │ ├── ErrorReducer.js │ ├── EventReducer.js │ ├── FilesReducer.js │ ├── NodeReducer.js │ └── index.js └── web3 │ ├── methods.js │ ├── view.js │ ├── vyp-worker.js │ ├── web3.js │ ├── web3Worker.js │ └── worker.js ├── menus └── atom-solidity.cson ├── package.json ├── rollup.config.js ├── spec └── atom-solidity-spec.js └── styles └── atom-solidity.less /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-react", 4 | [ "@babel/preset-env", { "targets": { "electron": "2.0.7" } } ] 5 | ], 6 | "plugins": ["@babel/plugin-proposal-object-rest-spread","emotion"] 7 | } 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: 'babel-eslint', 4 | parserOptions: { 5 | sourceType: 'module' 6 | }, 7 | "env": { 8 | "es6": true, 9 | "node": true 10 | }, 11 | "extends": ["standard", "eslint:recommended", "plugin:react/recommended", 'plugin:import/errors', 'plugin:import/warnings'], 12 | globals: { 13 | __static: true, 14 | atom: true 15 | }, 16 | "parserOptions": { 17 | "ecmaVersion": 6, 18 | "ecmaFeatures": { 19 | "jsx": true 20 | }, 21 | "sourceType": "module" 22 | }, 23 | "settings": { 24 | "react": { 25 | "version": "16.4.2" 26 | } 27 | }, 28 | "plugins": [ 29 | "react", 30 | "babel", 31 | "import" 32 | ], 33 | "rules": { 34 | "strict": 0, 35 | "babel/semi": 1, 36 | // tab indentation 37 | 'indent': ["warn", 4], 38 | "linebreak-style": [ 39 | "error", 40 | "unix" 41 | ], 42 | "quotes": [ 43 | "error", 44 | "single" 45 | ], 46 | // allow paren-less arrow functions 47 | 'arrow-parens': 0, 48 | 'space-before-function-paren': ["error", "never"], 49 | 'no-console': ["error", { allow: ["warn", "error", "log"] }], 50 | 'import/named': 2, 51 | 'import/namespace': 2, 52 | 'import/default': 2, 53 | 'import/export': 2, 54 | 'import/no-unresolved': 'off' 55 | } 56 | }; 57 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [ Linux, Windows, OSX ] 28 | - Etheratom version 4.5.3 29 | - apm version 30 | ``` 31 | apm 2.1.7 32 | npm 6.2.0 33 | node 8.9.3 x64 34 | atom 1.37.0 35 | python 2.7.16 36 | git 2.21.0 37 | ``` 38 | 39 | **Additional context** 40 | Add any other context about the problem here. 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | node_modules 4 | package-lock.json 5 | .idea/ 6 | .vscode/ 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | ### Project specific config ### 2 | language: generic 3 | 4 | env: 5 | global: 6 | - APM_TEST_PACKAGES="" 7 | - ATOM_LINT_WITH_BUNDLED_NODE="true" 8 | 9 | matrix: 10 | - ATOM_CHANNEL=stable 11 | 12 | os: 13 | - linux 14 | - osx 15 | 16 | ### Generic setup follows ### 17 | script: 18 | - curl -s -O https://raw.githubusercontent.com/atom/ci/master/build-package.sh 19 | - chmod u+x build-package.sh 20 | - ./build-package.sh 21 | 22 | notifications: 23 | email: 24 | on_success: never 25 | on_failure: change 26 | 27 | branches: 28 | only: 29 | - master 30 | - /^greenkeeper/.*$/ 31 | 32 | git: 33 | depth: 10 34 | 35 | sudo: false 36 | 37 | dist: trusty 38 | 39 | addons: 40 | apt: 41 | packages: 42 | - build-essential 43 | - fakeroot 44 | - git 45 | - libsecret-1-dev 46 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # This is list of Etheratom authors for copyright purposes. 2 | 3 | 0mkar <0mkar@protonmail.com> 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.1.0 - First Release 2 | * Every feature added 3 | * Every bug fixed 4 | 5 | ## 0.1.1 - Second Release 6 | * Merge pull requests 7 | * Fix async calls 8 | * Introduce solcjs [JavaScript bindings for the Solidity compiler](https://github.com/ethereum/solc-js) 9 | * Avail options to switch compiler environment 10 | 11 | ## 2.0.2 - Etheratom 12 | * Rename repository 13 | * Compile solidity files on save 14 | * Resize panel 15 | * Moved from CoffeeScript to ES6 16 | * Split web3 and ethereumjs-vm environments into separate modules 17 | * Dynamically load `ethereumjs-vm` to reduce package activation time 18 | * More errors added 19 | 20 | ## 4.0.5 21 | * Move web3js libraries into worker to load extension faster and provide non-blocking UI/UX 22 | * Easy connection management from Node panel 23 | * Easy WebSocket / RPC connection switch in Node panel 24 | * Save ABI after compilation 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Use [ethcode](https://marketplace.visualstudio.com/items?itemName=7finney.ethcode) in vscode for better development experience. 2 | 3 | # Etheratom 4 | 5 | [![Greenkeeper badge](https://badges.greenkeeper.io/0mkara/etheratom.svg)](https://greenkeeper.io/) 6 | [![Build Status](https://travis-ci.org/0mkara/etheratom.svg?branch=master)](https://travis-ci.org/0mkara/etheratom) 7 | [![Gitter](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/Ethereum-Devtools-Developers-Studio/etheratom?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) 8 | [![telegram](https://png.icons8.com/color/24/000000/telegram-app.png)](https://t.me/etheratom) 9 | 10 | Ethereum IDE plugin for hackable Atom editor. Compile smart contracts, deploy them to Ethereum networks. Efficient contract management interface. Integrated test suite for smart contracts. 11 | 12 | ![A screenshot of Etheratom package](https://user-images.githubusercontent.com/13261372/37828365-f43a0c8c-2ec0-11e8-8d09-d1c29d7168d3.png) 13 | 14 | # Sponsors 15 | ![gitcoin](https://s.gitcoin.co/static/v2/images/presskit/GitcoinLogoText.682e2321c67c.svg) 16 | ethereumfoundation 17 | 18 | # Support 19 | You can join our Telegram group for quick help in solving any issues at https://t.me/etheratom [![telegram](https://png.icons8.com/color/24/000000/telegram-app.png)](https://t.me/etheratom) 20 | 21 | Join our new gitter room for help - https://gitter.im/Ethereum-Devtools-Developers-Studio/etheratom 22 | 23 | #### Quick help 24 | Follow our [quick troubleshooting issue](https://github.com/0mkara/etheratom/issues/282) to get help about some known bugs and issues. 25 | 26 | # Requirements 27 | 28 | #### Use [Ganache](http://truffleframework.com/ganache/) or Install [geth](https://github.com/ethereum/go-ethereum) 29 | [Go Ethereum client installation instruction](https://www.ethereum.org/cli) 30 | **Or** 31 | You can just download binary from [https://geth.ethereum.org/downloads/](https://geth.ethereum.org/downloads/) and run. 32 | 33 | #### Run go-ethereum client 34 | Start geth node on testnet using following command: 35 | 36 | geth --goerli --rpc --rpcapi="eth,web3,personal" --ws --wsorigins="*" --wsapi="eth,web3,personal" console 37 | 38 | *Note:* Only solidity compilation is supported. `--wsorigins="*"` or `--wsorigins="file://"` is necessary to allow Atom to connect to go-ethereum websocket endpoint. 39 | 40 | # Installation 41 | 42 | `apm install etheratom` 43 | 44 | Or you can install [Etheratom](https://atom.io/packages/etheratom) from Atom packages. 45 | 46 | #### Install from source 47 | 48 | Clone git repository 49 | 50 | git clone https://github.com/0mkara/etheratom.git 51 | cd etheratom 52 | 53 | Install as atom package 54 | 55 | apm install 56 | apm link . 57 | 58 | # Configuration 59 | **Geth** defaults : **rpc** `http://127.0.0.1:8545/` **websocket** `ws://127.0.0.1:8546/` 60 | 61 | **Ganache** defaults : **rpc** `http://127.0.0.1:7545/` 62 | 63 | #### Go to package settings and set rpc address & websocket address. 64 | 65 | ![etheratom package config](https://user-images.githubusercontent.com/13261372/41284998-96a25e26-6e58-11e8-80a6-1860368bcaed.png) 66 | 67 | **Restart atom** to load your configuration changes. 68 | 69 | # Usage 70 | 71 | Activate Etheratom package `ctrl+alt+e` 72 | 73 | Compile solidity code with `ctrl+alt+c` or just by saving a solidity file with `ctrl+s` 74 | 75 | Show/hide etheratom panel `ctrl+alt+v` 76 | 77 | After compiling your solidity code click **Deploy to blockchain** button to deploy the contract on blockchain. Optionally you can deploy your contract at some previously created address. 78 | 79 | ![New panel features](https://user-images.githubusercontent.com/13261372/41285521-0dd4154c-6e5a-11e8-843d-505368a31302.png) 80 | 81 | ##### Follow [Etheratom Wiki](https://github.com/0mkara/etheratom/wiki) for more information. 82 | 83 | # Development guideline 84 | 85 | ##### Clone & code 86 | ``` 87 | git clone https://github.com/0mkara/etheratom.git 88 | cd etheratom 89 | ``` 90 | ##### Build 91 | `rollup -c` 92 | 93 | # Support development :heart: 94 | 95 | Etheratom aims to provide a clean interactive interface to develop solidity smart contracts, test them on testnet, do security analysis and deploy them on mainnet. **Etheratom needs your help!** 96 | 97 | **Etheratom is looking for financial help. Any organization or individual wants to help grow etheratom is requested to contact `0mkar@protonmail.com`** 98 | 99 | ## Ethereum :point_right: 0xd22fE4aEFed0A984B1165dc24095728EE7005a36 100 | -------------------------------------------------------------------------------- /fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0mkara/etheratom/f5900c52851f7469cb453850a93c94c7e1b191b3/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /formatSolc.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | 3 | const SOLJSON_PATH = __dirname + '/node_modules/solc/soljson.js'; 4 | const MODULE_OVERRIDE = 'var Module = {"ENVIRONMENT": "NODE"};'; 5 | const ENVIRONMENT_OVERRIDE_FROM = 'var ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof require==="function"&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER;var ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;' 6 | const ENVIRONMENT_OVERRIDE_TO = 'var ENVIRONMENT_IS_NODE=true;' 7 | 8 | const solSrc = fs.readFileSync(SOLJSON_PATH, 'utf8').replace(ENVIRONMENT_OVERRIDE_FROM, ENVIRONMENT_OVERRIDE_TO); 9 | 10 | fs.writeFileSync(SOLJSON_PATH, MODULE_OVERRIDE + solSrc) 11 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | import 'idempotent-babel-polyfill'; 3 | import { Etheratom } from './lib/ethereum-interface'; 4 | 5 | module.exports = new Etheratom({ 6 | config: atom.config, 7 | workspace: atom.workspace 8 | }); 9 | -------------------------------------------------------------------------------- /keymaps/atom-solidity.cson: -------------------------------------------------------------------------------- 1 | # Keybindings require three things to be fully defined: A selector that is 2 | # matched against the focused element, the keystroke and the command to 3 | # execute. 4 | # 5 | # Below is a basic keybinding which registers on all platforms by applying to 6 | # the root workspace element. 7 | 8 | # For more detailed documentation see 9 | # https://atom.io/docs/latest/behind-atom-keymaps-in-depth 10 | 'atom-workspace': 11 | 'ctrl-alt-e': 'eth-interface:activate' 12 | 'ctrl-alt-c': 'eth-interface:compile' 13 | 'ctrl-alt-v': 'eth-interface:toggle' 14 | 'atom-text-editor[data-grammar~="solidity"]:not([mini])': 'ctrl-alt-e': 'eth-interface:activate' 15 | 'atom-text-editor[data-grammar~="vyper"]:not([mini])': 'ctrl-alt-e': 'eth-interface:activate' 16 | -------------------------------------------------------------------------------- /lib/actions/AccountActions.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import { SET_ACCOUNTS, SET_COINBASE, SET_PASSWORD, SET_BALANCE } from './types'; 18 | 19 | export const setCoinbase = (coinbase) => { 20 | return (dispatch) => { 21 | dispatch({ type: SET_COINBASE, payload: coinbase }); 22 | }; 23 | }; 24 | 25 | export const setPassword = ({ password }) => { 26 | return (dispatch) => { 27 | dispatch({ type: SET_PASSWORD, payload: { password } }); 28 | }; 29 | }; 30 | 31 | export const setAccounts = ( accounts ) => { 32 | return (dispatch) => { 33 | dispatch({ type: SET_ACCOUNTS, payload: accounts }); 34 | }; 35 | }; 36 | 37 | export const setBalance = ({ balance }) => { 38 | return (dispatch) => { 39 | dispatch({ type: SET_BALANCE, payload: { balance } }); 40 | }; 41 | }; -------------------------------------------------------------------------------- /lib/actions/ClientActions.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | 18 | import { SET_CONNECTION_STATUS } from './types'; 19 | 20 | export const setConnectionStatus = (status) => { 21 | return (dispatch) => { 22 | dispatch({ type: SET_CONNECTION_STATUS, payload: status }); 23 | }; 24 | }; 25 | -------------------------------------------------------------------------------- /lib/actions/ContractActions.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import { SET_COMPILED, SET_PARAMS, ADD_INTERFACE, SET_DEPLOYED, SET_INSTANCE, SET_GAS_ESTIMATE } from './types'; 18 | 19 | export const contractCompiled = (dispatch, compiled) => { 20 | dispatch({ type: SET_COMPILED, payload: compiled }); 21 | }; 22 | 23 | export const setParamsInput = ({ contractName, abi }) => { 24 | return (dispatch) => { 25 | dispatch({ type: SET_PARAMS, payload: { contractName, abi } }); 26 | }; 27 | }; 28 | 29 | export const addInterface = ({ contractName, ContractABI }) => { 30 | return (dispatch) => { 31 | dispatch({ type: ADD_INTERFACE, payload: { contractName, interface: ContractABI } }); 32 | }; 33 | }; 34 | 35 | export const updateInterface = ({ contractName, ContractABI }) => { 36 | return (dispatch) => { 37 | dispatch({ type: ADD_INTERFACE, payload: { contractName, interface: ContractABI } }); 38 | }; 39 | }; 40 | 41 | export const setInstance = ({ contractName, instance }) => { 42 | return (dispatch) => { 43 | dispatch({ type: SET_INSTANCE, payload: { contractName, instance } }); 44 | }; 45 | }; 46 | 47 | export const setDeployed = ({ contractName, deployed }) => { 48 | return (dispatch) => { 49 | dispatch({ type: SET_DEPLOYED, payload: { contractName, deployed } }); 50 | }; 51 | }; 52 | 53 | export const setGasEstimate = ({ gasEstimate }) => { 54 | return (dispatch) => { 55 | dispatch({ type: SET_GAS_ESTIMATE, payload: { gasEstimate } }); 56 | }; 57 | }; 58 | -------------------------------------------------------------------------------- /lib/actions/ErrorActions.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import { SET_ERRORS, RESET_ERRORS } from './types'; 18 | 19 | export const setErrors = (payload) => { 20 | return (dispatch) => { 21 | dispatch({ type: SET_ERRORS, payload }); 22 | }; 23 | }; 24 | 25 | export const resetErrors = () => { 26 | return (dispatch) => { 27 | dispatch({ type: RESET_ERRORS }); 28 | }; 29 | }; 30 | -------------------------------------------------------------------------------- /lib/actions/EventActions.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import { ADD_EVENTS } from './types'; 18 | 19 | export const addNewEvents = ({ payload }) => { 20 | return (dispatch) => { 21 | dispatch({ type: ADD_EVENTS, payload }); 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /lib/actions/FilesActions.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import { RESET_SOURCES, SET_SOURCES } from './types'; 18 | 19 | export const setSources = (payload) => { 20 | return (dispatch) => { 21 | dispatch({ type: SET_SOURCES, payload }); 22 | }; 23 | }; 24 | 25 | export const resetSources = () => { 26 | return (dispatch) => { 27 | dispatch({ type: RESET_SOURCES }); 28 | }; 29 | }; 30 | -------------------------------------------------------------------------------- /lib/actions/NodeActions.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import { SET_SYNC_STATUS, SET_MINING, SET_HASH_RATE } from './types'; 18 | 19 | export const setSyncStatus = (status) => { 20 | return (dispatch) => { 21 | dispatch({ type: SET_SYNC_STATUS, payload: status }); 22 | }; 23 | }; 24 | 25 | export const setMining = (mining) => { 26 | return (dispatch) => { 27 | dispatch({ type: SET_MINING, payload: mining }); 28 | }; 29 | }; 30 | 31 | export const setHashrate = (hashrate) => { 32 | return (dispatch) => { 33 | dispatch({ type: SET_HASH_RATE, payload: hashrate }); 34 | }; 35 | }; 36 | -------------------------------------------------------------------------------- /lib/actions/index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | export * from './ContractActions'; 18 | export * from './AccountActions'; 19 | export * from './EventActions'; 20 | export * from './NodeActions'; 21 | export * from './ErrorActions'; 22 | export * from './FilesActions'; 23 | export * from './ClientActions'; 24 | -------------------------------------------------------------------------------- /lib/actions/types.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | export const RESET_CONTRACTS = 'reset_contracts'; 18 | export const SET_COMPILING = 'set_compiling'; 19 | export const SET_COMPILED = 'set_compiled'; 20 | export const RESET_COMPILED = 'reset_compiled'; 21 | export const SET_PARAMS = 'set_params'; 22 | export const ADD_INTERFACE = 'add_interface'; 23 | export const UPDATE_INTERFACE = 'update_interface'; 24 | export const UPDATE_OPTIONS = 'update_options'; 25 | export const ADD_TX_HASH = 'add_tx_hash'; 26 | export const SET_INSTANCE = 'set_instance'; 27 | export const SET_DEPLOYED = 'set_deployed'; 28 | export const SET_GAS_LIMIT = 'set_gas_limit'; 29 | export const SET_BALANCE = 'set_balance'; 30 | export const SET_GAS_ESTIMATE = 'set_gas_estimate'; 31 | 32 | // Files action types 33 | export const RESET_SOURCES = 'reset_sources'; 34 | export const SET_SOURCES = 'set_sources'; 35 | 36 | export const SET_COINBASE = 'set_coinbase'; 37 | export const SET_PASSWORD = 'set_password'; 38 | export const SET_ACCOUNTS = 'set_accounts'; 39 | 40 | export const SET_ERRORS = 'set_errors'; 41 | export const RESET_ERRORS = 'reset_errors'; 42 | 43 | // Ethereum client events 44 | export const ADD_PENDING_TRANSACTION = 'add_pending_transaction'; 45 | export const ADD_EVENTS = 'add_logs'; 46 | export const SET_EVENTS = 'set_events'; 47 | export const TEXT_ANALYSIS = 'text_analysis'; 48 | 49 | // Node variables 50 | export const SET_CONNECTED = 'set_connected'; 51 | export const SET_SYNC_STATUS = 'set_sync_status'; 52 | export const SET_SYNCING = 'set_syncing'; 53 | export const SET_MINING = 'set_mining'; 54 | export const SET_HASH_RATE = 'set_hash_rate'; 55 | 56 | // Client variables 57 | export const SET_CONNECTION_STATUS = 'set_connection_status'; 58 | export const FIRST_TIME_CHECK_ENABLE = 'first_time_check_enable'; 59 | export const IS_WS_PROVIDER = 'is_ws_provider'; 60 | export const IS_HTTP_PROVIDER = 'is_http_provider'; 61 | -------------------------------------------------------------------------------- /lib/components/CoinbaseView/index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import React from 'react'; 18 | import { connect } from 'react-redux'; 19 | import PropTypes from 'prop-types'; 20 | import { setCoinbase, setPassword } from '../../actions'; 21 | 22 | 23 | 24 | class CoinbaseView extends React.Component { 25 | constructor(props) { 26 | super(props); 27 | this.helpers = props.helpers; 28 | // const { balance } = props; 29 | this.state = { 30 | coinbase: props.accounts[0], 31 | password: '', 32 | toAddress: '', 33 | unlock_style: 'unlock-default', 34 | amount: 0 35 | }; 36 | this._handleAccChange = this._handleAccChange.bind(this); 37 | this._handlePasswordChange = this._handlePasswordChange.bind(this); 38 | this._handleUnlock = this._handleUnlock.bind(this); 39 | this._linkClick = this._linkClick.bind(this); 40 | this._refreshBal = this._refreshBal.bind(this); 41 | } 42 | async componentDidMount() { 43 | const { coinbase } = this.state; 44 | 45 | this.helpers.setDefaultAccount(coinbase); 46 | this.helpers.getBalance(coinbase); 47 | } 48 | 49 | async componentDidUpdate(prevProps, prevState) { 50 | const { coinbase } = this.state; 51 | if (this.state.coinbase !== prevState.coinbase) { 52 | this.helpers.setDefaultAccount(coinbase); 53 | this.helpers.getBalance(coinbase); 54 | } 55 | } 56 | 57 | async componentWillReceiveProps() { 58 | if (this.props.accounts[0]) { 59 | this.setState({ coinbase: this.props.accounts[0] }); 60 | } 61 | // this.setState({ balance: this.props.store.getState().account.balance }); 62 | } 63 | _linkClick(event) { 64 | const { coinbase } = this.state; 65 | atom.clipboard.write(coinbase); 66 | } 67 | async _handleAccChange(event) { 68 | const coinbase = event.target.value; 69 | const { setCoinbase } = this.props; 70 | this.helpers.setDefaultAccount(coinbase); 71 | this.helpers.getBalance(coinbase); 72 | setCoinbase(coinbase); 73 | this.setState({ coinbase }); 74 | } 75 | _handlePasswordChange(event) { 76 | const password = event.target.value; 77 | this.setState({ password }); 78 | // TODO: unless we show some indicator on `Unlock` let password set on change 79 | if (!(password.length - 1 > 0)) { 80 | this.setState({ unlock_style: 'unlock-default' }); 81 | } 82 | } 83 | _handleUnlock(event) { 84 | // TODO: here try to unlock geth backend node using coinbase and password and show result 85 | const { password, coinbase } = this.state; 86 | const { setCoinbase, setPassword } = this.props; 87 | if (password.length > 0) { 88 | setPassword({ password }); 89 | setCoinbase(coinbase); 90 | // TODO: Set web3.eth.defaultAccount on unlock 91 | this.helpers.setCoinbase(coinbase); 92 | this.setState({ unlock_style: 'unlock-active' }); 93 | } 94 | event.preventDefault(); 95 | } 96 | async _refreshBal() { 97 | const { coinbase } = this.state; 98 | await this.helpers.getBalance(coinbase); 99 | this.setState({ balance: this.props.store.getState().account.balance }); 100 | } 101 | render() { 102 | const { password, unlock_style } = this.state; 103 | const { balance, accounts, coinbase } = this.props; 104 | 105 | return ( 106 |
107 | {accounts.length > 0 && ( 108 |
109 |
113 | 126 | 127 |
128 | )} 129 | {accounts.length > 0 && ( 130 |
131 |
132 | 138 | 143 | 144 | )} 145 |
146 | ); 147 | } 148 | } 149 | 150 | CoinbaseView.propTypes = { 151 | helpers: PropTypes.any.isRequired, 152 | accounts: PropTypes.arrayOf(PropTypes.string), 153 | setCoinbase: PropTypes.function, 154 | store: PropTypes.any, 155 | balance: PropTypes.any, 156 | coinbase: PropTypes.any, 157 | setPassword: PropTypes.function 158 | }; 159 | 160 | const mapStateToProps = ({ account }) => { 161 | const { coinbase, password, accounts, balance } = account; 162 | return { coinbase, password, accounts, balance }; 163 | }; 164 | 165 | export default connect(mapStateToProps, { setCoinbase, setPassword })(CoinbaseView); 166 | -------------------------------------------------------------------------------- /lib/components/CompileBtn/index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import React from 'react'; 18 | import PropTypes from 'prop-types'; 19 | import { connect } from 'react-redux'; 20 | 21 | class CompileBtn extends React.Component { 22 | constructor(props) { 23 | super(props); 24 | this._handleSubmit = this._handleSubmit.bind(this); 25 | } 26 | async _handleSubmit() { 27 | const workspaceElement = atom.views.getView(atom.workspace); 28 | await atom.commands.dispatch(workspaceElement, 'eth-interface:compile'); 29 | } 30 | render() { 31 | const { compiling } = this.props; 32 | return ( 33 |
34 | { 35 | compiling && 36 | 37 | } 38 | { 39 | !compiling && 40 | 41 | } 42 |
43 | ); 44 | } 45 | } 46 | 47 | CompileBtn.propTypes = { 48 | compiling: PropTypes.bool 49 | }; 50 | 51 | const mapStateToProps = ({ contract }) => { 52 | const { compiling } = contract; 53 | return { compiling }; 54 | }; 55 | 56 | export default connect(mapStateToProps, {})(CompileBtn); 57 | -------------------------------------------------------------------------------- /lib/components/ContractCompiled/index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import React from 'react'; 18 | import { connect } from 'react-redux'; 19 | import ReactJson from 'react-json-view'; 20 | import { Tab, Tabs, TabList, TabPanel } from 'react-tabs'; 21 | import GasInput from '../GasInput'; 22 | import InputsForm from '../InputsForm'; 23 | import CreateButton from '../CreateButton'; 24 | import PropTypes from 'prop-types'; 25 | import { addInterface } from '../../actions'; 26 | import { saveAs } from 'file-saver'; 27 | const Blob = require('blob'); 28 | 29 | class ContractCompiled extends React.Component { 30 | constructor(props) { 31 | super(props); 32 | this.helpers = props.helpers; 33 | const { gasEstimate, interfaces, contractName } = props; 34 | this.state = { 35 | estimatedGas: gasEstimate, 36 | ContractABI: interfaces[props.contractName].interface, 37 | savePath: `${contractName}.abi` 38 | }; 39 | this._handleGasChange = this._handleGasChange.bind(this); 40 | this._handleInput = this._handleInput.bind(this); 41 | this._saveABI = this._saveABI.bind(this); 42 | } 43 | async componentDidMount() { 44 | const { clients } = this.props; 45 | console.log(clients); 46 | if(!clients[0].hasConnection) { 47 | return; 48 | } else { 49 | try { 50 | const { coinbase, bytecode } = this.props; 51 | const gas = await this.helpers.getGasEstimate(coinbase, bytecode); 52 | this.setState({ estimatedGas: gas }); 53 | } catch (e) { 54 | console.error(e); 55 | this.helpers.showPanelError(e); 56 | } 57 | } 58 | } 59 | async componentDidUpdate(prevProps, prevState) { 60 | if (prevProps.gasEstimate !== this.props.gasEstimate) { 61 | this.setState({ estimatedGas: this.props.gasEstimate }); 62 | } 63 | } 64 | _handleGasChange(event) { 65 | this.setState({ estimatedGas: parseInt(event.target.value) }); 66 | } 67 | _handleInput() { 68 | const { contractName, addInterface } = this.props; 69 | const { ContractABI } = this.state; 70 | addInterface({ contractName, ContractABI }); 71 | } 72 | _saveABI() { 73 | const { fileName } = this.props; 74 | const { ContractABI } = this.state; 75 | const savePath = `${fileName.split('.sol')[0]}.abi`; 76 | const json = JSON.stringify(ContractABI).replace(new RegExp('"', 'g'), '\''); 77 | const blob = new Blob([json], { type: 'text/plain;charset=utf-8' }); 78 | saveAs(blob, savePath); 79 | } 80 | 81 | render() { 82 | const { contractName, bytecode, index } = this.props; 83 | const { estimatedGas, ContractABI } = this.state; 84 | const savePath = `${contractName}.abi`; 85 | return ( 86 |
87 | {contractName} 88 |
89 |
{JSON.stringify(bytecode)}
90 |
91 |
92 | 93 | 94 |
95 | 96 |
Interface
97 |
98 | 99 |
Interface Object
100 |
101 |
103 |
104 | 105 | 106 |
{JSON.stringify(ContractABI)}
107 |
108 | 109 | 118 | 119 |
120 |
121 | { 122 | ContractABI.map((abi, i) => { 123 | return ; 124 | }) 125 | } 126 | 127 | { 128 | 135 | } 136 |
137 | ); 138 | } 139 | } 140 | ContractCompiled.propTypes = { 141 | helpers: PropTypes.any.isRequired, 142 | interfaces: PropTypes.object, 143 | gasEstimate: PropTypes.number, 144 | contractName: PropTypes.string, 145 | fileName: PropTypes.string, 146 | addInterface: PropTypes.func, 147 | bytecode: PropTypes.string, 148 | index: PropTypes.number, 149 | coinbase: PropTypes.string, 150 | clients: PropTypes.array.isRequired 151 | }; 152 | const mapStateToProps = ({ account, contract, clientReducer }) => { 153 | const { compiled, interfaces, gasEstimate } = contract; 154 | const { coinbase } = account; 155 | const { clients } = clientReducer; 156 | return { compiled, interfaces, coinbase, gasEstimate, clients }; 157 | }; 158 | 159 | export default connect(mapStateToProps, { addInterface })(ContractCompiled); 160 | -------------------------------------------------------------------------------- /lib/components/ContractExecution/index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import React from 'react'; 18 | import { connect } from 'react-redux'; 19 | import ReactJson from 'react-json-view'; 20 | import { Tab, Tabs, TabList, TabPanel } from 'react-tabs'; 21 | import InputsForm from '../InputsForm'; 22 | import FunctionABI from '../FunctionABI'; 23 | import PropTypes from 'prop-types'; 24 | 25 | class ContractExecution extends React.Component { 26 | constructor(props) { 27 | super(props); 28 | this.helpers = props.helpers; 29 | } 30 | render() { 31 | const { contractName, bytecode, index, contracts } = this.props; 32 | const contractOptions = contracts[contractName].options; 33 | const transactionHash = contracts[contractName].transactionHash; 34 | const ContractABI = contracts[contractName].options.jsonInterface; 35 | return ( 36 |
37 | {contractName} 38 |
39 |
{JSON.stringify(bytecode)}
40 |
41 |
42 | 43 | 44 |
45 | 46 |
Interface
47 |
48 | 49 |
Interface Object
50 |
51 |
52 |
53 | 54 | 55 |
{JSON.stringify(ContractABI)}
56 |
57 | 58 | 65 | 66 |
67 |
68 | { 69 | transactionHash && 70 |
71 | Transaction hash: 72 |
{transactionHash}
73 |
74 | } 75 | { 76 | !contractOptions.address && 77 |
78 | waiting to be mined 79 | 80 |
81 | } 82 | { 83 | contractOptions.address && 84 |
85 | Mined at: 86 |
{contractOptions.address}
87 |
88 | } 89 | { 90 | ContractABI.map((abi, i) => { 91 | return ; 92 | }) 93 | } 94 | 95 |
96 | ); 97 | } 98 | } 99 | 100 | ContractExecution.propTypes = { 101 | helpers: PropTypes.any.isRequired, 102 | contractName: PropTypes.string, 103 | bytecode: PropTypes.string, 104 | index: PropTypes.number, 105 | instances: PropTypes.any, 106 | contracts: PropTypes.any, 107 | interfaces: PropTypes.object 108 | }; 109 | 110 | const mapStateToProps = ({ contract }) => { 111 | const { contracts } = contract; 112 | return { contracts }; 113 | }; 114 | 115 | export default connect(mapStateToProps, {})(ContractExecution); 116 | -------------------------------------------------------------------------------- /lib/components/Contracts/index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import React from 'react'; 18 | import { connect, Provider } from 'react-redux'; 19 | import { Collapse } from 'react-collapse'; 20 | import ContractCompiled from '../ContractCompiled'; 21 | import ContractExecution from '../ContractExecution'; 22 | import ErrorView from '../ErrorView'; 23 | import PropTypes from 'prop-types'; 24 | import { setErrors, addInterface } from '../../actions'; 25 | 26 | class CollapsedFile extends React.Component { 27 | constructor(props) { 28 | super(props); 29 | this.helpers = props.helpers; 30 | this.state = { 31 | isOpened: false, 32 | toggleBtnStyle: 'btn icon icon-unfold inline-block-tight', 33 | toggleBtnTxt: 'Expand' 34 | }; 35 | this._toggleCollapse = this._toggleCollapse.bind(this); 36 | this._clearContract = this._clearContract.bind(this); 37 | } 38 | _toggleCollapse() { 39 | const { isOpened } = this.state; 40 | this.setState({ isOpened: !isOpened }); 41 | if (!isOpened) { 42 | this.setState({ 43 | toggleBtnStyle: 'btn btn-success icon icon-fold inline-block-tight', 44 | toggleBtnTxt: 'Collapse' 45 | }); 46 | } else { 47 | this.setState({ 48 | toggleBtnStyle: 'btn icon icon-unfold inline-block-tight', 49 | toggleBtnTxt: 'Expand' 50 | }); 51 | } 52 | } 53 | _clearContract() { 54 | // TODO: clear interface from store 55 | } 56 | 57 | render() { 58 | const { isOpened, toggleBtnStyle, toggleBtnTxt } = this.state; 59 | const { fileName, compiled, deployed, compiling, interfaces } = this.props; 60 | return ( 61 |
62 | 70 | 71 | { 72 | Object.keys(compiled.contracts[fileName]).map((contractName, index) => { 73 | const regexVyp = /([a-zA-Z0-9\s_\\.\-():])+(.vy|.v.py|.vyper.py)$/g; 74 | const bytecode = fileName.match(regexVyp) 75 | ? compiled.contracts[fileName][contractName].evm.bytecode.object.substring(2) 76 | : compiled.contracts[fileName][contractName].evm.bytecode.object; 77 | return ( 78 |
79 | { 80 | !deployed[contractName] && interfaces !== null && interfaces[contractName] && compiling === false && 81 | 88 | } 89 | { 90 | deployed[contractName] && 91 | 97 | } 98 |
99 | ); 100 | }) 101 | } 102 |
103 |
104 | ); 105 | } 106 | } 107 | class Contracts extends React.Component { 108 | constructor(props) { 109 | super(props); 110 | this.helpers = props.helpers; 111 | } 112 | componentDidUpdate(prevProps) { 113 | const { sources, compiled } = this.props; 114 | if (sources != prevProps.sources) { 115 | // Start compilation of contracts from here 116 | const workspaceElement = atom.views.getView(atom.workspace); 117 | atom.commands.dispatch(workspaceElement, 'eth-interface:compile'); 118 | } 119 | if (compiled !== null && compiled !== prevProps.compiled) { 120 | if (compiled.contracts) { 121 | for (const file of Object.entries(compiled.contracts)) { 122 | for (const [contractName, contract] of Object.entries(file[1])) { 123 | // Add interface to redux 124 | const ContractABI = contract.abi; 125 | this.props.addInterface({ contractName, ContractABI }); 126 | } 127 | } 128 | } 129 | if (compiled.errors) { 130 | this.props.setErrors(compiled.errors); 131 | } 132 | } 133 | } 134 | render() { 135 | const { compiled, deployed, compiling, interfaces } = this.props; 136 | return ( 137 | 138 | 139 |
140 | { 141 | compiled && compiled.contracts && 142 | Object.keys(compiled.contracts).map((fileName, index) => { 143 | return ( 144 | 153 | ); 154 | }) 155 | } 156 | { 157 | !compiled && 158 |

No compiled contract!

159 | } 160 |
161 | 162 |
163 |
164 |
165 | ); 166 | } 167 | } 168 | 169 | CollapsedFile.propTypes = { 170 | helpers: PropTypes.any.isRequired, 171 | contractName: PropTypes.string, 172 | bytecode: PropTypes.string, 173 | index: PropTypes.number, 174 | instances: PropTypes.any, 175 | interfaces: PropTypes.object, 176 | fileName: PropTypes.string, 177 | compiled: PropTypes.object, 178 | deployed: PropTypes.any, 179 | compiling: PropTypes.bool, 180 | }; 181 | 182 | Contracts.propTypes = { 183 | sources: PropTypes.object, 184 | helpers: PropTypes.any.isRequired, 185 | store: PropTypes.any.isRequired, 186 | compiled: PropTypes.object, 187 | deployed: PropTypes.any, 188 | compiling: PropTypes.bool, 189 | interfaces: PropTypes.object, 190 | addInterface: PropTypes.func, 191 | setErrors: PropTypes.func 192 | }; 193 | 194 | const mapStateToProps = ({ contract }) => { 195 | const { sources, compiled, deployed, compiling, interfaces } = contract; 196 | return { sources, compiled, deployed, compiling, interfaces }; 197 | }; 198 | 199 | export default connect(mapStateToProps, { addInterface, setErrors })(Contracts); 200 | -------------------------------------------------------------------------------- /lib/components/CreateButton/index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import React from 'react'; 18 | import { connect } from 'react-redux'; 19 | import PropTypes from 'prop-types'; 20 | import { setInstance, setDeployed, addNewEvents } from '../../actions'; 21 | 22 | class CreateButton extends React.Component { 23 | constructor(props) { 24 | super(props); 25 | this.helpers = props.helpers; 26 | this.state = { 27 | constructorParams: undefined, 28 | coinbase: props.coinbase, 29 | password: props.password, 30 | atAddress: undefined 31 | }; 32 | this._handleAtAddressChange = this._handleAtAddressChange.bind(this); 33 | this._handleSubmit = this._handleSubmit.bind(this); 34 | } 35 | async componentDidMount() { 36 | const { abi } = this.props; 37 | var inputs = []; 38 | for (let abiObj in abi) { 39 | if (abi[abiObj].type === 'constructor' && abi[abiObj].inputs.length > 0) { 40 | inputs = abi[abiObj].inputs; 41 | } 42 | } 43 | this.setState({ constructorParams: inputs }); 44 | } 45 | async _handleAtAddressChange(event) { 46 | this.setState({ atAddress: event.target.value }); 47 | } 48 | async _handleSubmit() { 49 | try { 50 | const { abi, bytecode, contractName, gas, coinbase, password } = this.props; 51 | const { atAddress } = this.state; 52 | const contractInterface = this.props.interfaces[contractName].interface; 53 | const constructor = contractInterface.find(interfaceItem => interfaceItem.type === 'constructor'); 54 | const params = []; 55 | if (constructor) { 56 | for (let input of constructor.inputs) { 57 | if (input.value) { 58 | params.push(input); 59 | } 60 | } 61 | } 62 | await this.helpers.create({ coinbase, password, atAddress, abi, bytecode, contractName, params, gas }); 63 | } catch (e) { 64 | console.error(e); 65 | this.helpers.showPanelError(e); 66 | } 67 | } 68 | render() { 69 | const { contractName } = this.props; 70 | return ( 71 |
72 | 77 | 78 | 82 | 83 |
84 | ); 85 | } 86 | } 87 | 88 | CreateButton.propTypes = { 89 | helpers: PropTypes.any.isRequired, 90 | coinbase: PropTypes.string, 91 | password: PropTypes.oneOfType([PropTypes.string, PropTypes.boolean]), 92 | interfaces: PropTypes.object, 93 | setInstance: PropTypes.func, 94 | setDeployed: PropTypes.func, 95 | addNewEvents: PropTypes.func, 96 | contractName: PropTypes.string, 97 | abi: PropTypes.object, 98 | bytecode: PropTypes.string, 99 | gas: PropTypes.number, 100 | }; 101 | 102 | const mapStateToProps = ({ contract, account }) => { 103 | const { compiled, interfaces } = contract; 104 | const { coinbase, password } = account; 105 | return { compiled, interfaces, coinbase, password }; 106 | }; 107 | 108 | export default connect(mapStateToProps, { setDeployed, setInstance, addNewEvents })(CreateButton); 109 | -------------------------------------------------------------------------------- /lib/components/ErrorView/index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import React from 'react'; 18 | import { connect } from 'react-redux'; 19 | import PropTypes from 'prop-types'; 20 | 21 | class ErrorView extends React.Component { 22 | constructor(props) { 23 | super(props); 24 | } 25 | render() { 26 | const { errormsg } = this.props; 27 | return ( 28 |
    29 | { 30 | errormsg.length > 0 && 31 | errormsg.map((msg, i) => { 32 | return ( 33 |
  • 34 | { 35 | msg.severity === 'warning' && 36 | {msg.formattedMessage || msg.message} 37 | } 38 | { 39 | msg.severity === 'error' && 40 | {msg.formattedMessage || msg.message} 41 | } 42 | { 43 | !msg.severity && 44 | {msg.message} 45 | } 46 |
  • 47 | ); 48 | }) 49 | } 50 |
51 | ); 52 | } 53 | } 54 | 55 | ErrorView.propTypes = { 56 | errormsg: PropTypes.any 57 | }; 58 | 59 | const mapStateToProps = ({ errors }) => { 60 | const { errormsg } = errors; 61 | return { errormsg }; 62 | }; 63 | 64 | export default connect(mapStateToProps, {})(ErrorView); 65 | -------------------------------------------------------------------------------- /lib/components/EventItem/index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import React from 'react'; 18 | import ReactJson from 'react-json-view'; 19 | import { Collapse } from 'react-collapse'; 20 | import PropTypes from 'prop-types'; 21 | 22 | class EventItem extends React.Component { 23 | constructor(props) { 24 | super(props); 25 | this.state = { 26 | isOpened: false, 27 | toggleBtnStyle: 'btn icon icon-unfold inline-block-tight', 28 | toggleBtnTxt: 'Expand' 29 | }; 30 | this._toggleCollapse = this._toggleCollapse.bind(this); 31 | } 32 | _toggleCollapse() { 33 | const { isOpened } = this.state; 34 | this.setState({ isOpened: !isOpened }); 35 | if(!isOpened) { 36 | this.setState({ 37 | toggleBtnStyle: 'btn btn-success icon icon-fold inline-block-tight', 38 | toggleBtnTxt: 'Collapse' 39 | }); 40 | } else { 41 | this.setState({ 42 | toggleBtnStyle: 'btn icon icon-unfold inline-block-tight', 43 | toggleBtnTxt: 'Expand' 44 | }); 45 | } 46 | } 47 | render() { 48 | const { event } = this.props; 49 | const { isOpened, toggleBtnStyle, toggleBtnTxt } = this.state; 50 | return ( 51 |
  • 52 | 60 | 61 | 69 | 70 |
  • 71 | ); 72 | } 73 | } 74 | 75 | EventItem.propTypes = { 76 | event: PropTypes.object 77 | }; 78 | 79 | export default EventItem; 80 | -------------------------------------------------------------------------------- /lib/components/Events/index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import React from 'react'; 18 | import { connect } from 'react-redux'; 19 | import EventItem from '../EventItem'; 20 | import PropTypes from 'prop-types'; 21 | 22 | class Events extends React.Component { 23 | constructor(props) { 24 | super(props); 25 | this.helpers = props.helpers; 26 | } 27 | render() { 28 | const { events } = this.props; 29 | const events_ = events.slice(); 30 | events_.reverse(); 31 | return ( 32 |
    33 |
      34 | { 35 | events_.length > 0 && 36 | events_.map((event, i) => { 37 | return ( 38 | 39 | ); 40 | }) 41 | } 42 | { 43 | !(events_.length > 0) && 44 |

      No events found!

      45 | } 46 |
    47 |
    48 | ); 49 | } 50 | } 51 | 52 | Events.propTypes = { 53 | helpers: PropTypes.any.isRequired, 54 | events: PropTypes.arrayOf(PropTypes.object) 55 | }; 56 | 57 | const mapStateToProps = ({ eventReducer }) => { 58 | const { events } = eventReducer; 59 | return { events }; 60 | }; 61 | 62 | export default connect(mapStateToProps, {})(Events); 63 | -------------------------------------------------------------------------------- /lib/components/FunctionABI/index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import React from 'react'; 18 | import { connect } from 'react-redux'; 19 | import PropTypes from 'prop-types'; 20 | import { updateInterface } from '../../actions'; 21 | 22 | class FunctionABI extends React.Component { 23 | constructor(props) { 24 | super(props); 25 | this.helpers = props.helpers; 26 | this._handleChange = this._handleChange.bind(this); 27 | this._handlePayableValue = this._handlePayableValue.bind(this); 28 | this._handleFallback = this._handleFallback.bind(this); 29 | this._handleSubmit = this._handleSubmit.bind(this); 30 | } 31 | _handleChange(i, j, event) { 32 | const { contractName, contracts } = this.props; 33 | const ContractABI = contracts[contractName].options.jsonInterface; 34 | const input = ContractABI[i].inputs[j]; 35 | input.value = event.target.value; 36 | ContractABI[i].inputs[j] = Object.assign({}, input); 37 | this.props.updateInterface({ contractName, ContractABI }); 38 | } 39 | _handlePayableValue(abi, event) { 40 | abi.payableValue = event.target.value; 41 | } 42 | async _handleFallback(abiItem) { 43 | const { contractName, coinbase, password, contracts } = this.props; 44 | const contract = contracts[contractName]; 45 | try { 46 | this.helpers.call({ coinbase, password, contract, abiItem }); 47 | } catch (e) { 48 | console.log(e); 49 | this.helpers.showPanelError(e); 50 | } 51 | } 52 | async _handleSubmit(methodItem) { 53 | try { 54 | const { contractName, coinbase, password, contracts } = this.props; 55 | const contract = contracts[contractName]; 56 | let params = []; 57 | for (let input of methodItem.inputs) { 58 | if (input.value) { 59 | params.push(input); 60 | } 61 | } 62 | this.helpers.call({ coinbase, password, contract, abiItem: methodItem, params }); 63 | } catch (e) { 64 | console.error(e); 65 | this.helpers.showPanelError(e); 66 | } 67 | } 68 | render() { 69 | const { contractName, interfaces } = this.props; 70 | const ContractABI = interfaces[contractName].interface; 71 | return ( 72 |
    73 | { 74 | ContractABI.map((abi, i) => { 75 | if (abi.type === 'function') { 76 | return ( 77 |
    78 |
    this._handleSubmit(abi)}> 79 | 80 | { 81 | abi.inputs.map((input, j) => { 82 | return ( 83 | this._handleChange(i, j, event)} 89 | key={j} 90 | /> 91 | ); 92 | }) 93 | } 94 | { 95 | abi.payable === true && 96 | this._handlePayableValue(abi, event)} 101 | /> 102 | } 103 |
    104 |
    105 | ); 106 | } 107 | if (abi.type === 'fallback') { 108 | return ( 109 |
    110 |
    { this._handleFallback(abi); }}> 111 | 112 | { 113 | abi.payable === true && 114 | this._handlePayableValue(abi, event)} 119 | /> 120 | } 121 |
    122 |
    123 | ); 124 | } 125 | }) 126 | } 127 |
    128 | ); 129 | } 130 | } 131 | 132 | FunctionABI.propTypes = { 133 | helpers: PropTypes.any.isRequired, 134 | contractName: PropTypes.string, 135 | interfaces: PropTypes.object, 136 | updateInterface: PropTypes.func, 137 | coinbase: PropTypes.string, 138 | password: PropTypes.string, 139 | instances: PropTypes.object, 140 | contracts: PropTypes.object 141 | }; 142 | 143 | const mapStateToProps = ({ contract, account }) => { 144 | const { compiled, interfaces, contracts } = contract; 145 | const { coinbase, password } = account; 146 | return { compiled, interfaces, contracts, coinbase, password }; 147 | }; 148 | 149 | export default connect(mapStateToProps, { updateInterface })(FunctionABI); 150 | -------------------------------------------------------------------------------- /lib/components/GasInput/index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import React from 'react'; 18 | import { connect } from 'react-redux'; 19 | import PropTypes from 'prop-types'; 20 | 21 | class GasInput extends React.Component { 22 | constructor(props) { 23 | super(props); 24 | this.state = { 25 | gas: props.gas 26 | }; 27 | } 28 | UNSAFE_componentWillReceiveProps(nextProps) { 29 | const { gas } = nextProps; 30 | this.setState({ gas }); 31 | } 32 | render() { 33 | const { gasLimit } = this.props; 34 | const { contractName } = this.props; 35 | return ( 36 |
    37 | 38 | 44 | 45 | 46 |
    47 | ); 48 | } 49 | } 50 | 51 | GasInput.propTypes = { 52 | contractName: PropTypes.string, 53 | interfaces: PropTypes.arrayOf(PropTypes.object), 54 | onChange: PropTypes.func, 55 | gasLimit: PropTypes.number, 56 | gas: PropTypes.number 57 | }; 58 | 59 | const mapStateToProps = ({ contract }) => { 60 | const { compiled, gasLimit } = contract; 61 | return { compiled, gasLimit }; 62 | }; 63 | 64 | export default connect(mapStateToProps, {})(GasInput); 65 | -------------------------------------------------------------------------------- /lib/components/InputsForm/index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import React from 'react'; 18 | import { connect } from 'react-redux'; 19 | import { setParamsInput } from '../../actions'; 20 | import PropTypes from 'prop-types'; 21 | 22 | class InputsForm extends React.Component { 23 | constructor(props) { 24 | super(props); 25 | this._handleChange = this._handleChange.bind(this); 26 | } 27 | _handleChange(input, event) { 28 | input.value = event.target.value; 29 | } 30 | render() { 31 | const { contractName, abi } = this.props; 32 | return ( 33 |
    34 | { 35 | abi.type === 'constructor' && 36 | abi.inputs.map((input, i) => { 37 | return ( 38 |
    39 | 40 | this._handleChange(input, e)} 44 | /> 45 |
    46 | ); 47 | }) 48 | } 49 |
    50 | ); 51 | } 52 | } 53 | 54 | InputsForm.propTypes = { 55 | onSubmit: PropTypes.func, 56 | contractName: PropTypes.string, 57 | abi: PropTypes.object 58 | }; 59 | 60 | const mapStateToProps = ({ contract }) => { 61 | const { compiled } = contract; 62 | return { compiled }; 63 | }; 64 | 65 | export default connect(mapStateToProps, { setParamsInput })(InputsForm); 66 | -------------------------------------------------------------------------------- /lib/components/LoaderView/index.js: -------------------------------------------------------------------------------- 1 | 'use babel'; 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import React from 'react'; 18 | import { connect } from 'react-redux'; 19 | import PropTypes from 'prop-types'; 20 | import ScaleLoader from 'react-spinners/ScaleLoader'; 21 | 22 | const loaderContainerStyle = { 23 | textAlign: 'center', 24 | justifyContent: 'center' 25 | }; 26 | 27 | class LoaderView extends React.Component { 28 | constructor(props) { 29 | super(props); 30 | this.store = this.props.store; 31 | } 32 | stateChange() { 33 | } 34 | componentDidUpdate() { 35 | 36 | } 37 | componentWillReceiveProps() { 38 | 39 | } 40 | render() { 41 | const { clients } = this.props; 42 | const { hasConnection } = clients[0]; 43 | 44 | // alert(hasConnection); 45 | 46 | return ( 47 |
    48 | 54 |
    55 | ); 56 | } 57 | } 58 | 59 | LoaderView.propTypes = { 60 | clients: PropTypes.any.isRequired, 61 | store: PropTypes.any, 62 | }; 63 | 64 | const mapStateToProps = ({ clientReducer }) => { 65 | const { clients } = clientReducer; 66 | return { clients }; 67 | }; 68 | export default connect(mapStateToProps)(LoaderView); 69 | -------------------------------------------------------------------------------- /lib/components/NodeControl/index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import React from 'react'; 18 | import { connect } from 'react-redux'; 19 | import { setAccounts, setSyncStatus, setMining, setHashrate, setCoinbase, setErrors } from '../../actions'; 20 | import PropTypes from 'prop-types'; 21 | 22 | class NodeControl extends React.Component { 23 | constructor(props) { 24 | super(props); 25 | this.helpers = props.helpers; 26 | this.helpers.isWsProvider(); 27 | this.helpers.isHttpProvider(); 28 | const { clients } = this.props; 29 | const client = clients[0]; 30 | this.state = { 31 | // TODO: get values from props 32 | wsProvider: client.isWsProvider, 33 | httpProvider: client.isHttpProvider, 34 | connected: client.hasConnection, 35 | toAddress: '', 36 | amount: 0, 37 | rpcAddress: atom.config.get('etheratom.rpcAddress'), 38 | websocketAddress: atom.config.get('etheratom.websocketAddress'), 39 | status: this.props.store.getState().node.status 40 | }; 41 | this._refreshSync = this._refreshSync.bind(this); 42 | this.getNodeInfo = this.getNodeInfo.bind(this); 43 | this._handleToAddrrChange = this._handleToAddrrChange.bind(this); 44 | this._handleSend = this._handleSend.bind(this); 45 | this._handleAmountChange = this._handleAmountChange.bind(this); 46 | this._handleWsChange = this._handleWsChange.bind(this); 47 | this._handleWsSubmit = this._handleWsSubmit.bind(this); 48 | this._handleRPCChange = this._handleRPCChange.bind(this); 49 | this._handleRPCSubmit = this._handleRPCSubmit.bind(this); 50 | } 51 | async componentDidMount() { 52 | this.getNodeInfo(); 53 | } 54 | async componentDidUpdate(prevProps, prevState) { 55 | if (this.state.httpProvider !== this.props.store.getState().clientReducer.clients[0].isHttpProvider) { 56 | this.setState({ httpProvider: this.props.store.getState().clientReducer.clients[0].isHttpProvider }); 57 | } 58 | if (this.state.wsProvider !== this.props.store.getState().clientReducer.clients[0].isWsProvider) { 59 | this.setState({ wsProvider: this.props.store.getState().clientReducer.clients[0].isWsProvider }); 60 | } 61 | } 62 | async _refreshSync() { 63 | await this.helpers.getAccounts(); 64 | this.getNodeInfo(); 65 | const { clients } = this.props; 66 | const client = clients[0]; 67 | this.setState({ 68 | wsProvider: client.isWsProvider, 69 | httpProvider: client.isHttpProvider, 70 | connected: client.hasConnection, 71 | }); 72 | } 73 | async getNodeInfo() { 74 | // get sync status 75 | await this.helpers.getSyncStat(); 76 | this.setState({ status: this.props.store.getState().node.status }); 77 | this.props.setSyncStatus(this.state.status); 78 | // get mining status 79 | await this.helpers.getMining(); 80 | // get hashrate 81 | await this.helpers.getHashrate(); 82 | // this.props.setHashrate(hashRate); 83 | } 84 | _handleToAddrrChange(event) { 85 | this.setState({ toAddress: event.target.value }); 86 | } 87 | _handleAmountChange(event) { 88 | this.setState({ amount: event.target.value }); 89 | } 90 | _handleWsChange(event) { 91 | atom.config.set('etheratom.websocketAddress', event.target.value); 92 | this.setState({ websocketAddress: event.target.value }); 93 | } 94 | _handleRPCChange(event) { 95 | atom.config.set('etheratom.rpcAddress', event.target.value); 96 | this.setState({ rpcAddress: event.target.value }); 97 | } 98 | async _handleWsSubmit(event) { 99 | event.preventDefault(); 100 | const { websocketAddress } = this.state; 101 | atom.config.set('etheratom.websocketAddress', websocketAddress); 102 | 103 | const newState = { 104 | wsProvider: this.props.store.getState().clientReducer.clients[0].isWsProvider, 105 | httpProvider: this.props.store.getState().clientReducer.clients[0].isHttpProvider, 106 | connected: this.props.store.getState().clientReducer.clients[0].hasConnection, 107 | toAddress: '', 108 | amount: 0, 109 | rpcAddress: atom.config.get('etheratom.rpcAddress'), 110 | websocketAddress: atom.config.get('etheratom.websocketAddress') 111 | }; 112 | 113 | this.setState(newState); 114 | // this.helpers.updateWeb3(); 115 | try { 116 | 117 | await this.helpers.getAccountsForNodeSubmit('node_ws', websocketAddress); 118 | } 119 | catch (e) { 120 | this.helpers.showPanelError('Error with Web Socket value. Please check again'); 121 | } 122 | } 123 | async _handleRPCSubmit(event) { 124 | event.preventDefault(); 125 | const { rpcAddress } = this.state; 126 | atom.config.set('etheratom.rpcAddress', rpcAddress); 127 | const newState = { 128 | wsProvider: this.props.store.getState().clientReducer.clients[0].isWsProvider, 129 | httpProvider: this.props.store.getState().clientReducer.clients[0].isHttpProvider, 130 | connected: this.props.store.getState().clientReducer.clients[0].hasConnection, 131 | toAddress: '', 132 | amount: 0, 133 | rpcAddress: atom.config.get('etheratom.rpcAddress'), 134 | websocketAddress: atom.config.get('etheratom.websocketAddress') 135 | }; 136 | 137 | this.setState(newState); 138 | // this.helpers.updateWeb3(); 139 | try { 140 | await this.helpers.getAccountsForNodeSubmit('node_rpc', rpcAddress); 141 | } 142 | catch (e) { 143 | 144 | this.helpers.showPanelError('Error with RPC value. Please check again'); 145 | } 146 | } 147 | async _handleSend() { 148 | try { 149 | const { password } = this.props; 150 | const { toAddress, amount } = this.state; 151 | await this.helpers.send(toAddress, amount, password); 152 | // this.helpers.showTransaction({ head: 'Transaction recipt:', data: txRecipt }); 153 | } catch (e) { 154 | this.helpers.showPanelError(e); 155 | } 156 | } 157 | render() { 158 | const { coinbase, status, syncing, mining, hashRate } = this.props; 159 | const { connected, wsProvider, httpProvider, toAddress, amount, rpcAddress, websocketAddress } = this.state; 160 | return ( 161 |
    162 |
    163 |
      164 |
    • 165 |
      166 | 167 | 172 |
      173 |
    • 174 |
    • 175 |
      176 | 177 | 182 |
      183 |
    • 184 |
    • 185 | Connected: 186 | {`${connected}`} 187 |
    • 188 |
    189 |
    190 |
      191 |
    • 192 | Coinbase: 193 | {coinbase} 194 |
    • 195 |
    196 | { 197 | (Object.keys(status).length > 0 && status instanceof Object) && 198 |
      199 |
    • 200 | Sync progress: 201 | 202 | {(100 * (status.currentBlock / status.highestBlock)).toFixed(2)}% 203 |
    • 204 |
    • 205 | Current Block: 206 | {status.currentBlock} 207 |
    • 208 |
    • 209 | Highest Block: 210 | {status.highestBlock} 211 |
    • 212 |
    • 213 | Known States: 214 | {status.knownStates} 215 |
    • 216 |
    • 217 | Pulled States 218 | {status.pulledStates} 219 |
    • 220 |
    • 221 | Starting Block: 222 | {status.startingBlock} 223 |
    • 224 |
    225 | } 226 | { 227 | !syncing && 228 |
      229 |
    • 230 | Syncing: 231 | {`${syncing}`} 232 |
    • 233 |
    234 | } 235 |
      236 |
    • 237 | Mining: 238 | {`${mining}`} 239 |
    • 240 |
    • 241 | Hashrate: 242 | {hashRate} 243 |
    • 244 |
    245 | 246 |
    247 | 253 | 259 | 264 |
    265 |
    266 | ); 267 | } 268 | } 269 | 270 | NodeControl.propTypes = { 271 | helpers: PropTypes.any.isRequired, 272 | syncing: PropTypes.bool, 273 | status: PropTypes.object, 274 | mining: PropTypes.bool, 275 | hashRate: PropTypes.number, 276 | coinbase: PropTypes.number, 277 | setHashrate: PropTypes.func, 278 | setMining: PropTypes.func, 279 | setSyncStatus: PropTypes.func, 280 | setAccounts: PropTypes.func, 281 | setCoinbase: PropTypes.func, 282 | setErrors: PropTypes.string, 283 | password: PropTypes.string, 284 | clients: PropTypes.array.isRequired, 285 | store: PropTypes.any, 286 | }; 287 | 288 | const mapStateToProps = ({ account, node, clientReducer }) => { 289 | const { coinbase, password } = account; 290 | const { status, syncing, mining, hashRate } = node; 291 | const { clients } = clientReducer; 292 | return { coinbase, password, status, syncing, mining, hashRate, clients }; 293 | }; 294 | 295 | export default connect(mapStateToProps, { setAccounts, setCoinbase, setSyncStatus, setMining, setHashrate, setErrors })(NodeControl); 296 | -------------------------------------------------------------------------------- /lib/components/RemixDebugger/index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import React from 'react'; 18 | import { connect, Provider } from 'react-redux'; 19 | import PropTypes from 'prop-types'; 20 | import { execution, init } from 'remix-lib'; 21 | import { TransactionDebugger as Debugger } from 'remix-debug'; 22 | class RemixDebugger extends React.Component { 23 | constructor(props) { 24 | super(props); 25 | } 26 | getDebugWeb3() { 27 | return new Promise((resolve, reject) => { 28 | execution.executionContext.detectNetwork((error, network) => { 29 | let web3; 30 | if (error || !network) { 31 | web3 = init.web3DebugNode(execution.executionContext.web3()); 32 | } else { 33 | const webDebugNode = init.web3DebugNode(network.name); 34 | web3 = !webDebugNode ? execution.executionContext.web3() : webDebugNode; 35 | } 36 | init.extendWeb3(web3); 37 | resolve(web3); 38 | }) 39 | }) 40 | } 41 | async _runRemixDebugging(blockNumber, txNumber, tx) { 42 | let lastCompilationResult; 43 | if (this.props.compiled) lastCompilationResult = this.props.compiled; 44 | var api = null; 45 | let web3 = await this.getDebugWeb3(); 46 | this.debugger = new Debugger({ 47 | web3, 48 | api, 49 | compiler: { lastCompilationResult } 50 | }); 51 | 52 | this.debugger.debug(blockNumber, txNumber, tx, () => { 53 | console.log('debugger detected'); 54 | }).catch((error) => { 55 | console.error(error); 56 | }) 57 | } 58 | render() { 59 | // const { blockNumber, txNumber, tx } = this.props; 60 | return ( 61 | 62 |
    63 |

    Remix-Debugger

    64 | {/* 65 | 68 | */} 69 | 72 |
    73 |
    74 | ); 75 | } 76 | } 77 | 78 | RemixDebugger.propTypes = { 79 | compiled: PropTypes.object, 80 | store: PropTypes.any, 81 | 82 | }; 83 | const mapStateToProps = ({ contract }) => { 84 | const { compiled } = contract; 85 | return { compiled }; 86 | }; 87 | export default connect(mapStateToProps, {})(RemixDebugger); 88 | -------------------------------------------------------------------------------- /lib/components/RemixTests/index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import React from 'react'; 18 | import { connect, Provider } from 'react-redux'; 19 | import PropTypes from 'prop-types'; 20 | import VirtualList from 'react-tiny-virtual-list'; 21 | import ErrorView from '../ErrorView'; 22 | import { setErrors, resetErrors } from '../../actions'; 23 | import { fork } from 'child_process'; 24 | 25 | Object.defineProperty(String.prototype, 'regexIndexOf', { 26 | value(regex, startpos) { 27 | const indexOf = this.substring(startpos || 0).search(regex); 28 | return (indexOf >= 0) ? (indexOf + (startpos || 0)) : indexOf; 29 | } 30 | }); 31 | 32 | class RemixTest extends React.Component { 33 | constructor(props) { 34 | super(props); 35 | this.state = { 36 | testResults: [], 37 | testResult: null, 38 | running: false 39 | }; 40 | } 41 | createWorker(fn) { 42 | const pkgPath = atom.packages.resolvePackagePath('etheratom'); 43 | return fork(`${pkgPath}/lib/web3/worker.js`); 44 | } 45 | componentDidMount() { 46 | this.props.resetErrors(); 47 | } 48 | componentDidUpdate(prevProps) { 49 | const { sources } = this.props; 50 | if (sources != prevProps.sources) { 51 | this._runRemixTests(); 52 | } 53 | } 54 | async _runRemixTests() { 55 | const { sources } = this.props; 56 | this.setState({ testResults: [], testResult: { totalFailing: 0, totalPassing: 0, totalTime: 0 }, running: true }); 57 | this.props.resetErrors(); 58 | try { 59 | const utWorker = this.createWorker(); 60 | utWorker.send({ command: 'runTests', payload: sources }); 61 | utWorker.on('message', m => { 62 | if (m._testCallback) { 63 | const result = m.result; 64 | const { testResults } = this.state; 65 | console.log(testResults); 66 | const t = testResults.slice(); 67 | t.push(result); 68 | this.setState({ testResults: t }); 69 | } 70 | if (m._resultsCallback) { 71 | const result = m.result; 72 | console.log(result); 73 | } 74 | if (m._finalCallback) { 75 | const result = m.result; 76 | this.setState({ testResult: result, running: false }); 77 | utWorker.kill(); 78 | } 79 | if (m._importFileCb) { 80 | const result = m.result; 81 | console.log(result); 82 | } 83 | if (m.error) { 84 | console.log(m); 85 | const e = m.error; 86 | this.props.setErrors(e); 87 | } 88 | }); 89 | utWorker.on('error', e => { 90 | throw e; 91 | }); 92 | utWorker.on('exit', (code, signal) => { 93 | this.setState({ running: false }); 94 | console.log('%c Compile worker process exited with ' + `code ${code} and signal ${signal}`, 'background: rgba(36, 194, 203, 0.3); color: #EF525B'); 95 | }); 96 | } catch (e) { 97 | this.props.setErrors(e); 98 | e.forEach(err => { 99 | console.error(err); 100 | }); 101 | } 102 | } 103 | async injectTests(source) { 104 | const s = /^(import)\s['"](remix_tests.sol|tests.sol)['"];/gm; 105 | if (source.content && source.content.regexIndexOf(s) < 0) { 106 | return source.content.replace(/(pragma solidity \^\d+\.\d+\.\d+;)/, '$1\nimport \'remix_tests.sol\';'); 107 | } 108 | } 109 | render() { 110 | const { testResults, testResult, running } = this.state; 111 | return ( 112 | 113 |
    114 |

    Test files should have [foo]_test.sol suffix

    115 |
    116 | 119 | { 120 | running && 121 | 122 | } 123 | { 124 | testResult && 125 |
    126 | Total failing: {testResult.totalFailing} 127 | Total passing: {testResult.totalPassing} 128 | Time: {testResult.totalTime} 129 |
    130 | } 131 |
    132 | 139 |
    140 | { 141 | testResults[index].type === 'contract' && 142 | 143 | } 144 | { 145 | testResults[index].type === 'testPass' && 146 | 147 | } 148 | { 149 | testResults[index].type === 'testFailure' && 150 | 151 | } 152 | 153 | {testResults[index].value} 154 | 155 |
    156 | } 157 | /> 158 |
    159 | 160 |
    161 |
    162 |
    163 | ); 164 | } 165 | } 166 | 167 | RemixTest.propTypes = { 168 | helpers: PropTypes.any.isRequired, 169 | sources: PropTypes.object, 170 | compiled: PropTypes.object, 171 | setErrors: PropTypes.func, 172 | resetErrors: PropTypes.func, 173 | store: PropTypes.any.isRequired 174 | }; 175 | 176 | const mapStateToProps = ({ files }) => { 177 | const { sources } = files; 178 | return { sources }; 179 | }; 180 | export default connect(mapStateToProps, { setErrors, resetErrors })(RemixTest); 181 | -------------------------------------------------------------------------------- /lib/components/StaticAnalysis/index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import React from 'react'; 18 | import { connect } from 'react-redux'; 19 | import { CodeAnalysis } from 'remix-analyzer'; 20 | import CheckboxTree from 'react-checkbox-tree'; 21 | import PropTypes from 'prop-types'; 22 | 23 | class StaticAnalysis extends React.Component { 24 | constructor(props) { 25 | super(props); 26 | this.helpers = props.helpers; 27 | this.anlsRunner = new CodeAnalysis(); 28 | this.state = { 29 | anlsModules: this.anlsRunner.modules(), 30 | nodes: this._getNodes(this.anlsRunner.modules()), 31 | checked: [], 32 | analysis: [], 33 | running: false 34 | }; 35 | this._runAnalysis = this._runAnalysis.bind(this); 36 | } 37 | componentDidMount() { 38 | // Mark all modules checked in the begining 39 | const { nodes } = this.state; 40 | const checked = []; 41 | for (let i = 0; i < nodes.length; i++) { 42 | checked.push(i); 43 | } 44 | this.setState({ checked }); 45 | } 46 | _getNodes(modules) { 47 | return modules.map((module, i) => { 48 | return Object.assign({}, {}, { value: i, label: module.description, index: i }); 49 | }); 50 | } 51 | async _runAnalysis() { 52 | const { checked } = this.state; 53 | const { compiled } = this.props; 54 | this.setState({ analysis: [], running: true }); 55 | if (compiled != null) { 56 | try { 57 | const analysis = await this.getAnalysis(compiled, checked); 58 | this.setState({ analysis, running: false }); 59 | } catch (e) { 60 | this.setState({ running: false }); 61 | throw e; 62 | } 63 | } else { 64 | this.setState({ running: false }); 65 | this.helpers.showPanelError('Compile the code first then, analyse it.'); 66 | } 67 | } 68 | async getAnalysis(compiled, checked) { 69 | return new Promise((resolve, reject) => { 70 | this.anlsRunner.run(compiled, checked, (analysis, error) => { 71 | if (error) { 72 | reject(error); 73 | return; 74 | } 75 | resolve(analysis); 76 | }); 77 | }); 78 | } 79 | render() { 80 | const { nodes, analysis, running } = this.state; 81 | return ( 82 |
    83 | this.setState({ checked })} 88 | showNodeIcon={false} 89 | /> 90 | 93 | { 94 | running && 95 | 96 | } 97 | { 98 | analysis.length > 0 && 99 | analysis.map((a, j) => { 100 | if (a.report.length > 0) { 101 | return ( 102 |
    103 | { 104 | a.report.map((report, i) => { 105 | return ( 106 |
    107 | { 108 | report.location && 109 | 110 | {report.location}{' '} 111 | 112 | } 113 | { 114 | report.warning && 115 | 116 | } 117 | { 118 | report.more && 119 |

    120 | 121 | {report.more} 122 | 123 |

    124 | } 125 |
    126 | ); 127 | }) 128 | } 129 |
    130 | ); 131 | } 132 | return; 133 | }) 134 | } 135 |
    136 | ); 137 | } 138 | } 139 | 140 | StaticAnalysis.propTypes = { 141 | helpers: PropTypes.any.isRequired, 142 | compiled: PropTypes.object, 143 | }; 144 | 145 | const mapStateToProps = ({ contract }) => { 146 | const { compiled } = contract; 147 | return { compiled }; 148 | }; 149 | 150 | export default connect(mapStateToProps, {})(StaticAnalysis); 151 | -------------------------------------------------------------------------------- /lib/components/TabView/index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import React from 'react'; 18 | import { Tab, Tabs, TabList, TabPanel } from 'react-tabs'; 19 | import { connect } from 'react-redux'; 20 | import PropTypes from 'prop-types'; 21 | import Contracts from '../Contracts'; 22 | import TxAnalyzer from '../TxAnalyzer'; 23 | import Events from '../Events'; 24 | import RemixTest from '../RemixTests'; 25 | import RemixDebugger from '../RemixDebugger'; 26 | import NodeControl from '../NodeControl'; 27 | import StaticAnalysis from '../StaticAnalysis'; 28 | 29 | class TabView extends React.Component { 30 | constructor(props) { 31 | super(props); 32 | this.helpers = props.helpers; 33 | this.state = { 34 | txBtnStyle: 'btn', 35 | eventBtnStyle: 'btn', 36 | newTxCounter: 0, 37 | newEventCounter: 0 38 | }; 39 | this._handleTabSelect = this._handleTabSelect.bind(this); 40 | } 41 | _handleTabSelect(index) { 42 | if (index === 3) { 43 | this.setState({ newTxCounter: 0, txBtnStyle: 'btn' }); 44 | } 45 | if (index === 4) { 46 | this.setState({ newEventCounter: 0, eventBtnStyle: 'btn' }); 47 | } 48 | } 49 | UNSAFE_componentWillReceiveProps(nextProps) { 50 | const { newTxCounter, newEventCounter } = this.state; 51 | if (this.props.pendingTransactions !== nextProps.pendingTransactions) { 52 | this.setState({ newTxCounter: newTxCounter + 1, txBtnStyle: 'btn btn-error' }); 53 | } 54 | if (this.props.events !== nextProps.events && nextProps.events.length > 0) { 55 | this.setState({ newEventCounter: newEventCounter + 1, eventBtnStyle: 'btn btn-error' }); 56 | } 57 | } 58 | render() { 59 | const { eventBtnStyle, txBtnStyle, newTxCounter, newEventCounter } = this.state; 60 | 61 | return ( 62 | this._handleTabSelect(index)} className="react-tabs vertical-tabs"> 63 | 64 |
    65 | 66 |
    Contract
    67 |
    68 | 69 |
    Tests
    70 |
    71 | 72 |
    Analysis
    73 |
    74 | 75 |
    76 | Transaction analyzer 77 | { 78 | newTxCounter > 0 && 79 | {newTxCounter} 80 | } 81 |
    82 |
    83 | 84 |
    Debugger
    85 |
    86 | 87 |
    88 | Events 89 | { 90 | newEventCounter > 0 && 91 | {newEventCounter} 92 | } 93 |
    94 |
    95 | 96 |
    Node
    97 |
    98 | 99 |
    Help
    100 |
    101 |
    102 |
    103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 |

    Help Etheratom to keep solidity development interactive.

    127 |

    Donate Ethereum: 0xd22fE4aEFed0A984B1165dc24095728EE7005a36

    128 |

    129 | Etheratom news #Etheratom 130 |

    131 |

    132 | Etheratom support t.me/etheratom 133 |

    134 |

    135 | Contact: 0mkar@protonmail.com 136 |

    137 |
    138 |
    139 | ); 140 | } 141 | } 142 | 143 | TabView.propTypes = { 144 | helpers: PropTypes.any.isRequired, 145 | store: PropTypes.any.isRequired, 146 | pendingTransactions: PropTypes.array, 147 | events: PropTypes.array, 148 | }; 149 | 150 | const mapStateToProps = ({ contract, eventReducer }) => { 151 | const { compiled } = contract; 152 | const { pendingTransactions, events } = eventReducer; 153 | return { compiled, pendingTransactions, events }; 154 | }; 155 | 156 | export default connect(mapStateToProps, {})(TabView); 157 | -------------------------------------------------------------------------------- /lib/components/TxAnalyzer/index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import React from 'react'; 18 | import { connect } from 'react-redux'; 19 | import { Collapse } from 'react-collapse'; 20 | import ReactJson from 'react-json-view'; 21 | import VirtualList from 'react-tiny-virtual-list'; 22 | import PropTypes from 'prop-types'; 23 | 24 | class TxAnalyzer extends React.Component { 25 | constructor(props) { 26 | super(props); 27 | this.helpers = props.helpers; 28 | this.state = { 29 | txHash: undefined, 30 | txAnalysis: props.txAnalysis, 31 | toggleBtnStyle: 'btn icon icon-unfold inline-block-tight', 32 | isOpened: false, 33 | }; 34 | this._handleTxHashChange = this._handleTxHashChange.bind(this); 35 | this._handleTxHashSubmit = this._handleTxHashSubmit.bind(this); 36 | this._toggleCollapse = this._toggleCollapse.bind(this); 37 | } 38 | componentDidMount() { 39 | const { pendingTransactions } = this.props; 40 | if (pendingTransactions.length < 10) { 41 | this.setState({ 42 | isOpened: true, 43 | toggleBtnStyle: 'btn btn-success icon icon-fold inline-block-tight' 44 | }); 45 | } 46 | } 47 | componentDidUpdate(prevProps) { 48 | if (prevProps.txAnalysis !== this.props.txAnalysis) { 49 | this.setState({ txAnalysis: this.props.txAnalysis }); 50 | } 51 | } 52 | _toggleCollapse() { 53 | const { isOpened } = this.state; 54 | this.setState({ isOpened: !isOpened }); 55 | if (!isOpened) { 56 | this.setState({ 57 | toggleBtnStyle: 'btn btn-success icon icon-fold inline-block-tight' 58 | }); 59 | } else { 60 | this.setState({ 61 | toggleBtnStyle: 'btn icon icon-unfold inline-block-tight' 62 | }); 63 | } 64 | } 65 | _handleTxHashChange(event) { 66 | this.setState({ txHash: event.target.value }); 67 | } 68 | async _handleTxHashSubmit() { 69 | const { txHash } = this.state; 70 | if (txHash) { 71 | try { 72 | const txAnalysis = await this.helpers.getTxAnalysis(txHash); 73 | this.setState({ txAnalysis }); 74 | } catch (e) { 75 | console.log(e); 76 | } 77 | } 78 | } 79 | render() { 80 | const { toggleBtnStyle, isOpened } = this.state; 81 | const { pendingTransactions, txAnalysis } = this.props; 82 | const transactions = pendingTransactions.slice(); 83 | transactions.reverse(); 84 | return ( 85 |
    86 |
    87 |
    88 |
    89 | 90 |
    91 |
    92 | 93 |
    94 |
    95 | 98 |
    99 | 100 | { 101 | transactions.length > 0 && 102 | 108 |
    109 | 110 | {transactions[index]} 111 | 112 |
    113 | } 114 | /> 115 | } 116 |
    117 | { 118 | (txAnalysis && txAnalysis.transaction) && 119 |
    120 |

    Transaction

    121 | 129 |
    130 | } 131 | { 132 | (txAnalysis && txAnalysis.transactionRecipt) && 133 |
    134 |

    Transaction receipt

    135 | 143 |
    144 | } 145 |
    146 | ); 147 | } 148 | } 149 | 150 | TxAnalyzer.propTypes = { 151 | helpers: PropTypes.any.isRequired, 152 | pendingTransactions: PropTypes.array, 153 | txAnalysis: PropTypes.any 154 | }; 155 | 156 | const mapStateToProps = ({ eventReducer }) => { 157 | const { pendingTransactions, txAnalysis } = eventReducer; 158 | return { pendingTransactions, txAnalysis }; 159 | }; 160 | 161 | export default connect(mapStateToProps, {})(TxAnalyzer); 162 | -------------------------------------------------------------------------------- /lib/components/VersionSelector/index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import React from 'react'; 18 | import PropTypes from 'prop-types'; 19 | import { connect } from 'react-redux'; 20 | import axios from 'axios'; 21 | 22 | class VersionSelector extends React.Component { 23 | constructor(props) { 24 | super(props); 25 | this.state = { 26 | availableVersions: [], 27 | selectedVersion: '', 28 | }; 29 | this._handleVersionSelector = this._handleVersionSelector.bind(this); 30 | } 31 | async _handleVersionSelector(event) { 32 | const selectedVersion = event.target.value; 33 | await this.setState({ selectedVersion }); 34 | atom.config.set('etheratom.versionSelector', selectedVersion); 35 | } 36 | async componentDidMount() { 37 | this.fetchVersionList(); 38 | } 39 | 40 | async fetchVersionList() { 41 | const versions = await axios.get('https://ethereum.github.io/solc-bin/bin/list.json'); 42 | this.setState({ 43 | availableVersions: versions.data.releases, 44 | selectedVersion: atom.config.get('etheratom.versionSelector'), 45 | }); 46 | } 47 | render() { 48 | const { availableVersions } = this.state; 49 | return ( 50 |
    51 |
    52 | 61 |
    62 |
    63 | ); 64 | } 65 | } 66 | 67 | VersionSelector.propTypes = { 68 | selectedVersion: PropTypes.string 69 | }; 70 | 71 | const mapStateToProps = ({ contract }) => { 72 | const { selectedVersion } = contract; 73 | return { selectedVersion }; 74 | }; 75 | 76 | export default connect(mapStateToProps, {})(VersionSelector); 77 | -------------------------------------------------------------------------------- /lib/ethereum-interface-view.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import { CompositeDisposable } from 'atom'; 18 | export class AtomSolidityView { 19 | constructor() { 20 | this.element = document.createElement; 21 | this.element = document.createElement('atom-panel'); 22 | this.element.classList.add('etheratom-panel'); 23 | let att = null; 24 | 25 | // empty div to handle resize 26 | let resizeNode = document.createElement('div'); 27 | resizeNode.onmousedown = this.handleMouseDown.bind(this); 28 | resizeNode.classList.add('etheratom-panel-resize-handle'); 29 | resizeNode.setAttribute('ref', 'resizehandle'); 30 | this.element.appendChild(resizeNode); 31 | 32 | let mainNode = document.createElement('div'); 33 | mainNode.classList.add('etheratom'); 34 | mainNode.classList.add('native-key-bindings'); 35 | mainNode.setAttribute('tabindex', '-1'); 36 | 37 | let message = document.createElement('div'); 38 | message.textContent = 'Etheratom IDE'; 39 | message.classList.add('compiler-info'); 40 | message.classList.add('block'); 41 | message.classList.add('highlight-info'); 42 | mainNode.appendChild(message); 43 | 44 | let compilerNode = document.createElement('div'); 45 | att = document.createAttribute('id'); 46 | att.value = 'client-options'; 47 | compilerNode.setAttributeNode(att); 48 | mainNode.appendChild(compilerNode); 49 | 50 | let loaderNode = document.createElement('div'); 51 | att = document.createAttribute('id'); 52 | att.value = 'loader'; 53 | loaderNode.setAttributeNode(att); 54 | mainNode.appendChild(loaderNode); 55 | 56 | let versionNode = document.createElement('div'); 57 | att = document.createAttribute('id'); 58 | att.value = 'version_selector'; 59 | versionNode.setAttributeNode(att); 60 | mainNode.appendChild(versionNode); 61 | 62 | let accountsNode = document.createElement('div'); 63 | att = document.createAttribute('id'); 64 | att.value = 'accounts-list'; 65 | accountsNode.setAttributeNode(att); 66 | mainNode.appendChild(accountsNode); 67 | 68 | let buttonNode = document.createElement('div'); 69 | att = document.createAttribute('id'); 70 | att.value = 'common-buttons'; 71 | buttonNode.setAttributeNode(att); 72 | buttonNode.classList.add('block'); 73 | 74 | let compileButton = document.createElement('div'); 75 | att = document.createAttribute('id'); 76 | att.value = 'compile_btn'; 77 | compileButton.setAttributeNode(att); 78 | compileButton.classList.add('inline-block'); 79 | 80 | buttonNode.appendChild(compileButton); 81 | mainNode.appendChild(buttonNode); 82 | 83 | let tabNode = document.createElement('div'); 84 | att = document.createAttribute('id'); 85 | att.value = 'tab_view'; 86 | tabNode.setAttributeNode(att); 87 | mainNode.appendChild(tabNode); 88 | 89 | let errorNode = document.createElement('div'); 90 | att = document.createAttribute('id'); 91 | att.value = 'compiled-error'; 92 | errorNode.setAttributeNode(att); 93 | errorNode.classList.add('compiled-error'); 94 | mainNode.appendChild(errorNode); 95 | 96 | // Finally append mainNode to element 97 | this.element.appendChild(mainNode); 98 | 99 | this.handleMouseDown = this.handleMouseDown.bind(this); 100 | this.handleMouseMove = this.handleMouseMove.bind(this); 101 | this.handleMouseUp = this.handleMouseUp.bind(this); 102 | this.dispose = this.dispose.bind(this); 103 | this.getElement = this.getElement.bind(this); 104 | this.destroy = this.destroy.bind(this); 105 | } 106 | handleMouseDown(e) { 107 | if (this.subscriptions != null) { 108 | this.subscriptions.dispose(); 109 | } 110 | 111 | const mouseUpHandler = (e) => this.handleMouseUp(e); 112 | const mouseMoveHandler = (e) => this.handleMouseMove(e); 113 | window.addEventListener('mousemove', mouseMoveHandler); 114 | window.addEventListener('mouseup', mouseUpHandler); 115 | 116 | this.subscriptions = new CompositeDisposable({ 117 | dispose: () => { 118 | window.removeEventListener('mousemove', mouseMoveHandler); 119 | } 120 | }, { 121 | dispose: () => { 122 | window.removeEventListener('mouseup', mouseUpHandler); 123 | } 124 | }); 125 | } 126 | handleMouseMove(e) { 127 | // Currently only vertical panel is working, may be later I should add horizontal panel 128 | const width = this.element.getBoundingClientRect().right - e.pageX; 129 | const vwidth = window.innerWidth; 130 | const vw = (width / vwidth) * 100 + 'vw'; 131 | this.element.style.width = vw; 132 | } 133 | handleMouseUp(e) { 134 | if (this.subscriptions) { 135 | this.subscriptions.dispose(); 136 | } 137 | } 138 | getElement() { 139 | return this.element; 140 | } 141 | dispose() { 142 | this.destroy(); 143 | } 144 | destroy() { 145 | return this.element.remove(); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /lib/ethereum-interface.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import { AtomSolidityView } from './ethereum-interface-view'; 18 | import Web3Env from './web3/web3'; 19 | import configureStore from './helpers/configureStore'; 20 | import { CompositeDisposable } from 'atom'; 21 | 22 | export class Etheratom { 23 | constructor(props) { 24 | this.subscriptions = new CompositeDisposable(); 25 | this.atomSolidityView = new AtomSolidityView(); 26 | this.modalPanel = null; 27 | this.loaded = false; 28 | this.store = configureStore(); 29 | } 30 | activate() { 31 | require('atom-package-deps').install('etheratom', true) 32 | .then(function() { 33 | console.log('All dependencies installed, good to go'); 34 | }); 35 | this.subscriptions.add(atom.commands.add('atom-workspace', { 36 | 'eth-interface:toggle': ((_this) => { 37 | return function() { 38 | _this.toggleView(); 39 | }; 40 | })(this), 41 | 'eth-interface:activate': ((_this) => { 42 | return function() { 43 | _this.toggleView(); 44 | }; 45 | })(this) 46 | })); 47 | this.modalPanel = atom.workspace.addRightPanel({ 48 | item: this.atomSolidityView.getElement(), 49 | visible: false 50 | }); 51 | // Initiate env 52 | this.load(); 53 | } 54 | deactivate() { 55 | this.modalPanel.destroy(); 56 | this.subscriptions.dispose(); 57 | this.atomSolidityView.destroy(); 58 | } 59 | load() { 60 | this.loadWeb3(); 61 | this.loaded = true; 62 | } 63 | loadWeb3() { 64 | if (this.Web3Interface) { 65 | return this.Web3Interface; 66 | } 67 | this.Web3Interface = new Web3Env(this.store); 68 | this.subscriptions.add(this.Web3Interface); 69 | return this.Web3Interface; 70 | } 71 | toggleView() { 72 | if (this.modalPanel.isVisible()) { 73 | return this.modalPanel.hide(); 74 | } else { 75 | return this.modalPanel.show(); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /lib/helpers/compiler-imports.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | 18 | /*eslint no-useless-escape: "warn"*/ 19 | /*eslint node/no-deprecated-api: "warn" */ 20 | import axios from 'axios'; 21 | import path from 'path'; 22 | import url from 'url'; 23 | import validUrl from 'valid-url'; 24 | import fs from 'fs'; 25 | 26 | async function handleGithubCall(fullpath, repoPath, path, filename, fileRoot) { 27 | return await axios({ 28 | method: 'get', 29 | url: 'https://api.github.com/repos/' + repoPath + '/contents/' + path, 30 | responseType: 'json' 31 | }).then(function(response) { 32 | if ('content' in response.data) { 33 | const buf = Buffer.from(response.data.content, 'base64'); 34 | fileRoot = fullpath.substring(0, fullpath.lastIndexOf('/')); 35 | fileRoot = fileRoot + '/'; 36 | const resp = { filename, content: buf.toString('UTF-8'), fileRoot }; 37 | return resp; 38 | } else { 39 | throw 'Content not received!'; 40 | } 41 | }); 42 | } 43 | async function handleNodeModulesImport(pathString, filename, fileRoot) { 44 | const o = { encoding: 'UTF-8' }; 45 | var modulesDir = fileRoot; 46 | 47 | while (true) { 48 | var p = path.join(modulesDir, 'node_modules', pathString, filename); 49 | try { 50 | const content = fs.readFileSync(p, o); 51 | fileRoot = path.join(modulesDir, 'node_modules', pathString); 52 | const response = { filename, content, fileRoot }; 53 | return response; 54 | } 55 | catch (err) { 56 | console.log(err); 57 | } 58 | 59 | // Recurse outwards until impossible 60 | var oldModulesDir = modulesDir; 61 | modulesDir = path.join(modulesDir, '..'); 62 | if (modulesDir === oldModulesDir) { 63 | break; 64 | } 65 | } 66 | 67 | } 68 | async function handleLocalImport(pathString, filename, fileRoot) { 69 | // if no relative/absolute path given then search in node_modules folder 70 | if (pathString && pathString.indexOf('.') !== 0 && pathString.indexOf('/') !== 0) { 71 | return handleNodeModulesImport(pathString, filename, fileRoot); 72 | } 73 | else { 74 | const o = { encoding: 'UTF-8' }; 75 | const p = pathString ? path.resolve(fileRoot, pathString, filename) : path.resolve(fileRoot, filename); 76 | const content = fs.readFileSync(p, o); 77 | fileRoot = pathString ? path.resolve(fileRoot, pathString) : fileRoot; 78 | const response = { filename, content, fileRoot }; 79 | return response; 80 | } 81 | } 82 | async function getHandlers() { 83 | return [ 84 | { 85 | type: 'local', 86 | match: /(^(?!(?:http:\/\/)|(?:https:\/\/)?(?:www.)?(?:github.com)))(^\/*[\w+-_/]*\/)*?(\w+\.sol)/g, 87 | handle: async(match, fileRoot) => { return await handleLocalImport(match[2], match[3], fileRoot); } 88 | }, 89 | { 90 | type: 'github', 91 | match: /^(https?:\/\/)?(www.)?github.com\/([^/]*\/[^/]*)(.*\/(\w+\.sol))/g, 92 | handle: async(match, fileRoot) => { 93 | return await handleGithubCall(match[0], match[3], match[4], match[5], fileRoot); 94 | } 95 | } 96 | ]; 97 | } 98 | async function resolveImports(fileRoot, sourcePath) { 99 | const handlers = await getHandlers(); 100 | let response = {}; 101 | for (const handler of handlers) { 102 | try { 103 | // here we are trying to find type of import path github/swarm/ipfs/local 104 | const match = handler.match.exec(sourcePath); 105 | if (match) { 106 | response = await handler.handle(match, fileRoot); 107 | break; 108 | } 109 | } catch (e) { 110 | throw e; 111 | } 112 | } 113 | return response; 114 | } 115 | export async function combineSource(fileRoot, sources) { 116 | let fn, importLine, ir; 117 | var matches = []; 118 | ir = /^(?:import){1}(.+){0,1}\s['"](.+)['"];/gm; 119 | let match = null; 120 | for (const fileName of Object.keys(sources)) { 121 | const source = sources[fileName].content; 122 | while ((match = ir.exec(source))) { 123 | matches.push(match); 124 | } 125 | for (let match of matches) { 126 | importLine = match[0]; 127 | const extra = match[1] ? match[1] : ''; 128 | if (validUrl.isUri(fileRoot)) { 129 | fn = url.URL.resolve(fileRoot, match[2]); 130 | } else { 131 | fn = match[2]; 132 | } 133 | try { 134 | // resolve anything other than remix_tests.sol & tests.sol 135 | if (fn.localeCompare('remix_tests.sol') != 0 && fn.localeCompare('tests.sol') != 0) { 136 | let subSorce = {}; 137 | const response = await resolveImports(fileRoot, fn); 138 | sources[fileName].content = sources[fileName].content.replace(importLine, 'import' + extra + ' \'' + response.filename + '\';'); 139 | subSorce[response.filename] = { content: response.content }; 140 | sources = Object.assign(await combineSource(response.fileRoot, subSorce), sources); 141 | } 142 | } catch (e) { 143 | throw e; 144 | } 145 | } 146 | } 147 | return sources; 148 | } 149 | -------------------------------------------------------------------------------- /lib/helpers/configureStore.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import etheratomReducers from '../reducers'; 18 | import logger from 'redux-logger'; 19 | import ReduxThunk from 'redux-thunk'; 20 | import { createStore, applyMiddleware } from 'redux'; 21 | 22 | export default function configureStore(initialState) { 23 | const middleWares = [ReduxThunk]; 24 | if(atom.inDevMode()) { 25 | middleWares.push(logger); 26 | } 27 | const store = createStore( 28 | etheratomReducers, 29 | initialState, 30 | applyMiddleware(...middleWares) 31 | ); 32 | return store; 33 | } 34 | -------------------------------------------------------------------------------- /lib/helpers/uiHelpers.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import { MessagePanelView, PlainMessageView } from 'atom-message-panel'; 18 | 19 | export function showPanelError(err_message) { 20 | let messages; 21 | messages = new MessagePanelView({ title: 'Etheratom report' }); 22 | messages.attach(); 23 | messages.add(new PlainMessageView({ message: err_message, className: 'red-message' })); 24 | } 25 | -------------------------------------------------------------------------------- /lib/reducers/AccountReducer.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import { SET_COINBASE, SET_PASSWORD, SET_ACCOUNTS, SET_BALANCE } from '../actions/types'; 18 | const INITIAL_STATE = { 19 | coinbase: '', 20 | password: false, 21 | accounts: [], 22 | balance: 0.00, 23 | }; 24 | export default (state = INITIAL_STATE, action) => { 25 | switch (action.type) { 26 | case SET_COINBASE: 27 | return { ...state, coinbase: action.payload }; 28 | case SET_PASSWORD: 29 | return { ...state, password: action.payload.password }; 30 | case SET_ACCOUNTS: 31 | return { ...state, accounts: action.payload }; 32 | case SET_BALANCE: 33 | return { ...state, balance: action.payload }; 34 | default: 35 | return state; 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /lib/reducers/ClientReducer.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import { SET_CONNECTION_STATUS, IS_WS_PROVIDER, IS_HTTP_PROVIDER, FIRST_TIME_CHECK_ENABLE } from '../actions/types'; 18 | const INITIAL_STATE = { 19 | clients: [ 20 | { 21 | provider: 'web3', 22 | desc: 'Backend ethereum node', 23 | hasConnection: false, 24 | firstTimeCheck: true, 25 | isWsProvider: false, 26 | isHttpProvider: false, 27 | } 28 | ] 29 | }; 30 | export default (state = INITIAL_STATE, action) => { 31 | switch (action.type) { 32 | case SET_CONNECTION_STATUS: 33 | return { ...state, clients: action.payload }; 34 | case FIRST_TIME_CHECK_ENABLE: 35 | // TODO: modify only one key:value 36 | return { ...state, clients: action.payload }; 37 | case IS_WS_PROVIDER: 38 | return { ...state, clients: action.payload }; 39 | case IS_HTTP_PROVIDER: 40 | return { ...state, clients: action.payload }; 41 | default: 42 | return state; 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /lib/reducers/ContractReducer.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import { 18 | SET_SOURCES, 19 | SET_COMPILING, 20 | SET_DEPLOYED, 21 | SET_COMPILED, 22 | RESET_COMPILED, 23 | RESET_CONTRACTS, 24 | SET_INSTANCE, 25 | SET_PARAMS, 26 | ADD_INTERFACE, 27 | UPDATE_INTERFACE, 28 | UPDATE_OPTIONS, 29 | ADD_TX_HASH, 30 | SET_GAS_LIMIT, 31 | SET_GAS_ESTIMATE 32 | } from '../actions/types'; 33 | const INITIAL_STATE = { 34 | compiled: null, 35 | compiling: false, 36 | deployed: false, 37 | interfaces: null, 38 | contracts: null, 39 | instances: null, 40 | gasLimit: 0, 41 | gasEstimate: 90000 42 | }; 43 | export default (state = INITIAL_STATE, action) => { 44 | switch (action.type) { 45 | case SET_SOURCES: 46 | return { ...state, sources: action.payload }; 47 | case SET_COMPILING: 48 | return { ...state, compiling: action.payload }; 49 | case SET_DEPLOYED: 50 | return { ...state, deployed: { ...state.deployed, [action.payload.contractName]: action.payload.deployed } }; 51 | case SET_COMPILED: 52 | return { ...state, compiled: action.payload }; 53 | case RESET_CONTRACTS: 54 | return { ...INITIAL_STATE }; 55 | case RESET_COMPILED: 56 | return { ...state, compiled: null, deployed: false, interfaces: null, instances: null }; 57 | case SET_INSTANCE: 58 | return { ...state, instances: { ...state.instances, [action.payload.contractName]: action.payload.instance } }; 59 | case SET_PARAMS: 60 | return { ...state, interfaces: { ...state.interfaces, [action.payload.contractName]: { interface: action.payload.interface } } }; 61 | case ADD_INTERFACE: 62 | return { ...state, interfaces: { ...state.interfaces, [action.payload.contractName]: { interface: action.payload.interface } } }; 63 | case UPDATE_INTERFACE: 64 | return { ...state, interfaces: { ...state.interfaces, [action.payload.contractName]: { interface: action.payload.interface } } }; 65 | case UPDATE_OPTIONS: 66 | // We want to access contracts like following: 67 | // contracts[myContract].options, contracts[myContract].methods, contracts[myContract].events 68 | return { 69 | ...state, 70 | contracts: { 71 | ...state.contracts, 72 | [action.payload.contractName]: { 73 | options: action.payload.options, 74 | transactionHash: (state.contracts && state.contracts[action.payload.contractName]) ? state.contracts[action.payload.contractName].transactionHash : null 75 | } 76 | } 77 | }; 78 | case ADD_TX_HASH: 79 | return { 80 | ...state, 81 | contracts: { 82 | ...state.contracts, 83 | [action.payload.contractName]: { 84 | transactionHash: action.payload.transactionHash, 85 | options: state.contracts[action.payload.contractName].options 86 | } 87 | } 88 | }; 89 | case SET_GAS_LIMIT: 90 | return { ...state, gasLimit: action.payload }; 91 | case SET_GAS_ESTIMATE: 92 | return { ...state, gasEstimate: action.payload.gasEstimate }; 93 | default: 94 | return state; 95 | } 96 | }; 97 | -------------------------------------------------------------------------------- /lib/reducers/ErrorReducer.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import { SET_ERRORS, RESET_ERRORS } from '../actions/types'; 18 | const INITIAL_STATE = { 19 | errormsg: [], 20 | }; 21 | export default (state = INITIAL_STATE, action) => { 22 | switch (action.type) { 23 | case SET_ERRORS: 24 | return { ...state, errormsg: action.payload }; 25 | case RESET_ERRORS: 26 | return { ...INITIAL_STATE }; 27 | default: 28 | return state; 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /lib/reducers/EventReducer.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import { ADD_PENDING_TRANSACTION, ADD_EVENTS, SET_EVENTS, TEXT_ANALYSIS } from '../actions/types'; 18 | const INITIAL_STATE = { 19 | pendingTransactions: [], 20 | events: [], 21 | txAnalysis: {} 22 | }; 23 | export default (state = INITIAL_STATE, action) => { 24 | switch (action.type) { 25 | case ADD_PENDING_TRANSACTION: 26 | return { ...state, pendingTransactions: [...state.pendingTransactions, action.payload] }; 27 | case ADD_EVENTS: 28 | return { ...state, events: [...state.events, action.payload] }; 29 | case SET_EVENTS: 30 | return { ...state, events: [] }; 31 | case TEXT_ANALYSIS: 32 | return { ...state, txAnalysis: action.payload }; 33 | default: 34 | return state; 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /lib/reducers/FilesReducer.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import { 18 | SET_SOURCES, 19 | RESET_SOURCES 20 | } from '../actions/types'; 21 | 22 | const INITIAL_STATE = { 23 | sources: {} 24 | }; 25 | 26 | export default (state = INITIAL_STATE, action) => { 27 | switch (action.type) { 28 | case SET_SOURCES: 29 | return { ...state, sources: action.payload }; 30 | case RESET_SOURCES: 31 | return { ...INITIAL_STATE }; 32 | default: 33 | return state; 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /lib/reducers/NodeReducer.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import { SET_SYNC_STATUS, SET_SYNCING, SET_MINING, SET_HASH_RATE } from '../actions/types'; 18 | const INITIAL_STATE = { 19 | syncing: false, 20 | status: {}, 21 | mining: false, 22 | hashRate: 0 23 | }; 24 | export default (state = INITIAL_STATE, action) => { 25 | switch (action.type) { 26 | case SET_SYNCING: 27 | return { ...state, syncing: action.payload }; 28 | case SET_SYNC_STATUS: 29 | return { ...state, status: action.payload }; 30 | case SET_MINING: 31 | return { ...state, mining: action.payload }; 32 | case SET_HASH_RATE: 33 | return { ...state, hashRate: action.payload }; 34 | default: 35 | return state; 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /lib/reducers/index.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import { combineReducers } from 'redux'; 18 | import FilesReducer from './FilesReducer'; 19 | import ContractReducer from './ContractReducer'; 20 | import AccountReducer from './AccountReducer'; 21 | import ErrorReducer from './ErrorReducer'; 22 | import EventReducer from './EventReducer'; 23 | import ClientReducer from './ClientReducer'; 24 | import NodeReducer from './NodeReducer'; 25 | 26 | export default combineReducers({ 27 | files: FilesReducer, 28 | contract: ContractReducer, 29 | account: AccountReducer, 30 | errors: ErrorReducer, 31 | eventReducer: EventReducer, 32 | clientReducer: ClientReducer, 33 | node: NodeReducer 34 | }); 35 | -------------------------------------------------------------------------------- /lib/web3/view.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | import React from 'react'; 18 | import ReactDOM from 'react-dom'; 19 | import Web3Helpers from './methods'; 20 | import TabView from '../components/TabView'; 21 | import CoinbaseView from '../components/CoinbaseView'; 22 | import VersionSelector from '../components/VersionSelector'; 23 | import CompileBtn from '../components/CompileBtn'; 24 | import { SET_ACCOUNTS, SET_COINBASE } from '../actions/types'; 25 | import LoaderView from '../components/LoaderView'; 26 | 27 | export default class View { 28 | constructor(store) { 29 | this.Accounts = []; 30 | this.coinbase = null; 31 | this.store = store; 32 | this.helpers = new Web3Helpers(this.store); 33 | } 34 | async createCoinbaseView() { 35 | try { 36 | await this.helpers.getAccounts(); 37 | ReactDOM.render(, document.getElementById('accounts-list')); 38 | } catch (e) { 39 | console.log(e); 40 | this.helpers.showPanelError('No account exists! Please create one.'); 41 | this.store.dispatch({ type: SET_ACCOUNTS, payload: [] }); 42 | this.store.dispatch({ type: SET_COINBASE, payload: '0x00' }); 43 | ReactDOM.render(, document.getElementById('accounts-list')); 44 | 45 | throw e; 46 | } 47 | } 48 | createButtonsView() { 49 | ReactDOM.render( 50 |
    51 | 52 | 53 |
    , 54 | document.getElementById('compile_btn')); 55 | } 56 | createTabView() { 57 | ReactDOM.render(, document.getElementById('tab_view')); 58 | } 59 | createVersionSelector() { 60 | ReactDOM.render(, document.getElementById('version_selector')); 61 | } 62 | createLoaderView() { 63 | ReactDOM.render(, document.getElementById('loader')); 64 | } 65 | 66 | createTextareaR(text) { 67 | var textNode; 68 | this.text = text; 69 | textNode = document.createElement('pre'); 70 | textNode.textContent = this.text; 71 | textNode.classList.add('large-code'); 72 | return textNode; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /lib/web3/vyp-worker.js: -------------------------------------------------------------------------------- 1 | const shell = require('shelljs'); 2 | const fs = require('fs'); 3 | 4 | function vyperCompiler(source) { 5 | const outputSelection = { 6 | // Enable the metadata and bytecode outputs of every single contract. 7 | '*': { 8 | '': ['ast'], 9 | '*': ['abi', 'evm.bytecode'] 10 | } 11 | }; 12 | var input_json = { 13 | 'language': 'Vyper', 14 | 'sources': source, 15 | 'settings': { 16 | 'evmVersion': 'byzantium' 17 | }, 18 | 'outputSelection': outputSelection 19 | }; 20 | fs.writeFileSync(__dirname + '/' + '.temp-vy.json', JSON.stringify(input_json, null, 4), 'UTF-8'); 21 | var args = 'vyper-json ' + __dirname + '/' + '.temp-vy.json'; 22 | var escaped = shell.exec(args); 23 | var m = { compiled: escaped }; 24 | fs.unlink(__dirname + '/' + '.temp-vy.json', ()=>{}); 25 | process.send(m); 26 | } 27 | process.on('message', (m) => { 28 | if (m.command == 'compile') { 29 | vyperCompiler(m.source); 30 | } 31 | }); 32 | -------------------------------------------------------------------------------- /lib/web3/web3.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | // Copyright 2018 Etheratom Authors 3 | // This file is part of Etheratom. 4 | 5 | // Etheratom is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | 10 | // Etheratom is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with Etheratom. If not, see . 17 | 18 | // web3.js should be use to handle all web3 compilation events 19 | // Every solidity file can be compiled in two ways jsvm and ethereum endpoint 20 | // After every command is invoked compilation endpoint should be chosen 21 | // If JsVM is compilation endpoint VM will be used to compile and execute solidity program 22 | 23 | /*eslint no-useless-escape: "warn"*/ 24 | import { CompositeDisposable } from 'atom'; 25 | import path from 'path'; 26 | import Web3Helpers from './methods'; 27 | import { combineSource } from '../helpers/compiler-imports'; 28 | import { showPanelError } from '../helpers/uiHelpers'; 29 | import View from './view'; 30 | 31 | 32 | import { 33 | RESET_COMPILED, 34 | SET_COMPILING, 35 | SET_ERRORS, 36 | SET_EVENTS, 37 | SET_SOURCES 38 | } from '../actions/types'; 39 | export default class Web3Env { 40 | constructor(store) { 41 | this.subscriptions = new CompositeDisposable(); 42 | this.web3Subscriptions = new CompositeDisposable(); 43 | this.saveSubscriptions = new CompositeDisposable(); 44 | this.compileSubscriptions = new CompositeDisposable(); 45 | 46 | // binding local functions 47 | this.checkReduxState = this.checkReduxState.bind(this); 48 | this.subscribeToWeb3Commands = this.subscribeToWeb3Commands.bind(this); 49 | this.subscribeToWeb3Events = this.subscribeToWeb3Events.bind(this); 50 | 51 | this.store = store; 52 | this.helpers = new Web3Helpers(this.store); 53 | this.havConnection = this.store.getState().clientReducer.clients[0].hasConnection; 54 | 55 | // Subscribing the redux state 56 | this.store.subscribe(this.checkReduxState); 57 | 58 | // subscribe to transaction through helpers 59 | this.helpers.subscribeTransaction(); 60 | // subscribe to eth connection through helpers 61 | this.helpers.subscribeETHconnection(); 62 | 63 | this.subscribeToWeb3Commands(); 64 | this.subscribeToWeb3Events(); 65 | this.helpers.checkConnection(); 66 | } 67 | 68 | checkReduxState() { 69 | this.havConnection = this.store.getState().clientReducer.clients[0].hasConnection; 70 | let firstCheck = this.store.getState().clientReducer.clients[0].firstTimeCheck; 71 | if (this.havConnection && firstCheck) { 72 | this.subscribeToWeb3Events(); 73 | } 74 | } 75 | 76 | dispose() { 77 | if (this.subscriptions) { 78 | this.subscriptions.dispose(); 79 | } 80 | this.subscriptions = null; 81 | 82 | if (this.saveSubscriptions) { 83 | this.saveSubscriptions.dispose(); 84 | } 85 | this.saveSubscriptions = null; 86 | 87 | if (this.web3Subscriptions) { 88 | this.web3Subscriptions.dispose(); 89 | } 90 | this.web3Subscriptions = null; 91 | } 92 | destroy() { 93 | if (this.saveSubscriptions) { 94 | this.saveSubscriptions.dispose(); 95 | } 96 | this.saveSubscriptions = null; 97 | 98 | if (this.compileSubscriptions) { 99 | this.compileSubscriptions.dispose(); 100 | } 101 | this.compileSubscriptions = null; 102 | 103 | if (this.web3Subscriptions) { 104 | this.web3Subscriptions.dispose(); 105 | } 106 | this.web3Subscriptions = null; 107 | } 108 | 109 | // Subscriptions 110 | subscribeToWeb3Commands() { 111 | 112 | if (!this.web3Subscriptions) { 113 | return; 114 | } 115 | this.web3Subscriptions.add(atom.commands.add('atom-workspace', 'eth-interface:compile', () => { 116 | if (this.compileSubscriptions) { 117 | this.compileSubscriptions.dispose(); 118 | } 119 | this.compileSubscriptions = new CompositeDisposable(); 120 | this.subscribeToCompileEvents(); 121 | })); 122 | } 123 | async subscribeToWeb3Events() { 124 | if (!this.web3Subscriptions) { 125 | return; 126 | } 127 | const state = this.store.getState(); 128 | const { clients } = state.clientReducer; 129 | const client = clients[0]; 130 | this.view = new View(this.store); 131 | console.log(client); 132 | if (!client.hasConnection) { 133 | this.view.createLoaderView(); 134 | this.view.createButtonsView(); 135 | this.view.createTabView(); 136 | this.view.createVersionSelector(); 137 | } else if (client.hasConnection) { 138 | this.view.createCoinbaseView(); 139 | this.view.createButtonsView(); 140 | this.view.createTabView(); 141 | this.view.createVersionSelector(); 142 | } 143 | this.web3Subscriptions.add(atom.workspace.observeTextEditors((editor) => { 144 | if (!editor || !editor.getBuffer()) { 145 | return; 146 | } 147 | 148 | this.web3Subscriptions.add(atom.config.observe('etheratom.compileOnSave', (compileOnSave) => { 149 | if (this.saveSubscriptions) { 150 | this.saveSubscriptions.dispose(); 151 | } 152 | this.saveSubscriptions = new CompositeDisposable(); 153 | if (compileOnSave) { 154 | this.subscribeToSaveEvents(); 155 | } 156 | })); 157 | })); 158 | } 159 | 160 | // Event subscriptions 161 | subscribeToSaveEvents() { 162 | if (!this.web3Subscriptions) { 163 | return; 164 | } 165 | this.saveSubscriptions.add(atom.workspace.observeTextEditors((editor) => { 166 | if (!editor || !editor.getBuffer()) { 167 | return; 168 | } 169 | 170 | const bufferSubscriptions = new CompositeDisposable(); 171 | bufferSubscriptions.add(editor.getBuffer().onDidSave((filePath) => { 172 | this.setSources(editor); 173 | })); 174 | bufferSubscriptions.add(editor.getBuffer().onDidDestroy(() => { 175 | bufferSubscriptions.dispose(); 176 | })); 177 | this.saveSubscriptions.add(bufferSubscriptions); 178 | })); 179 | } 180 | subscribeToCompileEvents() { 181 | if (!this.web3Subscriptions) { 182 | return; 183 | } 184 | this.compileSubscriptions.add(atom.workspace.observeActiveTextEditor((editor) => { 185 | if (!editor || !editor.getBuffer()) { 186 | return; 187 | } 188 | this.compile(editor); 189 | })); 190 | } 191 | 192 | // common functions 193 | async setSources(editor) { 194 | const filePath = editor.getPath(); 195 | const filename = filePath.replace(/^.*[\\/]/, ''); 196 | const regexSol = /([a-zA-Z0-9\s_\\.\-\(\):])+(.sol|.solidity)$/g; 197 | const regexVyp = /([a-zA-Z0-9\s_\\.\-\(\):])+(.vy|.v.py|.vyper.py)$/g; 198 | if (filePath.match(regexSol) || filePath.match(regexVyp)) { 199 | try { 200 | const dir = path.dirname(filePath); 201 | var sources = {}; 202 | sources[filename] = { content: editor.getText() }; 203 | sources = await combineSource(dir, sources); 204 | this.store.dispatch({ type: SET_SOURCES, payload: sources }); 205 | } catch (e) { 206 | console.error(e); 207 | showPanelError(e); 208 | } 209 | } else { 210 | const err = new Error('file type is not recognized as solidity or vyper file'); 211 | console.error(err); 212 | showPanelError(err); 213 | } 214 | } 215 | async compile(editor) { 216 | const filePath = editor.getPath(); 217 | const regexVyp = /([a-zA-Z0-9\s_\\.\-\(\):])+(.vy|.v.py|.vyper.py)$/g; 218 | const regexSol = /([a-zA-Z0-9\s_\\.\-\(\):])+(.sol|.solidity)$/g; 219 | // Reset redux store 220 | // this.store.dispatch({ type: SET_COMPILED, payload: null }); 221 | this.store.dispatch({ type: RESET_COMPILED }); 222 | this.store.dispatch({ type: SET_ERRORS, payload: [] }); 223 | this.store.dispatch({ type: SET_EVENTS, payload: [] }); 224 | 225 | if (filePath.match(regexSol)) { 226 | console.log('%c Compiling contract... ', 'background: rgba(36, 194, 203, 0.3); color: #EF525B'); 227 | this.store.dispatch({ type: SET_COMPILING, payload: true }); 228 | try { 229 | const state = this.store.getState(); 230 | const { sources } = state.files; 231 | delete sources['remix_tests.sol']; 232 | delete sources['tests.sol']; 233 | // TODO: delete _test files 234 | for (let filename in sources) { 235 | if (/^(.+)(_test.sol)/g.test(filename)) { 236 | delete sources[filename]; 237 | } 238 | } 239 | this.helpers.compileWeb3(sources); 240 | await this.helpers.getGasLimit(); 241 | } catch (e) { 242 | console.error(e); 243 | showPanelError(e); 244 | } 245 | } else if(filePath.match(regexVyp)) { 246 | console.log('%c Compiling contract... ', 'background: rgba(36, 194, 203, 0.3); color: #EF525B'); 247 | this.store.dispatch({ type: SET_COMPILING, payload: true }); 248 | try { 249 | const state = this.store.getState(); 250 | const { sources } = state.files; 251 | this.helpers.compileVyper(sources); 252 | } catch(e) { 253 | console.error(e); 254 | showPanelError(e); 255 | } 256 | } else { 257 | const err = new Error('file type is not recognized as solidity or vyper file'); 258 | console.error(err); 259 | showPanelError(err); 260 | return; 261 | } 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /lib/web3/web3Worker.js: -------------------------------------------------------------------------------- 1 | const Web3 = require('web3'); 2 | 3 | let web3 = {}; 4 | let globalContract; 5 | 6 | let createConnection = (address) => { 7 | return new Web3(address); 8 | }; 9 | 10 | let onTransaction = (web3) => { 11 | web3.eth.subscribe('pendingTransactions') 12 | .on('data', (transaction) => { 13 | process.send({ transaction: transaction }); 14 | }) 15 | .on('error', (e) => { 16 | return e; 17 | }); 18 | }; 19 | 20 | let subscription = (web3) => { 21 | web3.eth.subscribe('syncing') 22 | .on('data', (sync) => { 23 | process.send({ syncStarted: true }); 24 | if (typeof (sync) === 'boolean') { 25 | process.send({ isBooleanSync: sync }); 26 | } 27 | if (typeof (sync) === 'object') { 28 | process.send({ isObjectSync: sync }); 29 | } 30 | }) 31 | .on('changed', (isSyncing) => { 32 | process.send({ isSyncing: isSyncing }); 33 | }) 34 | .on('error', (e) => { 35 | process.send({ error: e.message }); 36 | }); 37 | }; 38 | 39 | let getGasEstimate = async(coinbase, bytecode, web3) => { 40 | if (!coinbase) { 41 | const error = new Error('No coinbase selected!'); 42 | process.send({ error: error }); 43 | } 44 | try { 45 | web3.eth.defaultAccount = coinbase; 46 | const gasEstimate = await web3.eth.estimateGas({ 47 | from: web3.eth.defaultAccount, 48 | data: '0x' + bytecode, 49 | }); 50 | process.send({ gasEstimate }); 51 | } catch (e) { 52 | throw e; 53 | } 54 | }; 55 | 56 | let getBalances = async(coinbase, web3) => { 57 | if (!coinbase) { 58 | const error = new Error('No coinbase selected!'); 59 | process.send({ error: error }); 60 | } 61 | try { 62 | const weiBalance = await web3.eth.getBalance(coinbase); 63 | const ethBalance = await web3.utils.fromWei(weiBalance, 'ether'); 64 | process.send({ 'ethBalance': ethBalance }); 65 | } catch (e) { 66 | process.send({ error: e.message }); 67 | } 68 | }; 69 | 70 | let setDefaultAccount = (coinbase, web3) => { 71 | try { 72 | web3.eth.defaultAccount = coinbase; 73 | process.send({ message: 'Default Account is set' }); 74 | } catch (error) { 75 | process.send({ error: error.message }); 76 | } 77 | }; 78 | 79 | let setCoinbase = async(coinbase, web3) => { 80 | try { 81 | web3.eth.defaultAccount = coinbase; 82 | process.send('Coinbase set Successfull'); 83 | } catch (e) { 84 | process.send({ error: e.message }); 85 | } 86 | }; 87 | 88 | let getSyncStat = async() => { 89 | try { 90 | process.send({ isSyncing: web3.eth.isSyncing() }); 91 | } catch (e) { 92 | process.send({ error: e.message }); 93 | } 94 | }; 95 | 96 | 97 | let getAccounts = async(web3) => { 98 | try { 99 | let accounts = await web3.eth.getAccounts(); 100 | process.send({ accounts }); 101 | } catch (e) { 102 | process.send({ error: e.message }); 103 | } 104 | }; 105 | 106 | let getAccountsForNodeSubmit = async(node_type, node_url) => { 107 | try { 108 | if (web3 == !undefined) { 109 | web3.currentProvider.connection.close(); 110 | } 111 | web3 = new Web3(node_url); 112 | let accounts = await web3.eth.getAccounts(); 113 | process.send({ getAccountsForNodeSubmit: accounts, node_type }); 114 | } catch (e) { 115 | process.send({ error: e.message }); 116 | } 117 | }; 118 | 119 | let isWsProvider = (web3) => { 120 | process.send({ isWsProvider: Object.is(web3.currentProvider.constructor, Web3.providers.WebsocketProvider) }); 121 | }; 122 | let isHttpProvider = (web3) => { 123 | process.send({ isHttpProvider: Object.is(web3.currentProvider.constructor, Web3.providers.HttpProvider) }); 124 | }; 125 | 126 | let checkConnection = (web3) => { 127 | try { 128 | if (web3.currentProvider) { 129 | web3.eth.isSyncing() 130 | .then(() => { 131 | process.send({ hasConnection: true }); 132 | }) 133 | .catch(() => { 134 | process.send({ error: { type: 'connection_error', message: 'Error could not connect to local geth instance!' } }); 135 | }) 136 | } else { 137 | process.send({ error: { type: 'connection_error', message: 'Error could not connect to local geth instance!' } }); 138 | } 139 | } catch (error) { 140 | process.send({ error: { type: 'connection_error', message: error.message } }); 141 | } 142 | }; 143 | 144 | const create = async(args, web3) => { 145 | process.send({ 'prepareCreate': { args } }); 146 | const { coinbase, password, abi, bytecode, gas, contractName, atAddress } = args; 147 | const address = atAddress ? atAddress : null; 148 | if (!coinbase) { 149 | const error = new Error('No coinbase selected!'); 150 | process.send({ error: error.message }); 151 | } 152 | web3.eth.defaultAccount = coinbase; 153 | try { 154 | if (password) { 155 | await web3.eth.personal.unlockAccount(coinbase, password); 156 | } 157 | try { 158 | const gasPrice = await web3.eth.getGasPrice(); 159 | if(address) { 160 | globalContract = await new web3.eth.Contract(abi, address, { 161 | from: web3.eth.defaultAccount, 162 | gasPrice: web3.utils.toHex(gasPrice) 163 | }); 164 | } else { 165 | globalContract = await new web3.eth.Contract(abi, { 166 | from: web3.eth.defaultAccount, 167 | data: '0x' + bytecode, 168 | gas: web3.utils.toHex(gas), 169 | gasPrice: web3.utils.toHex(gasPrice) 170 | }); 171 | } 172 | process.send({ options: globalContract.options, contractName }) 173 | return globalContract; 174 | } catch (e) { 175 | throw e; 176 | } 177 | } catch (e) { 178 | throw e; 179 | } 180 | }; 181 | const deploy = async(contract, params, contractName, web3) => { 182 | try { 183 | params = params.map(param => { 184 | var reg = /\w+(?=\[\d*\])/g; 185 | return (param.type.match(reg) || param.type.endsWith('[]') || param.type.includes('tuple')) ? JSON.parse(param.value) : param.value; 186 | }); 187 | contract.deploy({ arguments: params }) 188 | .send({ 189 | from: web3.eth.defaultAccount 190 | }) 191 | .on('transactionHash', transactionHash => { 192 | process.send({ transactionHash, contractName }); 193 | }) 194 | .on('receipt', txReceipt => { 195 | process.send({ txReceipt }); 196 | }) 197 | .on('confirmation', confirmationNumber => { 198 | process.send({ confirmationNumber }); 199 | }) 200 | .on('error', error => { 201 | process.send({ error: error.message }); 202 | }) 203 | .then(instance => { 204 | instance.events.allEvents({ fromBlock: 'latest' }) 205 | .on('logs', (logs) => { 206 | process.send({ logsEvents: logs }); 207 | }) 208 | .on('data', (data) => { 209 | process.send({ dataEvents: data }); 210 | }) 211 | .on('changed', (changed) => { 212 | process.send({ changedEvent: changed }); 213 | }) 214 | .on('error', (error) => { 215 | process.send({ error: error.message }); 216 | console.log(error); 217 | }); 218 | contract.options.address = instance.options.address; 219 | process.send({ options: instance.options, contractName }); 220 | }); 221 | } catch (e) { 222 | console.log(e); 223 | process.send({ error: e.message }); 224 | } 225 | }; 226 | 227 | let getMining = async(web3) => { 228 | try { 229 | let isMining = web3.eth.isMining(); 230 | process.send({ isMining }); 231 | } catch (error) { 232 | process.send({ error: error.message }); 233 | } 234 | }; 235 | let getHashrate = async(web3) => { 236 | try { 237 | web3.eth.getHashrate() 238 | .then((getHashrate) => { process.send({ getHashrate }); }); 239 | } catch (error) { 240 | process.send({ error: error.message }); 241 | } 242 | }; 243 | let getGasLimit = async(web3) => { 244 | try { 245 | const block = await web3.eth.getBlock('latest'); 246 | let gasLimit = block.gasLimit; 247 | process.send({ gasLimit }); 248 | } catch (error) { 249 | process.send({ error: error.message }); 250 | } 251 | }; 252 | 253 | let call = async(args, web3) => { 254 | const coinbase = args.coinbase; 255 | const password = args.password; 256 | const contract = args.contract; 257 | const abiItem = args.abiItem; 258 | var params = args.params || []; 259 | web3.eth.defaultAccount = coinbase; 260 | try { 261 | // Prepare params for call 262 | params = params.map(param => { 263 | var reg = /\w+(?=\[\d*\])/g; 264 | if (param.type.match(reg) || param.type.endsWith('[]') || param.type.includes('tuple')) { 265 | return JSON.parse(param.value); 266 | } 267 | if (param.type.indexOf('int') > -1) { 268 | return new web3.utils.BN(param.value).toNumber(); 269 | } 270 | return param.value; 271 | }); 272 | 273 | // Handle fallback 274 | if (abiItem.type === 'fallback') { 275 | if (password) { 276 | await web3.eth.personal.unlockAccount(coinbase, password); 277 | } 278 | const result = await web3.eth.sendTransaction({ 279 | from: coinbase, 280 | to: contract.options.address, 281 | value: abiItem.payableValue || 0 282 | }); 283 | process.send({ callResult: result, address: contract.options.address }); 284 | return false; 285 | } 286 | 287 | if (abiItem.constant === false || abiItem.payable === true) { 288 | if (password) { 289 | await web3.eth.personal.unlockAccount(coinbase, password); 290 | } 291 | if (params.length > 0) { 292 | const result = await globalContract.methods[abiItem.name](...params).send({ from: coinbase, value: abiItem.payableValue }); 293 | process.send({ callResult: result, address: contract.options.address }); 294 | return; 295 | } 296 | const result = await globalContract.methods[abiItem.name](...params).send({ from: coinbase, value: abiItem.payableValue }); 297 | process.send({ callResult: result, address: contract.options.address }); 298 | return; 299 | 300 | } 301 | if (params.length > 0) { 302 | const result = await globalContract.methods[abiItem.name](...params).call({ from: coinbase }); 303 | process.send({ callResult: result, address: contract.options.address }); 304 | return; 305 | } 306 | const result = await globalContract.methods[abiItem.name](...params).call({ from: coinbase }); 307 | process.send({ callResult: result, address: contract.options.address }); 308 | return; 309 | } 310 | catch (e) { 311 | process.send({ error: e.message }); 312 | } 313 | }; 314 | 315 | let send = async(params, web3) => { 316 | try { 317 | const coinbase = web3.eth.defaultAccount; 318 | if (params.password) { 319 | web3.eth.personal.unlockAccount(coinbase, params.password); 320 | } 321 | 322 | web3.eth.sendTransaction({ 323 | from: coinbase, 324 | to: params.to, 325 | value: params.amount 326 | }) 327 | .on('transactionHash', txHash => { 328 | process.send({ transactionHashonSend: txHash, head: 'Transaction hash:' }); 329 | }) 330 | .then(txRecipt => { 331 | process.send({ txReciptonSend: txRecipt, head: 'Transaction recipt:' }); 332 | }) 333 | .catch(e => { 334 | process.send({ error: e.message }); 335 | }); 336 | } catch (e) { 337 | process.send({ error: e.message }); 338 | } 339 | }; 340 | let inputsToArray = async(paramObject, web3) => { 341 | let inputsToArray; 342 | if (paramObject.type.endsWith('[]')) { 343 | inputsToArray = paramObject.value.split(',').map(val => web3.utils.toHex(val.trim())); 344 | process.send({ inputsToArray }); 345 | return; 346 | } 347 | inputsToArray = web3.utils.toHex(paramObject.value); 348 | process.send({ inputsToArray }); 349 | }; 350 | 351 | let getTxAnalysis = async(txHash, web3) => { 352 | try { 353 | const transaction = await web3.eth.getTransaction(txHash); 354 | const transactionRecipt = await web3.eth.getTransactionReceipt(txHash); 355 | process.send({ transaction, transactionRecipt }); 356 | } catch (e) { 357 | process.send({ error: e.message }); 358 | } 359 | }; 360 | 361 | process.on('message', async(message) => { 362 | try { 363 | if (message.action === 'set_rpc_ws') { 364 | if (Object.keys(web3).length === 0 && web3.constructor === Object) { 365 | process.send({ w: web3 }); 366 | if (message.hasOwnProperty('websocketAddress') && message.websocketAddress.length > 0) { 367 | web3 = createConnection(message.websocketAddress); 368 | process.send({ connected: true }); 369 | process.send(`Web3 Connection is Established on ${message.websocketAddress}`); 370 | } else if (message.hasOwnProperty('rpcAddress') && message.rpcAddress.length > 0 && message.websocketAddress.length == 0) { 371 | web3 = createConnection(message.rpcAddress); 372 | process.send({ connected: true }); 373 | process.send(`Web3 Connection is Established on ${message.rpcAddress}`); 374 | } else { 375 | process.send({ error: 'send rpc or ws address for establishing successfull connection' }); 376 | } 377 | } 378 | } 379 | // transaction process subscription 380 | if (message.action === 'subscribeTransaction') { 381 | onTransaction(web3); 382 | process.send({ transactionSubscribed: true, message: 'transaction has been subscribed' }); 383 | } 384 | // eth connection subscription 385 | if (message.action === 'ethSubscription') { 386 | subscription(web3); 387 | process.send({ ethSubscribed: true, message: 'ETH chanel has been subscribed' }); 388 | } 389 | // get Gas Estimate 390 | if (message.action === 'getGasEstimate' && message.hasOwnProperty('coinbase') && message.hasOwnProperty('bytecode')) { 391 | await getGasEstimate(message.coinbase, message.bytecode, web3); 392 | } 393 | // get Balance 394 | if (message.action === 'get_balances' && message.hasOwnProperty('coinbase')) { 395 | getBalances(message.coinbase, web3); 396 | } 397 | if (message.action === 'default_account_set' && message.hasOwnProperty('coinbase')) { 398 | await setDefaultAccount(message['coinbase'], web3); 399 | } 400 | if (message.action === 'set_coinbase' && message.hasOwnProperty('coinbase')) { 401 | await setCoinbase(message.coinbase, web3); 402 | } 403 | if (message.action === 'sync_stat') { 404 | await getSyncStat(); 405 | } 406 | if (message.action === 'check_connection') { 407 | await checkConnection(web3); 408 | } 409 | if (message.action === 'isWsProvider') { 410 | isWsProvider(web3); 411 | } 412 | if (message.action == 'isHttpProvider') { 413 | isHttpProvider(web3); 414 | } 415 | if (message.action === 'getAccounts') { 416 | getAccounts(web3); 417 | } 418 | if (message.action === 'create' && message.hasOwnProperty('argumentsForCreate')) { 419 | const args = message['argumentsForCreate']; 420 | const { params, contractName, atAddress } = args 421 | const contract = await create(args, web3); 422 | if(!atAddress) { 423 | deploy(contract, params, contractName, web3); 424 | } 425 | } 426 | if (message.action === 'getMiningStatus') { 427 | getMining(web3); 428 | } 429 | if (message.action === 'getHashrateStatus') { 430 | getHashrate(web3); 431 | } 432 | if (message.action === 'getGasLimit') { 433 | getGasLimit(web3); 434 | } 435 | if (message.action === 'getAccountsForNodeSubmit' && message.hasOwnProperty('node_url')) { 436 | getAccountsForNodeSubmit(message['node_type'], message['node_url']); 437 | } 438 | if (message.action === 'callDeployedContract' && message.hasOwnProperty('argumentsForCall')) { 439 | const args = message['argumentsForCall']; 440 | call(args, web3); 441 | } 442 | if (message.action === 'sendTransaction') { 443 | send(message.params, web3); 444 | } 445 | if (message.action === 'inputsToArray') { 446 | inputsToArray(message.paramObject, web3); 447 | } 448 | if (message.action === 'getTxAnalysis') { 449 | getTxAnalysis(message.txHash, web3); 450 | } 451 | } catch (error) { 452 | process.send({ error: error.message }); 453 | } 454 | }); 455 | module.exports = {}; 456 | -------------------------------------------------------------------------------- /lib/web3/worker.js: -------------------------------------------------------------------------------- 1 | const RemixTests = require('remix-tests'); 2 | const Solc = require('solc'); 3 | 4 | function _testCallback(result) { 5 | try { 6 | process.send({ _testCallback: '_testCallback', result }); 7 | } catch (e) { 8 | process.send({ error: e }); 9 | } 10 | } 11 | function _resultsCallback(e, result) { 12 | if(e) { 13 | process.send({ error: e }); 14 | } 15 | process.send({ _resultsCallback: '_resultsCallback', result }); 16 | } 17 | function _finalCallback(e, result) { 18 | if(e) { 19 | process.send({ error: e }); 20 | } 21 | process.send({ _finalCallback: '_finalCallback', result }); 22 | process.exit(0); 23 | } 24 | function _importFileCb(e, result) { 25 | if(e) { 26 | process.send({ error: e }); 27 | } 28 | } 29 | 30 | process.on('message', async(m) => { 31 | if (m.command === 'compile') { 32 | try { 33 | const input = m.payload; 34 | const installedSlocVersion = 'v' + Solc.version(); 35 | const requiredSolcVersion = m.version; 36 | 37 | if(installedSlocVersion.includes(requiredSolcVersion)) { 38 | const output = await Solc.compileStandardWrapper(JSON.stringify(input)); 39 | process.send({ compiled: output }); 40 | } else { 41 | Solc.loadRemoteVersion(requiredSolcVersion, async(err, solcSnapshot) => { 42 | if (err) { 43 | process.send({ error: err }); 44 | } else { 45 | const output = await solcSnapshot.compile(JSON.stringify(input)); 46 | process.send({ compiled: output }); 47 | } 48 | }); 49 | } 50 | } catch (e) { 51 | throw e; 52 | } 53 | } 54 | if (m.command === 'runTests') { 55 | try { 56 | const sources = m.payload; 57 | RemixTests.runTestSources(sources, _testCallback, _resultsCallback, _finalCallback, _importFileCb); 58 | } catch (e) { 59 | throw e; 60 | } 61 | } 62 | }); 63 | module.exports = {}; 64 | -------------------------------------------------------------------------------- /menus/atom-solidity.cson: -------------------------------------------------------------------------------- 1 | # See https://atom.io/docs/latest/hacking-atom-package-word-count#menus for more details 2 | 'context-menu': 3 | 'atom-text-editor': [ 4 | { 5 | 'label': 'Activate Etheratom' 6 | 'command': 'eth-interface:activate' 7 | } 8 | ] 9 | 'menu': [ 10 | { 11 | 'label': 'Packages' 12 | 'submenu': [ 13 | 'label': 'Etheratom' 14 | 'submenu': [ 15 | { 16 | 'label': 'Toggle view' 17 | 'command': 'eth-interface:toggle' 18 | } 19 | { 20 | 'label': 'Compile code' 21 | 'command': 'eth-interface:compile' 22 | } 23 | ] 24 | ] 25 | } 26 | ] 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "etheratom", 3 | "main": "build/main.js", 4 | "version": "4.6.0", 5 | "description": "Solidity compilation and Ethereum contract execution interface for hackable atom editor.", 6 | "keywords": [ 7 | "ethereum", 8 | "solidity", 9 | "web3", 10 | "ethereumjs" 11 | ], 12 | "activationCommands": { 13 | "atom-workspace": [ 14 | "eth-interface:activate", 15 | "eth-interface:toggle" 16 | ], 17 | "atom-text-editor[data-grammar~=\"solidity\"]:not([mini])": [ 18 | "eth-interface:compile" 19 | ] 20 | }, 21 | "activationHooks": [ 22 | "core:loaded-shell-environment" 23 | ], 24 | "repository": { 25 | "type": "git", 26 | "url": "https://github.com/0mkara/etheratom" 27 | }, 28 | "bugs": { 29 | "url": "https://github.com/0mkara/etheratom/issues" 30 | }, 31 | "license": "GPLv3", 32 | "engines": { 33 | "atom": ">=1.0.0 <2.0.0" 34 | }, 35 | "package-deps": [ 36 | "language-solidity" 37 | ], 38 | "dependencies": { 39 | "atom-message-panel": "^1.2.7", 40 | "atom-package-deps": "^5.0.0", 41 | "axios": "^0.18.0", 42 | "blob": "0.0.5", 43 | "create-react-class": "^15.6.2", 44 | "eslint-import-resolver-node": "^0.3.2", 45 | "file-saver": "^2.0.0", 46 | "idempotent-babel-polyfill": "^7.0.0", 47 | "md5": "^2.2.1", 48 | "prop-types": "^15.6.1", 49 | "react": "16.8.3", 50 | "react-addons-update": "^15.4.2", 51 | "react-checkbox-tree": "1.4.0", 52 | "react-collapse": "^4.0.3", 53 | "react-dom": "^16.8.3", 54 | "react-json-view": "1.19.1", 55 | "react-motion": "^0.5.2", 56 | "react-redux": "^5.0.7", 57 | "react-spinners": "^0.5.13", 58 | "react-tabs": "3.0.0", 59 | "react-tiny-virtual-list": "2.2.0", 60 | "redux": "^4.0.0", 61 | "redux-logger": "^3.0.6", 62 | "redux-thunk": "^2.2.0", 63 | "remix-analyzer": "^0.3.1", 64 | "remix-debug": "^0.3.16", 65 | "remix-lib": "^0.4.14", 66 | "remix-solidity": "0.3.1", 67 | "remix-tests": "0.1.14", 68 | "shelljs": "^0.8.3", 69 | "solc": "^0.5.13", 70 | "valid-url": "^1.0.9", 71 | "web3": "^1.0.0-beta.35" 72 | }, 73 | "configSchema": { 74 | "rpcAddress": { 75 | "title": "Ethereum rpc endpoint:", 76 | "description": "Point to local ethereum rpc endpoint. Used as HttpProvider.", 77 | "type": "string", 78 | "default": "", 79 | "order": 1 80 | }, 81 | "websocketAddress": { 82 | "title": "Ethereum websocket endpoint:", 83 | "description": "Point to local ethereum websocket endpoint. Used as WebsocketProvider.", 84 | "type": "string", 85 | "default": "", 86 | "order": 2 87 | }, 88 | "compileOnSave": { 89 | "title": "Compile Solidity on Save", 90 | "description": "Compile solidity code each time a file is saved", 91 | "type": "boolean", 92 | "default": true, 93 | "order": 3 94 | }, 95 | "versionSelector": { 96 | "title": "Solidity compiler version:", 97 | "description": "Selected version of Solidity compiler", 98 | "type": "string", 99 | "default": "latest", 100 | "order": 4 101 | } 102 | }, 103 | "scripts": { 104 | "postinstall": "npm install solc && node ./formatSolc.js", 105 | "build": "rollup -c" 106 | }, 107 | "devDependencies": { 108 | "@babel/core": "7.3.3", 109 | "@babel/plugin-proposal-object-rest-spread": "7.3.2", 110 | "@babel/preset-env": "7.3.1", 111 | "@babel/preset-react": "7.0.0", 112 | "@types/web3": "^1.0.19", 113 | "babel-eslint": "^10.0.1", 114 | "babel-plugin-emotion": "^10.0.14", 115 | "eslint": "^5.0.0", 116 | "eslint-config-standard": "^12.0.0", 117 | "eslint-plugin-babel": "^5.1.0", 118 | "eslint-plugin-import": "^2.12.0", 119 | "eslint-plugin-node": "^8.0.0", 120 | "eslint-plugin-promise": "^4.0.0", 121 | "eslint-plugin-react": "^7.8.2", 122 | "eslint-plugin-standard": "^4.0.0", 123 | "rollup-plugin-babel": "4.3.0", 124 | "rollup-plugin-commonjs": "9.2.1", 125 | "rollup-plugin-node-builtins": "^2.1.2", 126 | "rollup-plugin-node-resolve": "^4.0.0" 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import resolve from 'rollup-plugin-node-resolve'; 2 | import babel from 'rollup-plugin-babel'; 3 | import commonjs from 'rollup-plugin-commonjs'; 4 | import fs from 'fs'; 5 | import path from 'path'; 6 | import builtins from 'rollup-plugin-node-builtins'; 7 | const pkg = JSON.parse(fs.readFileSync(path.resolve('./package.json'), 'utf-8')); 8 | const external = Object.keys(pkg.dependencies || {}); 9 | external.push('atom'); 10 | external.push('fs'); 11 | external.push('child_process'); 12 | 13 | export default { 14 | input: 'index.js', 15 | output: { 16 | file: 'build/main.js', 17 | format: 'cjs', 18 | sourceMap: false 19 | }, 20 | plugins: [ 21 | resolve({ 22 | mainFields: ['module', 'main'], 23 | extensions: ['.js', '.jsx', '.json'], 24 | preferBuiltins: true 25 | }), 26 | babel({ 27 | exclude: 'node_modules/**' 28 | }), 29 | commonjs({ 30 | include: ['node_modules/**'] 31 | }), 32 | builtins() 33 | ], 34 | external 35 | }; 36 | -------------------------------------------------------------------------------- /spec/atom-solidity-spec.js: -------------------------------------------------------------------------------- 1 | 'use babel' 2 | /* global it, describe, expect */ 3 | 4 | // Use the command `window:run-package-specs` (cmd-alt-ctrl-p) to run specs. 5 | // 6 | // To run a specific `it` or `describe` block add an `f` to the front (e.g. `fit` 7 | // or `fdescribe`). Remove the `f` to unfocus the block. 8 | 9 | describe('Etheratom', async function() { 10 | describe('Test test', function() { 11 | it('Expect true to be true', function() { 12 | expect(true).toBe(true); 13 | }) 14 | }) 15 | }); 16 | -------------------------------------------------------------------------------- /styles/atom-solidity.less: -------------------------------------------------------------------------------- 1 | // The ui-variables file is provided by base themes provided by Atom. 2 | // 3 | // See https://github.com/atom/atom-dark-ui/blob/master/styles/ui-variables.less 4 | // for a full listing of what's available. 5 | @import "ui-variables"; 6 | @import "../node_modules/react-checkbox-tree/src/less/react-checkbox-tree.less"; 7 | 8 | // Color variables (appears count calculates by raw css) 9 | @color-bg: #2c313a; 10 | @color-br: #181a1f; 11 | @color-bg-child: #3a3f4b; 12 | 13 | // Height variables (appears count calculates by raw css) 14 | @height-max: 312px; 15 | 16 | // Font Awesome 17 | @font-face { 18 | font-family: 'FontAwesome'; 19 | font-weight: normal; 20 | font-style: normal; 21 | src: url(atom://etheratom/fonts/fontawesome-webfont.woff) format('woff'); 22 | } 23 | 24 | // Panel 25 | .etheratom-panel { 26 | display: flex; 27 | flex-direction: row; 28 | height: 100%; 29 | max-width: 50vw; 30 | width: 27vw; 31 | min-width: 20vw; 32 | overflow: scroll; 33 | &-resize-handle { 34 | flex: 0 0 0.3em; 35 | height: initial; 36 | right: auto; 37 | bottom: 0; 38 | cursor: col-resize; 39 | background-color: #353b45; 40 | } 41 | } 42 | 43 | .etheratom { 44 | width: 100%; 45 | min-width: 340px; 46 | 47 | select { 48 | border-color: #181a1f; 49 | } 50 | 51 | .row { 52 | display: flex; 53 | width: 100%; 54 | margin-top: 10px; 55 | padding: 0px 8px; 56 | } 57 | 58 | .icon { 59 | display: flex; 60 | justify-content: center; 61 | align-items: center; 62 | } 63 | .compiler-info { 64 | font-family: 'Hack', Serif; 65 | font-weight: bold; 66 | display: block; 67 | text-align: center; 68 | margin: 5px 0; 69 | padding: 5px 0; 70 | } 71 | .tx-header { 72 | font-family: 'Hack', Serif; 73 | font-weight: normal; 74 | font-size: small; 75 | display: block; 76 | text-align: center; 77 | margin: 5px 0; 78 | padding: 5px 0; 79 | } 80 | 81 | #version_selector { 82 | select { 83 | flex-grow: 1; 84 | width: 100%; 85 | height: 36px; 86 | background-color: @color-bg; 87 | border: 1px solid @color-br; 88 | max-height: @height-max; 89 | overflow-y: auto; 90 | padding: 0; 91 | position: relative; 92 | 93 | option { 94 | background-color: @color-bg-child; 95 | border: 1px solid @color-br; 96 | margin: 10px 0 0 0; 97 | max-height: @height-max; 98 | overflow-y: auto; 99 | padding: 0; 100 | position: relative; 101 | line-height: 2em; 102 | } 103 | } 104 | } 105 | #accounts-list { 106 | select { 107 | flex-grow: 1; 108 | width: 100%; 109 | height: 36px; 110 | background-color: @color-bg; 111 | border: 1px solid @color-br; 112 | max-height: @height-max; 113 | overflow-y: auto; 114 | padding: 0; 115 | position: relative; 116 | 117 | option { 118 | background-color: @color-bg-child; 119 | border: 1px solid @color-br; 120 | margin: 10px 0 0 0; 121 | max-height: @height-max; 122 | overflow-y: auto; 123 | padding: 0; 124 | position: relative; 125 | line-height: 2em; 126 | } 127 | } 128 | 129 | form { 130 | input { 131 | background-color: #2c313a; 132 | border: solid 1px #181a1f; 133 | height: 36px; 134 | } 135 | input:first-of-type { 136 | padding-left: 8px; 137 | width: 100%; 138 | background-color: @color-bg; 139 | } 140 | } 141 | } 142 | 143 | #client-options { 144 | text-align: center; 145 | display: block; 146 | .client-select { 147 | form { 148 | .clients { 149 | display: flex; 150 | flex-direction: row; 151 | justify-content: center; 152 | align-items: center; 153 | } 154 | } 155 | } 156 | } 157 | 158 | #common-buttons { 159 | text-align: center; 160 | } 161 | 162 | #compiled-error { 163 | ul { 164 | list-style: none; 165 | display: flex; 166 | flex-direction: column; 167 | justify-content: flex-start; 168 | align-items: flex-start; 169 | } 170 | } 171 | #test-error { 172 | ul { 173 | list-style: none; 174 | display: flex; 175 | flex-direction: column; 176 | justify-content: flex-start; 177 | align-items: flex-start; 178 | } 179 | } 180 | #NodeControl { 181 | .list-group { 182 | .list-item { 183 | margin-top: 2px; 184 | margin-bottom: 2px; 185 | 186 | .input-text { 187 | display: inline-block !important; 188 | max-width: 75%; 189 | } 190 | } 191 | } 192 | .row { 193 | padding: 0 !important; 194 | } 195 | 196 | form { 197 | input { 198 | background-color: #2c313a; 199 | border: solid 1px #181a1f; 200 | } 201 | input.smallbtn { 202 | width: auto !important; 203 | } 204 | input:first-of-type { 205 | flex: 1 0 150px; 206 | padding-left: 8px; 207 | width: 100%; 208 | background-color: @color-bg; 209 | } 210 | } 211 | } 212 | 213 | .input { 214 | background-color: @pane-item-background-color; 215 | border: solid 1px @pane-item-border-color; 216 | font-size: initial; 217 | margin: 2px; 218 | } 219 | 220 | .inputs { 221 | background-color: @input-background-color; 222 | border: solid 1px @input-border-color; 223 | font-weight: lighter; 224 | font-size: initial; 225 | } 226 | 227 | .contract-container { 228 | border-bottom: solid 2px @base-border-color; 229 | margin-bottom: 8px; 230 | padding: 5px; 231 | } 232 | 233 | .contract-name { 234 | margin: 2px 0; 235 | pading: 2px 0; 236 | } 237 | 238 | .large-code { 239 | max-height: 150px; 240 | margin: 10px 5px; 241 | &::selection { 242 | background-color: @background-color-selected; 243 | } 244 | } 245 | 246 | .call-button { 247 | background-color: @pane-item-background-color; 248 | border: solid 1px @pane-item-border-color; 249 | font-size: initial; 250 | margin: 2px; 251 | } 252 | 253 | .call-button-values { 254 | background-color: @input-background-color; 255 | border: solid 1px @input-border-color; 256 | font-weight: lighter; 257 | font-size: initial; 258 | margin: 2px 2px 2px 0; 259 | } 260 | 261 | .stat-sent { 262 | display: block; 263 | } 264 | 265 | .stat-mining { 266 | display: inline; 267 | color: #6494ed; 268 | } 269 | 270 | .stat-mining-align { 271 | vertical-align: middle; 272 | } 273 | 274 | // unlock button 275 | .unlock-default { 276 | background-color: @button-background-color; 277 | } 278 | 279 | .unlock-active { 280 | color: @text-color-highlight !important; 281 | background-color: @button-background-color-selected !important; 282 | } 283 | 284 | .file-collapse-label { 285 | display: flex; 286 | flex-direction: row; 287 | justify-content: space-between; 288 | } 289 | 290 | .gas-estimate-form { 291 | display: flex; 292 | flex-direction: row; 293 | justify-content: flex-start; 294 | align-items: center; 295 | } 296 | } 297 | .red-message { 298 | color: @text-color-error; 299 | } 300 | .green-message { 301 | color: @text-color-success; 302 | } 303 | .copy-btn { 304 | cursor: pointer; 305 | transition: all 0.2s ease-in-out; 306 | 307 | &:hover { 308 | color: @text-color-highlight; 309 | } 310 | 311 | &:focus,&:active { 312 | color: @text-color-success; 313 | } 314 | } 315 | 316 | // Tab view styling 317 | .vertical-tabs { 318 | display: flex; 319 | flex-direction: row; 320 | align-items: flex-start; 321 | 322 | .vertical { 323 | rotate: -90deg; 324 | } 325 | .tab_btns { 326 | display: flex; 327 | flex-direction: row-reverse; 328 | list-style: none; 329 | } 330 | .tablist { 331 | width: 0; 332 | margin-top: 25vh; 333 | } 334 | .react-tabs__tab-panel--selected { 335 | width: 90%; 336 | } 337 | .react-tabs__tab--selected { 338 | .btn { 339 | color: white; 340 | background-color: #21252b; 341 | background-image: linear-gradient(#2c313a, #21252b); 342 | } 343 | } 344 | } 345 | 346 | .form-btn { 347 | display: flex; 348 | justify-content: center; 349 | } 350 | 351 | .flex-row { 352 | display: flex; 353 | flex-direction: row; 354 | justify-content: flex-start; 355 | align-items: center; 356 | } 357 | 358 | .tx-list-container { 359 | height: 300px; 360 | } 361 | 362 | .tx-list-item { 363 | display: flex; 364 | flex-direction: row; 365 | justify-content: space-between; 366 | align-items: center; 367 | } 368 | 369 | .test-selector { 370 | display: flex; 371 | justify-content: space-between; 372 | align-items: center; 373 | } 374 | 375 | .test-result-list-item { 376 | display: flex; 377 | flex-direction: row; 378 | justify-content: flex-start; 379 | align-items: center; 380 | } 381 | 382 | .event-collapse-label { 383 | display: flex; 384 | flex-direction: row; 385 | justify-content: space-between; 386 | align-items: center; 387 | } 388 | 389 | .notify-badge { 390 | margin-left: 5px; 391 | margin-right: 5px; 392 | } 393 | 394 | .no-header { 395 | text-align: center; 396 | } 397 | 398 | .test-header { 399 | text-align: center; 400 | } 401 | 402 | .tab_btns li .icon-button { 403 | height: 100%; 404 | } 405 | .save-abi { 406 | display: flex; 407 | button { 408 | margin: 2px; 409 | } 410 | } 411 | --------------------------------------------------------------------------------