Skip to content

Commit 72e609a

Browse files
emizzle0x-r4bbit
authored andcommitted
feat(@embark/accounts-manager): Get alternative coinbase address
In dev mode, accounts are funded per the blockchain accounts config. In specific situations, there may not be enough funds on the account returned by `eth_coinbase`. In that case, and in the case when `eth_coinbase` returns `0x0` (or equivalent), loop through all accounts and find the one that has the most funds and use that as the coinbase account.
1 parent edf4347 commit 72e609a

File tree

1 file changed

+53
-3
lines changed
  • packages/plugins/accounts-manager/src

1 file changed

+53
-3
lines changed

packages/plugins/accounts-manager/src/index.ts

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export default class AccountsManager {
2626
// reset accounts backing variable as the accounts in config may have changed and
2727
// web.eth.getAccounts may return a different value now
2828
this._accounts = null;
29+
this._web3 = null;
2930

3031
// as the accounts may have changed, we need to fund the accounts again
3132
await this.parseAndFundAccounts();
@@ -54,14 +55,13 @@ export default class AccountsManager {
5455
}
5556

5657
private async parseAndFundAccounts() {
57-
const web3 = await this.web3;
5858
const accounts = await this.accounts;
59-
6059
if (!accounts.length || !this.embark.config.blockchainConfig.isDev) {
6160
return;
6261
}
6362
try {
64-
const coinbase = await web3.eth.getCoinbase();
63+
const web3 = await this.web3;
64+
const coinbase = await this.getCoinbaseAddress();
6565
const acctsFromConfig = AccountParser.parseAccountsConfig(this.embark.config.blockchainConfig.accounts, web3, dappPath(), this.logger, accounts);
6666
const accountsWithBalance = accounts.map((address) => {
6767
const acctFromConfig = acctsFromConfig.find((acctCfg) => acctCfg.address === address);
@@ -82,4 +82,54 @@ export default class AccountsManager {
8282
this.logger.error(__("Error funding accounts"), err.message || err);
8383
}
8484
}
85+
86+
async findAccountWithMostFunds() {
87+
const web3 = await this.web3;
88+
const accounts = await web3.eth.getAccounts();
89+
let highestBalance = {
90+
balance: web3.utils.toBN(0),
91+
account: ""
92+
};
93+
for (const account of accounts) {
94+
// eslint-disable-next-line no-await-in-loop
95+
const balance = web3.utils.toBN(await web3.eth.getBalance(account));
96+
if (balance.gt(highestBalance.balance)) {
97+
highestBalance = { balance, account };
98+
}
99+
}
100+
return highestBalance.account;
101+
}
102+
103+
async findAlternativeCoinbase() {
104+
try {
105+
return this.findAccountWithMostFunds();
106+
} catch (err) {
107+
throw new Error(`Error getting coinbase address: ${err.message || err}`);
108+
}
109+
}
110+
111+
async getCoinbaseAddress() {
112+
const web3 = await this.web3;
113+
try {
114+
const coinbaseAddress = await web3.eth.getCoinbase();
115+
// if the blockchain returns a zeroed address, we can find the account
116+
// with the most funds and use that as the "from" account to txfer
117+
// funds.
118+
if (!coinbaseAddress ||
119+
web3.utils.hexToNumberString(coinbaseAddress) === "0" || // matches 0x0 and 0x00000000000000000000000000000000000000
120+
(await web3.eth.getBalance(coinbaseAddress)) === "0"
121+
) {
122+
return this.findAlternativeCoinbase();
123+
}
124+
return coinbaseAddress;
125+
} catch (err) {
126+
// if the blockchain doesn't support 'eth_coinbase' RPC commands,
127+
// we can find the account with the most funds and use that as the
128+
// "from" account to txfer funds.
129+
if (err.message.includes("The method eth_coinbase does not exist/is not available")) {
130+
return this.findAlternativeCoinbase();
131+
}
132+
throw new Error(`Error finding coinbase address: ${err.message || err}`);
133+
}
134+
}
85135
}

0 commit comments

Comments
 (0)