mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 01:47:00 +01:00
Transaction-list-item-details pop up to display the correct token information on token approve item (#17422)
This commit is contained in:
parent
60f257fd62
commit
bc19856d5d
@ -1208,5 +1208,69 @@
|
|||||||
},
|
},
|
||||||
"hasRetried": false,
|
"hasRetried": false,
|
||||||
"hasCancelled": false
|
"hasCancelled": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"initialTransaction": {
|
||||||
|
"blockNumber": "6195527",
|
||||||
|
"id": 8401691827212777,
|
||||||
|
"metamaskNetworkId": "4",
|
||||||
|
"status": "confirmed",
|
||||||
|
"time": 1585088013000,
|
||||||
|
"txParams": {
|
||||||
|
"from": "0xe18035bf8712672935fdb4e5e431b1a0183d2dfc",
|
||||||
|
"to": "0xabca64466f257793eaa52fcfff5066894b76a149",
|
||||||
|
"nonce": "0x1",
|
||||||
|
"value": "0x0",
|
||||||
|
"data": "0x095ea7b30000000000000000000000009bc5baf874d2da8d216ae9f137804184ee5afef4000000000000000000000000000000000000000000000000000000000000c350",
|
||||||
|
"gas": "0xea60",
|
||||||
|
"maxFeePerGas": "0x4a817c800",
|
||||||
|
"maxPriorityFeePerGas": "0x4a817c800"
|
||||||
|
},
|
||||||
|
"hash": "0xbcb195f393f4468945b4045cd41bcdbc2f19ad75ae92a32cf153a3004e42009a",
|
||||||
|
"type": "approve",
|
||||||
|
"origin": "https://metamask.github.io"
|
||||||
|
},
|
||||||
|
"transactions": [
|
||||||
|
{
|
||||||
|
"blockNumber": "6195527",
|
||||||
|
"id": 8401691827212777,
|
||||||
|
"metamaskNetworkId": "4",
|
||||||
|
"status": "confirmed",
|
||||||
|
"time": 1585088013000,
|
||||||
|
"txParams": {
|
||||||
|
"from": "0xe18035bf8712672935fdb4e5e431b1a0183d2dfc",
|
||||||
|
"to": "0xabca64466f257793eaa52fcfff5066894b76a149",
|
||||||
|
"nonce": "0x1",
|
||||||
|
"value": "0x0",
|
||||||
|
"data": "0x095ea7b30000000000000000000000009bc5baf874d2da8d216ae9f137804184ee5afef4000000000000000000000000000000000000000000000000000000000000c350",
|
||||||
|
"gas": "0xea60",
|
||||||
|
"maxFeePerGas": "0x4a817c800",
|
||||||
|
"maxPriorityFeePerGas": "0x4a817c800"
|
||||||
|
},
|
||||||
|
"hash": "0xbcb195f393f4468945b4045cd41bcdbc2f19ad75ae92a32cf153a3004e42009a",
|
||||||
|
"type": "approve"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryTransaction": {
|
||||||
|
"blockNumber": "6195527",
|
||||||
|
"id": 8401691827212777,
|
||||||
|
"metamaskNetworkId": "4",
|
||||||
|
"status": "confirmed",
|
||||||
|
"time": 1585088013000,
|
||||||
|
"txParams": {
|
||||||
|
"from": "0xe18035bf8712672935fdb4e5e431b1a0183d2dfc",
|
||||||
|
"to": "0xabca64466f257793eaa52fcfff5066894b76a149",
|
||||||
|
"nonce": "0x1",
|
||||||
|
"value": "0x0",
|
||||||
|
"data": "0x095ea7b30000000000000000000000009bc5baf874d2da8d216ae9f137804184ee5afef4000000000000000000000000000000000000000000000000000000000000c350",
|
||||||
|
"gas": "0xea60",
|
||||||
|
"maxFeePerGas": "0x4a817c800",
|
||||||
|
"maxPriorityFeePerGas": "0x4a817c800"
|
||||||
|
},
|
||||||
|
"hash": "0xbcb195f393f4468945b4045cd41bcdbc2f19ad75ae92a32cf153a3004e42009a",
|
||||||
|
"type": "approve"
|
||||||
|
},
|
||||||
|
"hasRetried": false,
|
||||||
|
"hasCancelled": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -196,11 +196,11 @@ describe('Create token, approve token and approve token without gas', function (
|
|||||||
const approveTokenTask = await driver.waitForSelector({
|
const approveTokenTask = await driver.waitForSelector({
|
||||||
// Selects only the very first transaction list item immediately following the 'Pending' header
|
// Selects only the very first transaction list item immediately following the 'Pending' header
|
||||||
css: '.transaction-list__completed-transactions .transaction-list-item:first-child .list-item__heading',
|
css: '.transaction-list__completed-transactions .transaction-list-item:first-child .list-item__heading',
|
||||||
text: 'Approve token spending cap',
|
text: 'Approve TST spending cap',
|
||||||
});
|
});
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await approveTokenTask.getText(),
|
await approveTokenTask.getText(),
|
||||||
'Approve token spending cap',
|
'Approve TST spending cap',
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -339,11 +339,11 @@ describe('Create token, approve token and approve token without gas', function (
|
|||||||
const approveTokenTask = await driver.waitForSelector({
|
const approveTokenTask = await driver.waitForSelector({
|
||||||
// Select only the heading of the first entry in the transaction list.
|
// Select only the heading of the first entry in the transaction list.
|
||||||
css: '.transaction-list__completed-transactions .transaction-list-item:first-child .list-item__heading',
|
css: '.transaction-list__completed-transactions .transaction-list-item:first-child .list-item__heading',
|
||||||
text: 'Approve token spending cap',
|
text: 'Approve TST spending cap',
|
||||||
});
|
});
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await approveTokenTask.getText(),
|
await approveTokenTask.getText(),
|
||||||
'Approve token spending cap',
|
'Approve TST spending cap',
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -426,11 +426,11 @@ describe('Create token, approve token and approve token without gas', function (
|
|||||||
const approveTokenTask = await driver.waitForSelector({
|
const approveTokenTask = await driver.waitForSelector({
|
||||||
// Select only the heading of the first entry in the transaction list.
|
// Select only the heading of the first entry in the transaction list.
|
||||||
css: '.transaction-list__completed-transactions .transaction-list-item:first-child .list-item__heading',
|
css: '.transaction-list__completed-transactions .transaction-list-item:first-child .list-item__heading',
|
||||||
text: 'Approve token spending cap',
|
text: 'Approve TST spending cap',
|
||||||
});
|
});
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await approveTokenTask.getText(),
|
await approveTokenTask.getText(),
|
||||||
'Approve token spending cap',
|
'Approve TST spending cap',
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -490,11 +490,11 @@ describe('Create token, approve token and approve token without gas', function (
|
|||||||
// check transaction in Activity tab
|
// check transaction in Activity tab
|
||||||
const approveTokenTask = await driver.waitForSelector({
|
const approveTokenTask = await driver.waitForSelector({
|
||||||
css: '.transaction-list__completed-transactions .transaction-list-item:first-child .list-item__heading',
|
css: '.transaction-list__completed-transactions .transaction-list-item:first-child .list-item__heading',
|
||||||
text: 'Approve token spending cap',
|
text: 'Approve TST spending cap',
|
||||||
});
|
});
|
||||||
assert.equal(
|
assert.equal(
|
||||||
await approveTokenTask.getText(),
|
await approveTokenTask.getText(),
|
||||||
'Approve token spending cap',
|
'Approve TST spending cap',
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -131,7 +131,7 @@ describe('NFTs', function () {
|
|||||||
// Verify transaction
|
// Verify transaction
|
||||||
const completedTx = await driver.findElement('.list-item__title');
|
const completedTx = await driver.findElement('.list-item__title');
|
||||||
const completedTxText = await completedTx.getText();
|
const completedTxText = await completedTx.getText();
|
||||||
assert.equal(completedTxText, 'Approve token spending cap');
|
assert.equal(completedTxText, 'Approve TDC spending cap');
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -200,7 +200,7 @@ describe('NFTs', function () {
|
|||||||
// Verify transaction
|
// Verify transaction
|
||||||
const completedTx = await driver.findElement('.list-item__title');
|
const completedTx = await driver.findElement('.list-item__title');
|
||||||
const completedTxText = await completedTx.getText();
|
const completedTxText = await completedTx.getText();
|
||||||
assert.equal(completedTxText, 'Approve Token with no spend limit');
|
assert.equal(completedTxText, 'Approve TDC with no spend limit');
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -272,7 +272,7 @@ describe('NFTs', function () {
|
|||||||
// Verify transaction
|
// Verify transaction
|
||||||
const completedTx = await driver.findElement('.list-item__title');
|
const completedTx = await driver.findElement('.list-item__title');
|
||||||
const completedTxText = await completedTx.getText();
|
const completedTxText = await completedTx.getText();
|
||||||
assert.equal(completedTxText, 'Approve Token with no spend limit');
|
assert.equal(completedTxText, 'Approve TDC with no spend limit');
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -16,6 +16,7 @@ import {
|
|||||||
|
|
||||||
import { useGasFeeEstimates } from '../../../hooks/useGasFeeEstimates';
|
import { useGasFeeEstimates } from '../../../hooks/useGasFeeEstimates';
|
||||||
import { GasEstimateTypes } from '../../../../shared/constants/gas';
|
import { GasEstimateTypes } from '../../../../shared/constants/gas';
|
||||||
|
import { getTokens } from '../../../ducks/metamask/metamask';
|
||||||
import TransactionListItem from '.';
|
import TransactionListItem from '.';
|
||||||
|
|
||||||
const FEE_MARKET_ESTIMATE_RETURN_VALUE = {
|
const FEE_MARKET_ESTIMATE_RETURN_VALUE = {
|
||||||
@ -88,6 +89,8 @@ const generateUseSelectorRouter = (opts) => (selector) => {
|
|||||||
);
|
);
|
||||||
} else if (selector === getShouldShowFiat) {
|
} else if (selector === getShouldShowFiat) {
|
||||||
return opts.shouldShowFiat ?? false;
|
return opts.shouldShowFiat ?? false;
|
||||||
|
} else if (selector === getTokens) {
|
||||||
|
return opts.tokens ?? [];
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { getKnownMethodData } from '../selectors/selectors';
|
import { useEffect, useState } from 'react';
|
||||||
|
import {
|
||||||
|
getDetectedTokensInCurrentNetwork,
|
||||||
|
getKnownMethodData,
|
||||||
|
getTokenList,
|
||||||
|
} from '../selectors/selectors';
|
||||||
import {
|
import {
|
||||||
getStatusKey,
|
getStatusKey,
|
||||||
getTransactionTypeTitle,
|
getTransactionTypeTitle,
|
||||||
@ -7,6 +12,7 @@ import {
|
|||||||
import { camelCaseToCapitalize } from '../helpers/utils/common.util';
|
import { camelCaseToCapitalize } from '../helpers/utils/common.util';
|
||||||
import { PRIMARY, SECONDARY } from '../helpers/constants/common';
|
import { PRIMARY, SECONDARY } from '../helpers/constants/common';
|
||||||
import {
|
import {
|
||||||
|
getAssetDetails,
|
||||||
getTokenAddressParam,
|
getTokenAddressParam,
|
||||||
getTokenIdParam,
|
getTokenIdParam,
|
||||||
} from '../helpers/utils/token-util';
|
} from '../helpers/utils/token-util';
|
||||||
@ -93,6 +99,8 @@ export function useTransactionDisplayData(transactionGroup) {
|
|||||||
const currentAsset = useCurrentAsset();
|
const currentAsset = useCurrentAsset();
|
||||||
const knownTokens = useSelector(getTokens);
|
const knownTokens = useSelector(getTokens);
|
||||||
const knownNfts = useSelector(getNfts);
|
const knownNfts = useSelector(getNfts);
|
||||||
|
const detectedTokens = useSelector(getDetectedTokensInCurrentNetwork) || [];
|
||||||
|
const tokenList = useSelector(getTokenList);
|
||||||
const t = useI18nContext();
|
const t = useI18nContext();
|
||||||
|
|
||||||
const { initialTransaction, primaryTransaction } = transactionGroup;
|
const { initialTransaction, primaryTransaction } = transactionGroup;
|
||||||
@ -121,18 +129,53 @@ export function useTransactionDisplayData(transactionGroup) {
|
|||||||
// This value is used to determine whether we should look inside txParams.data
|
// This value is used to determine whether we should look inside txParams.data
|
||||||
// to pull out and render token related information
|
// to pull out and render token related information
|
||||||
const isTokenCategory = TOKEN_CATEGORY_HASH[type];
|
const isTokenCategory = TOKEN_CATEGORY_HASH[type];
|
||||||
|
|
||||||
// these values are always instantiated because they are either
|
// these values are always instantiated because they are either
|
||||||
// used by or returned from hooks. Hooks must be called at the top level,
|
// used by or returned from hooks. Hooks must be called at the top level,
|
||||||
// so as an additional safeguard against inappropriately associating token
|
// so as an additional safeguard against inappropriately associating token
|
||||||
// transfers, we pass an additional argument to these hooks that will be
|
// transfers, we pass an additional argument to these hooks that will be
|
||||||
// false for non-token transactions. This additional argument forces the
|
// false for non-token transactions. This additional argument forces the
|
||||||
// hook to return null
|
// hook to return null
|
||||||
const token =
|
let token = null;
|
||||||
isTokenCategory &&
|
const [currentAssetDetails, setCurrentAssetDetails] = useState(null);
|
||||||
|
|
||||||
|
if (isTokenCategory) {
|
||||||
|
token =
|
||||||
knownTokens.find(({ address }) =>
|
knownTokens.find(({ address }) =>
|
||||||
isEqualCaseInsensitive(address, recipientAddress),
|
isEqualCaseInsensitive(address, recipientAddress),
|
||||||
|
) ||
|
||||||
|
detectedTokens.find(({ address }) =>
|
||||||
|
isEqualCaseInsensitive(address, recipientAddress),
|
||||||
|
) ||
|
||||||
|
tokenList[recipientAddress.toLowerCase()];
|
||||||
|
}
|
||||||
|
useEffect(() => {
|
||||||
|
async function getAndSetAssetDetails() {
|
||||||
|
if (isTokenCategory && !token) {
|
||||||
|
const assetDetails = await getAssetDetails(
|
||||||
|
recipientAddress,
|
||||||
|
senderAddress,
|
||||||
|
initialTransaction?.txParams?.data,
|
||||||
|
knownNfts,
|
||||||
);
|
);
|
||||||
|
setCurrentAssetDetails(assetDetails);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getAndSetAssetDetails();
|
||||||
|
}, [
|
||||||
|
isTokenCategory,
|
||||||
|
token,
|
||||||
|
recipientAddress,
|
||||||
|
senderAddress,
|
||||||
|
initialTransaction?.txParams?.data,
|
||||||
|
knownNfts,
|
||||||
|
]);
|
||||||
|
if (currentAssetDetails) {
|
||||||
|
token = {
|
||||||
|
address: currentAssetDetails.toAddress,
|
||||||
|
symbol: currentAssetDetails.symbol,
|
||||||
|
decimals: currentAssetDetails.decimals,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const tokenData = useTokenData(
|
const tokenData = useTokenData(
|
||||||
initialTransaction?.txParams?.data,
|
initialTransaction?.txParams?.data,
|
||||||
|
@ -10,7 +10,11 @@ import {
|
|||||||
getCurrentCurrency,
|
getCurrentCurrency,
|
||||||
getCurrentChainId,
|
getCurrentChainId,
|
||||||
} from '../selectors';
|
} from '../selectors';
|
||||||
import { getTokens, getNativeCurrency } from '../ducks/metamask/metamask';
|
import {
|
||||||
|
getTokens,
|
||||||
|
getNativeCurrency,
|
||||||
|
getNfts,
|
||||||
|
} from '../ducks/metamask/metamask';
|
||||||
import { getMessage } from '../helpers/utils/i18n-helper';
|
import { getMessage } from '../helpers/utils/i18n-helper';
|
||||||
import messages from '../../app/_locales/en/messages.json';
|
import messages from '../../app/_locales/en/messages.json';
|
||||||
import { ASSET_ROUTE, DEFAULT_ROUTE } from '../helpers/constants/routes';
|
import { ASSET_ROUTE, DEFAULT_ROUTE } from '../helpers/constants/routes';
|
||||||
@ -143,6 +147,18 @@ const expectedResults = [
|
|||||||
isPending: false,
|
isPending: false,
|
||||||
displayedStatusKey: TransactionStatus.confirmed,
|
displayedStatusKey: TransactionStatus.confirmed,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Approve ABC spending cap',
|
||||||
|
category: TransactionGroupCategory.approval,
|
||||||
|
subtitle: `metamask.github.io`,
|
||||||
|
subtitleContainsOrigin: true,
|
||||||
|
primaryCurrency: '0.00000000000005 ABC',
|
||||||
|
senderAddress: '0xe18035bf8712672935fdb4e5e431b1a0183d2dfc',
|
||||||
|
recipientAddress: '0xabca64466f257793eaa52fcfff5066894b76a149',
|
||||||
|
secondaryCurrency: undefined,
|
||||||
|
displayedStatusKey: TransactionStatus.confirmed,
|
||||||
|
isPending: false,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
let useSelector, useI18nContext, useTokenFiatAmount;
|
let useSelector, useI18nContext, useTokenFiatAmount;
|
||||||
@ -166,9 +182,7 @@ describe('useTransactionDisplayData', () => {
|
|||||||
useTokenFiatAmountHooks,
|
useTokenFiatAmountHooks,
|
||||||
'useTokenFiatAmount',
|
'useTokenFiatAmount',
|
||||||
);
|
);
|
||||||
useTokenFiatAmount.returns((tokenAddress) => {
|
useTokenFiatAmount.returns(undefined);
|
||||||
return tokenAddress ? '1 TST' : undefined;
|
|
||||||
});
|
|
||||||
useI18nContext = sinon.stub(i18nhooks, 'useI18nContext');
|
useI18nContext = sinon.stub(i18nhooks, 'useI18nContext');
|
||||||
useI18nContext.returns((key, variables) =>
|
useI18nContext.returns((key, variables) =>
|
||||||
getMessage('en', messages, key, variables),
|
getMessage('en', messages, key, variables),
|
||||||
@ -194,6 +208,8 @@ describe('useTransactionDisplayData', () => {
|
|||||||
return 'ETH';
|
return 'ETH';
|
||||||
} else if (selector === getCurrentChainId) {
|
} else if (selector === getCurrentChainId) {
|
||||||
return CHAIN_IDS.MAINNET;
|
return CHAIN_IDS.MAINNET;
|
||||||
|
} else if (selector === getNfts) {
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user