diff --git a/extensions/etherscan-general/index.html b/extensions/etherscan-general/index.html new file mode 100644 index 0000000000..c20c036bc0 --- /dev/null +++ b/extensions/etherscan-general/index.html @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + +
Etherscan - Network Status
+
+ +
+ + diff --git a/extensions/etherscan-general/index.js b/extensions/etherscan-general/index.js new file mode 100644 index 0000000000..f5a8ffd17c --- /dev/null +++ b/extensions/etherscan-general/index.js @@ -0,0 +1,109 @@ +/* global XMLHttpRequest */ +var remix = new window.RemixExtension() +var container +var updateBtn +var network +var currentNetWork = '' +var networks = { + 'Main': '', + 'Ropsten': 'ropsten', + 'Kovan': 'kovan', + 'Rinkeby': 'rinkeby' +} + +function load () { + container = document.getElementById('container') + updateBtn = document.getElementById('updateBtn') + network = document.getElementById('network') + + var log = function (call, msg) { + container.innerHTML += '
' + call + ': ' + msg + '
' + } + + updateBtn.addEventListener('click', function () { + container.innerHTML = '' + if (networks[currentNetWork] !== undefined) { + getBlockNumber(log) + getLatestBlockInfo(log) + getGasPrice(log) + } else { + container.innerHTML = 'current network not available through etherscan API' + } + }) + + getToken(function (error, result) { + if (error) console.log(error) + if (!result) { + remix.call('config', 'setConfig', ['config.json', '{ apikey: "" }'], function (error, result) { + if (error) return console.log(error) + }) + } + }) + setInterval(function () { + remix.call('app', 'detectNetWork', [], function (error, result) { + if (error) console.log(error) + if (network.innerHTML !== result[0].name + ' - ' + result[0].id) { + currentNetWork = result[0].name + container.innerHTML = '' + network.innerHTML = result[0].name + ' - ' + result[0].id + } + }) + }, 1000) +} + +function getToken (callback) { + remix.call('config', 'getConfig', ['config.json'], function (error, result) { + if (error) return callback(error) + if (result[0]) { + try { + result = JSON.parse(result[0]) + } catch (e) { + return callback(e.message) + } + callback(null, result.apikey) + } else { + container.innerHTML = 'no api key found' + callback('no api key found') + } + }) +} + +function httpGetAsync (url, callback) { + var xmlHttp = new XMLHttpRequest() + xmlHttp.onreadystatechange = function () { + if (xmlHttp.readyState === 4 && xmlHttp.status === 200) { + callback(xmlHttp.responseText) + } + } + xmlHttp.open('GET', url, true) + xmlHttp.send(null) +} + +function getBlockNumber (callback) { + getToken(function (error, apikey) { + if (error) console.log(error) + httpGetAsync('https://api-' + networks[currentNetWork] + '.etherscan.io/api?module=proxy&action=eth_blockNumber&apikey=' + apikey, function (result) { + callback('latest block number', result) + }) + }) +} + +function getLatestBlockInfo (callback) { + getToken(function (error, apikey) { + if (error) console.log(error) + httpGetAsync('https://api-' + networks[currentNetWork] + '.etherscan.io/api?module=proxy&action=eth_getBlockByNumber&tag=latest&boolean=true&apikey=' + apikey, function (result) { + callback('latest block', result) + }) + }) +} + +function getGasPrice (callback) { + getToken(function (error, apikey) { + if (error) console.log(error) + httpGetAsync('https://api-' + networks[currentNetWork] + '.etherscan.io/api?module=proxy&action=eth_gasPrice&apikey=' + apikey, function (result) { + callback('current gas price', result) + }) + }) +} + +setTimeout(load, 1000) diff --git a/src/app/plugin/index.js b/src/app/plugin/index.js new file mode 100644 index 0000000000..14b7bf27ea --- /dev/null +++ b/src/app/plugin/index.js @@ -0,0 +1,55 @@ +'use strict' + +class RemixExtension { + constructor () { + this._notifications = {} + this._pendingRequests = {} + this._id = 0 + window.addEventListener('message', (event) => this._newMessage(event), false) + } + + listen (key, type, callback) { + if (!this._notifications[key]) this._notifications[key] = {} + this._notifications[key][type] = callback + } + + call (key, type, params, callback) { + this._id++ + this._pendingRequests[this._id] = callback + window.parent.postMessage(JSON.stringify({ + action: 'request', + key, + type, + value: params, + id: this._id + }), '*') + } + + _newMessage (event) { + if (!event.data) return + if (typeof event.data !== 'string') return + + var msg + try { + msg = JSON.parse(event.data) + } catch (e) { + return console.log('unable to parse data') + } + const {action, key, type, value} = msg + if (action === 'notification') { + if (this._notifications[key] && this._notifications[key][type]) { + this._notifications[key][type](value) + } + } else if (action === 'response') { + const {id, error} = msg + if (this._pendingRequests[id]) { + this._pendingRequests[id](error, value) + delete this._pendingRequests[id] + } + } + } +} + +if (window) window.RemixExtension = RemixExtension +if (module && module.exports) module.exports = RemixExtension + diff --git a/src/app/plugin/package.json b/src/app/plugin/package.json new file mode 100644 index 0000000000..ae2bbda9a0 --- /dev/null +++ b/src/app/plugin/package.json @@ -0,0 +1,71 @@ +{ + "name": "remix-extension", + "version": "0.0.1", + "description": "Ethereum IDE and tools for the web", + "contributors": [ + { + "name": "Yann Levreau", + "email": "yann@ethdev.com" + } + ], + "main": "./index.js", + "dependencies": { + "babel-eslint": "^7.1.1", + "babel-plugin-transform-object-assign": "^6.22.0", + "babel-preset-es2015": "^6.24.0", + "babelify": "^7.3.0", + "standard": "^7.0.1", + "tape": "^4.6.0" + }, + "scripts": { + "browserify": "browserify index.js -o bundle.js" + }, + "standard": { + "ignore": [ + "node_modules/*" + ], + "parser": "babel-eslint" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/ethereum/remix-ide.git" + }, + "author": "cpp-ethereum team", + "license": "MIT", + "bugs": { + "url": "https://github.com/ethereum/remix-ide/issues" + }, + "homepage": "https://github.com/ethereum/remix-ide#readme", + "browserify": { + "transform": [ + [ + "babelify", + { + "plugins": [ + [ + "fast-async", + { + "runtimePatten": null, + "compiler": { + "promises": true, + "es7": true, + "noRuntime": true, + "wrapAwait": true + } + } + ], + "transform-object-assign" + ] + } + ], + [ + "babelify", + { + "presets": [ + "es2015" + ] + } + ] + ] + } +} diff --git a/src/app/plugin/pluginAPI.js b/src/app/plugin/pluginAPI.js index ebd9b694e4..4298db9624 100644 --- a/src/app/plugin/pluginAPI.js +++ b/src/app/plugin/pluginAPI.js @@ -12,6 +12,12 @@ module.exports = (fileProviders, compiler, udapp, tabbedMenu) => { }, updateTitle: (mod, title, cb) => { tabbedMenu.updateTabTitle(mod, title) + if (cb) cb() + }, + detectNetWork: (mod, cb) => { + executionContext.detectNetwork((error, network) => { + cb(error, network) + }) } }, config: { diff --git a/src/app/plugin/plugins.js b/src/app/plugin/plugins.js index 68cdb2e31e..3ce3c17e3c 100644 --- a/src/app/plugin/plugins.js +++ b/src/app/plugin/plugins.js @@ -5,4 +5,10 @@ module.exports = { url: 'https://remix-plugin.oraclize.it', title: 'Oraclize' } + /* + 'etherscan-general': { + url: 'http://127.0.0.1:8081', + title: 'Etherscan-general' + } + */ } diff --git a/src/app/tabs/settings-tab.js b/src/app/tabs/settings-tab.js index 6b406f86ed..f051ebc886 100644 --- a/src/app/tabs/settings-tab.js +++ b/src/app/tabs/settings-tab.js @@ -150,15 +150,12 @@ module.exports = class SettingsTab {
Plugin
-
- - Do not use this alpha feature if you are not sure what you are doing! -
+
{ onLoadPlugin('oraclize') }} type="button" value="Oraclize" class="${css.pluginLoad}">
+
{ onLoadPlugin('etherscan-general') }} type="button" value="Etherscan-general" class="${css.pluginLoad}">
${self._view.pluginInput}
- { onLoadPlugin('oraclize') }} type="button" value="Oraclize" class="${css.pluginLoad}">
` self._view.config.remixd = yo` diff --git a/test-browser/plugin/index-raw.html b/test-browser/plugin/index-raw.html new file mode 100644 index 0000000000..ce0eba546d --- /dev/null +++ b/test-browser/plugin/index-raw.html @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + +
PLUGIN
+ +
+ add config
+ remove config
+ get config
+ oraclize contract creation
+ account creation
+ change title
+
+
+ + diff --git a/test-browser/plugin/index.html b/test-browser/plugin/index.html index 2cb1662902..ff73cb0a23 100644 --- a/test-browser/plugin/index.html +++ b/test-browser/plugin/index.html @@ -30,7 +30,8 @@ - + + @@ -40,6 +41,9 @@ add config
remove config
get config
+ oraclize contract creation
+ account creation
+ change title

