Skip to content

Commit 6b9f081

Browse files
authored
Merge branch 'main' into feat/musd-455-bring-back-claim-section-on-asset-details-screen
2 parents 3992198 + 27cc72a commit 6b9f081

33 files changed

Lines changed: 4131 additions & 115 deletions

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ scripts/build.sh @MetaMask/mobile-pla
4747
fingerprint.config.js @MetaMask/mobile-platform
4848
builds.yml @MetaMask/mobile-platform
4949
.github/workflows/push-eas-update.yml @MetaMask/mobile-admins
50+
.github/workflows/upload-to-testflight.yml @MetaMask/mobile-admins
5051
scripts/update-expo-channel.js @MetaMask/mobile-admins
5152
certs/certificate.pem @MetaMask/mobile-admins
5253
ios/fastlane/ @MetaMask/mobile-admins

.github/workflows/build.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ on:
1313
required: false
1414
type: boolean
1515
default: false
16+
source_branch:
17+
description: 'Branch, tag, or SHA to build'
18+
required: false
19+
type: string
20+
default: ''
1621
ref:
1722
description: 'Git ref to checkout when skip_version_bump is true. Defaults to the triggering event ref.'
1823
required: false
@@ -60,7 +65,7 @@ jobs:
6065
contents: write
6166
id-token: write
6267
with:
63-
base-branch: ${{ github.ref_name }}
68+
base-branch: ${{ inputs.source_branch != '' && inputs.source_branch || github.ref_name }}
6469
secrets:
6570
PR_TOKEN: ${{ secrets.PR_TOKEN }}
6671

@@ -75,8 +80,12 @@ jobs:
7580
signing_aws_role: ${{ steps.config.outputs.signing_aws_role }}
7681
signing_aws_secret: ${{ steps.config.outputs.signing_aws_secret }}
7782
signing_android_keystore_path: ${{ steps.config.outputs.signing_android_keystore_path }}
83+
checkout_ref_for_setup: ${{ !inputs.skip_version_bump && needs.update-build-version.outputs.commit-hash || (inputs.source_branch != '' && inputs.source_branch || github.ref_name) }}
7884
steps:
7985
- uses: actions/checkout@v4
86+
with:
87+
fetch-depth: 0
88+
ref: ${{ !inputs.skip_version_bump && needs.update-build-version.outputs.commit-hash || (inputs.source_branch != '' && inputs.source_branch || github.ref_name) }}
8089
- name: Setup Node.js
8190
uses: actions/setup-node@v4
8291
with:
@@ -110,6 +119,8 @@ jobs:
110119
platform: ${{ inputs.platform == 'both' && fromJSON('["android", "ios"]') || fromJSON(format('["{0}"]', inputs.platform)) }}
111120
uses: ./.github/workflows/setup-node-modules.yml
112121
with:
122+
ref: ${{ needs.prepare.outputs.checkout_ref_for_setup }}
123+
fetch-depth: 0
113124
checkout-submodules: true
114125
platform: ${{ matrix.platform }}
115126
build_name: ${{ inputs.build_name }}

.github/workflows/expo-dev-build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ on:
2020
workflow_dispatch:
2121

2222
permissions:
23-
contents: read
23+
contents: write
2424
id-token: write
2525

2626
jobs:

.github/workflows/generate-rc-test-plan.yml

Lines changed: 367 additions & 0 deletions
Large diffs are not rendered by default.

.github/workflows/upload-to-testflight.yml

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ name: Upload to TestFlight
66
on:
77
workflow_dispatch:
88
inputs:
9+
source_branch:
10+
description: 'Branch, tag, or SHA to build'
11+
required: true
12+
type: string
13+
default: 'main'
914
environment:
1015
description: 'Build environment / track'
1116
required: true
@@ -38,6 +43,7 @@ jobs:
3843
build_name: main-${{ inputs.environment || 'rc' }}
3944
platform: ios
4045
skip_version_bump: false
46+
source_branch: ${{ inputs.source_branch }}
4147
secrets: inherit
4248

