Skip to content

feat(4173): Send flow with contextual chain selector#13938

Merged
Prithpal-Sooriya merged 178 commits into
mainfrom
feat-4173-send-flow-with-contextual-chain-selector
Aug 11, 2025
Merged

feat(4173): Send flow with contextual chain selector#13938
Prithpal-Sooriya merged 178 commits into
mainfrom
feat-4173-send-flow-with-contextual-chain-selector

Conversation

@EtherWizard33

@EtherWizard33 EtherWizard33 commented Mar 10, 2025

Copy link
Copy Markdown
Contributor

Description

This PR introduces contextual chain selection to the send flow, moving away from the global network selector pattern to enable users to select networks specifically within the context of sending assets. This change allows users to filter and send assets based on their chosen chain without affecting the global application state.

Changelog

CHANGELOG entry: Added contextual network selector in send flow

Related issues

Contributes to: #13674

Manual testing steps

Feature: Contextual Network Picker
  Scenario: user presses Contextual Network Picker in send flow
    Then can select different networks
    Then can select different tokens based on the contextual network chosen regardless of the globally selected network

Screenshots/Recordings

Before (feature flag OFF) After (feature flag ON)
Screenshot 2025-08-07 at 12 54 18 PM Screenshot 2025-08-07 at 12 51 11 PM

Before

NA

After

NA

Pre-merge author checklist

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.

EtherWizard33 and others added 19 commits February 19, 2025 19:05
…ature can work when its feature flags are enabled

make sure to include all env vars:
export MM_MULTICHAIN_V1_ENABLED="true"
export MM_CHAIN_PERMISSIONS="true"
export MM_PER_DAPP_SELECTED_NETWORK="1"
export MULTICHAIN_V1="true"
- Replace direct checks of process.env.MM_PER_DAPP_SELECTED_NETWORK in AccountPermissionsConnected.tsx with the isPerDappSelectedNetworkEnabled function.
- Update ethereum-chain-utils.js to use isPerDappSelectedNetworkEnabled when switching networks.
- Modify selectedNetworkController selectors to use isPerDappSelectedNetworkEnabled for feature flag checks.
- Add the isPerDappSelectedNetworkEnabled utility in util/networks/index.js.

This change centralizes the per-DApp network logic for better consistency and maintainability.
Add a touchable favicon to the permission summary header that enables network
switching for dapps. This combines the dapp's identity (favicon/token) with
network selection in a single interactive component.

- Replace static WebsiteIcon with touchable BadgeWrapper pattern
- Add network badge to indicate current network
- Enable network switching via network selector bottom sheet
- Add fallback to AvatarToken when favicon unavailable
- Guard implementation behind per-dapp network selection feature flag
- Preserve original WebsiteIcon when feature disabled

This matches the interaction pattern from AccountPermissionsConnected,
providing a consistent way to manage dapp-specific networks across the app.
…flag

The domain logo container view was incorrectly placed outside the per-dapp network
feature flag check. This change moves the container view inside the feature flag
condition to ensure consistent UI behavior when the feature is enabled/disabled.

- Moved View wrapper inside isPerDappSelectedNetworkEnabled() check
- Simplified conditional rendering logic
- Maintains existing functionality but with proper feature flag control
…permission sumamry is displayed, keep showing the WebsiteIcon rather than the AvatarFavicon.
…1Enabled rather than its 'corresponding' env variable MULTICHAIN_V1
Remove the permission check for non-permitted network flows in dapps, paving the way for the per-dapp-selected-network feature. Temporary screens handling these flows are pending removal upon feature completion.
- Replace global network selectors with origin-specific useNetworkInfo hook
- Update network name and image source to be origin-aware
- Update test snapshot for network name changes
- Add origin prop to AccountFromToInfoCard for per-dapp network info
- Add debug logs for transaction review flow
@github-actions