diff --git a/test-browser/plugin/plugin.js b/test-browser/plugin/plugin.js new file mode 100644 index 0000000000..cb85e84672 --- /dev/null +++ b/test-browser/plugin/plugin.js @@ -0,0 +1,56 @@ + +/* +test contract creation +*/ +var addrResolverByteCode = '0x6060604052341561000f57600080fd5b33600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061033c8061005f6000396000f300606060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806338cc483114610067578063767800de146100bc578063a6f9dae114610111578063d1d80fdf1461014a575b600080fd5b341561007257600080fd5b61007a610183565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156100c757600080fd5b6100cf6101ac565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561011c57600080fd5b610148600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506101d1565b005b341561015557600080fd5b610181600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610271565b005b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561022d57600080fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156102cd57600080fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505600a165627a7a723058201b23355f578cb9a23c0a43a440ab2631b62df7be0a8e759812a70f01344224da0029' + +const addrResolverTx = { + gasLimit: '0x2710', + from: '0xca35b7d915458ef540ade6068dfe2f44e8fa733c', + data: addrResolverByteCode, + value: '0x00', + useCall: false +} +var extension = new window.RemixExtension() +window.onload = function () { + extension.listen('compiler', 'compilationFinished', function () { + console.log(arguments) + }) + + setInterval(function () { + extension.call('app', 'detectNetWork', [], function (error, result) { + console.log(error, result) + }) + }, 5000) + + document.querySelector('input#testmessageadd').addEventListener('click', function () { + extension.call('config', 'setConfig', [document.getElementById('filename').value, document.getElementById('valuetosend').value], + function (error, result) { console.log(error, result) }) + }) + + document.querySelector('input#testmessageremove').addEventListener('click', function () { + extension.call('config', 'removeConfig', [document.getElementById('filename').value], + function (error, result) { console.log(error, result) }) + }) + + document.querySelector('input#testmessagerget').addEventListener('click', function () { + extension.call('config', 'getConfig', [document.getElementById('filename').value], + function (error, result) { console.log(error, result) }) + }) + + document.querySelector('input#testcontractcreation').addEventListener('click', function () { + extension.call('udapp', 'runTx', [addrResolverTx], + function (error, result) { console.log(error, result) }) + }) + + document.querySelector('input#testaccountcreation').addEventListener('click', function () { + extension.call('udapp', 'createVMAccount', ['71975fbf7fe448e004ac7ae54cad0a383c3906055a75468714156a07385e96ce', '0x56BC75E2D63100000'], + function (error, result) { console.log(error, result) }) + }) + + var k = 0 + document.querySelector('input#testchangetitle').addEventListener('click', function () { + extension.call('app', 'updateTitle', ['changed title ' + k++], + function (error, result) { console.log(error, result) }) + }) +}