From 7ed393d38c7758ae30f95ddb573ba39fe77e6163 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Thu, 8 Aug 2019 15:14:37 -0400 Subject: [PATCH] add fund account so that custom accounts can now deploy!! --- packages/embark-accounts-manager/package.json | 2 + .../src/fundAccount.js | 75 +++++++++++++++++++ packages/embark-accounts-manager/src/index.ts | 53 +++++++++---- .../src/provider.js | 2 +- packages/embark-typings/src/embark.d.ts | 1 + 5 files changed, 119 insertions(+), 14 deletions(-) create mode 100644 packages/embark-accounts-manager/src/fundAccount.js diff --git a/packages/embark-accounts-manager/package.json b/packages/embark-accounts-manager/package.json index dcc7d4ea1..e11afcfcc 100644 --- a/packages/embark-accounts-manager/package.json +++ b/packages/embark-accounts-manager/package.json @@ -45,6 +45,8 @@ }, "dependencies": { "@babel/runtime-corejs2": "7.3.1", + "async": "2.6.1", + "embark-i18n": "^4.1.0-beta.3", "embark-utils": "^4.1.0-beta.5", "web3": "1.0.0-beta.37" }, diff --git a/packages/embark-accounts-manager/src/fundAccount.js b/packages/embark-accounts-manager/src/fundAccount.js new file mode 100644 index 000000000..9b4be690c --- /dev/null +++ b/packages/embark-accounts-manager/src/fundAccount.js @@ -0,0 +1,75 @@ +const async = require('async'); +const TARGET = 0x7FFFFFFFFFFFFFFF; +const ALREADY_FUNDED = 'alreadyFunded'; + +export default function fundAccount(web3, accountAddress, hexBalance, callback) { + if (!hexBalance) { + hexBalance = TARGET; + } + const targetBalance = web3.utils.toBN(hexBalance); + let accountBalance; + let coinbaseAddress; + let lastNonce; + let gasPrice; + + async.waterfall([ + function getAccountBalance(next) { + web3.eth.getBalance(accountAddress, (err, balance) => { + if (err) { + return next(err); + } + balance = web3.utils.toBN(balance); + if (balance.gte(targetBalance)) { + return next(ALREADY_FUNDED); + } + accountBalance = balance; + next(); + }); + }, + function getNeededParams(next) { + async.parallel([ + function getCoinbaseAddress(paraCb) { + web3.eth.getCoinbase() + .then((address) => { + coinbaseAddress = address; + paraCb(); + }).catch(paraCb); + }, + function getGasPrice(paraCb) { + web3.eth.getGasPrice((err, price) => { + if (err) { + return paraCb(err); + } + gasPrice = price; + paraCb(); + }); + } + ], (err, _result) => { + next(err); + }); + }, + function getNonce(next) { + web3.eth.getTransactionCount(coinbaseAddress, (err, nonce) => { + if (err) { + return next(err); + } + lastNonce = nonce; + next(); + }); + }, + function sendTransaction(next) { + web3.eth.sendTransaction({ + from: coinbaseAddress, + to: accountAddress, + value: targetBalance.sub(accountBalance), + gasPrice: gasPrice, + nonce: lastNonce + }, next); + } + ], (err) => { + if (err && err !== ALREADY_FUNDED) { + return callback(err); + } + callback(); + }); +} diff --git a/packages/embark-accounts-manager/src/index.ts b/packages/embark-accounts-manager/src/index.ts index c1aa61b3e..cabd7f074 100644 --- a/packages/embark-accounts-manager/src/index.ts +++ b/packages/embark-accounts-manager/src/index.ts @@ -1,19 +1,30 @@ +import async from "async"; import {Embark, Events, Logger} /* supplied by @types/embark in packages/embark-typings */ from "embark"; +import {__} from "embark-i18n"; import {AccountParser, dappPath} from "embark-utils"; -const Web3 = require("web3"); -const ethUtil = require("ethereumjs-util"); +import Web3 from "web3"; + +import fundAccount from "./fundAccount"; export default class AccountsManager { private readonly logger: Logger; private readonly events: Events; private accounts: any[]; private web3: any; + private ready: boolean; constructor(private readonly embark: Embark, _options: any) { this.logger = embark.logger; this.events = embark.events; this.accounts = []; + this.ready = false; + this.events.setCommandHandler("accounts-manager:onReady", (cb) => { + if (this.ready) { + return cb(); + } + this.events.once("accounts-manager:ready", cb); + }); this.events.request("proxy:onReady", () => { this.parseAccounts(); }); @@ -21,16 +32,10 @@ export default class AccountsManager { this.events.setCommandHandler("accounts:get", (cb: any) => { cb(null, this.accounts); }); - - this.embark.registerActionForEvent("blockchain:proxy:request", this.checkBlockchainRequest.bind(this)); - this.embark.registerActionForEvent("blockchain:proxy:response", this.checkBlockchainResponse.bind(this)); } private async checkBlockchainRequest(params: any, callback: (error: any, result: any) => void) { - if (!this.accounts.length) { - return callback(null, params); - } - if (params.reqData.method === "eth_sendTransaction") { + if (params.reqData.method === "eth_sendTransaction" && this.accounts.length) { // Check if we have that account in our wallet const account = this.accounts.find((acc) => Web3.utils.toChecksumAddress(acc.address) === Web3.utils.toChecksumAddress(params.reqData.params[0].from)); if (account) { @@ -48,16 +53,23 @@ export default class AccountsManager { } private async checkBlockchainResponse(params: any, callback: (error: any, result: any) => void) { - if (!this.accounts.length) { - return callback(null, params); - } - if (params.reqData.method === "eth_accounts") { + if (params.reqData.method === "eth_accounts" && this.accounts.length) { params.respData.result = this.accounts.map((acc) => acc.address); return callback(null, params); } callback(null, params); } + private setReady() { + if (this.ready) { + return; + } + this.embark.registerActionForEvent("blockchain:proxy:request", this.checkBlockchainRequest.bind(this)); + this.embark.registerActionForEvent("blockchain:proxy:response", this.checkBlockchainResponse.bind(this)); + this.ready = true; + this.events.emit("accounts-manager:ready"); + } + private async parseAccounts() { if (!this.web3) { const provider = await this.events.request2("blockchain:client:provider", "ethereum"); @@ -66,5 +78,20 @@ export default class AccountsManager { // TODO add fund account const nodeAccounts = await this.web3.eth.getAccounts(); this.accounts = AccountParser.parseAccountsConfig(this.embark.config.blockchainConfig.accounts, this.web3, dappPath(), this.logger, nodeAccounts); + + if (!this.accounts.length || !this.embark.config.blockchainConfig.isDev) { + return this.setReady(); + } + async.eachLimit(this.accounts, 1, (account, eachCb) => { + if (!account.address) { + return eachCb(); + } + fundAccount(this.web3, account.address, account.hexBalance, eachCb); + }, (err) => { + if (err) { + this.logger.error(__("Error funding accounts"), err.message || err); + } + this.setReady(); + }); } } diff --git a/packages/embark-blockchain-connector/src/provider.js b/packages/embark-blockchain-connector/src/provider.js index 09f74af3f..c04b949f5 100644 --- a/packages/embark-blockchain-connector/src/provider.js +++ b/packages/embark-blockchain-connector/src/provider.js @@ -1,4 +1,4 @@ -import { __ } from 'embark-i18n'; +import {__} from 'embark-i18n'; const async = require('async'); const { AccountParser, dappPath } = require('embark-utils'); const fundAccount = require('./fundAccount'); diff --git a/packages/embark-typings/src/embark.d.ts b/packages/embark-typings/src/embark.d.ts index 93530e952..69db50965 100644 --- a/packages/embark-typings/src/embark.d.ts +++ b/packages/embark-typings/src/embark.d.ts @@ -36,6 +36,7 @@ export interface Config { wsOrigins: string; rpcCorsDomain: string; wsRPC: boolean; + isDev: boolean; }; webServerConfig: { certOptions: {