/* global */ 'use strict' var $ = require('jquery') var ethJSUtil = require('ethereumjs-util') var BN = ethJSUtil.BN var EventManager = require('ethereum-remix').lib.EventManager var crypto = require('crypto') var async = require('async') var TxRunner = require('./app/execution/txRunner') var yo = require('yo-yo') var txFormat = require('./app/execution/txFormat') var txHelper = require('./app/execution/txHelper') var txExecution = require('./app/execution/txExecution') var helper = require('./lib/helper') var modalDialogCustom = require('./app/ui/modal-dialog-custom') var executionContext = require('./execution-context') // copy to copyToClipboard const copy = require('clipboard-copy') // -------------- styling ---------------------- var csjs = require('csjs-inject') var remix = require('ethereum-remix') var styleGuide = remix.ui.styleGuide var styles = styleGuide() var css = csjs` .instanceTitleContainer { display: flex; align-items: center; } .title { ${styles.dropdown} width: 400px; display: flex; justify-content: space-between; align-items: center; overflow: hidden; word-break: break-word; line-height: initial; background-color: ${styles.colors.white}; } .titleText { margin-right: 1em; word-break: break-word; min-width: 230px; } .instance { ${styles.displayBox} margin-bottom: 2px; padding: 10px 15px 6px 15px; } .instance .title:before { content: "\\25BE"; margin-right: 5%; } .instance.hidesub .title:before { content: "\\25B8"; margin-right: 5%; } .instance.hidesub > * { display: none; } .instance.hidesub .title { display: flex; } .copy { font-size: 13px; cursor: pointer; opacity: 0.8; margin-left: 3%; color: ${styles.colors.blue}; } .copy:hover{ color: ${styles.colors.grey}; } .buttonsContainer { margin-top: 2%; } .contractActions { display: flex; } .instanceButton {} .closeIcon { font-size: 10px; position: relative; top: -5px; right: -2px; } .udappClose { margin-left: 3%; align-self: center; } ` /* trigger debugRequested */ function UniversalDApp (opts = {}) { this.event = new EventManager() var self = this self._api = opts.api self.removable = opts.opt.removable self.removable_instance = opts.opt.removable_instance self.el = yo`
` self.personalMode = opts.opt.personalMode || false self.contracts self.transactionContextAPI executionContext.event.register('contextChanged', this, function (context) { self.reset(self.contracts) }) self.txRunner = new TxRunner({}, { queueTxs: true, personalMode: this.personalMode }) } UniversalDApp.prototype.reset = function (contracts, transactionContextAPI) { this.el.innerHTML = '' this.contracts = contracts this.transactionContextAPI = transactionContextAPI this.accounts = {} if (executionContext.isVM()) { this._addAccount('3cd7232cd6f3fc66a57a6bedc1a8ed6c228fff0a327e169c2bcc5e869ed49511', '0x56BC75E2D63100000') this._addAccount('2ac6c190b09897cd8987869cc7b918cfea07ee82038d492abce033c75c1b1d0c', '0x56BC75E2D63100000') this._addAccount('dae9801649ba2d95a21e688b56f77905e5667c44ce868ec83f82e838712a2c7a', '0x56BC75E2D63100000') this._addAccount('d74aa6d18aa79a05f3473dd030a97d3305737cbc8337d940344345c1f6b72eea', '0x56BC75E2D63100000') this._addAccount('71975fbf7fe448e004ac7ae54cad0a383c3906055a65468714156a07385e96ce', '0x56BC75E2D63100000') executionContext.vm().stateManager.cache.flush(function () {}) } this.txRunner = new TxRunner(this.accounts, { queueTxs: true, personalMode: this.personalMode }) } UniversalDApp.prototype.newAccount = function (password, cb) { if (!executionContext.isVM()) { if (!this.personalMode) { return cb('Not running in personal mode') } executionContext.web3().personal.newAccount(password, cb) } else { var privateKey do { privateKey = crypto.randomBytes(32) } while (!ethJSUtil.isValidPrivate(privateKey)) this._addAccount(privateKey) cb(null, '0x' + ethJSUtil.privateToAddress(privateKey)) } } UniversalDApp.prototype._addAccount = function (privateKey, balance) { var self = this if (!executionContext.isVM()) { throw new Error('_addAccount() cannot be called in non-VM mode') } if (self.accounts) { privateKey = new Buffer(privateKey, 'hex') var address = ethJSUtil.privateToAddress(privateKey) // FIXME: we don't care about the callback, but we should still make this proper executionContext.vm().stateManager.putAccountBalance(address, balance || '0xf00000000000000001', function cb () {}) self.accounts['0x' + address.toString('hex')] = { privateKey: privateKey, nonce: 0 } } } UniversalDApp.prototype.getAccounts = function (cb) { var self = this if (!executionContext.isVM()) { // Weirdness of web3: listAccounts() is sync, `getListAccounts()` is async // See: https://github.com/ethereum/web3.js/issues/442 if (self.personalMode) { executionContext.web3().personal.getListAccounts(cb) } else { executionContext.web3().eth.getAccounts(cb) } } else { if (!self.accounts) { return cb('No accounts?') } cb(null, Object.keys(self.accounts)) } } UniversalDApp.prototype.getBalance = function (address, cb) { var self = this address = ethJSUtil.stripHexPrefix(address) if (!executionContext.isVM()) { executionContext.web3().eth.getBalance(address, function (err, res) { if (err) { cb(err) } else { cb(null, res.toString(10)) } }) } else { if (!self.accounts) { return cb('No accounts?') } executionContext.vm().stateManager.getAccountBalance(new Buffer(address, 'hex'), function (err, res) { if (err) { cb('Account not found') } else { cb(null, new BN(res).toString(10)) } }) } } // TODO this function was named before "appendChild". // this will render an instance: contract name, contract address, and all the public functions // basically this has to be called for the "atAddress" (line 393) and when a contract creation succeed // this returns a DOM element UniversalDApp.prototype.renderInstance = function (contract, address, contractName) { function remove () { $instance.remove() } var $instance = $(``) var context = executionContext.isVM() ? 'memory' : 'blockchain' address = (address.slice(0, 2) === '0x' ? '' : '0x') + address.toString('hex') var shortAddress = helper.shortenAddress(address) var title = yo`