4349
testflight-upload-summary:
@@ -48,6 +54,7 @@ jobs:
4854
- uses: actions/checkout@v4
4955
with:
5056
fetch-depth: 0
57+
ref: ${{ inputs.source_branch }}
5158
- name: Display TestFlight upload summary
5259
run: |
5360
BUILD_VERSION=$(node -p "require('./package.json').version")
@@ -56,18 +63,19 @@ jobs:
5663
echo ""
5764
echo "| Field | Value |"
5865
echo "| --- | --- |"
66+
echo "| **Workflow ref** | ${{ github.ref_name }} (required for AWS) |"
67+
echo "| **Source branch** | ${{ inputs.source_branch }} |"
5968
echo "| **Build name** | main-${{ inputs.environment || 'rc' }} |"
6069
echo "| **Build version** | ${BUILD_VERSION} |"
6170
echo "| **TestFlight group** | ${{ inputs.testflight_group || 'MetaMask BETA & Release Candidates' }} |"
62-
echo "| **Branch** | ${{ github.ref_name }} |"
6371
} >> "$GITHUB_STEP_SUMMARY"
6472
65-
# Uses GitHub Environment "apple" for App Store Connect API secrets.
73+
# Pulls App Store Connect API keys from AWS Secrets Manager (OIDC).
74+
# Workflow must run from main; build uses inputs.source_branch.
6675
upload-ios-testflight:
6776
name: Upload iOS to TestFlight
6877
needs: [build, testflight-upload-summary]
6978
runs-on: ghcr.io/cirruslabs/macos-runner:sequoia-xl
70-
environment: apple
7179
steps:
7280
- name: Checkout repository
7381
uses: actions/checkout@v4
@@ -97,22 +105,63 @@ jobs:
97105
case "$IPA" in /*) ABS="$IPA" ;; *) ABS="$PWD/$IPA" ;; esac
98106
echo "path=$ABS" >> "$GITHUB_OUTPUT"
99107
108+
- name: Configure AWS credentials
109+
uses: aws-actions/configure-aws-credentials@v4
110+
with:
111+
role-to-assume: ${{ secrets.AWS_ROLE_APPLE_TESTFLIGHT }}
112+
aws-region: 'us-east-2'
113+
114+
- name: Fetch Apple API keys from AWS Secrets Manager
115+
run: |
116+
echo "🔐 Fetching App Store Connect API keys from Secrets Manager..."
117+
secret_id="metamask-mobile-main-apple-api-keys"
118+
secret_json=$(aws secretsmanager get-secret-value \
119+
--region 'us-east-2' \
120+
--secret-id "$secret_id" \
121+
--query SecretString \
122+
--output text)
123+
124+
for key in APP_STORE_CONNECT_API_KEY_ISSUER_ID APP_STORE_CONNECT_API_KEY_KEY_ID; do
125+
value=$(echo "$secret_json" | jq -r --arg k "$key" '.[$k] // empty')
126+
if [ -z "$value" ]; then
127+
echo "::error::Missing key in secret: $key"
128+
exit 1
129+
fi
130+
echo "::add-mask::$value"
131+
echo "${key}=${value}" >> "$GITHUB_ENV"
132+
done
133+
134+
key=APP_STORE_CONNECT_API_KEY_KEY_CONTENT
135+
value=$(echo "$secret_json" | jq -r --arg k "$key" '.[$k] // empty')
136+
if [ -z "$value" ]; then
137+
echo "::error::Missing key in secret: $key"
138+
exit 1
139+
fi
140+
while IFS= read -r line || [ -n "$line" ]; do
141+
[ -n "$line" ] && echo "::add-mask::$line"
142+
done <<< "$(printf '%s\n' "$value")"
143+
144+
delim="APPLEP8$(openssl rand -hex 16)"
145+
{
146+
printf '%s<<%s\n' "$key" "$delim"
147+
printf '%s\n' "$value"
148+
printf '%s\n' "$delim"
149+
} >> "$GITHUB_ENV"
150+
151+
echo "✅ Apple API keys loaded from AWS"
152+
100153
- name: Setup App Store Connect API Key
101154
run: |
102155
bash scripts/setup-app-store-connect-api-key.sh \
103156
"$APP_STORE_CONNECT_API_KEY_ISSUER_ID" \
104157
"$APP_STORE_CONNECT_API_KEY_KEY_ID" \
105158
"$APP_STORE_CONNECT_API_KEY_KEY_CONTENT"
106-
env:
107-
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
108-
APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY_ID }}
109-
APP_STORE_CONNECT_API_KEY_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY_CONTENT }}
110159
111160
- name: Upload to TestFlight
112161
run: |
113162
bash scripts/upload-to-testflight.sh \
114163
"github_actions_main-${{ inputs.environment || 'rc' }}" \
115-
"${{ github.ref_name }}" \
164+
"${{ inputs.source_branch }}" \
116165
"${{ steps.ipa.outputs.path }}" \
117166
"${{ inputs.testflight_group || 'MetaMask BETA & Release Candidates' }}"
118167

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,3 +185,8 @@ temp/
185185
tests/coverage-systems/
186186

187187
runway-artifacts/
188+
189+
# E2E AI Analyzer output files
190+
release-test-plan.json
191+
release-delta.json
192+
release-signoffs.json
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
diff --git a/dist/TokenBalancesController.cjs b/dist/TokenBalancesController.cjs
2+
index 8df3058aea9bd28aaabe1d09f8c3b38fa5949600..39468505fed9c6776a193917fed0cea73de65c23 100644
3+
--- a/dist/TokenBalancesController.cjs
4+
+++ b/dist/TokenBalancesController.cjs
5+
@@ -805,18 +805,30 @@ async function _TokenBalancesController_importUntrackedTokens(balances) {
6+
if (!changes.length) {
7+
return;
8+
}
9+
- const chainConfigs = {};
10+
- for (const [chainId, status] of changes) {
11+
- const hexChainId = (0, exports.caipChainIdToHex)(chainId);
12+
- chainConfigs[hexChainId] =
13+
- status === 'down'
14+
- ? { interval: __classPrivateFieldGet(this, _TokenBalancesController_defaultInterval, "f") }
15+
- : { interval: __classPrivateFieldGet(this, _TokenBalancesController_websocketActivePollingInterval, "f") };
16+
- }
17+
- const jitterDelay = Math.random() * __classPrivateFieldGet(this, _TokenBalancesController_defaultInterval, "f");
18+
- setTimeout(() => {
19+
- this.updateChainPollingConfigs(chainConfigs, { immediateUpdate: true });
20+
- }, jitterDelay);
21+
+ try {
22+
+ const chainConfigs = {};
23+
+ for (const [chainId, status] of changes) {
24+
+ if ((0, utils_1.isCaipChainId)(chainId) &&
25+
+ (0, utils_1.parseCaipChainId)(chainId).namespace !== 'eip155') {
26+
+ continue;
27+
+ }
28+
+ const hexChainId = (0, exports.caipChainIdToHex)(chainId);
29+
+ chainConfigs[hexChainId] =
30+
+ status === 'down'
31+
+ ? { interval: __classPrivateFieldGet(this, _TokenBalancesController_defaultInterval, "f") }
32+
+ : { interval: __classPrivateFieldGet(this, _TokenBalancesController_websocketActivePollingInterval, "f") };
33+
+ }
34+
+ if (Object.keys(chainConfigs).length === 0) {
35+
+ return;
36+
+ }
37+
+ const jitterDelay = Math.random() * __classPrivateFieldGet(this, _TokenBalancesController_defaultInterval, "f");
38+
+ setTimeout(() => {
39+
+ this.updateChainPollingConfigs(chainConfigs, { immediateUpdate: true });
40+
+ }, jitterDelay);
41+
+ }
42+
+ catch (error) {
43+
+ console.warn('Error processing accumulated status changes:', error);
44+
+ }
45+
};
46+
exports.default = TokenBalancesController;
47+
//# sourceMappingURL=TokenBalancesController.cjs.map
48+
\ No newline at end of file

app/components/UI/Tokens/TokenList/TokenList.tsx

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import React, {
22
useCallback,
3-
useLayoutEffect,
43
useRef,
54
useMemo,
65
useEffect,
@@ -84,10 +83,6 @@ const TokenListComponent = ({
8483
const navigation = useNavigation();
8584
const { trackEvent, createEventBuilder } = useAnalytics();
8685

87-
useLayoutEffect(() => {
88-
listRef.current?.recomputeViewableItems();
89-
}, [isTokenNetworkFilterEqualCurrentNetwork]);
90-
9186
// Apply maxItems limit if specified
9287
const displayTokenKeys = useMemo(
9388
() => (tokenKeys || []).slice(0, maxItems || undefined),

app/core/HardwareWallet/components/HardwareWalletBottomSheet/contents/ConnectingContent.test.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,19 +57,18 @@ describe('ConnectingContent', () => {
5757
expect(getByTestId(CONNECTING_CONTENT_TEST_ID)).toBeOnTheScreen();
5858
});
5959

60-
it('renders activity indicator', () => {
60+
it('renders spinner', () => {
6161
const { getByTestId } = renderComponent();
6262

6363
expect(getByTestId(CONNECTING_CONTENT_SPINNER_TEST_ID)).toBeOnTheScreen();
6464
});
6565

66-
it('renders tips', () => {
66+
it('renders connection tips', () => {
6767
const { getByText } = renderComponent();
6868

6969
expect(
7070
getByText('hardware_wallet.connecting.tips_header'),
7171
).toBeOnTheScreen();
72-
// All tips are rendered with { device: deviceName } interpolation params
7372
expect(
7473
getByText(/hardware_wallet\.connecting\.tip_unlock/),
7574
).toBeOnTheScreen();
@@ -79,8 +78,5 @@ describe('ConnectingContent', () => {
7978
expect(
8079
getByText(/hardware_wallet\.connecting\.tip_enable_bluetooth/),
8180
).toBeOnTheScreen();
82-
expect(
83-
getByText(/hardware_wallet\.connecting\.tip_dnd_off/),
84-
).toBeOnTheScreen();
8581
});
8682
});

0 commit comments

Comments
 (0)