Skip to content

Commit 2f327cd

Browse files
authored
feat: add price alerts basic setup (MetaMask#31477)
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> <!-- mms-check directive vocabulary — read by .github/scripts/shared/pr-template-checks.ts at module load to build the validation plan. Directives are invisible in rendered markdown and must NOT be removed or edited without updating the validator registry. type=text Section must contain non-placeholder prose. type=changelog Section must have a valid CHANGELOG entry: line. type=issue-link Section must have a Fixes:/Closes:/Refs: line with a value. type=manual-testing Section must have real testing steps or an explicit N/A. type=screenshot Section must have evidence (image/URL) or an explicit N/A. type=checklist Section must have all checkboxes consciously checked. required=true|false Whether a missing/invalid section blocks the PR check. Sections without a directive are checked for structural presence only. --> ## **Description** Adds the initial implementation of **Price Alerts** behind the `priceAlertsEnabled` remote feature flag (version-gated). When enabled, a notification icon appears in the Token Details header for any token with a known price. Tapping it opens a manage view that either shows existing alerts or drops straight into the create flow if none exist yet. The create screen lets users set a target price via a keypad or quick-percentage pills (5/10/20/30%), toggle whether the alert repeats, and see a live ± % indicator against the current price. On save the alert is POSTed to `https://price-alerts.api.cx.metamask.io` using a bearer token from `AuthenticationController`. Delete and toggle-active actions in the manage view are stubbed for a follow-up PR, as is the "Price change" alert type tab. <!-- mms-check: type=text required=true --> <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- mms-check: type=changelog required=true --> <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: add price alerts basic setup ## **Related issues** <!-- mms-check: type=issue-link required=true --> Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-3351 ## **Manual testing steps** <!-- mms-check: type=manual-testing required=true --> ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- mms-check: type=screenshot required=true --> <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** No price alerts support ### **After** https://github.com/user-attachments/assets/142f2842-0cd5-4692-b013-00566257e36b ## **Pre-merge author checklist** <!-- mms-check: type=checklist required=true --> <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [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. #### Performance checks (if applicable) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [x] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] 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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > New authenticated backend integration (bearer token) for user alert CRUD on token flows; mitigated by remote flag gating and incomplete manage mutations (delete/toggle TODO). > > **Overview** > Introduces **price alerts** behind the version-gated remote flag `priceAlertsEnabled`. When on, Token Details shows a notification control (only if price &gt; 0 and CAIP-19 `assetId` resolves) that opens **manage** or **create** flows for that asset. > > **Create** supports “price reaches” with a keypad, quick ±5/10/20/30% pills, recurring toggle, and live % vs current price; saves via authenticated `POST` to the price-alerts API (`asset`, `threshold`, `recurring`). **Manage** loads alerts per asset (React Query), replaces into create when the list is empty or fetch fails, and lists thresholds with recurring/once labels—**delete** and **active toggle** are UI-only stubs. A second tab (“price change”) shows an under-development placeholder. > > Wiring adds `PRICE_ALERTS_API_URL` / `AppConstants.PRICE_ALERTS_API`, navigation routes and screens, i18n, feature-flag registry entry, and broad unit test coverage. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 8ee8d6b. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 81c1a39 commit 2f327cd

24 files changed

Lines changed: 2417 additions & 6 deletions

File tree

.js.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ export DECODING_API_URL: 'https://signature-insights.api.cx.metamask.io/v1'
8080
# URL of security alerts API used to validate dApp requests.
8181
export SECURITY_ALERTS_API_URL="https://security-alerts.api.cx.metamask.io"
8282

83+
# URL of the price alerts API. Override to http://localhost:3333 for local dev.
84+
export PRICE_ALERTS_API_URL="https://price-alerts.dev-api.cx.metamask.io"
85+
8386
# URL of the compliance API used for wallet compliance checks.
8487
export COMPLIANCE_API_URL="https://compliance.api.cx.metamask.io"
8588

app/components/Nav/Main/MainNavigator.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ import RewardsSelectSheet from '../../UI/Rewards/components/RewardsSelectSheet';
171171

172172
import SitesFullView from '../../Views/SitesFullView/SitesFullView';
173173
import { TokenDetails } from '../../UI/TokenDetails/Views/TokenDetails';
174+
import CreatePriceAlertView from '../../UI/Assets/PriceAlerts/Views/CreatePriceAlertView/CreatePriceAlertView';
175+
import ManagePriceAlertsView from '../../UI/Assets/PriceAlerts/Views/ManagePriceAlertsView/ManagePriceAlertsView';
174176
import BenefitFullView from '../../UI/Rewards/Views/BenefitFullView';
175177
import BenefitsFullView from '../../UI/Rewards/Views/BenefitsFullView';
176178
import MoneyTabPressTracker from '../../UI/Money/components/MoneyTabPressTracker';
@@ -211,6 +213,14 @@ const AssetStackFlow = (props) => (
211213
name={Routes.TRANSACTION_DETAILS}
212214
component={TransactionDetails}
213215
/>
216+
<NativeStack.Screen
217+
name={Routes.CREATE_PRICE_ALERT}
218+
component={CreatePriceAlertView}
219+
/>
220+
<NativeStack.Screen
221+
name={Routes.MANAGE_PRICE_ALERTS}
222+
component={ManagePriceAlertsView}
223+
/>
214224
</NativeStack.Navigator>
215225
);
216226

app/components/UI/AssetOverview/TokenOverview.testIds.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import enContent from '../../../../locales/languages/en.json';
33
export const TokenOverviewSelectorsIDs = {
44
CONTAINER: 'token-asset-overview',
55
TOKEN_PRICE: 'token-price',
6+
PRICE_ALERT_BUTTON: 'token-price-alert-button',
67
SEND_BUTTON: 'token-send-button',
78
RECEIVE_BUTTON: 'token-receive-button',
89
BUY_BUTTON: 'token-buy-button',

0 commit comments

Comments
 (0)