Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6d2ff1b
fix: Improve URL detection in `SitesSearchFooter` (#30801)
FrederikBolding Jun 1, 2026
321590f
refactor: enhance UI spacing in various components for improved layou…
PatrykLucka Jun 1, 2026
da9ed39
chore: handle optional RelatedAsset fields after ai-controllers updat…
zone-live Jun 1, 2026
df1afd8
chore: bump assets controller v8.1.0 (#30836)
salimtb Jun 1, 2026
d1b6346
fix(agentic): fixture account setup (#30750)
abretonc7s Jun 1, 2026
13349a0
fix: cp-7.80.0 prevent send flow from submitting to zero address afte…
OGPoyraz Jun 1, 2026
9491d92
fix(perps): fix leverage pill display on SPCX market page when access…
abretonc7s Jun 1, 2026
df7d393
feat: add on_create trigger mode to triage forwarder (#30727)
OGPoyraz Jun 1, 2026
51b5e2c
fix: add token to `AssetsController` when `assetsUnifyState` is enabl…
OGPoyraz Jun 1, 2026
45668fd
fix: fix warning display on missing symbols (#30811)
sahar-fehri Jun 1, 2026
fa851e7
fix(metamask-pay): cp-7.80.0 use latest on-chain nonce for EIP-7702 a…
matthewwalsh0 Jun 1, 2026
21d192a
chore: QuickBuy, add high price impact warnings (#30788)
zone-live Jun 1, 2026
1d8c326
feat(onboarding): preselect ramp asset on wallet home fund step (TMCU…
wachunei Jun 1, 2026
942d766
fix: lock Quick Buy bottom sheet height to prevent layout shift (#30853)
xavier-brochard Jun 1, 2026
21bb94f
test: performance, reduce DOM complexity and improve navigation for p…
javiergarciavera Jun 1, 2026
14486dc
ci: Update `add-team-label` and `check-template-and-add-labels` workf…
Mrtenz Jun 1, 2026
e0ac448
refactor(analytics): PR E3 migrate AccountBackupStep1 to useAnalytics…
NicolasMassart Jun 1, 2026
13f5030
fix: auto-select fiat payment method for supported transaction types …
OGPoyraz Jun 1, 2026
aa57ae9
ci: Add temporary fallback to Patroll token in `check-template-and-ad…
Mrtenz Jun 1, 2026
1ecd8b0
chore: assets controllers (#30848)
bergarces Jun 1, 2026
4a1ec82
chore(predict): build predict positions screen route with positions a…
caieu Jun 1, 2026
fb5a689
fix: Clear Predict claim on back dismissal (#30761)
pedronfigueiredo Jun 1, 2026
eacbd59
chore: add gainers and losers section in Explore/Now (#30837)
juanmigdr Jun 1, 2026
02c85c2
feat: add world cup predictions in explore (FF gated) (#30854)
juanmigdr Jun 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion .github/workflows/add-team-label.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,29 @@ jobs:
name: Add team label
if: ${{ !github.event.pull_request.head.repo.fork }}
runs-on: ubuntu-latest
permissions:
id-token: write
steps:
- name: Get planning token
id: planning-token
uses: MetaMask/github-tools/.github/actions/get-token@v1
with:
token-exchange-url: ${{ vars.TOKEN_EXCHANGE_URL }}
target-repository: MetaMask/MetaMask-planning
permissions: |
contents: read

- name: Get label token
id: label-token
uses: MetaMask/github-tools/.github/actions/get-token@v1
with:
token-exchange-url: ${{ vars.TOKEN_EXCHANGE_URL }}
permissions: |
contents: read
pull_requests: write

- name: Add team label
uses: MetaMask/github-tools/.github/actions/add-team-label@v1
with:
team-label-token: ${{ secrets.TEAM_LABEL_TOKEN }}
planning-token: ${{ steps.planning-token.outputs.token }}
team-label-token: ${{ steps.label-token.outputs.token }}
16 changes: 15 additions & 1 deletion .github/workflows/check-template-and-add-labels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ jobs:
runs-on: ubuntu-latest
needs: [is-fork-pull-request]
if: ${{ always() && github.event_name != 'merge_group' && (github.event_name == 'issues' || (github.event_name == 'pull_request_target' && needs.is-fork-pull-request.outputs.IS_FORK == 'false')) }}
permissions:
contents: read
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
Expand All @@ -46,9 +49,20 @@ jobs:
retry_wait_seconds: 30
command: cd .github/scripts && yarn --immutable

- name: Get access token
id: get-token
uses: MetaMask/github-tools/.github/actions/get-token@v1
continue-on-error: true
with:
token-exchange-url: ${{ vars.TOKEN_EXCHANGE_URL }}
permissions: |
issues: write
members: read
pull_requests: write

- name: Check template and add labels
id: check-template-and-add-labels
env:
LABEL_TOKEN: ${{ secrets.LABEL_TOKEN }}
LABEL_TOKEN: ${{ steps.get-token.outputs.token || secrets.LABEL_TOKEN }}
run: npm run check-template-and-add-labels
working-directory: '.github/scripts'
18 changes: 13 additions & 5 deletions .github/workflows/performance-test-runner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@ on:
required: false
type: string
default: e2e
description: 'Build variant for app artifacts (e2e, rc, or exp)'
description: 'Deprecated for env; kept for workflow_call compatibility. Use feature_flags_environment for client-config API.'
feature_flags_environment:
required: false
type: string
default: rc
description: 'client-config API environment (rc, exp, test). Independent of BrowserStack build_variant.'
secrets:
BROWSERSTACK_USERNAME:
required: true
Expand All @@ -58,6 +63,8 @@ on:
required: true
TEST_SRP_3:
required: true
TEST_SRP_4:
required: true
E2E_PASSWORD:
required: true
MM_SENTRY_DSN_TEST:
Expand Down Expand Up @@ -170,10 +177,10 @@ jobs:
SENTRY_REAL_DSN="${{ secrets.MM_SENTRY_DSN }}"
SELECTED_SENTRY_DSN=""
SENTRY_ENVIRONMENT="github-actions-performance-e2e"
BUILD_VARIANT="${{ inputs.build_variant }}"
FEATURE_FLAGS_ENV="${{ inputs.feature_flags_environment }}"

if [[ "$BUILD_VARIANT" != "rc" && "$BUILD_VARIANT" != "exp" && "$BUILD_VARIANT" != "e2e" ]]; then
echo "❌ Invalid build_variant '$BUILD_VARIANT'. Expected 'e2e', 'rc', or 'exp'."
if [[ "$FEATURE_FLAGS_ENV" != "rc" && "$FEATURE_FLAGS_ENV" != "exp" && "$FEATURE_FLAGS_ENV" != "test" && "$FEATURE_FLAGS_ENV" != "dev" && "$FEATURE_FLAGS_ENV" != "prod" ]]; then
echo "❌ Invalid feature_flags_environment '$FEATURE_FLAGS_ENV'. Expected rc, exp, test, dev, or prod."
exit 1
fi

Expand Down Expand Up @@ -219,11 +226,12 @@ jobs:
echo "TEST_SRP_1=${{ secrets.TEST_SRP_1 }}"
echo "TEST_SRP_2=${{ secrets.TEST_SRP_2 }}"
echo "TEST_SRP_3=${{ secrets.TEST_SRP_3 }}"
echo "TEST_SRP_4=${{ secrets.TEST_SRP_4 }}"
echo "E2E_PASSWORD=${{ secrets.E2E_PASSWORD }}"
echo "E2E_PERFORMANCE_SENTRY_DSN=$SELECTED_SENTRY_DSN"
echo "E2E_PERFORMANCE_SENTRY_ENVIRONMENT=$SENTRY_ENVIRONMENT"
echo "E2E_PERFORMANCE_SENTRY_RELEASE=${{ github.sha }}"
echo "E2E_PERFORMANCE_BUILD_VARIANT=$BUILD_VARIANT"
echo "E2E_PERFORMANCE_BUILD_VARIANT=$FEATURE_FLAGS_ENV"
echo "DISABLE_VIDEO_DOWNLOAD=true"
} >> "$GITHUB_ENV"

Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/run-performance-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ on:
required: false
type: string
build_variant:
description: 'Build variant (e2e = e2e environment, exp = experimental, rc = release)'
description: 'BrowserStack build profile (e2e = build-e2e, works on feature branches; rc = build-rc, release branches only; exp = experimental)'
required: false
type: string
default: 'e2e'
Expand All @@ -97,6 +97,7 @@ env:
TEST_SRP_1: ${{ secrets.TEST_SRP_1 }}
TEST_SRP_2: ${{ secrets.TEST_SRP_2 }}
TEST_SRP_3: ${{ secrets.TEST_SRP_3 }}
TEST_SRP_4: ${{ secrets.TEST_SRP_4 }}
E2E_PASSWORD: ${{ secrets.E2E_PASSWORD }}
DISABLE_VIDEO_DOWNLOAD: true

Expand Down Expand Up @@ -216,6 +217,7 @@ jobs:
uses: ./.github/workflows/build-ios-upload-to-browserstack.yml
needs: [determine-branch-name]
if: false # temporarily disabled — iOS tests not yet active
# if: (!inputs.browserstack_app_url_ios_onboarding && !inputs.browserstack_app_url_ios_imported_wallet)
with:
branch_name: ${{ needs.determine-branch-name.outputs.branch_name }}
build_variant: ${{ inputs.build_variant || 'e2e' }}
Expand Down Expand Up @@ -259,6 +261,7 @@ jobs:
determine-branch-name,
]
if: false # temporarily disabled — Android only
# if: always() && !failure() && !cancelled() && (needs.trigger-ios-dual-versions.result == 'skipped' || needs.trigger-ios-dual-versions.result == 'success') && (inputs.browserstack_app_url_ios_onboarding != '' || needs.trigger-ios-dual-versions.outputs.without-srp-browserstack-url != '')
with:
platform: ios
build_type: onboarding
Expand Down Expand Up @@ -322,6 +325,7 @@ jobs:
determine-branch-name,
]
if: false # temporarily disabled — Android only
# if: always() && !cancelled() && (needs.trigger-ios-dual-versions.result == 'skipped' || needs.trigger-ios-dual-versions.result == 'success') && (inputs.browserstack_app_url_ios_imported_wallet != '' || needs.trigger-ios-dual-versions.outputs.with-srp-browserstack-url != '')
with:
platform: ios
build_type: imported-wallet
Expand Down
49 changes: 46 additions & 3 deletions .github/workflows/triage-forwarder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ name: Triage Agent Forwarder

on:
issues:
types: [labeled]
types: [labeled, opened]

jobs:
forward:
forward-labeled:
runs-on: ubuntu-latest
if: github.event.label.name == 'ta-needs-triage'
if: github.event.action == 'labeled' && github.event.label.name == 'ta-needs-triage'
permissions:
id-token: write
steps:
Expand Down Expand Up @@ -49,3 +49,46 @@ jobs:
--arg action "${{ github.event.action }}" \
--arg label "${{ github.event.label.name }}" \
'{event_type: "triage-issue", client_payload: {repo_owner: $owner, repo_name: $name, issue_number: $number, event_action: $action, event_label_name: $label, trigger_mode: "label"}}')"

forward-opened:
runs-on: ubuntu-latest
if: github.event.action == 'opened'
permissions:
id-token: write
steps:
- name: Get OIDC Token
id: oidc
run: |
OIDC_TOKEN=$(curl -sSf -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=api://token-exchange-service" | jq -r '.value')
echo "::add-mask::$OIDC_TOKEN"
echo "oidc_token=$OIDC_TOKEN" >> "$GITHUB_OUTPUT"

- name: Exchange for Installation Token
id: exchange
env:
OIDC_TOKEN: ${{ steps.oidc.outputs.oidc_token }}
run: |
RESPONSE=$(curl -sSf -X POST "${{ vars.TOKEN_EXCHANGE_URL }}/api/exchange/token" \
-H "Content-Type: application/json" \
-d "$(jq -cn \
--arg oidcToken "$OIDC_TOKEN" \
--arg targetRepo "MetaMask/triage-agent" \
'{oidcToken: $oidcToken, targetRepo: $targetRepo, requested_permissions: {contents: "write", metadata: "read"}}')")
TOKEN=$(echo "$RESPONSE" | jq -r '.token')
echo "::add-mask::$TOKEN"
echo "token=$TOKEN" >> "$GITHUB_OUTPUT"

- name: Dispatch to triage-agent
env:
TOKEN: ${{ steps.exchange.outputs.token }}
run: |
curl -sSf -X POST \
-H "Authorization: token $TOKEN" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/MetaMask/triage-agent/dispatches" \
-d "$(jq -cn \
--arg owner "${{ github.repository_owner }}" \
--arg name "${{ github.event.repository.name }}" \
--arg number "${{ github.event.issue.number }}" \
'{event_type: "triage-issue", client_payload: {repo_owner: $owner, repo_name: $name, issue_number: $number, event_action: "opened", trigger_mode: "on_create"}}')"
Original file line number Diff line number Diff line change
Expand Up @@ -3552,6 +3552,172 @@ describe('PerpsMarketDetailsView', () => {
expect(getAllByText('ETH-USD').length).toBeGreaterThanOrEqual(1);
});

it('enriches market data when route maxLeverage is unformatted', async () => {
mockRouteParams.market = {
symbol: 'xyz:SPCX',
name: 'SPCX',
price: '$0.00',
change24h: '+$0.00',
change24hPercent: '+0.00%',
volume: '$0',
maxLeverage: '100',
};

mockUsePerpsMarketsImpl.mockImplementation(() => ({
markets: [
{
symbol: 'xyz:SPCX',
name: 'SPCX',
price: '$0.00',
change24h: '+$0.00',
change24hPercent: '+0.00%',
volume: '$0',
maxLeverage: '5x',
volumeNumber: 0,
},
],
isLoading: false,
error: null,
refresh: jest.fn(),
isRefreshing: false,
}));

const { getByText, queryByText } = renderWithProvider(
<PerpsConnectionProvider>
<PerpsMarketDetailsView />
</PerpsConnectionProvider>,
{
state: initialState,
},
);

await waitFor(() => {
expect(getByText('5x')).toBeOnTheScreen();
});
expect(queryByText('100')).toBeNull();
});

it('passes enriched SPCX leverage defaults to order screen', async () => {
const { usePerpsMarketData } = jest.requireMock('../../hooks');
mockRouteParams.market = {
symbol: 'xyz:SPCX',
name: 'SPCX',
price: '$0.00',
change24h: '+$0.00',
change24hPercent: '+0.00%',
volume: '$0',
maxLeverage: '100',
};

mockUsePerpsMarketsImpl.mockImplementation(() => ({
markets: [
{
symbol: 'xyz:SPCX',
name: 'SPCX',
price: '$0.00',
change24h: '+$0.00',
change24hPercent: '+0.00%',
volume: '$0',
maxLeverage: '5x',
volumeNumber: 0,
},
],
isLoading: false,
error: null,
refresh: jest.fn(),
isRefreshing: false,
}));
usePerpsMarketData.mockReturnValue({
marketData: { szDecimals: 2, maxLeverage: 5 },
isLoading: false,
error: null,
refetch: jest.fn(),
});

try {
const { getByTestId, getByText } = renderWithProvider(
<PerpsConnectionProvider>
<PerpsMarketDetailsView />
</PerpsConnectionProvider>,
{
state: initialState,
},
);

await waitFor(() => {
expect(getByText('5x')).toBeOnTheScreen();
});

await act(async () => {
fireEvent.press(
getByTestId(PerpsMarketDetailsViewSelectorsIDs.LONG_BUTTON),
);
});

expect(mockNavigateToOrder).toHaveBeenCalledWith(
expect.objectContaining({
asset: 'xyz:SPCX',
defaultMaxLeverage: 5,
defaultSzDecimals: 2,
direction: 'long',
source: 'perp_asset_screen',
}),
);
} finally {
usePerpsMarketData.mockReturnValue({
marketData: null,
isLoading: false,
error: null,
refetch: jest.fn(),
});
}
});

it('enriches unformatted route market without market source', async () => {
mockRouteParams.market = {
symbol: 'SPCX',
name: 'SPCX',
price: '$0.00',
change24h: '+$0.00',
change24hPercent: '+0.00%',
volume: '$0',
maxLeverage: '100',
};

mockUsePerpsMarketsImpl.mockImplementation(() => ({
markets: [
{
symbol: 'SPCX',
name: 'SPCX',
price: '$0.00',
change24h: '+$0.00',
change24hPercent: '+0.00%',
volume: '$0',
maxLeverage: '5x',
volumeNumber: 0,
},
],
isLoading: false,
error: null,
refresh: jest.fn(),
isRefreshing: false,
}));

const { getByText, queryByText } = renderWithProvider(
<PerpsConnectionProvider>
<PerpsMarketDetailsView />
</PerpsConnectionProvider>,
{
state: initialState,
},
);

await waitFor(() => {
expect(getByText('5x')).toBeOnTheScreen();
});
expect(queryByText('100')).toBeNull();
});

it('enriches market data from usePerpsMarkets when route has minimal data', async () => {
// Route has minimal market data (no maxLeverage)
mockRouteParams.market = {
Expand Down
Loading
Loading