Copy link
Copy Markdown
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@EtherWizard33 EtherWizard33 changed the base branch from main to feat-4144-per-dapp-selected-network-poc-2 March 10, 2025 13:57
@EtherWizard33 EtherWizard33 added No QA Needed Apply this label when your PR does not need any QA effort. and removed Run Smoke E2E labels Mar 10, 2025
@EtherWizard33 EtherWizard33 added No E2E Smoke Needed and removed No QA Needed Apply this label when your PR does not need any QA effort. labels Mar 10, 2025
This commit:
- Adds redux state to track chain ID specifically in send flow context
- Dispatches chain ID updates when switching networks from send flow
- Adds selector and logging to monitor contextual chain ID changes
- Only tracks chain ID when network selector is used from send flow
…r reducer

- Move contextual chain ID from transaction to networkSelector reducer
- Update selectors to read from new location
- Add debug logging for state transitions
- Reset contextual chain ID when canceling transaction
- Initialize contextual chain ID in SendTo component
- Display network name in navbar using contextual chain ID

BREAKING CHANGE: sendFlowContextualChainId moved from transaction to networkSelector reducer
@github-actions

github-actions Bot commented Aug 7, 2025

Copy link
Copy Markdown
Contributor

https://bitrise.io/ Bitrise

✅✅✅ pr_smoke_e2e_pipeline passed on Bitrise! ✅✅✅

Commit hash: 8a6c564
Build link: https://app.bitrise.io/app/be69d4368ee7e86d/pipelines/5e8dd1a5-9719-4995-a5c1-3f7eca622131

Note

  • You can kick off another pr_smoke_e2e_pipeline on Bitrise by removing and re-applying the Run Smoke E2E label on the pull request

…4173-send-flow-with-contextual-chain-selector
Comment thread .github/pull-request-template.md
Comment thread app/actions/sendFlow/index.js Outdated

@Prithpal-Sooriya Prithpal-Sooriya left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes look okay, some minor nit comments which I'll polish up.

I'll also try to get the code coverage higher.

const hexChainId = useMemo(
() => (chainId ? toHex(chainId) : null),
[chainId],
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Hexadecimal Strings Passed to Conversion Functions

The chainId and contextualChainId variables, which are already in hexadecimal format, are incorrectly passed to conversion functions like toHex() and toHexadecimal(). These functions expect a number or decimal string, not an already hex-formatted string, which can lead to conversion errors or unexpected behavior.

Additional Locations (1)
Fix in Cursor Fix in Web

@github-actions

github-actions Bot commented Aug 8, 2025

Copy link
Copy Markdown
Contributor

https://bitrise.io/ Bitrise

✅✅✅ pr_smoke_e2e_pipeline passed on Bitrise! ✅✅✅

Commit hash: 4967799
Build link: https://app.bitrise.io/app/be69d4368ee7e86d/pipelines/857bebc0-0648-4db9-be9a-5b0887e397b0

Note

  • You can kick off another pr_smoke_e2e_pipeline on Bitrise by removing and re-applying the Run Smoke E2E label on the pull request

isContextualNetworkEnabled,
sendFlowNetworkData,
globalNetworkImage,
]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: we can make dependency more specific here like perDappNetworkInfo.networkImageSource, sendFlowNetworkData.imageSource .

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, let me refactor that now

// The line `!isContextualChainId && renderNonEvmNetworks(false)` should be tested to ensure:
// 1. Non-EVM networks render when isContextualChainId is false (source != SEND_FLOW || no contextual chain ID)
// 2. Non-EVM networks do NOT render when isContextualChainId is true (source == SEND_FLOW && contextual chain ID exists)
// This requires complex mocking of selectors that causes import chain issues

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: is this todo to be merged to main ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, this needs to be removed. Will do so here in a moment

jpuri
jpuri previously approved these changes Aug 11, 2025

@jpuri jpuri left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, code changes look good 👍

@github-actions

github-actions Bot commented Aug 11, 2025

