diff --git a/lib/plugins/wallet/geth/base.js b/lib/plugins/wallet/geth/base.js index bced95d1..6674dfd3 100644 --- a/lib/plugins/wallet/geth/base.js +++ b/lib/plugins/wallet/geth/base.js @@ -52,6 +52,23 @@ function isStrictAddress (cryptoCode, toAddress, settings, operatorId) { function sendCoins (account, tx, settings, operatorId) { const { toAddress, cryptoAtoms, cryptoCode } = tx + const isErc20Token = coins.utils.isErc20Token(cryptoCode) + + if (isErc20Token) { + return generateErc20Tx(toAddress, defaultWallet(account), cryptoAtoms, false, cryptoCode) + .then(pify(web3.eth.sendSignedTransaction)) + .then(txid => { + return pify(web3.eth.getTransaction)(txid) + .then(tx => { + if (!tx) return { txid } + + const fee = new BN(tx.gas).times(new BN(tx.gasPrice)).decimalPlaces(0) + + return { txid, fee } + }) + }) + } + return generateTx(toAddress, defaultWallet(account), cryptoAtoms, false, cryptoCode) .then(pify(web3.eth.sendSignedTransaction)) .then(txid => { @@ -97,17 +114,66 @@ function _balance (includePending, address, cryptoCode) { .then(balance => balance ? BN(balance) : BN(0)) } +function generateErc20Tx (_toAddress, wallet, amount, includesFee, cryptoCode) { + const fromAddress = '0x' + wallet.getAddress().toString('hex') + + const toAddress = coins.utils.getErc20Token(cryptoCode).contractAddress + + const contract = new web3.eth.Contract(ABI.ERC20, toAddress) + const contractData = contract.methods.transfer(_toAddress.toLowerCase(), hex(amount)) + + const txTemplate = { + from: fromAddress, + to: toAddress, + value: hex(BN(0)), + data: contractData.encodeABI() + } + + const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.London }) + + const promises = [ + pify(contractData.estimateGas)(txTemplate), + pify(web3.eth.getTransactionCount)(fromAddress), + pify(web3.eth.getBlock)('pending') + ] + + return Promise.all(promises) + .then(([gas, txCount, { baseFeePerGas }]) => [ + BN(gas), + _.max([0, txCount, lastUsedNonces[fromAddress] + 1]), + BN(baseFeePerGas) + ]) + .then(([gas, txCount, baseFeePerGas]) => { + lastUsedNonces[fromAddress] = txCount + + const maxPriorityFeePerGas = new BN(web3.utils.toWei('2.5', 'gwei')) // web3 default value + const maxFeePerGas = new BN(2).times(baseFeePerGas).plus(maxPriorityFeePerGas) + + const rawTx = { + chainId: 1, + nonce: txCount, + maxPriorityFeePerGas: web3.utils.toHex(maxPriorityFeePerGas), + maxFeePerGas: web3.utils.toHex(maxFeePerGas), + gasLimit: hex(gas), + to: toAddress, + from: fromAddress, + value: hex(BN(0)), + data: contractData.encodeABI() + } + + const tx = FeeMarketEIP1559Transaction.fromTxData(rawTx, { common }) + const privateKey = wallet.getPrivateKey() + + const signedTx = tx.sign(privateKey) + + return '0x' + signedTx.serialize().toString('hex') + }) +} + function generateTx (_toAddress, wallet, amount, includesFee, cryptoCode) { const fromAddress = '0x' + wallet.getAddress().toString('hex') - const isErc20Token = coins.utils.isErc20Token(cryptoCode) - const toAddress = isErc20Token ? coins.utils.getErc20Token(cryptoCode).contractAddress : _toAddress.toLowerCase() - - let contract, contractData - if (isErc20Token) { - contract = new web3.eth.Contract(ABI.ERC20, toAddress) - contractData = isErc20Token && contract.methods.transfer(_toAddress.toLowerCase(), hex(toSend)).encodeABI() - } + const toAddress = _toAddress.toLowerCase() const txTemplate = { from: fromAddress, @@ -115,8 +181,6 @@ function generateTx (_toAddress, wallet, amount, includesFee, cryptoCode) { value: amount.toString() } - if (isErc20Token) txTemplate.data = contractData - const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.London }) const promises = [ @@ -151,11 +215,7 @@ function generateTx (_toAddress, wallet, amount, includesFee, cryptoCode) { gasLimit: hex(gas), to: toAddress, from: fromAddress, - value: isErc20Token ? hex(BN(0)) : hex(toSend) - } - - if (isErc20Token) { - rawTx.data = contractData + value: hex(toSend) } const tx = FeeMarketEIP1559Transaction.fromTxData(rawTx, { common })