diff options
author | Chi Kei Chan <chikeichan@gmail.com> | 2019-03-22 07:03:30 +0800 |
---|---|---|
committer | Dan J Miller <danjm.com@gmail.com> | 2019-03-22 07:03:30 +0800 |
commit | 31175625b446cb5d18b17db23018bca8b14d280c (patch) | |
tree | f54e159883deef003fb281267025edf796eb8004 /ui/app/ducks/confirm-transaction | |
parent | 7287133e15fab22299e07704206e85bc855d1064 (diff) | |
download | tangerine-wallet-browser-31175625b446cb5d18b17db23018bca8b14d280c.tar tangerine-wallet-browser-31175625b446cb5d18b17db23018bca8b14d280c.tar.gz tangerine-wallet-browser-31175625b446cb5d18b17db23018bca8b14d280c.tar.bz2 tangerine-wallet-browser-31175625b446cb5d18b17db23018bca8b14d280c.tar.lz tangerine-wallet-browser-31175625b446cb5d18b17db23018bca8b14d280c.tar.xz tangerine-wallet-browser-31175625b446cb5d18b17db23018bca8b14d280c.tar.zst tangerine-wallet-browser-31175625b446cb5d18b17db23018bca8b14d280c.zip |
Folder restructure (#6304)
* Remove ui/app/keychains/
* Remove ui/app/img/ (unused images)
* Move conversion-util to helpers/utils/
* Move token-util to helpers/utils/
* Move /helpers/*.js inside /helpers/utils/
* Move util tests inside /helpers/utils/
* Renameand move confirm-transaction/util.js to helpers/utils/
* Move higher-order-components to helpers/higher-order-components/
* Move infura-conversion.json to helpers/constants/
* Move all utility functions to helpers/utils/
* Move pages directory to top-level
* Move all constants to helpers/constants/
* Move metametrics inside helpers/
* Move app and root inside pages/
* Move routes inside helpers/
* Re-organize ducks/
* Move reducers to ducks/
* Move selectors inside selectors/
* Move test out of test folder
* Move action, reducer, store inside store/
* Move ui components inside ui/
* Move UI components inside ui/
* Move connected components inside components/app/
* Move i18n-helper inside helpers/
* Fix unit tests
* Fix unit test
* Move pages components
* Rename routes component
* Move reducers to ducks/index
* Fix bad path in unit test
Diffstat (limited to 'ui/app/ducks/confirm-transaction')
-rw-r--r-- | ui/app/ducks/confirm-transaction/confirm-transaction.duck.js | 420 | ||||
-rw-r--r-- | ui/app/ducks/confirm-transaction/confirm-transaction.duck.test.js | 685 |
2 files changed, 1105 insertions, 0 deletions
diff --git a/ui/app/ducks/confirm-transaction/confirm-transaction.duck.js b/ui/app/ducks/confirm-transaction/confirm-transaction.duck.js new file mode 100644 index 000000000..4edf8a70c --- /dev/null +++ b/ui/app/ducks/confirm-transaction/confirm-transaction.duck.js @@ -0,0 +1,420 @@ +import { + conversionRateSelector, + currentCurrencySelector, + unconfirmedTransactionsHashSelector, + getNativeCurrency, +} from '../../selectors/confirm-transaction' + +import { + getValueFromWeiHex, + getTransactionFee, + getHexGasTotal, + addFiat, + addEth, + increaseLastGasPrice, + hexGreaterThan, +} from '../../helpers/utils/confirm-tx.util' + +import { + getTokenData, + getMethodData, + isSmartContractAddress, + sumHexes, +} from '../../helpers/utils/transactions.util' + +import { getSymbolAndDecimals } from '../../helpers/utils/token-util' +import { conversionUtil } from '../../helpers/utils/conversion-util' +import { addHexPrefix } from 'ethereumjs-util' + +// Actions +const createActionType = action => `metamask/confirm-transaction/${action}` + +const UPDATE_TX_DATA = createActionType('UPDATE_TX_DATA') +const CLEAR_TX_DATA = createActionType('CLEAR_TX_DATA') +const UPDATE_TOKEN_DATA = createActionType('UPDATE_TOKEN_DATA') +const CLEAR_TOKEN_DATA = createActionType('CLEAR_TOKEN_DATA') +const UPDATE_METHOD_DATA = createActionType('UPDATE_METHOD_DATA') +const CLEAR_METHOD_DATA = createActionType('CLEAR_METHOD_DATA') +const CLEAR_CONFIRM_TRANSACTION = createActionType('CLEAR_CONFIRM_TRANSACTION') +const UPDATE_TRANSACTION_AMOUNTS = createActionType('UPDATE_TRANSACTION_AMOUNTS') +const UPDATE_TRANSACTION_FEES = createActionType('UPDATE_TRANSACTION_FEES') +const UPDATE_TRANSACTION_TOTALS = createActionType('UPDATE_TRANSACTION_TOTALS') +const UPDATE_TOKEN_PROPS = createActionType('UPDATE_TOKEN_PROPS') +const UPDATE_NONCE = createActionType('UPDATE_NONCE') +const UPDATE_TO_SMART_CONTRACT = createActionType('UPDATE_TO_SMART_CONTRACT') +const FETCH_DATA_START = createActionType('FETCH_DATA_START') +const FETCH_DATA_END = createActionType('FETCH_DATA_END') + +// Initial state +const initState = { + txData: {}, + tokenData: {}, + methodData: {}, + tokenProps: { + tokenDecimals: '', + tokenSymbol: '', + }, + fiatTransactionAmount: '', + fiatTransactionFee: '', + fiatTransactionTotal: '', + ethTransactionAmount: '', + ethTransactionFee: '', + ethTransactionTotal: '', + hexTransactionAmount: '', + hexTransactionFee: '', + hexTransactionTotal: '', + nonce: '', + toSmartContract: false, + fetchingData: false, +} + +// Reducer +export default function reducer ({ confirmTransaction: confirmState = initState }, action = {}) { + switch (action.type) { + case UPDATE_TX_DATA: + return { + ...confirmState, + txData: { + ...action.payload, + }, + } + case CLEAR_TX_DATA: + return { + ...confirmState, + txData: {}, + } + case UPDATE_TOKEN_DATA: + return { + ...confirmState, + tokenData: { + ...action.payload, + }, + } + case CLEAR_TOKEN_DATA: + return { + ...confirmState, + tokenData: {}, + } + case UPDATE_METHOD_DATA: + return { + ...confirmState, + methodData: { + ...action.payload, + }, + } + case CLEAR_METHOD_DATA: + return { + ...confirmState, + methodData: {}, + } + case UPDATE_TRANSACTION_AMOUNTS: + const { fiatTransactionAmount, ethTransactionAmount, hexTransactionAmount } = action.payload + return { + ...confirmState, + fiatTransactionAmount: fiatTransactionAmount || confirmState.fiatTransactionAmount, + ethTransactionAmount: ethTransactionAmount || confirmState.ethTransactionAmount, + hexTransactionAmount: hexTransactionAmount || confirmState.hexTransactionAmount, + } + case UPDATE_TRANSACTION_FEES: + const { fiatTransactionFee, ethTransactionFee, hexTransactionFee } = action.payload + return { + ...confirmState, + fiatTransactionFee: fiatTransactionFee || confirmState.fiatTransactionFee, + ethTransactionFee: ethTransactionFee || confirmState.ethTransactionFee, + hexTransactionFee: hexTransactionFee || confirmState.hexTransactionFee, + } + case UPDATE_TRANSACTION_TOTALS: + const { fiatTransactionTotal, ethTransactionTotal, hexTransactionTotal } = action.payload + return { + ...confirmState, + fiatTransactionTotal: fiatTransactionTotal || confirmState.fiatTransactionTotal, + ethTransactionTotal: ethTransactionTotal || confirmState.ethTransactionTotal, + hexTransactionTotal: hexTransactionTotal || confirmState.hexTransactionTotal, + } + case UPDATE_TOKEN_PROPS: + const { tokenSymbol = '', tokenDecimals = '' } = action.payload + return { + ...confirmState, + tokenProps: { + ...confirmState.tokenProps, + tokenSymbol, + tokenDecimals, + }, + } + case UPDATE_NONCE: + return { + ...confirmState, + nonce: action.payload, + } + case UPDATE_TO_SMART_CONTRACT: + return { + ...confirmState, + toSmartContract: action.payload, + } + case FETCH_DATA_START: + return { + ...confirmState, + fetchingData: true, + } + case FETCH_DATA_END: + return { + ...confirmState, + fetchingData: false, + } + case CLEAR_CONFIRM_TRANSACTION: + return initState + default: + return confirmState + } +} + +// Action Creators +export function updateTxData (txData) { + return { + type: UPDATE_TX_DATA, + payload: txData, + } +} + +export function clearTxData () { + return { + type: CLEAR_TX_DATA, + } +} + +export function updateTokenData (tokenData) { + return { + type: UPDATE_TOKEN_DATA, + payload: tokenData, + } +} + +export function clearTokenData () { + return { + type: CLEAR_TOKEN_DATA, + } +} + +export function updateMethodData (methodData) { + return { + type: UPDATE_METHOD_DATA, + payload: methodData, + } +} + +export function clearMethodData () { + return { + type: CLEAR_METHOD_DATA, + } +} + +export function updateTransactionAmounts (amounts) { + return { + type: UPDATE_TRANSACTION_AMOUNTS, + payload: amounts, + } +} + +export function updateTransactionFees (fees) { + return { + type: UPDATE_TRANSACTION_FEES, + payload: fees, + } +} + +export function updateTransactionTotals (totals) { + return { + type: UPDATE_TRANSACTION_TOTALS, + payload: totals, + } +} + +export function updateTokenProps (tokenProps) { + return { + type: UPDATE_TOKEN_PROPS, + payload: tokenProps, + } +} + +export function updateNonce (nonce) { + return { + type: UPDATE_NONCE, + payload: nonce, + } +} + +export function updateToSmartContract (toSmartContract) { + return { + type: UPDATE_TO_SMART_CONTRACT, + payload: toSmartContract, + } +} + +export function setFetchingData (isFetching) { + return { + type: isFetching ? FETCH_DATA_START : FETCH_DATA_END, + } +} + +export function updateGasAndCalculate ({ gasLimit, gasPrice }) { + gasLimit = addHexPrefix(gasLimit) + gasPrice = addHexPrefix(gasPrice) + return (dispatch, getState) => { + const { confirmTransaction: { txData } } = getState() + const newTxData = { + ...txData, + txParams: { + ...txData.txParams, + gas: gasLimit, + gasPrice, + }, + } + + dispatch(updateTxDataAndCalculate(newTxData)) + } +} + +function increaseFromLastGasPrice (txData) { + const { lastGasPrice, txParams: { gasPrice: previousGasPrice } = {} } = txData + + // Set the minimum to a 10% increase from the lastGasPrice. + const minimumGasPrice = increaseLastGasPrice(lastGasPrice) + const gasPriceBelowMinimum = hexGreaterThan(minimumGasPrice, previousGasPrice) + const gasPrice = (!previousGasPrice || gasPriceBelowMinimum) ? minimumGasPrice : previousGasPrice + + return { + ...txData, + txParams: { + ...txData.txParams, + gasPrice, + }, + } +} + +export function updateTxDataAndCalculate (txData) { + return (dispatch, getState) => { + const state = getState() + const currentCurrency = currentCurrencySelector(state) + const conversionRate = conversionRateSelector(state) + const nativeCurrency = getNativeCurrency(state) + + dispatch(updateTxData(txData)) + + const { txParams: { value = '0x0', gas: gasLimit = '0x0', gasPrice = '0x0' } = {} } = txData + + const fiatTransactionAmount = getValueFromWeiHex({ + value, fromCurrency: nativeCurrency, toCurrency: currentCurrency, conversionRate, numberOfDecimals: 2, + }) + const ethTransactionAmount = getValueFromWeiHex({ + value, fromCurrency: nativeCurrency, toCurrency: nativeCurrency, conversionRate, numberOfDecimals: 6, + }) + + dispatch(updateTransactionAmounts({ + fiatTransactionAmount, + ethTransactionAmount, + hexTransactionAmount: value, + })) + + const hexTransactionFee = getHexGasTotal({ gasLimit, gasPrice }) + + const fiatTransactionFee = getTransactionFee({ + value: hexTransactionFee, + fromCurrency: nativeCurrency, + toCurrency: currentCurrency, + numberOfDecimals: 2, + conversionRate, + }) + const ethTransactionFee = getTransactionFee({ + value: hexTransactionFee, + fromCurrency: nativeCurrency, + toCurrency: nativeCurrency, + numberOfDecimals: 6, + conversionRate, + }) + + dispatch(updateTransactionFees({ fiatTransactionFee, ethTransactionFee, hexTransactionFee })) + + const fiatTransactionTotal = addFiat(fiatTransactionFee, fiatTransactionAmount) + const ethTransactionTotal = addEth(ethTransactionFee, ethTransactionAmount) + const hexTransactionTotal = sumHexes(value, hexTransactionFee) + + dispatch(updateTransactionTotals({ + fiatTransactionTotal, + ethTransactionTotal, + hexTransactionTotal, + })) + } +} + +export function setTransactionToConfirm (transactionId) { + return async (dispatch, getState) => { + const state = getState() + const unconfirmedTransactionsHash = unconfirmedTransactionsHashSelector(state) + const transaction = unconfirmedTransactionsHash[transactionId] + + if (!transaction) { + console.error(`Transaction with id ${transactionId} not found`) + return + } + + if (transaction.txParams) { + const { lastGasPrice } = transaction + const txData = lastGasPrice ? increaseFromLastGasPrice(transaction) : transaction + dispatch(updateTxDataAndCalculate(txData)) + + const { txParams } = transaction + const { to } = txParams + + if (txParams.data) { + const { tokens: existingTokens } = state + const { data, to: tokenAddress } = txParams + + try { + dispatch(setFetchingData(true)) + const methodData = await getMethodData(data) + + dispatch(updateMethodData(methodData)) + } catch (error) { + dispatch(updateMethodData({})) + dispatch(setFetchingData(false)) + } + + try { + const toSmartContract = await isSmartContractAddress(to) + dispatch(updateToSmartContract(toSmartContract)) + dispatch(setFetchingData(false)) + } catch (error) { + dispatch(setFetchingData(false)) + } + + const tokenData = getTokenData(data) + dispatch(updateTokenData(tokenData)) + + try { + const tokenSymbolData = await getSymbolAndDecimals(tokenAddress, existingTokens) || {} + const { symbol: tokenSymbol = '', decimals: tokenDecimals = '' } = tokenSymbolData + dispatch(updateTokenProps({ tokenSymbol, tokenDecimals })) + } catch (error) { + dispatch(updateTokenProps({ tokenSymbol: '', tokenDecimals: '' })) + } + } + + if (txParams.nonce) { + const nonce = conversionUtil(txParams.nonce, { + fromNumericBase: 'hex', + toNumericBase: 'dec', + }) + + dispatch(updateNonce(nonce)) + } + } else { + dispatch(updateTxData(transaction)) + } + } +} + +export function clearConfirmTransaction () { + return { + type: CLEAR_CONFIRM_TRANSACTION, + } +} diff --git a/ui/app/ducks/confirm-transaction/confirm-transaction.duck.test.js b/ui/app/ducks/confirm-transaction/confirm-transaction.duck.test.js new file mode 100644 index 000000000..483f2f56d --- /dev/null +++ b/ui/app/ducks/confirm-transaction/confirm-transaction.duck.test.js @@ -0,0 +1,685 @@ +import assert from 'assert' +import configureMockStore from 'redux-mock-store' +import thunk from 'redux-thunk' +import sinon from 'sinon' + +import ConfirmTransactionReducer, * as actions from './confirm-transaction.duck.js' + +const initialState = { + txData: {}, + tokenData: {}, + methodData: {}, + tokenProps: { + tokenDecimals: '', + tokenSymbol: '', + }, + fiatTransactionAmount: '', + fiatTransactionFee: '', + fiatTransactionTotal: '', + ethTransactionAmount: '', + ethTransactionFee: '', + ethTransactionTotal: '', + hexTransactionAmount: '', + hexTransactionFee: '', + hexTransactionTotal: '', + nonce: '', + toSmartContract: false, + fetchingData: false, +} + +const UPDATE_TX_DATA = 'metamask/confirm-transaction/UPDATE_TX_DATA' +const CLEAR_TX_DATA = 'metamask/confirm-transaction/CLEAR_TX_DATA' +const UPDATE_TOKEN_DATA = 'metamask/confirm-transaction/UPDATE_TOKEN_DATA' +const CLEAR_TOKEN_DATA = 'metamask/confirm-transaction/CLEAR_TOKEN_DATA' +const UPDATE_METHOD_DATA = 'metamask/confirm-transaction/UPDATE_METHOD_DATA' +const CLEAR_METHOD_DATA = 'metamask/confirm-transaction/CLEAR_METHOD_DATA' +const UPDATE_TRANSACTION_AMOUNTS = 'metamask/confirm-transaction/UPDATE_TRANSACTION_AMOUNTS' +const UPDATE_TRANSACTION_FEES = 'metamask/confirm-transaction/UPDATE_TRANSACTION_FEES' +const UPDATE_TRANSACTION_TOTALS = 'metamask/confirm-transaction/UPDATE_TRANSACTION_TOTALS' +const UPDATE_TOKEN_PROPS = 'metamask/confirm-transaction/UPDATE_TOKEN_PROPS' +const UPDATE_NONCE = 'metamask/confirm-transaction/UPDATE_NONCE' +const UPDATE_TO_SMART_CONTRACT = 'metamask/confirm-transaction/UPDATE_TO_SMART_CONTRACT' +const FETCH_DATA_START = 'metamask/confirm-transaction/FETCH_DATA_START' +const FETCH_DATA_END = 'metamask/confirm-transaction/FETCH_DATA_END' +const CLEAR_CONFIRM_TRANSACTION = 'metamask/confirm-transaction/CLEAR_CONFIRM_TRANSACTION' + +describe('Confirm Transaction Duck', () => { + describe('State changes', () => { + const mockState = { + confirmTransaction: { + txData: { + id: 1, + }, + tokenData: { + name: 'abcToken', + }, + methodData: { + name: 'approve', + }, + tokenProps: { + tokenDecimals: '3', + tokenSymbol: 'ABC', + }, + fiatTransactionAmount: '469.26', + fiatTransactionFee: '0.01', + fiatTransactionTotal: '1.000021', + ethTransactionAmount: '1', + ethTransactionFee: '0.000021', + ethTransactionTotal: '469.27', + hexTransactionAmount: '', + hexTransactionFee: '0x1319718a5000', + hexTransactionTotal: '', + nonce: '0x0', + toSmartContract: false, + fetchingData: false, + }, + } + + it('should initialize state', () => { + assert.deepEqual( + ConfirmTransactionReducer({}), + initialState + ) + }) + + it('should return state unchanged if it does not match a dispatched actions type', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: 'someOtherAction', + value: 'someValue', + }), + { ...mockState.confirmTransaction }, + ) + }) + + it('should set txData when receiving a UPDATE_TX_DATA action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: UPDATE_TX_DATA, + payload: { + id: 2, + }, + }), + { + ...mockState.confirmTransaction, + txData: { + ...mockState.confirmTransaction.txData, + id: 2, + }, + } + ) + }) + + it('should clear txData when receiving a CLEAR_TX_DATA action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: CLEAR_TX_DATA, + }), + { + ...mockState.confirmTransaction, + txData: {}, + } + ) + }) + + it('should set tokenData when receiving a UPDATE_TOKEN_DATA action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: UPDATE_TOKEN_DATA, + payload: { + name: 'defToken', + }, + }), + { + ...mockState.confirmTransaction, + tokenData: { + ...mockState.confirmTransaction.tokenData, + name: 'defToken', + }, + } + ) + }) + + it('should clear tokenData when receiving a CLEAR_TOKEN_DATA action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: CLEAR_TOKEN_DATA, + }), + { + ...mockState.confirmTransaction, + tokenData: {}, + } + ) + }) + + it('should set methodData when receiving a UPDATE_METHOD_DATA action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: UPDATE_METHOD_DATA, + payload: { + name: 'transferFrom', + }, + }), + { + ...mockState.confirmTransaction, + methodData: { + ...mockState.confirmTransaction.methodData, + name: 'transferFrom', + }, + } + ) + }) + + it('should clear methodData when receiving a CLEAR_METHOD_DATA action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: CLEAR_METHOD_DATA, + }), + { + ...mockState.confirmTransaction, + methodData: {}, + } + ) + }) + + it('should update transaction amounts when receiving an UPDATE_TRANSACTION_AMOUNTS action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: UPDATE_TRANSACTION_AMOUNTS, + payload: { + fiatTransactionAmount: '123.45', + ethTransactionAmount: '.5', + hexTransactionAmount: '0x1', + }, + }), + { + ...mockState.confirmTransaction, + fiatTransactionAmount: '123.45', + ethTransactionAmount: '.5', + hexTransactionAmount: '0x1', + } + ) + }) + + it('should update transaction fees when receiving an UPDATE_TRANSACTION_FEES action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: UPDATE_TRANSACTION_FEES, + payload: { + fiatTransactionFee: '123.45', + ethTransactionFee: '.5', + hexTransactionFee: '0x1', + }, + }), + { + ...mockState.confirmTransaction, + fiatTransactionFee: '123.45', + ethTransactionFee: '.5', + hexTransactionFee: '0x1', + } + ) + }) + + it('should update transaction totals when receiving an UPDATE_TRANSACTION_TOTALS action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: UPDATE_TRANSACTION_TOTALS, + payload: { + fiatTransactionTotal: '123.45', + ethTransactionTotal: '.5', + hexTransactionTotal: '0x1', + }, + }), + { + ...mockState.confirmTransaction, + fiatTransactionTotal: '123.45', + ethTransactionTotal: '.5', + hexTransactionTotal: '0x1', + } + ) + }) + + it('should update tokenProps when receiving an UPDATE_TOKEN_PROPS action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: UPDATE_TOKEN_PROPS, + payload: { + tokenSymbol: 'DEF', + tokenDecimals: '1', + }, + }), + { + ...mockState.confirmTransaction, + tokenProps: { + tokenSymbol: 'DEF', + tokenDecimals: '1', + }, + } + ) + }) + + it('should update nonce when receiving an UPDATE_NONCE action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: UPDATE_NONCE, + payload: '0x1', + }), + { + ...mockState.confirmTransaction, + nonce: '0x1', + } + ) + }) + + it('should update nonce when receiving an UPDATE_TO_SMART_CONTRACT action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: UPDATE_TO_SMART_CONTRACT, + payload: true, + }), + { + ...mockState.confirmTransaction, + toSmartContract: true, + } + ) + }) + + it('should set fetchingData to true when receiving a FETCH_DATA_START action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: FETCH_DATA_START, + }), + { + ...mockState.confirmTransaction, + fetchingData: true, + } + ) + }) + + it('should set fetchingData to false when receiving a FETCH_DATA_END action', () => { + assert.deepEqual( + ConfirmTransactionReducer({ confirmTransaction: { fetchingData: true } }, { + type: FETCH_DATA_END, + }), + { + fetchingData: false, + } + ) + }) + + it('should clear confirmTransaction when receiving a FETCH_DATA_END action', () => { + assert.deepEqual( + ConfirmTransactionReducer(mockState, { + type: CLEAR_CONFIRM_TRANSACTION, + }), + { + ...initialState, + } + ) + }) + }) + + describe('Single actions', () => { + it('should create an action to update txData', () => { + const txData = { test: 123 } + const expectedAction = { + type: UPDATE_TX_DATA, + payload: txData, + } + + assert.deepEqual( + actions.updateTxData(txData), + expectedAction + ) + }) + + it('should create an action to clear txData', () => { + const expectedAction = { + type: CLEAR_TX_DATA, + } + + assert.deepEqual( + actions.clearTxData(), + expectedAction + ) + }) + + it('should create an action to update tokenData', () => { + const tokenData = { test: 123 } + const expectedAction = { + type: UPDATE_TOKEN_DATA, + payload: tokenData, + } + + assert.deepEqual( + actions.updateTokenData(tokenData), + expectedAction + ) + }) + + it('should create an action to clear tokenData', () => { + const expectedAction = { + type: CLEAR_TOKEN_DATA, + } + + assert.deepEqual( + actions.clearTokenData(), + expectedAction + ) + }) + + it('should create an action to update methodData', () => { + const methodData = { test: 123 } + const expectedAction = { + type: UPDATE_METHOD_DATA, + payload: methodData, + } + + assert.deepEqual( + actions.updateMethodData(methodData), + expectedAction + ) + }) + + it('should create an action to clear methodData', () => { + const expectedAction = { + type: CLEAR_METHOD_DATA, + } + + assert.deepEqual( + actions.clearMethodData(), + expectedAction + ) + }) + + it('should create an action to update transaction amounts', () => { + const transactionAmounts = { test: 123 } + const expectedAction = { + type: UPDATE_TRANSACTION_AMOUNTS, + payload: transactionAmounts, + } + + assert.deepEqual( + actions.updateTransactionAmounts(transactionAmounts), + expectedAction + ) + }) + + it('should create an action to update transaction fees', () => { + const transactionFees = { test: 123 } + const expectedAction = { + type: UPDATE_TRANSACTION_FEES, + payload: transactionFees, + } + + assert.deepEqual( + actions.updateTransactionFees(transactionFees), + expectedAction + ) + }) + + it('should create an action to update transaction totals', () => { + const transactionTotals = { test: 123 } + const expectedAction = { + type: UPDATE_TRANSACTION_TOTALS, + payload: transactionTotals, + } + + assert.deepEqual( + actions.updateTransactionTotals(transactionTotals), + expectedAction + ) + }) + + it('should create an action to update tokenProps', () => { + const tokenProps = { + tokenDecimals: '1', + tokenSymbol: 'abc', + } + const expectedAction = { + type: UPDATE_TOKEN_PROPS, + payload: tokenProps, + } + + assert.deepEqual( + actions.updateTokenProps(tokenProps), + expectedAction + ) + }) + + it('should create an action to update nonce', () => { + const nonce = '0x1' + const expectedAction = { + type: UPDATE_NONCE, + payload: nonce, + } + + assert.deepEqual( + actions.updateNonce(nonce), + expectedAction + ) + }) + + it('should create an action to set fetchingData to true', () => { + const expectedAction = { + type: FETCH_DATA_START, + } + + assert.deepEqual( + actions.setFetchingData(true), + expectedAction + ) + }) + + it('should create an action to set fetchingData to false', () => { + const expectedAction = { + type: FETCH_DATA_END, + } + + assert.deepEqual( + actions.setFetchingData(false), + expectedAction + ) + }) + + it('should create an action to clear confirmTransaction', () => { + const expectedAction = { + type: CLEAR_CONFIRM_TRANSACTION, + } + + assert.deepEqual( + actions.clearConfirmTransaction(), + expectedAction + ) + }) + }) + + describe('Thunk actions', done => { + beforeEach(() => { + global.eth = { + getCode: sinon.stub().callsFake( + address => Promise.resolve(address && address.match(/isContract/) ? 'not-0x' : '0x') + ), + } + }) + + afterEach(() => { + global.eth.getCode.resetHistory() + }) + + it('updates txData and gas on an existing transaction in confirmTransaction', () => { + const mockState = { + metamask: { + conversionRate: 468.58, + currentCurrency: 'usd', + }, + confirmTransaction: { + ethTransactionAmount: '1', + ethTransactionFee: '0.000021', + ethTransactionTotal: '1.000021', + fetchingData: false, + fiatTransactionAmount: '469.26', + fiatTransactionFee: '0.01', + fiatTransactionTotal: '469.27', + hexGasTotal: '0x1319718a5000', + methodData: {}, + nonce: '', + tokenData: {}, + tokenProps: { + tokenDecimals: '', + tokenSymbol: '', + }, + txData: { + estimatedGas: '0x5208', + gasLimitSpecified: false, + gasPriceSpecified: false, + history: [], + id: 2603411941761054, + loadingDefaults: false, + metamaskNetworkId: '3', + origin: 'faucet.metamask.io', + simpleSend: true, + status: 'unapproved', + time: 1530838113716, + }, + }, + } + + const middlewares = [thunk] + const mockStore = configureMockStore(middlewares) + const store = mockStore(mockState) + const expectedActions = [ + 'metamask/confirm-transaction/UPDATE_TX_DATA', + 'metamask/confirm-transaction/UPDATE_TRANSACTION_AMOUNTS', + 'metamask/confirm-transaction/UPDATE_TRANSACTION_FEES', + 'metamask/confirm-transaction/UPDATE_TRANSACTION_TOTALS', + ] + + store.dispatch(actions.updateGasAndCalculate({ gasLimit: '0x2', gasPrice: '0x25' })) + + const storeActions = store.getActions() + assert.equal(storeActions.length, expectedActions.length) + storeActions.forEach((action, index) => assert.equal(action.type, expectedActions[index])) + }) + + it('updates txData and updates gas values in confirmTransaction', () => { + const txData = { + estimatedGas: '0x5208', + gasLimitSpecified: false, + gasPriceSpecified: false, + history: [], + id: 2603411941761054, + loadingDefaults: false, + metamaskNetworkId: '3', + origin: 'faucet.metamask.io', + simpleSend: true, + status: 'unapproved', + time: 1530838113716, + txParams: { + from: '0xc5ae6383e126f901dcb06131d97a88745bfa88d6', + gas: '0x33450', + gasPrice: '0x2540be400', + to: '0x81b7e08f65bdf5648606c89998a9cc8164397647', + value: '0xde0b6b3a7640000', + }, + } + const mockState = { + metamask: { + conversionRate: 468.58, + currentCurrency: 'usd', + }, + confirmTransaction: { + ethTransactionAmount: '1', + ethTransactionFee: '0.000021', + ethTransactionTotal: '1.000021', + fetchingData: false, + fiatTransactionAmount: '469.26', + fiatTransactionFee: '0.01', + fiatTransactionTotal: '469.27', + hexGasTotal: '0x1319718a5000', + methodData: {}, + nonce: '', + tokenData: {}, + tokenProps: { + tokenDecimals: '', + tokenSymbol: '', + }, + txData: { + ...txData, + txParams: { + ...txData.txParams, + }, + }, + }, + } + + const middlewares = [thunk] + const mockStore = configureMockStore(middlewares) + const store = mockStore(mockState) + const expectedActions = [ + 'metamask/confirm-transaction/UPDATE_TX_DATA', + 'metamask/confirm-transaction/UPDATE_TRANSACTION_AMOUNTS', + 'metamask/confirm-transaction/UPDATE_TRANSACTION_FEES', + 'metamask/confirm-transaction/UPDATE_TRANSACTION_TOTALS', + ] + + store.dispatch(actions.updateTxDataAndCalculate(txData)) + + const storeActions = store.getActions() + assert.equal(storeActions.length, expectedActions.length) + storeActions.forEach((action, index) => assert.equal(action.type, expectedActions[index])) + }) + + it('updates confirmTransaction transaction', done => { + const mockState = { + metamask: { + conversionRate: 468.58, + currentCurrency: 'usd', + network: '3', + unapprovedTxs: { + 2603411941761054: { + estimatedGas: '0x5208', + gasLimitSpecified: false, + gasPriceSpecified: false, + history: [], + id: 2603411941761054, + loadingDefaults: false, + metamaskNetworkId: '3', + origin: 'faucet.metamask.io', + simpleSend: true, + status: 'unapproved', + time: 1530838113716, + txParams: { + from: '0xc5ae6383e126f901dcb06131d97a88745bfa88d6', + gas: '0x33450', + gasPrice: '0x2540be400', + to: '0x81b7e08f65bdf5648606c89998a9cc8164397647', + value: '0xde0b6b3a7640000', + }, + }, + }, + }, + confirmTransaction: {}, + } + + const middlewares = [thunk] + const mockStore = configureMockStore(middlewares) + const store = mockStore(mockState) + const expectedActions = [ + 'metamask/confirm-transaction/UPDATE_TX_DATA', + 'metamask/confirm-transaction/UPDATE_TRANSACTION_AMOUNTS', + 'metamask/confirm-transaction/UPDATE_TRANSACTION_FEES', + 'metamask/confirm-transaction/UPDATE_TRANSACTION_TOTALS', + ] + + store.dispatch(actions.setTransactionToConfirm(2603411941761054)) + .then(() => { + const storeActions = store.getActions() + assert.equal(storeActions.length, expectedActions.length) + + storeActions.forEach((action, index) => assert.equal(action.type, expectedActions[index])) + done() + }) + }) + }) +}) |