Merge pull request #393 from poanetwork/vb-send-all-tokens
Send all option for tokens send
This commit is contained in:
commit
414ad22b39
|
@ -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(
|
||||
|
|
|
@ -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)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue