Send all option for tokens send
This commit is contained in:
parent
205c101ff8
commit
40bcc25a76
|
@ -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 ethUtil from 'ethereumjs-util'
|
||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
|
|
||||||
|
@ -6,17 +6,10 @@ export function calcMaxAmount ({ balance, gasTotal, sendToken, tokenBalance }) {
|
||||||
const { decimals } = sendToken || {}
|
const { decimals } = sendToken || {}
|
||||||
const multiplier = Math.pow(10, Number(decimals || 0))
|
const multiplier = Math.pow(10, Number(decimals || 0))
|
||||||
|
|
||||||
|
|
||||||
let maxBalance
|
let maxBalance
|
||||||
if (sendToken) {
|
if (sendToken) {
|
||||||
maxBalance = multiplyCurrencies(
|
const tokenBalanceBN = new BigNumber(tokenBalance.toString())
|
||||||
tokenBalance,
|
maxBalance = tokenBalanceBN.div(multiplier).toString()
|
||||||
multiplier,
|
|
||||||
{
|
|
||||||
toNumericBase: 'hex',
|
|
||||||
multiplicandBase: 16,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
const maxBalanceInWei =
|
const maxBalanceInWei =
|
||||||
subtractCurrencies(
|
subtractCurrencies(
|
||||||
|
|
|
@ -18,7 +18,8 @@ import log from 'loglevel'
|
||||||
import SendProfile from './send-profile'
|
import SendProfile from './send-profile'
|
||||||
import SendHeader from './send-header'
|
import SendHeader from './send-header'
|
||||||
import ErrorComponent from '../error'
|
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 {
|
class SendTransactionScreen extends PersistentForm {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
|
@ -30,13 +31,12 @@ class SendTransactionScreen extends PersistentForm {
|
||||||
balance: 0,
|
balance: 0,
|
||||||
decimals: 0,
|
decimals: 0,
|
||||||
},
|
},
|
||||||
amount: '',
|
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
}
|
}
|
||||||
PersistentForm.call(this)
|
PersistentForm.call(this)
|
||||||
}
|
}
|
||||||
render () {
|
render () {
|
||||||
const { isLoading, token, amount } = this.state
|
const { isLoading, token } = this.state
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<Loading isLoading={isLoading} loadingMessage="Loading..." />
|
<Loading isLoading={isLoading} loadingMessage="Loading..." />
|
||||||
|
@ -50,6 +50,7 @@ class SendTransactionScreen extends PersistentForm {
|
||||||
identities,
|
identities,
|
||||||
addressBook,
|
addressBook,
|
||||||
error,
|
error,
|
||||||
|
updateSendTo,
|
||||||
} = props
|
} = props
|
||||||
const nextDisabled = token.balance <= 0
|
const nextDisabled = token.balance <= 0
|
||||||
|
|
||||||
|
@ -67,18 +68,20 @@ class SendTransactionScreen extends PersistentForm {
|
||||||
network={network}
|
network={network}
|
||||||
identities={identities}
|
identities={identities}
|
||||||
addressBook={addressBook}
|
addressBook={addressBook}
|
||||||
|
updateSendTo={updateSendTo}
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
<section className="flex-row flex-center">
|
<section className="flex-row flex-center">
|
||||||
<input className="large-input"
|
<input className="large-input"
|
||||||
name="amount"
|
name="amount"
|
||||||
value={amount}
|
value={this.props.amount || ''}
|
||||||
onChange={(e) => this.amountDidChange(e.target.value)}
|
onChange={(e) => this.amountDidChange(e.target.value)}
|
||||||
placeholder="Amount"
|
placeholder="Amount"
|
||||||
type="number"
|
type="number"
|
||||||
style={{
|
style={{
|
||||||
marginRight: '6px',
|
marginRight: '6px',
|
||||||
}}
|
}}
|
||||||
|
disabled={!!this.props.maxModeOn}
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
onClick={() => this.onSubmit()}
|
onClick={() => this.onSubmit()}
|
||||||
|
@ -86,13 +89,22 @@ class SendTransactionScreen extends PersistentForm {
|
||||||
>Next
|
>Next
|
||||||
</button>
|
</button>
|
||||||
</section>
|
</section>
|
||||||
|
<section className="flex-row flex-left amount-max-container"><AmountMaxButton /></section>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
this.getTokensMetadata()
|
this.getTokensMetadata()
|
||||||
.then(() => {
|
.then((token) => {
|
||||||
|
this.props.updateSendToken(token)
|
||||||
|
|
||||||
|
const {
|
||||||
|
sendToken,
|
||||||
|
tokenContract,
|
||||||
|
address,
|
||||||
|
} = this.props
|
||||||
|
this.props.updateSendTokenBalance({sendToken, tokenContract, address})
|
||||||
this.createFreshTokenTracker()
|
this.createFreshTokenTracker()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -102,16 +114,17 @@ class SendTransactionScreen extends PersistentForm {
|
||||||
this.tokenInfoGetter = tokenInfoGetter()
|
this.tokenInfoGetter = tokenInfoGetter()
|
||||||
const { tokenAddress, network } = this.props
|
const { tokenAddress, network } = this.props
|
||||||
const { symbol = '', decimals = 0 } = await this.tokenInfoGetter(tokenAddress)
|
const { symbol = '', decimals = 0 } = await this.tokenInfoGetter(tokenAddress)
|
||||||
|
const token = {
|
||||||
|
address: tokenAddress,
|
||||||
|
network,
|
||||||
|
symbol,
|
||||||
|
decimals,
|
||||||
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
token: {
|
token,
|
||||||
address: tokenAddress,
|
|
||||||
network,
|
|
||||||
symbol,
|
|
||||||
decimals,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return Promise.resolve()
|
return Promise.resolve(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount () {
|
componentWillUnmount () {
|
||||||
|
@ -120,6 +133,9 @@ class SendTransactionScreen extends PersistentForm {
|
||||||
this.tracker.stop()
|
this.tracker.stop()
|
||||||
this.tracker.removeListener('update', this.balanceUpdater)
|
this.tracker.removeListener('update', this.balanceUpdater)
|
||||||
this.tracker.removeListener('error', this.showError)
|
this.tracker.removeListener('error', this.showError)
|
||||||
|
this.props.updateSendAmount(null)
|
||||||
|
this.props.setMaxModeTo(false)
|
||||||
|
this.props.updateSendTo('')
|
||||||
}
|
}
|
||||||
|
|
||||||
createFreshTokenTracker () {
|
createFreshTokenTracker () {
|
||||||
|
@ -176,14 +192,13 @@ class SendTransactionScreen extends PersistentForm {
|
||||||
}
|
}
|
||||||
|
|
||||||
amountDidChange (amount) {
|
amountDidChange (amount) {
|
||||||
this.setState({
|
this.props.updateSendAmount(amount)
|
||||||
amount,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async onSubmit () {
|
async onSubmit () {
|
||||||
const state = this.state || {}
|
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 recipient = state.recipient || document.querySelector('input[name="address"]').value.replace(/^[.\s]+|[.\s]+$/g, '')
|
||||||
let nickname = state.nickname || ' '
|
let nickname = state.nickname || ' '
|
||||||
if (typeof recipient === 'object') {
|
if (typeof recipient === 'object') {
|
||||||
|
@ -284,6 +299,12 @@ const mapStateToProps = (state) => {
|
||||||
network: state.metamask.network,
|
network: state.metamask.network,
|
||||||
addressBook: state.metamask.addressBook,
|
addressBook: state.metamask.addressBook,
|
||||||
tokenAddress: state.appState.currentView.tokenAddress,
|
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]
|
result.error = result.warning && result.warning.split('.')[0]
|
||||||
|
@ -307,6 +328,11 @@ const mapDispatchToProps = dispatch => {
|
||||||
txParams,
|
txParams,
|
||||||
confTxScreenParams,
|
confTxScreenParams,
|
||||||
) => dispatch(actions.signTokenTx(tokenAddress, toAddress, tokensValueWithDec, 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 {
|
return {
|
||||||
addToAddressBook: (recipient, nickname) => dispatch(actions.addToAddressBook(recipient, nickname)),
|
addToAddressBook: (recipient, nickname) => dispatch(actions.addToAddressBook(recipient, nickname)),
|
||||||
showAccountsPage: () => dispatch(actions.showAccountsPage()),
|
showAccountsPage: () => dispatch(actions.showAccountsPage()),
|
||||||
displayWarning: (msg) => dispatch(actions.displayWarning(msg)),
|
displayWarning: msg => dispatch(actions.displayWarning(msg)),
|
||||||
hideWarning: () => dispatch(actions.hideWarning()),
|
hideWarning: () => dispatch(actions.hideWarning()),
|
||||||
getPendingNonce: (address) => dispatch(actions.getPendingNonce(address)),
|
getPendingNonce: address => dispatch(actions.getPendingNonce(address)),
|
||||||
signTx: (txParams) => dispatch(actions.signTx(txParams)),
|
signTx: txParams => dispatch(actions.signTx(txParams)),
|
||||||
updateSendAmount: (amount) => dispatch(actions.updateSendAmount(amount)),
|
updateSendAmount: amount => dispatch(actions.updateSendAmount(amount)),
|
||||||
setMaxModeTo: (maxMode) => dispatch(actions.setMaxModeTo(maxMode)),
|
setMaxModeTo: maxMode => dispatch(actions.setMaxModeTo(maxMode)),
|
||||||
updateSendTo: (to, nickname) => dispatch(actions.updateSendTo(to, nickname)),
|
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_SEND_ERRORS: 'UPDATE_SEND_ERRORS',
|
||||||
UPDATE_MAX_MODE: 'UPDATE_MAX_MODE',
|
UPDATE_MAX_MODE: 'UPDATE_MAX_MODE',
|
||||||
UPDATE_SEND: 'UPDATE_SEND',
|
UPDATE_SEND: 'UPDATE_SEND',
|
||||||
|
UPDATE_SEND_TOKEN: 'UPDATE_SEND_TOKEN',
|
||||||
CLEAR_SEND: 'CLEAR_SEND',
|
CLEAR_SEND: 'CLEAR_SEND',
|
||||||
OPEN_FROM_DROPDOWN: 'OPEN_FROM_DROPDOWN',
|
OPEN_FROM_DROPDOWN: 'OPEN_FROM_DROPDOWN',
|
||||||
CLOSE_FROM_DROPDOWN: 'CLOSE_FROM_DROPDOWN',
|
CLOSE_FROM_DROPDOWN: 'CLOSE_FROM_DROPDOWN',
|
||||||
|
@ -230,6 +231,7 @@ const actions = {
|
||||||
updateSendMemo,
|
updateSendMemo,
|
||||||
setMaxModeTo,
|
setMaxModeTo,
|
||||||
updateSend,
|
updateSend,
|
||||||
|
updateSendToken,
|
||||||
updateSendErrors,
|
updateSendErrors,
|
||||||
clearSend,
|
clearSend,
|
||||||
setSelectedAddress,
|
setSelectedAddress,
|
||||||
|
@ -1133,7 +1135,7 @@ function showChooseContractExecutorPage ({methodSelected, methodABI, inputValues
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSendTokenBalance ({
|
function updateSendTokenBalance ({
|
||||||
selectedToken,
|
sendToken,
|
||||||
tokenContract,
|
tokenContract,
|
||||||
address,
|
address,
|
||||||
}) {
|
}) {
|
||||||
|
@ -1144,7 +1146,7 @@ function updateSendTokenBalance ({
|
||||||
return tokenBalancePromise
|
return tokenBalancePromise
|
||||||
.then(usersToken => {
|
.then(usersToken => {
|
||||||
if (usersToken) {
|
if (usersToken) {
|
||||||
const newTokenBalance = calcTokenBalance({ selectedToken, usersToken })
|
const newTokenBalance = calcTokenBalance({ sendToken, usersToken })
|
||||||
dispatch(setSendTokenBalance(newTokenBalance.toString(10)))
|
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 () {
|
function clearSend () {
|
||||||
return {
|
return {
|
||||||
type: actions.CLEAR_SEND,
|
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:
|
case actions.CLEAR_SEND:
|
||||||
return extend(metamaskState, {
|
return extend(metamaskState, {
|
||||||
send: {
|
send: {
|
||||||
|
|
|
@ -46,6 +46,8 @@ const selectors = {
|
||||||
priceEstimateToWei,
|
priceEstimateToWei,
|
||||||
getCurrentEthBalance,
|
getCurrentEthBalance,
|
||||||
getSendToken,
|
getSendToken,
|
||||||
|
getSendTokenAddress,
|
||||||
|
getSendTokenContract,
|
||||||
getTokenBalance,
|
getTokenBalance,
|
||||||
getSendFromBalance,
|
getSendFromBalance,
|
||||||
getSendFromObject,
|
getSendFromObject,
|
||||||
|
@ -269,6 +271,17 @@ function getSendToken (state) {
|
||||||
return state.metamask.send.token
|
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) {
|
function getTokenBalance (state) {
|
||||||
return state.metamask.send.tokenBalance
|
return state.metamask.send.tokenBalance
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue