|
|
|
@ -10,14 +10,19 @@ const MemoTextArea = require('./components/send/memo-textarea') |
|
|
|
|
const GasFeeDisplay = require('./components/send/gas-fee-display-v2') |
|
|
|
|
|
|
|
|
|
const { MIN_GAS_TOTAL } = require('./components/send/send-constants') |
|
|
|
|
const abi = require('human-standard-token-abi') |
|
|
|
|
|
|
|
|
|
const { |
|
|
|
|
multiplyCurrencies, |
|
|
|
|
conversionGreaterThan, |
|
|
|
|
} = require('./conversion-util') |
|
|
|
|
const { |
|
|
|
|
calcTokenAmount, |
|
|
|
|
} = require('./token-util') |
|
|
|
|
const { |
|
|
|
|
isBalanceSufficient, |
|
|
|
|
} = require('./components/send/send-utils.js') |
|
|
|
|
isTokenBalanceSufficient, |
|
|
|
|
} = require('./components/send/send-utils') |
|
|
|
|
const { isValidAddress } = require('./util') |
|
|
|
|
|
|
|
|
|
module.exports = SendTransactionScreen |
|
|
|
@ -40,6 +45,37 @@ function SendTransactionScreen () { |
|
|
|
|
this.validateAmount = this.validateAmount.bind(this) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const getParamsForGasEstimate = function (selectedAddress, symbol, data) { |
|
|
|
|
const estimatedGasParams = { |
|
|
|
|
from: selectedAddress, |
|
|
|
|
gas: '746a528800', |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (symbol) { |
|
|
|
|
Object.assign(estimatedGasParams, { value: '0x0' }) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (data) { |
|
|
|
|
Object.assign(estimatedGasParams, { data }) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return estimatedGasParams |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
SendTransactionScreen.prototype.updateSendTokenBalance = function (usersToken) { |
|
|
|
|
if (!usersToken) return |
|
|
|
|
|
|
|
|
|
const { |
|
|
|
|
selectedToken = {}, |
|
|
|
|
updateSendTokenBalance, |
|
|
|
|
} = this.props |
|
|
|
|
const { decimals } = selectedToken || {} |
|
|
|
|
|
|
|
|
|
const tokenBalance = calcTokenAmount(usersToken.balance.toString(), decimals) |
|
|
|
|
|
|
|
|
|
updateSendTokenBalance(tokenBalance) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
SendTransactionScreen.prototype.componentWillMount = function () { |
|
|
|
|
const { |
|
|
|
|
updateTokenExchangeRate, |
|
|
|
@ -49,32 +85,25 @@ SendTransactionScreen.prototype.componentWillMount = function () { |
|
|
|
|
selectedAddress, |
|
|
|
|
data, |
|
|
|
|
updateGasTotal, |
|
|
|
|
updateSendTokenBalance, |
|
|
|
|
from, |
|
|
|
|
tokenContract, |
|
|
|
|
} = this.props |
|
|
|
|
const { symbol } = selectedToken || {} |
|
|
|
|
|
|
|
|
|
const estimateGasParams = { |
|
|
|
|
from: selectedAddress, |
|
|
|
|
gas: '746a528800', |
|
|
|
|
} |
|
|
|
|
const { symbol, decimals } = selectedToken || {} |
|
|
|
|
|
|
|
|
|
if (symbol) { |
|
|
|
|
updateTokenExchangeRate(symbol) |
|
|
|
|
Object.assign(estimateGasParams, { value: '0x0' }) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (data) { |
|
|
|
|
Object.assign(estimateGasParams, { data }) |
|
|
|
|
} |
|
|
|
|
const estimateGasParams = getParamsForGasEstimate(selectedAddress, symbol, data) |
|
|
|
|
|
|
|
|
|
Promise |
|
|
|
|
.all([ |
|
|
|
|
getGasPrice(), |
|
|
|
|
estimateGas({ |
|
|
|
|
from: selectedAddress, |
|
|
|
|
gas: '746a528800', |
|
|
|
|
}), |
|
|
|
|
estimateGas(estimateGasParams), |
|
|
|
|
tokenContract && tokenContract.balanceOf(from.address) |
|
|
|
|
]) |
|
|
|
|
.then(([gasPrice, gas]) => { |
|
|
|
|
.then(([gasPrice, gas, usersToken]) => { |
|
|
|
|
|
|
|
|
|
const newGasTotal = multiplyCurrencies(gas, gasPrice, { |
|
|
|
|
toNumericBase: 'hex', |
|
|
|
@ -82,9 +111,36 @@ SendTransactionScreen.prototype.componentWillMount = function () { |
|
|
|
|
multiplierBase: 16, |
|
|
|
|
}) |
|
|
|
|
updateGasTotal(newGasTotal) |
|
|
|
|
this.updateSendTokenBalance(usersToken) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
SendTransactionScreen.prototype.componentDidUpdate = function (prevProps) { |
|
|
|
|
const { |
|
|
|
|
from: { balance }, |
|
|
|
|
gasTotal, |
|
|
|
|
tokenBalance, |
|
|
|
|
amount, |
|
|
|
|
selectedToken, |
|
|
|
|
} = this.props |
|
|
|
|
const { |
|
|
|
|
from: { balance: prevBalance }, |
|
|
|
|
gasTotal: prevGasTotal, |
|
|
|
|
tokenBalance: prevTokenBalance, |
|
|
|
|
} = prevProps |
|
|
|
|
|
|
|
|
|
const notFirstRender = [prevBalance, prevGasTotal].every(n => n !== null) |
|
|
|
|
|
|
|
|
|
const balanceHasChanged = balance !== prevBalance |
|
|
|
|
const gasTotalHasChange = gasTotal !== prevGasTotal |
|
|
|
|
const tokenBalanceHasChanged = selectedToken && tokenBalance !== prevTokenBalance |
|
|
|
|
const amountValidationChange = balanceHasChanged || gasTotalHasChange || tokenBalanceHasChanged |
|
|
|
|
|
|
|
|
|
if (notFirstRender && amountValidationChange) { |
|
|
|
|
this.validateAmount(amount) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
SendTransactionScreen.prototype.renderHeaderIcon = function () { |
|
|
|
|
const { selectedToken } = this.props |
|
|
|
|
|
|
|
|
@ -144,12 +200,31 @@ SendTransactionScreen.prototype.renderErrorMessage = function (errorType) { |
|
|
|
|
: null |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
SendTransactionScreen.prototype.handleFromChange = async function (newFrom) { |
|
|
|
|
const { |
|
|
|
|
from, |
|
|
|
|
updateSendFrom, |
|
|
|
|
updateSendTokenBalance, |
|
|
|
|
tokenContract, |
|
|
|
|
selectedToken, |
|
|
|
|
} = this.props |
|
|
|
|
const { decimals } = selectedToken || {} |
|
|
|
|
|
|
|
|
|
if (tokenContract) { |
|
|
|
|
const usersToken = await tokenContract.balanceOf(newFrom.address) |
|
|
|
|
this.updateSendTokenBalance(usersToken) |
|
|
|
|
} |
|
|
|
|
updateSendFrom(newFrom) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
SendTransactionScreen.prototype.renderFromRow = function () { |
|
|
|
|
const { |
|
|
|
|
from, |
|
|
|
|
fromAccounts, |
|
|
|
|
conversionRate, |
|
|
|
|
updateSendFrom, |
|
|
|
|
updateSendTokenBalance, |
|
|
|
|
tokenContract, |
|
|
|
|
} = this.props |
|
|
|
|
|
|
|
|
|
const { fromDropdownOpen } = this.state |
|
|
|
@ -163,7 +238,7 @@ SendTransactionScreen.prototype.renderFromRow = function () { |
|
|
|
|
dropdownOpen: fromDropdownOpen, |
|
|
|
|
accounts: fromAccounts, |
|
|
|
|
selectedAccount: from, |
|
|
|
|
onSelect: updateSendFrom, |
|
|
|
|
onSelect: newFrom => this.handleFromChange(newFrom), |
|
|
|
|
openDropdown: () => this.setState({ fromDropdownOpen: true }), |
|
|
|
|
closeDropdown: () => this.setState({ fromDropdownOpen: false }), |
|
|
|
|
conversionRate, |
|
|
|
@ -239,21 +314,31 @@ SendTransactionScreen.prototype.validateAmount = function (value) { |
|
|
|
|
primaryCurrency, |
|
|
|
|
selectedToken, |
|
|
|
|
gasTotal, |
|
|
|
|
tokenBalance, |
|
|
|
|
} = this.props |
|
|
|
|
const { decimals } = selectedToken || {} |
|
|
|
|
const amount = value |
|
|
|
|
|
|
|
|
|
let amountError = null |
|
|
|
|
|
|
|
|
|
const sufficientBalance = isBalanceSufficient({ |
|
|
|
|
amount, |
|
|
|
|
amount: selectedToken ? '0x0' : amount, |
|
|
|
|
gasTotal, |
|
|
|
|
balance, |
|
|
|
|
primaryCurrency, |
|
|
|
|
selectedToken, |
|
|
|
|
amountConversionRate, |
|
|
|
|
conversionRate, |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
let sufficientTokens |
|
|
|
|
if (selectedToken) { |
|
|
|
|
sufficientTokens = isTokenBalanceSufficient({ |
|
|
|
|
tokenBalance, |
|
|
|
|
amount, |
|
|
|
|
decimals, |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const amountLessThanZero = conversionGreaterThan( |
|
|
|
|
{ value: 0, fromNumericBase: 'dec' }, |
|
|
|
|
{ value: amount, fromNumericBase: 'hex' }, |
|
|
|
@ -261,6 +346,8 @@ SendTransactionScreen.prototype.validateAmount = function (value) { |
|
|
|
|
|
|
|
|
|
if (!sufficientBalance) { |
|
|
|
|
amountError = 'Insufficient funds.' |
|
|
|
|
} else if (selectedToken && !sufficientTokens) { |
|
|
|
|
amountError = 'Insufficient tokens.' |
|
|
|
|
} else if (amountLessThanZero) { |
|
|
|
|
amountError = 'Can not send negative amounts of ETH.' |
|
|
|
|
} |
|
|
|
@ -275,10 +362,9 @@ SendTransactionScreen.prototype.renderAmountRow = function () { |
|
|
|
|
convertedCurrency, |
|
|
|
|
amountConversionRate, |
|
|
|
|
errors, |
|
|
|
|
amount, |
|
|
|
|
} = this.props |
|
|
|
|
|
|
|
|
|
const { amount } = this.state |
|
|
|
|
|
|
|
|
|
return h('div.send-v2__form-row', [ |
|
|
|
|
|
|
|
|
|
h('div.send-v2__form-label', [ |
|
|
|
@ -335,8 +421,7 @@ SendTransactionScreen.prototype.renderGasRow = function () { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
SendTransactionScreen.prototype.renderMemoRow = function () { |
|
|
|
|
const { updateSendMemo } = this.props |
|
|
|
|
const { memo } = this.state |
|
|
|
|
const { updateSendMemo, memo } = this.props |
|
|
|
|
|
|
|
|
|
return h('div.send-v2__form-row', [ |
|
|
|
|
|
|
|
|
|