Copy link
Copy Markdown
Contributor

https://bitrise.io/ Bitrise

❌❌❌ pr_smoke_e2e_pipeline failed on Bitrise! ❌❌❌

Commit hash: 5e82193
Build link: https://app.bitrise.io/app/be69d4368ee7e86d/pipelines/a6501a80-4573-41c5-a920-b25898a0843d

Note

  • You can rerun any failed steps by opening the Bitrise build, tapping Rebuild on the upper right then Rebuild unsuccessful Workflows
  • You can kick off another pr_smoke_e2e_pipeline on Bitrise by removing and re-applying the Run Smoke E2E label on the pull request

Tip

  • Check the documentation if you have any doubts on how to understand the failure on bitrise

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Network Mismatch in Contextual Send Flow

When the "Remove Global Network Selector" (contextual send flow) feature is enabled, AccountFromToInfoCard computes the correct chainId (contextual or global) but fails to pass it to AddressFrom. The AddressFrom component still receives an incorrect or undefined chainId because the prop is gated by isPerDappSelectedNetworkEnabled(). This leads to AddressFrom displaying the wrong network name/icon and balances on the confirm screen. The computed chainId should be passed to AddressFrom when the contextual feature is enabled.

app/components/UI/AccountFromToInfoCard/AccountFromToInfoCard.tsx#L183-L207

return (
<View style={styles.container}>
{fromAddress && (
<AddressFrom
chainId={
isPerDappSelectedNetworkEnabled()
? transactionState?.chainId
: undefined
}
asset={selectedAsset}
from={fromAddress}
origin={origin}
/>
)}
{existingToAddress === undefined && confusableCollection.length ? (
<TouchableOpacity onPress={() => setShowWarningModal(true)}>
{addressTo}
</TouchableOpacity>
) : (
addressTo
)}
<InfoModal
body={
<Text style={styles.text}>
{strings('transaction.confusable_msg')}

app/components/UI/AccountFromToInfoCard/AccountFromToInfoCard.tsx#L30-L50

const AccountFromToInfoCard = (props: AccountFromToInfoCardProps) => {
const {
internalAccounts,
ticker,
transactionState,
origin,
chainId: globalChainId,
contextualChainId,
} = props;
const {
transaction: { from: rawFromAddress, data, to },
transactionTo,
transactionFromName,
selectedAsset,
ensRecipient,
} = transactionState;
const chainId = isRemoveGlobalNetworkSelectorEnabled()
? contextualChainId || globalChainId
: globalChainId;
const fromAddress = toFormattedAddress(rawFromAddress);

Fix in Cursor Fix in Web

Comment thread app/components/UI/Navbar/index.js
Comment thread app/components/Views/confirmations/legacy/SendFlow/Confirm/index.js
Comment thread app/components/Views/confirmations/legacy/SendFlow/Confirm/index.js
@Prithpal-Sooriya

Copy link
Copy Markdown
Contributor

Sonar cloud coverage is skipped as we've added a decent amount of tests and coverage.
There will also be another PR that performs a large refactor and we can follow up with more tests after the refactor is in.

@github-actions

github-actions Bot commented Aug 11, 2025

Copy link
Copy Markdown
Contributor

https://bitrise.io/ Bitrise

✅✅✅ pr_smoke_e2e_pipeline passed on Bitrise! ✅✅✅

Commit hash: d21b070
Build link: https://app.bitrise.io/app/be69d4368ee7e86d/pipelines/ccf335ca-b255-4f0d-a32b-f37250da5469

Note

  • You can kick off another pr_smoke_e2e_pipeline on Bitrise by removing and re-applying the Run Smoke E2E label on the pull request

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Contextual Chain ID Not Passed to Address Component

When the contextual send flow is enabled (isRemoveGlobalNetworkSelectorEnabled), the AccountFromToInfoCard component computes a contextual chainId. However, this computed chainId is not passed to the AddressFrom component. AddressFrom consequently falls back to using the global chainId (based on isPerDappSelectedNetworkEnabled logic), causing the 'From' card to display the global network name and balance instead of the contextual network's information.

app/components/UI/AccountFromToInfoCard/AccountFromToInfoCard.tsx#L46-L50

const chainId = isRemoveGlobalNetworkSelectorEnabled()
? contextualChainId || globalChainId
: globalChainId;
const fromAddress = toFormattedAddress(rawFromAddress);

app/components/UI/AccountFromToInfoCard/AccountFromToInfoCard.tsx#L159-L179

const result = decodeTransferData('transfer', data) as string[];
toAddr = result[0];
}
if (toAddr) {
setToAddress(toAddr);
}
}, [data, fromAddress, selectedAsset, ticker, to]);
const addressTo = (
<AddressTo
addressToReady
confusableCollection={
(existingToAddress === undefined && confusableCollection) || []
}
displayExclamation={
existingToAddress === undefined && !!confusableCollection.length
}
isConfirmScreen
layout="vertical"
toAddressName={toAccountName}
toSelectedAddress={toAddress}

Fix in Cursor Fix in Web

: undefined
}
/>
),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Navbar Displays Hex Instead of Network Name

