1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 01:39:44 +01:00

Fix recent recipient order (#16346)

This commit is contained in:
amerkadicE 2023-02-09 18:45:52 +01:00 committed by GitHub
parent 26f6ae4c7c
commit 0c2af508ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 118 additions and 28 deletions

View File

@ -93,6 +93,7 @@ export default class ConfirmTransactionBase extends Component {
sendTransaction: PropTypes.func,
showTransactionConfirmedModal: PropTypes.func,
showRejectTransactionsConfirmationModal: PropTypes.func,
toAccounts: PropTypes.object,
toAddress: PropTypes.string,
tokenData: PropTypes.object,
tokenProps: PropTypes.object,
@ -103,6 +104,7 @@ export default class ConfirmTransactionBase extends Component {
txData: PropTypes.object,
unapprovedTxCount: PropTypes.number,
customGas: PropTypes.object,
addToAddressBookIfNew: PropTypes.func,
// Component props
actionKey: PropTypes.string,
contentComponent: PropTypes.node,
@ -803,10 +805,16 @@ export default class ConfirmTransactionBase extends Component {
maxPriorityFeePerGas,
baseFeePerGas,
methodData,
addToAddressBookIfNew,
toAccounts,
toAddress,
} = this.props;
const { submitting } = this.state;
const { name } = methodData;
if (txData.type === TransactionType.simpleSend) {
addToAddressBookIfNew(toAddress, toAccounts);
}
if (submitting) {
return;
}

View File

@ -13,6 +13,7 @@ import {
getNextNonce,
tryReverseResolveAddress,
setDefaultHomeActiveTabName,
addToAddressBook,
} from '../../store/actions';
import { isBalanceSufficient } from '../send/send.utils';
import { shortenAddress, valuesFor } from '../../helpers/utils/util';
@ -44,7 +45,9 @@ import {
updateGasFees,
getIsGasEstimatesLoading,
getNativeCurrency,
getSendToAccounts,
} from '../../ducks/metamask/metamask';
import { addHexPrefix } from '../../../app/scripts/lib/util';
import {
parseStandardTokenTransactionData,
@ -74,6 +77,14 @@ const customNonceMerge = (txData) =>
}
: txData;
function addressIsNew(toAccounts, newAddress) {
const newAddressNormalized = newAddress.toLowerCase();
const foundMatching = toAccounts.some(
({ address }) => address.toLowerCase() === newAddressNormalized,
);
return !foundMatching;
}
const mapStateToProps = (state, ownProps) => {
const {
toAddress: propsToAddress,
@ -122,6 +133,8 @@ const mapStateToProps = (state, ownProps) => {
toAddress = propsToAddress || tokenToAddress || txParamsToAddress;
}
const toAccounts = getSendToAccounts(state);
const tokenList = getTokenList(state);
const toName =
@ -196,6 +209,7 @@ const mapStateToProps = (state, ownProps) => {
balance,
fromAddress,
fromName,
toAccounts,
toAddress,
toEns,
toName,
@ -277,6 +291,13 @@ export const mapDispatchToProps = (dispatch) => {
updateTransactionGasFees: (gasFees) => {
dispatch(updateGasFees({ ...gasFees, expectHexWei: true }));
},
showBuyModal: () => dispatch(showModal({ name: 'DEPOSIT_ETHER' })),
addToAddressBookIfNew: (newAddress, toAccounts, nickname = '') => {
const hexPrefixedAddress = addHexPrefix(newAddress);
if (addressIsNew(toAccounts, hexPrefixedAddress)) {
dispatch(addToAddressBook(hexPrefixedAddress, nickname));
}
},
};
};

View File

@ -58,4 +58,71 @@ describe('Add Recipient Component', () => {
expect(container).toMatchSnapshot();
});
});
describe('Recent recipient order', () => {
const recentRecipientState = {
...mockState,
metamask: {
...mockState.metamask,
addressBook: {
'0x5': {
'0x0000000000000000000000000000000000000001': {
address: '0x0000000000000000000000000000000000000001',
chainId: '0x5',
isEns: false,
memo: '',
name: '',
},
'0x0000000000000000000000000000000000000002': {
address: '0x0000000000000000000000000000000000000002',
chainId: '0x5',
isEns: false,
memo: '',
name: '',
},
'0x0000000000000000000000000000000000000003': {
address: '0x0000000000000000000000000000000000000003',
chainId: '0x5',
isEns: false,
memo: '',
name: '',
},
},
},
currentNetworkTxList: [
{
time: 1674425700001,
txParams: {
to: '0x0000000000000000000000000000000000000001',
},
},
{
time: 1674425700002,
txParams: {
to: '0x0000000000000000000000000000000000000002',
},
},
{
time: 1674425700003,
txParams: {
to: '0x0000000000000000000000000000000000000003',
},
},
],
},
};
const mockStore = configureMockStore()(recentRecipientState);
it('should render latest used recipient first', () => {
const { getAllByTestId } = renderWithProvider(
<AddRecipient />,
mockStore,
);
const recipientList = getAllByTestId('recipient');
expect(recipientList[0]).toHaveTextContent('0x0000...0003');
expect(recipientList[1]).toHaveTextContent('0x0000...0002');
});
});
});

View File

@ -3,6 +3,7 @@ import {
getAddressBook,
getAddressBookEntry,
getMetaMaskAccountsOrdered,
currentNetworkTxListSelector,
} from '../../../../selectors';
import {
@ -35,6 +36,22 @@ function mapStateToProps(state) {
const addressBook = getAddressBook(state);
const txList = [...currentNetworkTxListSelector(state)].reverse();
const nonContacts = addressBook
.filter(({ name }) => !name)
.map((nonContact) => {
const nonContactTx = txList.find(
(transaction) =>
transaction.txParams.to === nonContact.address.toLowerCase(),
);
return { ...nonContact, timestamp: nonContactTx?.time };
});
nonContacts.sort((a, b) => {
return b.timestamp - a.timestamp;
});
const ownedAccounts = getMetaMaskAccountsOrdered(state);
return {
@ -44,7 +61,7 @@ function mapStateToProps(state) {
domainResolution,
domainError: getDomainError(state),
domainWarning: getDomainWarning(state),
nonContacts: addressBook.filter(({ name }) => !name),
nonContacts,
ownedAccounts,
isUsingMyAccountsForRecipientSearch:
getIsUsingMyAccountForRecipientSearch(state),

View File

@ -16,6 +16,7 @@ jest.mock('../../../../selectors', () => ({
{ name: `account1:mockState` },
{ name: `account2:mockState` },
],
currentNetworkTxListSelector: (s) => `currentNetworkTxListSelector:${s}`,
}));
jest.mock('../../../../ducks/domains', () => ({

View File

@ -11,13 +11,10 @@ import { SEND_STAGES } from '../../../ducks/send';
export default class SendFooter extends Component {
static propTypes = {
addToAddressBookIfNew: PropTypes.func,
resetSendState: PropTypes.func,
disabled: PropTypes.bool.isRequired,
history: PropTypes.object,
sign: PropTypes.func,
to: PropTypes.string,
toAccounts: PropTypes.array,
sendStage: PropTypes.string,
sendErrors: PropTypes.object,
mostRecentOverviewPage: PropTypes.string.isRequired,
@ -52,11 +49,9 @@ export default class SendFooter extends Component {
async onSubmit(event) {
event.preventDefault();
const { addToAddressBookIfNew, sign, to, toAccounts, history } = this.props;
const { sign, history } = this.props;
const { trackEvent } = this.context;
// TODO: add nickname functionality
await addToAddressBookIfNew(to, toAccounts);
const promise = sign();
Promise.resolve(promise).then(() => {

View File

@ -1,5 +1,5 @@
import { connect } from 'react-redux';
import { addToAddressBook, cancelTx } from '../../../store/actions';
import { cancelTx } from '../../../store/actions';
import {
resetSendState,
getSendStage,
@ -10,20 +10,11 @@ import {
getDraftTransactionID,
} from '../../../ducks/send';
import { getMostRecentOverviewPage } from '../../../ducks/history/history';
import { addHexPrefix } from '../../../../app/scripts/lib/util';
import { getSendToAccounts } from '../../../ducks/metamask/metamask';
import SendFooter from './send-footer.component';
export default connect(mapStateToProps, mapDispatchToProps)(SendFooter);
function addressIsNew(toAccounts, newAddress) {
const newAddressNormalized = newAddress.toLowerCase();
const foundMatching = toAccounts.some(
({ address }) => address.toLowerCase() === newAddressNormalized,
);
return !foundMatching;
}
function mapStateToProps(state) {
return {
disabled: isSendFormInvalid(state),
@ -41,12 +32,5 @@ function mapDispatchToProps(dispatch) {
resetSendState: () => dispatch(resetSendState()),
cancelTx: (t) => dispatch(cancelTx(t)),
sign: () => dispatch(signTransaction()),
addToAddressBookIfNew: (newAddress, toAccounts, nickname = '') => {
const hexPrefixedAddress = addHexPrefix(newAddress);
if (addressIsNew(toAccounts, hexPrefixedAddress)) {
// TODO: nickname, i.e. addToAddressBook(recipient, nickname)
dispatch(addToAddressBook(hexPrefixedAddress, nickname));
}
},
};
}

View File

@ -13,7 +13,6 @@ export default {
mostRecentOverviewPage: { control: 'text' },
sendErrors: { control: 'object' },
history: { action: 'history' },
addToAddressBookIfNew: { action: 'addToAddressBookIfNew' },
resetSendState: { action: 'resetSendState' },
},
};

View File

@ -13,7 +13,6 @@ import SendFooter from '.';
const mockResetSendState = jest.fn();
const mockSendTransaction = jest.fn();
const mockAddtoAddressBook = jest.fn();
const mockCancelTx = jest.fn();
jest.mock('../../../ducks/send/index.js', () => ({
@ -23,7 +22,6 @@ jest.mock('../../../ducks/send/index.js', () => ({
}));
jest.mock('../../../store/actions.ts', () => ({
addToAddressBook: () => mockAddtoAddressBook,
cancelTx: () => mockCancelTx,
}));
@ -108,7 +106,6 @@ describe('SendFooter Component', () => {
fireEvent.click(nextText);
await waitFor(() => {
expect(mockAddtoAddressBook).toHaveBeenCalled();
expect(mockSendTransaction).toHaveBeenCalled();
expect(props.history.push).toHaveBeenCalledWith(
CONFIRM_TRANSACTION_ROUTE,

View File

@ -103,6 +103,7 @@ const baseStore = {
addressBook: {
[CHAIN_IDS.GOERLI]: [],
},
currentNetworkTxList: [],
cachedBalances: {
[CHAIN_IDS.GOERLI]: {},
},