Skip to content

Commit

Permalink
feat: display staking transaction methods (#12110)
Browse files Browse the repository at this point in the history
## **Description**

Display staking transaction methods in the transaction confirmation
rather than `Unknown Method`.

Specifically:

- Provide new `TransactionType` values in the `addTransaction` options.
- Add action keys for staking transaction types.
- Upgrade `@metamask/transaction-controller` to `38.2.0`.

## **Related issues**

Fixes: [#2012](MetaMask/mobile-planning#2012)

## **Manual testing steps**

1. Add `export MM_POOLED_STAKING_UI_ENABLED="true"` to `.js.env`.
2. Create each staking transaction type.
3. Verify method is correct and not `Unknown Method`.

## **Screenshots/Recordings**

### **Before**

<img width="200" alt="Before"
src="https://github.com/user-attachments/assets/c68c7f06-eb73-4d09-b02e-939ac4232a1c">

### **After**

<img width="200" alt="Deposit"
src="https://github.com/user-attachments/assets/3cf566eb-8269-4ea9-a2bf-246cbf80f787">

<img width="200" alt="Claim"
src="https://github.com/user-attachments/assets/5704717d-e037-4e25-9ad2-b345fd53d8cf">

<img width="200" alt="Unstake"
src="https://github.com/user-attachments/assets/5d0f0e5e-138f-4913-93b6-9fc28233b244">

<img width="200" alt="Activity List"
src="https://github.com/user-attachments/assets/6d8c7224-4fdb-45c2-8b30-2cdeae0eb97c">

## **Pre-merge author checklist**

- [x] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
  • Loading branch information
matthewwalsh0 committed Nov 5, 2024
1 parent 48017cb commit 8714034
Show file tree
Hide file tree
Showing 11 changed files with 90 additions and 38 deletions.
7 changes: 6 additions & 1 deletion app/components/UI/Stake/hooks/usePoolStakedClaim/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { PooledStake, PooledStakingContract } from '@metamask/stake-sdk';
import { useStakeContext } from '../useStakeContext';
import trackErrorAsAnalytics from '../../../../../util/metrics/TrackError/trackErrorAsAnalytics';
import { WalletDevice } from '@metamask/transaction-controller';
import {
TransactionType,
WalletDevice,
} from '@metamask/transaction-controller';
import { addTransaction } from '../../../../../util/transaction-controller';
import { ORIGIN_METAMASK } from '@metamask/controller-utils';
import {
Expand Down Expand Up @@ -42,6 +45,7 @@ const attemptMultiCallClaimTransaction = async (
return addTransaction(txParams, {
deviceConfirmedOn: WalletDevice.MM_MOBILE,
origin: ORIGIN_METAMASK,
type: TransactionType.stakingClaim,
});
};

Expand Down Expand Up @@ -84,6 +88,7 @@ const attemptSingleClaimTransaction = async (
return addTransaction(txParams, {
deviceConfirmedOn: WalletDevice.MM_MOBILE,
origin: ORIGIN_METAMASK,
type: TransactionType.stakingClaim,
});
};

Expand Down
2 changes: 2 additions & 0 deletions app/components/UI/Stake/hooks/usePoolStakedDeposit/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ChainId, PooledStakingContract } from '@metamask/stake-sdk';
import {
TransactionParams,
TransactionType,
WalletDevice,
} from '@metamask/transaction-controller';
import { ORIGIN_METAMASK, toHex } from '@metamask/controller-utils';
Expand Down Expand Up @@ -63,6 +64,7 @@ const attemptDepositTransaction =
return await addTransaction(txParams, {
deviceConfirmedOn: WalletDevice.MM_MOBILE,
origin: ORIGIN_METAMASK,
type: TransactionType.stakingDeposit,
});
} catch (e) {
const errorMessage = (e as Error).message;
Expand Down
2 changes: 2 additions & 0 deletions app/components/UI/Stake/hooks/usePoolStakedUnstake/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { PooledStakingContract, ChainId } from '@metamask/stake-sdk';
import { useStakeContext } from '../useStakeContext';
import {
TransactionParams,
TransactionType,
WalletDevice,
} from '@metamask/transaction-controller';
import { addTransaction } from '../../../../../util/transaction-controller';
Expand Down Expand Up @@ -50,6 +51,7 @@ const attemptUnstakeTransaction =
return await addTransaction(txParams, {
deviceConfirmedOn: WalletDevice.MM_MOBILE,
origin: ORIGIN_METAMASK,
type: TransactionType.stakingUnstake,
});
} catch (e) {
const errorMessage = (e as Error).message;
Expand Down
6 changes: 3 additions & 3 deletions app/components/Views/confirmations/Approval/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ class Approval extends PureComponent {
*/
trackEditScreen = async () => {
const { transaction } = this.props;
const actionKey = await getTransactionReviewActionKey(transaction);
const actionKey = await getTransactionReviewActionKey({ transaction });
this.props.metrics.trackEvent(
MetaMetricsEvents.TRANSACTIONS_EDIT_TRANSACTION,
{
Expand Down Expand Up @@ -374,8 +374,8 @@ class Approval extends PureComponent {
request_source: this.originIsMMSDKRemoteConn
? AppConstants.REQUEST_SOURCES.SDK_REMOTE_CONN
: this.originIsWalletConnect
? AppConstants.REQUEST_SOURCES.WC
: AppConstants.REQUEST_SOURCES.IN_APP_BROWSER,
? AppConstants.REQUEST_SOURCES.WC
: AppConstants.REQUEST_SOURCES.IN_APP_BROWSER,
};

try {
Expand Down
2 changes: 1 addition & 1 deletion app/components/Views/confirmations/Send/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ class Send extends PureComponent {
*/
trackEditScreen = async () => {
const { transaction } = this.props;
const actionKey = await getTransactionReviewActionKey(transaction);
const actionKey = await getTransactionReviewActionKey({ transaction });
this.props.metrics.trackEvent(
MetaMetricsEvents.TRANSACTIONS_EDIT_TRANSACTION,
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,10 @@ class TransactionReview extends PureComponent {
* Object containing blockaid validation response for confirmation
*/
securityAlertResponse: PropTypes.object,
/**
* Object containing the current transaction metadata
*/
transactionMetadata: PropTypes.object,
};

state = {
Expand Down Expand Up @@ -316,6 +320,7 @@ class TransactionReview extends PureComponent {
const {
transaction,
transaction: { data, to, value },
transactionMetadata,
tokens,
chainId,
tokenList,
Expand All @@ -327,7 +332,13 @@ class TransactionReview extends PureComponent {
showHexData = showHexData || data;
const approveTransaction =
isApprovalTransaction(data) && (!value || isZeroValue(value));
const actionKey = await getTransactionReviewActionKey(transaction, chainId);

const actionKey = await getTransactionReviewActionKey({
...transactionMetadata,
transaction,
txParams: undefined
}, chainId);

if (approveTransaction) {
let contract = tokenList[safeToChecksumAddress(to)];
if (!contract) {
Expand Down Expand Up @@ -701,6 +712,7 @@ const mapStateToProps = (state) => ({
selectCurrentTransactionMetadata(state)?.simulationData,
useTransactionSimulations: selectUseTransactionSimulations(state),
securityAlertResponse: selectCurrentTransactionSecurityAlertResponse(state),
transactionMetadata: selectCurrentTransactionMetadata(state),
});

TransactionReview.contextType = ThemeContext;
Expand Down
57 changes: 34 additions & 23 deletions app/util/transactions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
ERC721,
ERC1155,
} from '@metamask/controller-utils';
import { isEIP1559Transaction } from '@metamask/transaction-controller';
import { isEIP1559Transaction, TransactionType } from '@metamask/transaction-controller';
import { swapsUtils } from '@metamask/swaps-controller';
import Engine from '../../core/Engine';
import I18n, { strings } from '../../../locales/i18n';
Expand Down Expand Up @@ -124,6 +124,9 @@ const reviewActionKeys = {
[SET_APPROVE_FOR_ALL_ACTION_KEY]: strings(
'transactions.tx_review_set_approval_for_all',
),
[TransactionType.stakingClaim]: strings('transactions.tx_review_staking_claim'),
[TransactionType.stakingDeposit]: strings('transactions.tx_review_staking_deposit'),
[TransactionType.stakingUnstake]: strings('transactions.tx_review_staking_unstake'),
};

/**
Expand All @@ -142,6 +145,9 @@ const actionKeys = {
[SET_APPROVE_FOR_ALL_ACTION_KEY]: strings(
'transactions.set_approval_for_all',
),
[TransactionType.stakingClaim]: strings('transactions.tx_review_staking_claim'),
[TransactionType.stakingDeposit]: strings('transactions.tx_review_staking_deposit'),
[TransactionType.stakingUnstake]: strings('transactions.tx_review_staking_unstake'),
};

/**
Expand Down Expand Up @@ -395,33 +401,38 @@ export async function isCollectibleAddress(address, tokenId) {
* @returns {string} - Corresponding transaction action key
*/
export async function getTransactionActionKey(transaction, chainId) {
// This condition is needed until the transaction reducer be refactored
if (!transaction.txParams) {
transaction.txParams = transaction.transaction;
const { type } = transaction ?? {};
const txParams = transaction.txParams ?? transaction.transaction ?? {};
const { data, to } = txParams;

if ([TransactionType.stakingClaim, TransactionType.stakingDeposit, TransactionType.stakingUnstake].includes(type)) {
return type;
}

if (!to) {
return CONTRACT_METHOD_DEPLOY;
}
const { txParams: { data, to } = {} } = transaction;
if (!to) return CONTRACT_METHOD_DEPLOY;
if (to === getSwapsContractAddress(chainId))

if (to === getSwapsContractAddress(chainId)) {
return SWAPS_TRANSACTION_ACTION_KEY;
let ret;
}

// if data in transaction try to get method data
if (data && data !== '0x') {
const methodData = await getMethodData(data);
const { name } = methodData;
const { name } = await getMethodData(data);
if (name) return name;
}

const toSmartContract =
transaction.toSmartContract !== undefined
? transaction.toSmartContract
: await isSmartContractAddress(to);

if (toSmartContract) {
// There is no data or unknown method data, if is smart contract
ret = SMART_CONTRACT_INTERACTION_ACTION_KEY;
} else {
// If there is no data and no smart contract interaction
ret = SEND_ETHER_ACTION_KEY;
return SMART_CONTRACT_INTERACTION_ACTION_KEY;
}
return ret;

return SEND_ETHER_ACTION_KEY;
}

/**
Expand Down Expand Up @@ -455,11 +466,11 @@ export async function getActionKey(tx, selectedAddress, ticker, chainId) {
? strings('transactions.self_sent_unit', { unit: currencySymbol })
: strings('transactions.self_sent_ether')
: currencySymbol
? strings('transactions.received_unit', { unit: currencySymbol })
: strings('transactions.received_ether')
? strings('transactions.received_unit', { unit: currencySymbol })
: strings('transactions.received_ether')
: currencySymbol
? strings('transactions.sent_unit', { unit: currencySymbol })
: strings('transactions.sent_ether');
? strings('transactions.sent_unit', { unit: currencySymbol })
: strings('transactions.sent_ether');
}
const transactionActionKey = actionKeys[actionKey];

Expand All @@ -478,7 +489,7 @@ export async function getActionKey(tx, selectedAddress, ticker, chainId) {
* @returns {string} - Transaction function type
*/
export async function getTransactionReviewActionKey(transaction, chainId) {
const actionKey = await getTransactionActionKey({ transaction }, chainId);
const actionKey = await getTransactionActionKey(transaction, chainId);
const transactionReviewActionKey = reviewActionKeys[actionKey];
if (transactionReviewActionKey) {
return transactionReviewActionKey;
Expand Down Expand Up @@ -1029,7 +1040,7 @@ export const parseTransactionEIP1559 = (
maxPriorityFeeNative,
nativeCurrency,
Boolean(maxPriorityFeePerGasTimesGasLimitHex) &&
maxPriorityFeePerGasTimesGasLimitHex !== '0x0',
maxPriorityFeePerGasTimesGasLimitHex !== '0x0',
);
const renderableMaxPriorityFeeConversion = formatCurrency(
maxPriorityFeeConversion,
Expand Down Expand Up @@ -1528,7 +1539,7 @@ export const getIsSwapApproveOrSwapTransaction = (
(swapsUtils.isValidContractAddress(chainId, to) ||
(data?.startsWith(APPROVE_FUNCTION_SIGNATURE) &&
decodeApproveData(data).spenderAddress?.toLowerCase() ===
swapsUtils.getSwapsContractAddress(chainId)))
swapsUtils.getSwapsContractAddress(chainId)))
);
};

Expand Down
21 changes: 19 additions & 2 deletions app/util/transactions/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
} from '.';
import Engine from '../../core/Engine';
import { strings } from '../../../locales/i18n';
import { TransactionType } from '@metamask/transaction-controller';

jest.mock('@metamask/controller-utils', () => ({
...jest.requireActual('@metamask/controller-utils'),
Expand Down Expand Up @@ -1019,6 +1020,19 @@ describe('Transactions utils :: getTransactionActionKey', () => {
const actionKey = await getTransactionActionKey(transaction, chainId);
expect(actionKey).toBe(TOKEN_METHOD_INCREASE_ALLOWANCE);
});

it.each([
TransactionType.stakingClaim,
TransactionType.stakingDeposit,
TransactionType.stakingUnstake,
])('returns transaction type if type is %s', async (type) => {
const transaction = { type };
const chainId = '1';

const actionKey = await getTransactionActionKey(transaction, chainId);

expect(actionKey).toBe(type);
});
});

describe('Transactions utils :: getFourByteSignature', () => {
Expand Down Expand Up @@ -1086,14 +1100,17 @@ describe('Transactions utils :: getTransactionReviewActionKey', () => {
const chainId = '1';
it('returns `Unknown Method` review action key when transaction action key exists', async () => {
const expectedReviewActionKey = 'Unknown Method';
const result = await getTransactionReviewActionKey(transaction, chainId);
const result = await getTransactionReviewActionKey(
{ transaction },
chainId,
);
expect(result).toEqual(expectedReviewActionKey);
});

it('returns correct review action key', async () => {
const expectedReviewActionKey = 'Increase Allowance';
const result = await getTransactionReviewActionKey(
{ ...transaction, data: INCREASE_ALLOWANCE_SIGNATURE },
{ transaction: { ...transaction, data: INCREASE_ALLOWANCE_SIGNATURE } },
chainId,
);
expect(result).toEqual(expectedReviewActionKey);
Expand Down
3 changes: 3 additions & 0 deletions locales/languages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1668,6 +1668,9 @@
"tx_review_approve": "Approve",
"tx_review_increase_allowance": "Increase Allowance",
"tx_review_set_approval_for_all": "Set Approval For All",
"tx_review_staking_claim": "Staking Claim",
"tx_review_staking_deposit": "Staking Deposit",
"tx_review_staking_unstake": "Unstake",
"sent_ether": "Sent Ether",
"self_sent_ether": "Sent Yourself Ether",
"received_ether": "Received Ether",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@
"@metamask/stake-sdk": "^0.2.13",
"@metamask/swappable-obj-proxy": "^2.1.0",
"@metamask/swaps-controller": "^9.0.12",
"@metamask/transaction-controller": "^38.1.0",
"@metamask/transaction-controller": "^38.2.0",
"@metamask/utils": "^9.2.1",
"@ngraveio/bc-ur": "^1.1.6",
"@notifee/react-native": "^9.0.0",
Expand Down
12 changes: 6 additions & 6 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4452,7 +4452,7 @@
resolved "https://registry.yarnpkg.com/@metamask/contract-metadata/-/contract-metadata-2.2.0.tgz#277764d0d56e37180ae7644a9d11eb96295b36fc"
integrity sha512-SM6A4C7vXNbVpgMTX67kfW8QWvu3eSXxMZlY5PqZBTkvri1s9zgQ0uwRkK5r2VXNEoVmXCDnnEX/tX5EzzgNUQ==

"@metamask/controller-utils@^11.0.0", "@metamask/controller-utils@^11.0.2", "@metamask/controller-utils@^11.3.0", "@metamask/controller-utils@^11.4.1", "@metamask/controller-utils@^11.4.2":
"@metamask/controller-utils@^11.0.0", "@metamask/controller-utils@^11.0.2", "@metamask/controller-utils@^11.3.0", "@metamask/controller-utils@^11.4.2":
version "11.4.2"
resolved "https://registry.yarnpkg.com/@metamask/controller-utils/-/controller-utils-11.4.2.tgz#0186c62c841ec94f60a67d0764dc7ab59c176c51"
integrity sha512-4zGfTTpjDgvRxo/tb3v1NBu0V/b2bqaDpSQC0noi5A4sm1yiZhyzqBY9+Zg11s8G/imp7+jvYRP1QM6OjFgIjQ==
Expand Down Expand Up @@ -5661,10 +5661,10 @@
lodash "^4.17.21"
uuid "^8.3.2"

"@metamask/transaction-controller@^38.1.0":
version "38.1.0"
resolved "https://registry.yarnpkg.com/@metamask/transaction-controller/-/transaction-controller-38.1.0.tgz#4c1fd277a0b6977c60a48c723a9660cbc5c9aeef"
integrity sha512-C0gkslTgx8X+CF/g9NSnGPexHzws3AfpYJSSbz1JJjgU9aq37qm/abAhUcEBM0kCCp7Zs2NF7KCzFenfbDkS8Q==
"@metamask/transaction-controller@^38.2.0":
version "38.2.0"
resolved "https://registry.yarnpkg.com/@metamask/transaction-controller/-/transaction-controller-38.2.0.tgz#45b12b871b7502cdf2d8a6846f7ed006787bb3b1"
integrity sha512-fTN9oPt5p9Wh5AoeX3ahZmwVs/TqQVZxqMw8YT7Tbcmyw1n1gRZIo2KDOSZnWM8cchOzppHp4e/QEcxpSdki8w==
dependencies:
"@ethereumjs/common" "^3.2.0"
"@ethereumjs/tx" "^4.2.0"
Expand All @@ -5673,7 +5673,7 @@
"@ethersproject/contracts" "^5.7.0"
"@ethersproject/providers" "^5.7.0"
"@metamask/base-controller" "^7.0.2"
"@metamask/controller-utils" "^11.4.1"
"@metamask/controller-utils" "^11.4.2"
"@metamask/eth-query" "^4.0.0"
"@metamask/metamask-eth-abis" "^3.1.1"
"@metamask/nonce-tracker" "^6.0.0"
Expand Down

0 comments on commit 8714034

Please sign in to comment.