The getSendFlowTitle function has two issues:

  1. It passes sendFlowContextualChainId (a hex chain ID) as the networkName prop to NavbarTitle. When showSelectedNetwork is enabled, this incorrectly displays the hex chain ID instead of a human-readable network name in the header.
  2. It uses isRemoveGlobalNetworkSelectorEnabled() without importing the function, which will cause a ReferenceError or runtime crash.
Fix in Cursor Fix in Web

accounts: selectAccounts(state),
contractExchangeRates: selectContractExchangeRatesByChainId(state, chainId),
contractBalances: selectContractBalances(state),
contractBalancesByChainId: selectContractBalancesByContextualChainId(state),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Global Chain ID Misused in Send Flow

On the Confirm screen, when isRemoveGlobalNetworkSelectorEnabled is true, mapStateToProps incorrectly derives conversionRate, contractExchangeRates, ticker, and providerType using the global chainId instead of the sendFlowContextualChainId. This results in incorrect fiat conversions and network metadata being displayed.

Fix in Cursor Fix in Web

const currentNetworkClientId = isRemoveGlobalNetworkSelectorEnabled()
? NetworkController.findNetworkClientIdByChainId(chainId) ||
globalNetworkClientId
: globalNetworkClientId;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Network Selector Uses Incorrect Chain ID

When the contextual network selector feature is enabled, the addTransaction call in the Confirm component incorrectly derives the networkClientId from the global chainId instead of the sendFlowContextualChainId. This can result in transactions being submitted on the wrong network. The networkClientId should be resolved from the contextual chain configuration (e.g., sendFlowContextualNetworkConfiguration), similar to how getGasLimit is handled.

Fix in Cursor Fix in Web

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
71.3% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@github-actions

Copy link
Copy Markdown
Contributor

Hi @EtherWizard33,

on the day following feat or perf PR merge, PM and author to test changes on main (feature + exploratory around the edges) using the latest nightly build with casual user persona and also a power user persona where performance might be a challenge. Please record the testing in a video, check the relevant post-merge checklist box below, and post the video in a comment at the bottom of this PR.

Author validation checklist

  • Validated the changes in main branch using the nightly build
  • Video shared

PM validation checklist

  • Validated the changes in main branch using the nightly build
  • Video shared

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

external-contributor needs-validation Post merge validation No QA Needed Apply this label when your PR does not need any QA effort. release-7.54.0 Issue or pull request that will be included in release 7.54.0 Remove GNS size-XL skip-sonar-cloud Only used for bypassing sonar cloud when failures are not relevant to the changes. team-core-extension-ux Core Extension UX team

Projects

None yet

Development

Successfully merging this pull request may close these issues.