Send all option for tokens send

This commit is contained in:
Victor Baranov 2020-06-15 15:45:29 +03:00
parent 205c101ff8
commit 40bcc25a76
6 changed files with 104 additions and 34 deletions

View File

@ -1,4 +1,4 @@
import { multiplyCurrencies, subtractCurrencies, BIG_NUMBER_WEI_MULTIPLIER } from '../../../../../ui/app/conversion-util'
import { subtractCurrencies, BIG_NUMBER_WEI_MULTIPLIER } from '../../../../../ui/app/conversion-util'
import ethUtil from 'ethereumjs-util'
import BigNumber from 'bignumber.js'
@ -6,17 +6,10 @@ export function calcMaxAmount ({ balance, gasTotal, sendToken, tokenBalance }) {
const { decimals } = sendToken || {}
const multiplier = Math.pow(10, Number(decimals || 0))
let maxBalance
if (sendToken) {
maxBalance = multiplyCurrencies(
tokenBalance,
multiplier,
{
toNumericBase: 'hex',
multiplicandBase: 16,
},
)
const tokenBalanceBN = new BigNumber(tokenBalance.toString())
maxBalance = tokenBalanceBN.div(multiplier).toString()
} else {
const maxBalanceInWei =
subtractCurrencies(

View File

@ -18,7 +18,8 @@ import log from 'loglevel'
import SendProfile from './send-profile'
import SendHeader from './send-header'
import ErrorComponent from '../error'
import { getMetaMaskAccounts } from '../../../../ui/app/selectors'
import { getMetaMaskAccounts, getSendToken, getSendTo, getTokenBalance, getSendTokenContract } from '../../../../ui/app/selectors'
import AmountMaxButton from './amount-max-button'
class SendTransactionScreen extends PersistentForm {
constructor (props) {
@ -30,13 +31,12 @@ class SendTransactionScreen extends PersistentForm {
balance: 0,
decimals: 0,
},
amount: '',
isLoading: true,
}
PersistentForm.call(this)
}
render () {
const { isLoading, token, amount } = this.state
const { isLoading, token } = this.state
if (isLoading) {
return (
<Loading isLoading={isLoading} loadingMessage="Loading..." />
@ -50,6 +50,7 @@ class SendTransactionScreen extends PersistentForm {
identities,
addressBook,
error,
updateSendTo,
} = props
const nextDisabled = token.balance <= 0
@ -67,18 +68,20 @@ class SendTransactionScreen extends PersistentForm {
network={network}
identities={identities}
addressBook={addressBook}
updateSendTo={updateSendTo}
/>
</section>
<section className="flex-row flex-center">
<input className="large-input"
name="amount"
value={amount}
value={this.props.amount || ''}
onChange={(e) => this.amountDidChange(e.target.value)}
placeholder="Amount"
type="number"
style={{
marginRight: '6px',
}}
disabled={!!this.props.maxModeOn}
/>
<button
onClick={() => this.onSubmit()}
@ -86,13 +89,22 @@ class SendTransactionScreen extends PersistentForm {
>Next
</button>
</section>
<section className="flex-row flex-left amount-max-container"><AmountMaxButton /></section>
</div>
)
}
componentDidMount () {
this.getTokensMetadata()
.then(() => {
.then((token) => {
this.props.updateSendToken(token)
const {
sendToken,
tokenContract,
address,
} = this.props
this.props.updateSendTokenBalance({sendToken, tokenContract, address})
this.createFreshTokenTracker()
})
}
@ -102,16 +114,17 @@ class SendTransactionScreen extends PersistentForm {
this.tokenInfoGetter = tokenInfoGetter()
const { tokenAddress, network } = this.props
const { symbol = '', decimals = 0 } = await this.tokenInfoGetter(tokenAddress)
const token = {
address: tokenAddress,
network,
symbol,
decimals,
}
this.setState({
token: {
address: tokenAddress,
network,
symbol,
decimals,
},
token,
})
return Promise.resolve()
return Promise.resolve(token)
}
componentWillUnmount () {
@ -120,6 +133,9 @@ class SendTransactionScreen extends PersistentForm {
this.tracker.stop()
this.tracker.removeListener('update', this.balanceUpdater)
this.tracker.removeListener('error', this.showError)
this.props.updateSendAmount(null)
this.props.setMaxModeTo(false)
this.props.updateSendTo('')
}
createFreshTokenTracker () {
@ -176,14 +192,13 @@ class SendTransactionScreen extends PersistentForm {
}
amountDidChange (amount) {
this.setState({
amount,
})
this.props.updateSendAmount(amount)
}
async onSubmit () {
const state = this.state || {}
const { token, amount } = state
const { token } = state
const { amount } = this.props
let recipient = state.recipient || document.querySelector('input[name="address"]').value.replace(/^[.\s]+|[.\s]+$/g, '')
let nickname = state.nickname || ' '
if (typeof recipient === 'object') {
@ -284,6 +299,12 @@ const mapStateToProps = (state) => {
network: state.metamask.network,
addressBook: state.metamask.addressBook,
tokenAddress: state.appState.currentView.tokenAddress,
to: getSendTo(state),
sendToken: getSendToken(state),
amount: state.metamask.send.amount,
maxModeOn: state.metamask.send.maxModeOn,
tokenBalance: getTokenBalance(state),
tokenContract: getSendTokenContract(state),
}
result.error = result.warning && result.warning.split('.')[0]
@ -307,6 +328,11 @@ const mapDispatchToProps = dispatch => {
txParams,
confTxScreenParams,
) => dispatch(actions.signTokenTx(tokenAddress, toAddress, tokensValueWithDec, txParams, confTxScreenParams)),
updateSendTokenBalance: props => dispatch(actions.updateSendTokenBalance(props)),
setMaxModeTo: maxMode => dispatch(actions.setMaxModeTo(maxMode)),
updateSendAmount: amount => dispatch(actions.updateSendAmount(amount)),
updateSendTo: (to, nickname) => dispatch(actions.updateSendTo(to, nickname)),
updateSendToken: token => dispatch(actions.updateSendToken(token)),
}
}

View File

@ -289,14 +289,14 @@ function mapDispatchToProps (dispatch) {
return {
addToAddressBook: (recipient, nickname) => dispatch(actions.addToAddressBook(recipient, nickname)),
showAccountsPage: () => dispatch(actions.showAccountsPage()),
displayWarning: (msg) => dispatch(actions.displayWarning(msg)),
displayWarning: msg => dispatch(actions.displayWarning(msg)),
hideWarning: () => dispatch(actions.hideWarning()),
getPendingNonce: (address) => dispatch(actions.getPendingNonce(address)),
signTx: (txParams) => dispatch(actions.signTx(txParams)),
updateSendAmount: (amount) => dispatch(actions.updateSendAmount(amount)),
setMaxModeTo: (maxMode) => dispatch(actions.setMaxModeTo(maxMode)),
getPendingNonce: address => dispatch(actions.getPendingNonce(address)),
signTx: txParams => dispatch(actions.signTx(txParams)),
updateSendAmount: amount => dispatch(actions.updateSendAmount(amount)),
setMaxModeTo: maxMode => dispatch(actions.setMaxModeTo(maxMode)),
updateSendTo: (to, nickname) => dispatch(actions.updateSendTo(to, nickname)),
updateSendHexData: (txData) => dispatch(actions.updateSendHexData(txData)),
updateSendHexData: txData => dispatch(actions.updateSendHexData(txData)),
}
}

View File

@ -212,6 +212,7 @@ const actions = {
UPDATE_SEND_ERRORS: 'UPDATE_SEND_ERRORS',
UPDATE_MAX_MODE: 'UPDATE_MAX_MODE',
UPDATE_SEND: 'UPDATE_SEND',
UPDATE_SEND_TOKEN: 'UPDATE_SEND_TOKEN',
CLEAR_SEND: 'CLEAR_SEND',
OPEN_FROM_DROPDOWN: 'OPEN_FROM_DROPDOWN',
CLOSE_FROM_DROPDOWN: 'CLOSE_FROM_DROPDOWN',
@ -230,6 +231,7 @@ const actions = {
updateSendMemo,
setMaxModeTo,
updateSend,
updateSendToken,
updateSendErrors,
clearSend,
setSelectedAddress,
@ -1133,7 +1135,7 @@ function showChooseContractExecutorPage ({methodSelected, methodABI, inputValues
}
function updateSendTokenBalance ({
selectedToken,
sendToken,
tokenContract,
address,
}) {
@ -1144,7 +1146,7 @@ function updateSendTokenBalance ({
return tokenBalancePromise
.then(usersToken => {
if (usersToken) {
const newTokenBalance = calcTokenBalance({ selectedToken, usersToken })
const newTokenBalance = calcTokenBalance({ sendToken, usersToken })
dispatch(setSendTokenBalance(newTokenBalance.toString(10)))
}
})
@ -1218,6 +1220,13 @@ function updateSend (newSend) {
}
}
function updateSendToken (token) {
return {
type: actions.UPDATE_SEND_TOKEN,
value: token,
}
}
function clearSend () {
return {
type: actions.CLEAR_SEND,

View File

@ -283,6 +283,35 @@ function reduceMetamask (state, action) {
},
})
case actions.UPDATE_SEND_TOKEN:
const newSend = {
...metamaskState.send,
token: action.value,
}
// erase token-related state when switching back to native currency
if (newSend.editingTransactionId && !newSend.token) {
const unapprovedTx = newSend?.unapprovedTxs?.[newSend.editingTransactionId] || {}
const txParams = unapprovedTx.txParams || {}
Object.assign(newSend, {
tokenBalance: null,
balance: '0',
from: unapprovedTx.from || '',
unapprovedTxs: {
...newSend.unapprovedTxs,
[newSend.editingTransactionId]: {
...unapprovedTx,
txParams: {
...txParams,
data: '',
},
},
},
})
}
return Object.assign(metamaskState, {
send: newSend,
})
case actions.CLEAR_SEND:
return extend(metamaskState, {
send: {

View File

@ -46,6 +46,8 @@ const selectors = {
priceEstimateToWei,
getCurrentEthBalance,
getSendToken,
getSendTokenAddress,
getSendTokenContract,
getTokenBalance,
getSendFromBalance,
getSendFromObject,
@ -269,6 +271,17 @@ function getSendToken (state) {
return state.metamask.send.token
}
function getSendTokenAddress (state) {
return getSendToken(state)?.address
}
function getSendTokenContract (state) {
const sendTokenAddress = getSendTokenAddress(state)
return sendTokenAddress
? global.eth.contract(abi).at(sendTokenAddress)
: null
}
function getTokenBalance (state) {
return state.metamask.send.tokenBalance
}