Copy disabled (too large)
Download .txt
Showing preview only (24,557K chars total). Download the full file to get everything.
Repository: safe-global/web-core
Branch: dev
Commit: c32b790cabd0
Files: 5930
Total size: 22.0 MB
Directory structure:
gitextract_0zone9s6/
├── .claude/
│ ├── commands/
│ │ ├── speckit.analyze.md
│ │ ├── speckit.checklist.md
│ │ ├── speckit.clarify.md
│ │ ├── speckit.constitution.md
│ │ ├── speckit.implement.md
│ │ ├── speckit.plan.md
│ │ ├── speckit.specify.md
│ │ ├── speckit.tasks.md
│ │ └── speckit.taskstoissues.md
│ └── skills/
│ ├── cypress-e2e/
│ │ └── SKILL.md
│ ├── design.figma-to-code/
│ │ ├── SKILL.md
│ │ └── reference.md
│ ├── design.prototype/
│ │ └── SKILL.md
│ ├── design.sync-component/
│ │ └── SKILL.md
│ ├── design.sync-variables/
│ │ └── SKILL.md
│ └── design.verify/
│ └── SKILL.md
├── .codescene.yml
├── .cursor/
│ └── rules/
│ ├── cypress-e2e.mdc
│ └── safe-monorepo.mdc
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug-report.md
│ │ ├── feature-request.md
│ │ ├── task.md
│ │ └── tech-debt.md
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── actions/
│ │ ├── branch-slug/
│ │ │ └── action.yml
│ │ ├── build/
│ │ │ └── action.yml
│ │ ├── build-storybook/
│ │ │ └── action.yml
│ │ ├── cache-deps/
│ │ │ └── action.yml
│ │ ├── corepack/
│ │ │ └── action.yml
│ │ ├── cypress/
│ │ │ └── action.yml
│ │ ├── upload-coverage/
│ │ │ └── action.yml
│ │ ├── upload-to-storage-branch/
│ │ │ └── action.yml
│ │ └── yarn/
│ │ └── action.yml
│ ├── dependabot.yml
│ ├── scripts/
│ │ ├── capture-mobile-screenshots.js
│ │ ├── capture-page-screenshots.js
│ │ ├── capture-web-storybook-screenshots.js
│ │ ├── generate-mobile-story-urls.js
│ │ ├── generate-web-story-urls.js
│ │ ├── map-files-to-routes.js
│ │ └── publish/
│ │ ├── download-artifact.js
│ │ ├── post-comment.js
│ │ └── resolve-pr.js
│ └── workflows/
│ ├── claude-code-review.yml
│ ├── mobile-checks.yml
│ ├── mobile-dev-release.yml
│ ├── mobile-e2e.yml
│ ├── mobile-storybook-screenshots.yml
│ ├── mobile-unit-tests.yml
│ ├── package-utils-unit-tests.yml
│ ├── page-screenshots-build.yml
│ ├── page-screenshots-publish.yml
│ ├── store-codegen-check.yml
│ ├── store-codegen-drift.yml
│ ├── tx-builder-checks.yml
│ ├── tx-builder-deploy.yml
│ ├── web-argos-e2e.yml
│ ├── web-checks.yml
│ ├── web-chromatic.yml
│ ├── web-deploy-dev.yml
│ ├── web-deploy-dockerhub.yml
│ ├── web-e2e-full-ondemand.yml
│ ├── web-e2e-hp-ondemand.yml
│ ├── web-e2e-prod-ondemand.yml
│ ├── web-e2e-smoke.yml
│ ├── web-nextjs-bundle-analysis.yml
│ ├── web-release-start.yml
│ ├── web-storybook-screenshots-build.yml
│ ├── web-storybook-screenshots-publish.yml
│ ├── web-storybook-tests.yml
│ ├── web-tag-release.yml
│ └── web-unit-tests.yml
├── .gitignore
├── .husky/
│ ├── commit-msg
│ ├── pre-commit
│ └── pre-push
├── .lintstagedrc.mjs
├── .nvmrc
├── .prettierignore
├── .prettierrc
├── .specify/
│ ├── memory/
│ │ └── constitution.md
│ ├── scripts/
│ │ └── bash/
│ │ ├── check-prerequisites.sh
│ │ ├── common.sh
│ │ ├── create-new-feature.sh
│ │ ├── setup-plan.sh
│ │ └── update-agent-context.sh
│ └── templates/
│ ├── agent-file-template.md
│ ├── checklist-template.md
│ ├── plan-template.md
│ ├── spec-template.md
│ └── tasks-template.md
├── .vscode/
│ └── settings.json
├── .yarn/
│ └── patches/
│ ├── @tamagui-image-npm-2.0.0-rc.26-04087a216c.patch
│ ├── next-npm-15.5.8-7d525d02b9.patch
│ ├── react-native-ble-plx+3.5.0.patch
│ ├── react-native-device-crypto-npm-0.1.7-dbd2698fc4.patch
│ ├── react-native-npm-0.83.4-77634a290c.patch
│ └── react-native-qrcode-styled-npm-0.3.3-b5336fc77c.patch
├── .yarnrc.yml
├── AGENTS.md
├── CLAUDE.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── README.md
├── apps/
│ ├── mobile/
│ │ ├── .eas/
│ │ │ └── build/
│ │ │ └── build-and-maestro-test.yml
│ │ ├── .easignore
│ │ ├── .gitignore
│ │ ├── .storybook/
│ │ │ ├── index.ts
│ │ │ ├── main.ts
│ │ │ ├── mocks/
│ │ │ │ ├── expo-fast-refresh.js
│ │ │ │ ├── react-native-quick-crypto.js
│ │ │ │ ├── react-native-reanimated.js
│ │ │ │ ├── react-native-worklets/
│ │ │ │ │ ├── index.js
│ │ │ │ │ └── package.json
│ │ │ │ └── react-refresh.js
│ │ │ ├── preview.tsx
│ │ │ ├── storybook.requires.d.ts
│ │ │ └── tsconfig.json
│ │ ├── AGENTS.md
│ │ ├── README.md
│ │ ├── __mocks__/
│ │ │ ├── fileMock.js
│ │ │ ├── react-native-capture-protection.js
│ │ │ └── react-native-collapsible-tab-view.tsx
│ │ ├── app.config.ts
│ │ ├── assets/
│ │ │ ├── android/
│ │ │ │ └── drawable/
│ │ │ │ ├── baseline_arrow_outward_24.xml
│ │ │ │ ├── baseline_auto_awesome_motion_24.xml
│ │ │ │ ├── baseline_content_copy_24.xml
│ │ │ │ ├── baseline_create_24.xml
│ │ │ │ ├── baseline_delete_24.xml
│ │ │ │ ├── baseline_explore_24.xml
│ │ │ │ └── ic_notification.xml
│ │ │ └── fonts/
│ │ │ └── safe-icons/
│ │ │ └── safe-icons.icomoon.json
│ │ ├── babel.config.js
│ │ ├── docs/
│ │ │ ├── analytics.md
│ │ │ ├── code-style.md
│ │ │ ├── e2e-tests-guidelines.md
│ │ │ ├── push-notifications.md
│ │ │ └── release-procedure.md
│ │ ├── e2e/
│ │ │ ├── README.md
│ │ │ ├── config.yaml
│ │ │ ├── tests/
│ │ │ │ ├── app-update/
│ │ │ │ │ ├── force-update.yml
│ │ │ │ │ └── soft-update.yml
│ │ │ │ ├── assets/
│ │ │ │ │ ├── __suite__.yml
│ │ │ │ │ ├── change-currency.yml
│ │ │ │ │ ├── view-positions.yml
│ │ │ │ │ └── view-tokens-and-nfts.yml
│ │ │ │ ├── connect-signer/
│ │ │ │ │ ├── __suite__.yml
│ │ │ │ │ ├── connect-signer-collision.yml
│ │ │ │ │ ├── connect-signer-not-owner.yml
│ │ │ │ │ ├── connect-signer-success.yml
│ │ │ │ │ ├── reconnect-wrong-wallet.yml
│ │ │ │ │ ├── wc-gate-reconnect.yml
│ │ │ │ │ └── wc-gate-switch-network.yml
│ │ │ │ ├── onboarding/
│ │ │ │ │ ├── __suite__.yml
│ │ │ │ │ ├── add-existing-safe.yml
│ │ │ │ │ ├── add-safe-and-import-signer.yml
│ │ │ │ │ ├── enhanced-onboarding-flow.yml
│ │ │ │ │ ├── import-signer-private-key.yml
│ │ │ │ │ ├── import-signer-seed-phrase.yml
│ │ │ │ │ ├── import-signer.yml
│ │ │ │ │ └── new-user-onboarding.yml
│ │ │ │ ├── settings/
│ │ │ │ │ ├── __suite__.yml
│ │ │ │ │ ├── address-book.yml
│ │ │ │ │ ├── change-theme.yml
│ │ │ │ │ ├── state-preservation.yml
│ │ │ │ │ └── view-account-info.yml
│ │ │ │ └── transactions/
│ │ │ │ ├── history/
│ │ │ │ │ ├── __suite__.yml
│ │ │ │ │ ├── add-owner-threshold.yml
│ │ │ │ │ ├── batch-transaction.yml
│ │ │ │ │ ├── bulk-transactions.yml
│ │ │ │ │ ├── change-threshold.yml
│ │ │ │ │ ├── contract-interaction-delete-allowance.yml
│ │ │ │ │ ├── contract-interaction-deposit.yml
│ │ │ │ │ ├── disable-module.yml
│ │ │ │ │ ├── limit-order.yml
│ │ │ │ │ ├── received-transaction.yml
│ │ │ │ │ ├── rejected-transaction.yml
│ │ │ │ │ ├── remove-owner.yml
│ │ │ │ │ ├── sent-transaction.yml
│ │ │ │ │ ├── stake-claim.yml
│ │ │ │ │ ├── stake-deposit.yml
│ │ │ │ │ ├── swap-order.yml
│ │ │ │ │ ├── swap-owner.yml
│ │ │ │ │ └── view-transaction-history.yml
│ │ │ │ └── pending/
│ │ │ │ ├── batch-transaction.yml
│ │ │ │ ├── conflicting-transactions.yml
│ │ │ │ ├── limit-order.yml
│ │ │ │ ├── on-chain-rejection.yml
│ │ │ │ ├── safe-shield/
│ │ │ │ │ ├── approve-malicious.yml
│ │ │ │ │ ├── batch-2-actions.yml
│ │ │ │ │ ├── batch-3-actions-benign.yml
│ │ │ │ │ ├── batch-3-actions-warn.yml
│ │ │ │ │ ├── batch-malicious.yml
│ │ │ │ │ ├── contract-interaction-malicious.yml
│ │ │ │ │ ├── pending-bridge-unknown-network.yml
│ │ │ │ │ ├── pending-bridge.yml
│ │ │ │ │ ├── send-dai-malicious.yml
│ │ │ │ │ ├── send-matic-benign.yml
│ │ │ │ │ ├── send-matic-malicious.yml
│ │ │ │ │ ├── settings-change-fallback-handler.yml
│ │ │ │ │ └── settings-change.yml
│ │ │ │ ├── send-transaction.yml
│ │ │ │ ├── set-fallback-handler.yml
│ │ │ │ ├── settings-change.yml
│ │ │ │ ├── swap-order.yml
│ │ │ │ └── twap-order.yml
│ │ │ └── utils/
│ │ │ ├── assertions/
│ │ │ │ ├── verify-action-detail.yml
│ │ │ │ ├── verify-actions-list.yml
│ │ │ │ ├── verify-advanced-details.yml
│ │ │ │ ├── verify-balance-change.yml
│ │ │ │ ├── verify-clipboard-content.yml
│ │ │ │ ├── verify-explorer-link.yml
│ │ │ │ ├── verify-review-and-execute.yml
│ │ │ │ ├── verify-safe-shield-sheet.yml
│ │ │ │ ├── verify-safe-shield-widget.yml
│ │ │ │ ├── verify-share-link.yml
│ │ │ │ ├── verify-tx-checks.yml
│ │ │ │ ├── verify-tx-confirmations.yml
│ │ │ │ ├── verify-tx-details.yml
│ │ │ │ ├── verify-tx-history-confirmations.yml
│ │ │ │ ├── verify-tx-info.yml
│ │ │ │ ├── verify-tx-network.yml
│ │ │ │ ├── verify-tx-recipient.yml
│ │ │ │ └── verify-tx-sender.yml
│ │ │ ├── components/
│ │ │ │ ├── advanced-details/
│ │ │ │ │ ├── data.yml
│ │ │ │ │ └── parameters.yml
│ │ │ │ ├── pending-tx/
│ │ │ │ │ ├── batch-tx-card.yml
│ │ │ │ │ ├── batch-tx.yml
│ │ │ │ │ ├── conflicting-txs-card.yml
│ │ │ │ │ ├── limit-order-tx-card.yml
│ │ │ │ │ ├── limit-order-tx.yml
│ │ │ │ │ ├── on-chain-rejection-tx-card.yml
│ │ │ │ │ ├── on-chain-rejection-tx.yml
│ │ │ │ │ ├── send-tx-card.yml
│ │ │ │ │ ├── send-tx.yml
│ │ │ │ │ ├── setFallbackHandler-tx-card.yml
│ │ │ │ │ ├── setFallbackHandler-tx.yml
│ │ │ │ │ ├── settings-change-new-signer-tx-card.yml
│ │ │ │ │ ├── settings-change-new-signer-tx.yml
│ │ │ │ │ ├── swap-order-tx-card.yml
│ │ │ │ │ ├── swap-order-tx.yml
│ │ │ │ │ ├── tap-tx-card.yml
│ │ │ │ │ ├── twap-order-tx-card.yml
│ │ │ │ │ └── twap-order-tx.yml
│ │ │ │ └── tx-history/
│ │ │ │ ├── add-owner-with-threshold-tx-card.yml
│ │ │ │ ├── add-owner-with-threshold-tx.yml
│ │ │ │ ├── batch-tx-card.yml
│ │ │ │ ├── batch-tx.yml
│ │ │ │ ├── bulk-tx-card.yml
│ │ │ │ ├── bulk-tx.yml
│ │ │ │ ├── change-threshold-tx-card.yml
│ │ │ │ ├── change-threshold-tx.yml
│ │ │ │ ├── contract-interaction-tx-card.yml
│ │ │ │ ├── contract-interaction-tx.yml
│ │ │ │ ├── disable-module-tx-card.yml
│ │ │ │ ├── disable-module-tx.yml
│ │ │ │ ├── limit-order-tx-card.yml
│ │ │ │ ├── limit-order-tx.yml
│ │ │ │ ├── received-tx-card.yml
│ │ │ │ ├── received-tx.yml
│ │ │ │ ├── reject-tx-card.yml
│ │ │ │ ├── reject-tx.yml
│ │ │ │ ├── remove-owner-tx-card.yml
│ │ │ │ ├── remove-owner-tx.yml
│ │ │ │ ├── sent-tx-card.yml
│ │ │ │ ├── sent-tx.yml
│ │ │ │ ├── stake-claim-tx-card.yml
│ │ │ │ ├── stake-claim-tx.yml
│ │ │ │ ├── stake-deposit-tx-card.yml
│ │ │ │ ├── stake-deposit-tx.yml
│ │ │ │ ├── swap-order-tx-card.yml
│ │ │ │ ├── swap-order-tx.yml
│ │ │ │ ├── swap-owner-tx-card.yml
│ │ │ │ └── swap-owner-tx.yml
│ │ │ ├── scripts/
│ │ │ │ └── defaults.js
│ │ │ └── setup/
│ │ │ ├── app-start.yml
│ │ │ ├── open-review-and-execute.yml
│ │ │ └── switch-safe.yml
│ │ ├── eas.json
│ │ ├── eslint.config.mjs
│ │ ├── expo-plugins/
│ │ │ ├── ssl-pinning/
│ │ │ │ ├── README.md
│ │ │ │ └── withSSLPinning.js
│ │ │ ├── withDrawableAssets.js
│ │ │ └── withNotificationIcons.js
│ │ ├── firebase.json
│ │ ├── index.js
│ │ ├── jest.config.js
│ │ ├── metro.config.js
│ │ ├── openapi-config.ts
│ │ ├── package.json
│ │ ├── queries.js
│ │ ├── resources/
│ │ │ └── icons/
│ │ │ ├── README.md
│ │ │ └── safe-icons/
│ │ │ ├── font/
│ │ │ │ ├── demo.html
│ │ │ │ └── style.css
│ │ │ └── safe-icons.icomoon.json
│ │ ├── scripts/
│ │ │ ├── generateIconTypes.js
│ │ │ ├── getCertificates.js
│ │ │ └── reset-project.js
│ │ ├── src/
│ │ │ ├── app/
│ │ │ │ ├── (import-accounts)/
│ │ │ │ │ ├── _layout.tsx
│ │ │ │ │ ├── form.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── signers.tsx
│ │ │ │ ├── (send)/
│ │ │ │ │ ├── _layout.tsx
│ │ │ │ │ ├── amount.tsx
│ │ │ │ │ ├── recipient.tsx
│ │ │ │ │ ├── scan-qr.tsx
│ │ │ │ │ └── token.tsx
│ │ │ │ ├── (tabs)/
│ │ │ │ │ ├── _layout.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── settings.tsx
│ │ │ │ │ └── transactions.tsx
│ │ │ │ ├── +html.tsx
│ │ │ │ ├── +native-intent.tsx
│ │ │ │ ├── +not-found.tsx
│ │ │ │ ├── _layout.tsx
│ │ │ │ ├── accounts-sheet.tsx
│ │ │ │ ├── action-details.tsx
│ │ │ │ ├── address-book.tsx
│ │ │ │ ├── app-settings.tsx
│ │ │ │ ├── biometrics-opt-in.tsx
│ │ │ │ ├── change-estimated-fee-sheet.tsx
│ │ │ │ ├── change-signer-sheet.tsx
│ │ │ │ ├── confirm-transaction.tsx
│ │ │ │ ├── confirmations-sheet.tsx
│ │ │ │ ├── conflict-transaction-sheet.tsx
│ │ │ │ ├── contact.tsx
│ │ │ │ ├── currency.tsx
│ │ │ │ ├── developer.tsx
│ │ │ │ ├── execute-transaction/
│ │ │ │ │ ├── _layout.tsx
│ │ │ │ │ ├── ledger-connect.tsx
│ │ │ │ │ ├── ledger-pairing.tsx
│ │ │ │ │ └── ledger-review.tsx
│ │ │ │ ├── execution-error.tsx
│ │ │ │ ├── execution-success.tsx
│ │ │ │ ├── get-started.tsx
│ │ │ │ ├── history-transaction-details.tsx
│ │ │ │ ├── how-to-execute-sheet.tsx
│ │ │ │ ├── import-data/
│ │ │ │ │ ├── _layout.tsx
│ │ │ │ │ ├── enter-password.tsx
│ │ │ │ │ ├── file-selection.tsx
│ │ │ │ │ ├── help-import.tsx
│ │ │ │ │ ├── import-error.tsx
│ │ │ │ │ ├── import-progress.tsx
│ │ │ │ │ ├── import-success.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── review-data.tsx
│ │ │ │ ├── import-signers/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── _layout.test.tsx
│ │ │ │ │ ├── _layout.tsx
│ │ │ │ │ ├── connect-signer-error.tsx
│ │ │ │ │ ├── connect-signer-success.tsx
│ │ │ │ │ ├── hardware-devices.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── ledger-addresses.tsx
│ │ │ │ │ ├── ledger-connect.tsx
│ │ │ │ │ ├── ledger-error.tsx
│ │ │ │ │ ├── ledger-pairing.tsx
│ │ │ │ │ ├── ledger-success.tsx
│ │ │ │ │ ├── loading.tsx
│ │ │ │ │ ├── name-signer.tsx
│ │ │ │ │ ├── private-key-error.tsx
│ │ │ │ │ ├── private-key-success.tsx
│ │ │ │ │ ├── private-key.tsx
│ │ │ │ │ ├── reconnect-error.tsx
│ │ │ │ │ ├── seed-phrase-addresses.tsx
│ │ │ │ │ └── signer.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── manage-tokens-sheet.tsx
│ │ │ │ ├── networks-sheet.tsx
│ │ │ │ ├── notifications-center.tsx
│ │ │ │ ├── notifications-opt-in.tsx
│ │ │ │ ├── notifications-settings.tsx
│ │ │ │ ├── onboarding.tsx
│ │ │ │ ├── pending-transactions.tsx
│ │ │ │ ├── protocol-detail-sheet.tsx
│ │ │ │ ├── review-and-confirm.tsx
│ │ │ │ ├── review-and-execute.tsx
│ │ │ │ ├── safe-shield-details-sheet.tsx
│ │ │ │ ├── share.tsx
│ │ │ │ ├── sign-transaction/
│ │ │ │ │ ├── _layout.tsx
│ │ │ │ │ ├── ledger-connect.tsx
│ │ │ │ │ ├── ledger-pairing.tsx
│ │ │ │ │ └── ledger-review.tsx
│ │ │ │ ├── signers/
│ │ │ │ │ ├── [address]/
│ │ │ │ │ │ └── private-key.tsx
│ │ │ │ │ ├── [address].tsx
│ │ │ │ │ ├── _layout.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── signing-error.tsx
│ │ │ │ ├── signing-success.tsx
│ │ │ │ ├── transaction-actions.tsx
│ │ │ │ ├── transaction-checks.tsx
│ │ │ │ └── transaction-parameters/
│ │ │ │ ├── (tabs)/
│ │ │ │ │ ├── _layout.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── parameters.tsx
│ │ │ │ └── _layout.tsx
│ │ │ ├── components/
│ │ │ │ ├── ActionsRow/
│ │ │ │ │ ├── ActionsRow.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── Alert/
│ │ │ │ │ ├── Alert.stories.tsx
│ │ │ │ │ ├── Alert.test.tsx
│ │ │ │ │ ├── Alert.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── theme.ts
│ │ │ │ ├── Badge/
│ │ │ │ │ ├── Badge.test.tsx
│ │ │ │ │ ├── Badge.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── Badge.test.tsx.snap
│ │ │ │ │ ├── badge.stories.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── theme.ts
│ │ │ │ ├── BadgeWrapper/
│ │ │ │ │ ├── BadgeWrapper.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── BlurredIdenticonBackground/
│ │ │ │ │ ├── BlurredIdenticonBackground.stories.tsx
│ │ │ │ │ ├── BlurredIdenticonBackground.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Camera/
│ │ │ │ │ ├── QrCamera.test.tsx
│ │ │ │ │ ├── QrCamera.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── useCameraPermissionFlow.test.ts
│ │ │ │ │ └── useCameraPermissionFlow.ts
│ │ │ │ ├── ChainIndicator/
│ │ │ │ │ ├── ChainIndicator.stories.tsx
│ │ │ │ │ ├── ChainIndicator.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── ChainsDisplay/
│ │ │ │ │ ├── ChainsDisplay.stories.tsx
│ │ │ │ │ ├── ChainsDisplay.test.tsx
│ │ │ │ │ ├── ChainsDisplay.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── CloseButton/
│ │ │ │ │ ├── CloseButton.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── ComingSoon/
│ │ │ │ │ └── ComingSoon.tsx
│ │ │ │ ├── Container/
│ │ │ │ │ ├── Container.stories.tsx
│ │ │ │ │ ├── Container.test.tsx
│ │ │ │ │ ├── Container.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── Container.test.tsx.snap
│ │ │ │ │ └── index.ts
│ │ │ │ ├── CopyButton/
│ │ │ │ │ ├── CopyButton.stories.tsx
│ │ │ │ │ ├── CopyButton.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── DataRow/
│ │ │ │ │ ├── DataRow.stories.tsx
│ │ │ │ │ ├── DataRow.test.tsx
│ │ │ │ │ ├── DataRow.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── Dropdown/
│ │ │ │ │ ├── DropdownLabel.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── sheetComponents.tsx
│ │ │ │ ├── EncodedData/
│ │ │ │ │ ├── EncodedData.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── ErrorBoundary/
│ │ │ │ │ ├── SilentErrorBoundary.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── EthAddress/
│ │ │ │ │ ├── ETHAddress.stories.tsx
│ │ │ │ │ ├── ETHAddress.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── ExecutingMonitor/
│ │ │ │ │ ├── ExecutingMonitor.test.tsx
│ │ │ │ │ ├── ExecutingMonitor.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── Fiat/
│ │ │ │ │ ├── Fiat.test.tsx
│ │ │ │ │ ├── Fiat.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── FiatChange/
│ │ │ │ │ ├── FiatChange.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── FiatChange.test.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── FloatingContainer/
│ │ │ │ │ ├── FloatingContainer.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── GradientText/
│ │ │ │ │ ├── GradientText.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── HashDisplay/
│ │ │ │ │ ├── HashDisplay.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── HashDisplay.test.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── HexDataDisplay/
│ │ │ │ │ ├── HexDataDisplay.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── Identicon/
│ │ │ │ │ ├── Identicon.stories.tsx
│ │ │ │ │ ├── Identicon.test.tsx
│ │ │ │ │ ├── Identicon.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── InfoSheet/
│ │ │ │ │ ├── InfoSheet.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── InnerShadow/
│ │ │ │ │ ├── InnerShadow.test.tsx
│ │ │ │ │ ├── InnerShadow.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── InnerShadow.test.tsx.snap
│ │ │ │ │ └── index.ts
│ │ │ │ ├── LinearGradient/
│ │ │ │ │ ├── LinearGradien.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── LoadableSwitch/
│ │ │ │ │ ├── LoadableSwitch.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── Loader/
│ │ │ │ │ ├── Loader.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── LoadingScreen/
│ │ │ │ │ ├── LoadingScreen.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── Logo/
│ │ │ │ │ ├── Logo.test.tsx
│ │ │ │ │ ├── Logo.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── NetworkBadge/
│ │ │ │ │ ├── NetworkBadge.stories.tsx
│ │ │ │ │ ├── NetworkBadge.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── theme.ts
│ │ │ │ ├── NetworkRow/
│ │ │ │ │ ├── NetworkRow.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── OptIn/
│ │ │ │ │ ├── OptIn.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── ParametersButton/
│ │ │ │ │ ├── ParametersButton.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── ProposalBadge/
│ │ │ │ │ ├── ProposalBadge.stories.tsx
│ │ │ │ │ ├── ProposalBadge.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ReadOnlyWarningModal/
│ │ │ │ │ ├── ReadOnlyWarningModal.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── RiskAcknowledgmentCheckbox/
│ │ │ │ │ ├── RiskAcknowledgmentCheckbox.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── SVGs/
│ │ │ │ │ └── SafeWalletLogo.tsx
│ │ │ │ ├── SafeAccountInput/
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ ├── useImportSafe.test.tsx
│ │ │ │ │ │ └── useImportSafe.ts
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SafeAvatar/
│ │ │ │ │ ├── SafeAvatar.stories.tsx
│ │ │ │ │ └── SafeAvatar.tsx
│ │ │ │ ├── SafeBottomSheet/
│ │ │ │ │ ├── SafeBottomSheet.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── SafeButton/
│ │ │ │ │ ├── SafeButton.stories.tsx
│ │ │ │ │ ├── SafeButton.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── SafeCard/
│ │ │ │ │ ├── SafeCard.stories.tsx
│ │ │ │ │ ├── SafeCard.test.tsx
│ │ │ │ │ ├── SafeCard.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── SafeFontIcon/
│ │ │ │ │ ├── SafeFontIcon.stories.tsx
│ │ │ │ │ ├── SafeFontIcon.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── SafeInput/
│ │ │ │ │ ├── SafeInput.stories.tsx
│ │ │ │ │ ├── SafeInput.test.tsx
│ │ │ │ │ ├── SafeInput.tsx
│ │ │ │ │ ├── SafeInputWithLabel.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── styled.ts
│ │ │ │ │ ├── theme.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── SafeListItem/
│ │ │ │ │ ├── SafeListItem.test.tsx
│ │ │ │ │ ├── SafeListItem.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── SafeListItem.test.tsx.snap
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── theme.ts
│ │ │ │ ├── SafeSearchBar/
│ │ │ │ │ └── SafeSearchBar.tsx
│ │ │ │ ├── SafeSkeleton/
│ │ │ │ │ ├── SafeSkeleton.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SafeTab/
│ │ │ │ │ ├── SafeTab.tsx
│ │ │ │ │ ├── SafeTabBar.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── theme.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── SelectExecutor/
│ │ │ │ │ ├── SelectExecutor.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── SelectSigner/
│ │ │ │ │ ├── SelectSigner.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── ShareButton/
│ │ │ │ │ ├── ShareButton.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── SignerTypeBadge/
│ │ │ │ │ ├── SignerTypeBadge.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── SigningMonitor/
│ │ │ │ │ ├── SigningMonitor.test.tsx
│ │ │ │ │ ├── SigningMonitor.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── StatusBanners/
│ │ │ │ │ └── PendingTransactions/
│ │ │ │ │ ├── PendingTransactions.stories.tsx
│ │ │ │ │ ├── PendingTransactions.test.tsx
│ │ │ │ │ ├── PendingTransactions.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── PendingTransactions.test.tsx.snap
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SwapHeader/
│ │ │ │ │ ├── SwapHeader.test.tsx
│ │ │ │ │ ├── SwapHeader.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── Tab/
│ │ │ │ │ └── TabNameContext.tsx
│ │ │ │ ├── Tag/
│ │ │ │ │ ├── Tag.stories.tsx
│ │ │ │ │ ├── Tag.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── ThresholdBadge/
│ │ │ │ │ ├── ThresholdBadge.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── Title/
│ │ │ │ │ ├── LargeHeaderTitle.tsx
│ │ │ │ │ ├── NavBarTitle.tsx
│ │ │ │ │ ├── SectionTitle.tsx
│ │ │ │ │ ├── Title.test.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── TokenAmount/
│ │ │ │ │ ├── TokenAmount.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── TokenIcon/
│ │ │ │ │ ├── TokenIcon.test.tsx
│ │ │ │ │ ├── TokenIcon.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── TransactionProcessingState/
│ │ │ │ │ ├── TransactionProcessingState.test.tsx
│ │ │ │ │ ├── TransactionProcessingState.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── TransactionSkeleton/
│ │ │ │ │ ├── TransactionSkeleton.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TxInfo/
│ │ │ │ │ ├── TxInfo.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── types.ts
│ │ │ │ ├── ValidatorRow/
│ │ │ │ │ ├── ValidatorRow.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── ValidatorStatus/
│ │ │ │ │ ├── ValidatorStatus.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── navigation/
│ │ │ │ │ ├── TabBarIcon.test.tsx
│ │ │ │ │ ├── TabBarIcon.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ └── transactions-list/
│ │ │ │ └── Card/
│ │ │ │ ├── AccountCard/
│ │ │ │ │ ├── AccountCard.stories.tsx
│ │ │ │ │ ├── AccountCard.test.tsx
│ │ │ │ │ ├── AccountCard.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── AssetsCard/
│ │ │ │ │ ├── AssetsCard.test.tsx
│ │ │ │ │ ├── AssetsCard.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SignersCard/
│ │ │ │ │ ├── SignersCard.test.tsx
│ │ │ │ │ ├── SignersCard.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── StakingTxDepositCard/
│ │ │ │ │ ├── StakingTxDepositCard.stories.tsx
│ │ │ │ │ ├── StakingTxDepositCard.test.tsx
│ │ │ │ │ ├── StakingTxDepositCard.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── StakingTxDepositCard.test.tsx.snap
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── StakingTxExitCard/
│ │ │ │ │ ├── StakingTxExitCard.stories.tsx
│ │ │ │ │ ├── StakingTxExitCard.test.tsx
│ │ │ │ │ ├── StakingTxExitCard.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── StakingTxExitCard.test.tsx.snap
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── StakingTxWithdrawCard/
│ │ │ │ │ ├── StakingTxWithdrawCard.stories.tsx
│ │ │ │ │ ├── StakingTxWithdrawCard.test.tsx
│ │ │ │ │ ├── StakingTxWithdrawCard.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── StakingTxWithdrawCard.test.tsx.snap
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TxBatchCard/
│ │ │ │ │ ├── TxBatchCard.stories.tsx
│ │ │ │ │ ├── TxBatchCard.test.tsx
│ │ │ │ │ ├── TxBatchCard.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── TxBatchCard.test.tsx.snap
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TxBridgeCard/
│ │ │ │ │ ├── TxBridgeCard.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── TxConflictingCard/
│ │ │ │ │ ├── TxConflictingCard.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TxContractInteractionCard/
│ │ │ │ │ ├── TxContractInteractionCard.stories.tsx
│ │ │ │ │ ├── TxContractInteractionCard.test.tsx
│ │ │ │ │ ├── TxContractInteractionCard.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TxCreationCard/
│ │ │ │ │ ├── TxCreationCard.stories.tsx
│ │ │ │ │ ├── TxCreationCard.test.tsx
│ │ │ │ │ ├── TxCreationCard.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── TxGroupedCard/
│ │ │ │ │ ├── TxGroupedCard.stories.tsx
│ │ │ │ │ ├── TxGroupedCard.test.tsx
│ │ │ │ │ ├── TxGroupedCard.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TxLifiSwapCard/
│ │ │ │ │ ├── TxLifiSwapCard.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── TxOrderCard/
│ │ │ │ │ ├── SellOrder.tsx
│ │ │ │ │ ├── TwapOrder.tsx
│ │ │ │ │ ├── TxOrderCard.stories.tsx
│ │ │ │ │ ├── TxOrderCard.test.tsx
│ │ │ │ │ ├── TxOrderCard.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TxRejectionCard/
│ │ │ │ │ ├── TxRejectionCard.stories.tsx
│ │ │ │ │ ├── TxRejectionCard.test.tsx
│ │ │ │ │ ├── TxRejectionCard.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TxSafeAppCard/
│ │ │ │ │ ├── TxSafeAppCard.stories.tsx
│ │ │ │ │ ├── TxSafeAppCard.test.tsx
│ │ │ │ │ ├── TxSafeAppCard.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TxSettingsCard/
│ │ │ │ │ ├── TxSettingCard.stories.tsx
│ │ │ │ │ ├── TxSettingCard.test.tsx
│ │ │ │ │ ├── TxSettingsCard.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── TxSettingCard.test.tsx.snap
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TxTokenCard/
│ │ │ │ │ ├── TxTokenCard.stories.tsx
│ │ │ │ │ ├── TxTokenCard.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── VaultTxDepositCard/
│ │ │ │ │ ├── VaultTxDepositCard.test.tsx
│ │ │ │ │ ├── VaultTxDepositCard.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── VaultTxDepositCard.test.tsx.snap
│ │ │ │ │ └── index.tsx
│ │ │ │ └── VaultTxRedeemCard/
│ │ │ │ ├── VaultTxRedeemCard.test.tsx
│ │ │ │ ├── VaultTxRedeemCard.tsx
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── VaultTxRedeemCard.test.tsx.snap
│ │ │ │ └── index.tsx
│ │ │ ├── config/
│ │ │ │ └── constants.ts
│ │ │ ├── context/
│ │ │ │ └── NotificationsContext.tsx
│ │ │ ├── features/
│ │ │ │ ├── AccountsSheet/
│ │ │ │ │ ├── AccountItem/
│ │ │ │ │ │ ├── AccountItem.stories.tsx
│ │ │ │ │ │ ├── AccountItem.test.tsx
│ │ │ │ │ │ ├── AccountItem.tsx
│ │ │ │ │ │ ├── hooks/
│ │ │ │ │ │ │ └── useEditAccountItem.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── utils/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ └── editAccountHelpers.test.ts
│ │ │ │ │ │ ├── editAccountHelpers.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── AccountsSheet.container.tsx
│ │ │ │ │ ├── MyAccounts/
│ │ │ │ │ │ ├── MyAccounts.container.test.tsx
│ │ │ │ │ │ ├── MyAccounts.container.tsx
│ │ │ │ │ │ ├── MyAccountsFooter.test.tsx
│ │ │ │ │ │ ├── MyAccountsFooter.tsx
│ │ │ │ │ │ ├── hooks/
│ │ │ │ │ │ │ ├── useMyAccountsAnalytics.test.ts
│ │ │ │ │ │ │ ├── useMyAccountsAnalytics.ts
│ │ │ │ │ │ │ └── useMyAccountsSortable.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── AccountsSheet.container.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ActionDetails/
│ │ │ │ │ ├── ActionDetails.container.tsx
│ │ │ │ │ ├── ActionsDetails.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── utils.tsx
│ │ │ │ ├── AddressBook/
│ │ │ │ │ ├── Contact/
│ │ │ │ │ │ ├── ContactDetail.container.tsx
│ │ │ │ │ │ ├── ContactDisplayName.container.tsx
│ │ │ │ │ │ ├── ContactForm.container.tsx
│ │ │ │ │ │ ├── NetworkSelector/
│ │ │ │ │ │ │ ├── AllNetworksItem.tsx
│ │ │ │ │ │ │ ├── ChainItem.tsx
│ │ │ │ │ │ │ ├── NetworkSelector.tsx
│ │ │ │ │ │ │ ├── NetworkSelectorContent.tsx
│ │ │ │ │ │ │ ├── NetworkSelectorHeader.tsx
│ │ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ │ └── NetworkSelectorHeader.test.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ ├── ContactActionButton.tsx
│ │ │ │ │ │ │ ├── ContactAddressField.tsx
│ │ │ │ │ │ │ ├── ContactHeader.tsx
│ │ │ │ │ │ │ ├── ContactName.tsx
│ │ │ │ │ │ │ ├── ContactNameField.tsx
│ │ │ │ │ │ │ ├── ContactNetworkRow.tsx
│ │ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ │ ├── ContactActionButton.test.tsx
│ │ │ │ │ │ │ │ ├── ContactAddressField.test.tsx
│ │ │ │ │ │ │ │ ├── ContactHeader.test.tsx
│ │ │ │ │ │ │ │ ├── ContactName.test.tsx
│ │ │ │ │ │ │ │ └── ContactNetworkRow.test.tsx
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── hooks/
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ ├── useContactNetworkData.test.ts
│ │ │ │ │ │ │ ├── useContactNetworkData.ts
│ │ │ │ │ │ │ ├── useDeleteContact.test.ts
│ │ │ │ │ │ │ ├── useDeleteContact.ts
│ │ │ │ │ │ │ ├── useEditContact.test.ts
│ │ │ │ │ │ │ └── useEditContact.ts
│ │ │ │ │ │ └── schemas/
│ │ │ │ │ │ ├── contactSchema.test.ts
│ │ │ │ │ │ ├── contactSchema.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── List/
│ │ │ │ │ │ ├── AddressBookList.container.test.tsx
│ │ │ │ │ │ ├── AddressBookList.container.tsx
│ │ │ │ │ │ ├── ContactItemActions.container.tsx
│ │ │ │ │ │ ├── List.container.test.tsx
│ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ ├── AddressBookListView.test.tsx
│ │ │ │ │ │ │ ├── AddressBookListView.tsx
│ │ │ │ │ │ │ ├── List/
│ │ │ │ │ │ │ │ ├── ContactItem.tsx
│ │ │ │ │ │ │ │ ├── ContactListItems.tsx
│ │ │ │ │ │ │ │ ├── EmptyAddressBookDark.tsx
│ │ │ │ │ │ │ │ ├── EmptyAddressBookLight.tsx
│ │ │ │ │ │ │ │ ├── NoContacts.tsx
│ │ │ │ │ │ │ │ ├── NoContactsFound.tsx
│ │ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ │ └── ListView.test.tsx
│ │ │ │ │ │ └── hooks/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── useContactActions.test.ts
│ │ │ │ │ │ └── useContactActions.ts
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── AdvancedDetails/
│ │ │ │ │ ├── TxData.container.tsx
│ │ │ │ │ ├── TxParameters.container.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ └── Receiver/
│ │ │ │ │ │ ├── Receiver.tsx
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ └── Receiver.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── formatters/
│ │ │ │ │ │ ├── arrayValue.test.tsx
│ │ │ │ │ │ ├── arrayValue.tsx
│ │ │ │ │ │ ├── singleValue.test.tsx
│ │ │ │ │ │ └── singleValue.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── utils/
│ │ │ │ │ ├── formatParameters.test.tsx
│ │ │ │ │ ├── formatParameters.tsx
│ │ │ │ │ ├── formatTxDetails.test.tsx
│ │ │ │ │ └── formatTxDetails.tsx
│ │ │ │ ├── AppUpdate/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── ForceUpdateScreen.tsx
│ │ │ │ │ │ └── SoftUpdatePrompt.tsx
│ │ │ │ │ ├── constants.ts
│ │ │ │ │ └── hooks/
│ │ │ │ │ ├── appUpdateE2eState.ts
│ │ │ │ │ ├── useAppUpdateCheck.e2e.ts
│ │ │ │ │ └── useAppUpdateCheck.ts
│ │ │ │ ├── Assets/
│ │ │ │ │ ├── Assets.container.tsx
│ │ │ │ │ ├── Assets.error.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── AssetsHeader/
│ │ │ │ │ │ │ ├── AssetsHeader.container.tsx
│ │ │ │ │ │ │ ├── AssetsHeader.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ └── styles.ts
│ │ │ │ │ │ ├── Balance/
│ │ │ │ │ │ │ ├── Balance.container.tsx
│ │ │ │ │ │ │ ├── Balance.tsx
│ │ │ │ │ │ │ ├── ChainItems.tsx
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── Fallback/
│ │ │ │ │ │ │ ├── Fallback.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── ManageTokensSheet/
│ │ │ │ │ │ │ ├── ManageTokensSheet.container.tsx
│ │ │ │ │ │ │ ├── ManageTokensSheet.test.tsx
│ │ │ │ │ │ │ ├── ManageTokensSheet.tsx
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── NFTs/
│ │ │ │ │ │ │ ├── NFTItem.tsx
│ │ │ │ │ │ │ ├── NFTs.container.test.tsx
│ │ │ │ │ │ │ ├── NFTs.container.tsx
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── Navbar/
│ │ │ │ │ │ │ ├── Navbar.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ └── theme.ts
│ │ │ │ │ │ ├── NoFunds/
│ │ │ │ │ │ │ ├── EmptyNFT.tsx
│ │ │ │ │ │ │ ├── EmptyToken.tsx
│ │ │ │ │ │ │ ├── NoFunds.test.tsx
│ │ │ │ │ │ │ ├── NoFunds.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── Positions/
│ │ │ │ │ │ │ ├── PositionItem/
│ │ │ │ │ │ │ │ ├── PositionFiatChange.test.tsx
│ │ │ │ │ │ │ │ ├── PositionFiatChange.tsx
│ │ │ │ │ │ │ │ ├── PositionItem.test.tsx
│ │ │ │ │ │ │ │ ├── PositionItem.tsx
│ │ │ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ │ │ ├── PositionFiatChange.test.tsx.snap
│ │ │ │ │ │ │ │ │ └── PositionItem.test.tsx.snap
│ │ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ │ ├── Positions.container.test.tsx
│ │ │ │ │ │ │ ├── Positions.container.tsx
│ │ │ │ │ │ │ ├── PositionsEmpty/
│ │ │ │ │ │ │ │ ├── PositionsEmpty.test.tsx
│ │ │ │ │ │ │ │ ├── PositionsEmpty.tsx
│ │ │ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ │ │ └── PositionsEmpty.test.tsx.snap
│ │ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ │ ├── PositionsError/
│ │ │ │ │ │ │ │ ├── PositionsError.test.tsx
│ │ │ │ │ │ │ │ ├── PositionsError.tsx
│ │ │ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ │ │ └── PositionsError.test.tsx.snap
│ │ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ │ ├── ProtocolDetailSheet/
│ │ │ │ │ │ │ │ ├── ProtocolDetailSheet.container.tsx
│ │ │ │ │ │ │ │ ├── ProtocolDetailSheet.tsx
│ │ │ │ │ │ │ │ ├── ProtocolDetailSheetHeader.tsx
│ │ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ │ ├── utils.test.ts
│ │ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ │ ├── ProtocolSection/
│ │ │ │ │ │ │ │ ├── ProtocolSection.test.tsx
│ │ │ │ │ │ │ │ ├── ProtocolSection.tsx
│ │ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── ReadOnly/
│ │ │ │ │ │ │ ├── ReadOnly.container.test.tsx
│ │ │ │ │ │ │ ├── ReadOnly.container.tsx
│ │ │ │ │ │ │ ├── ReadOnly.tsx
│ │ │ │ │ │ │ └── ReadOnlyIconBlock.tsx
│ │ │ │ │ │ └── Tokens/
│ │ │ │ │ │ ├── TokenItem.tsx
│ │ │ │ │ │ ├── Tokens.container.test.tsx
│ │ │ │ │ │ ├── Tokens.container.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── useTokenBalances.ts
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ └── usePositions.ts
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.ts
│ │ │ │ ├── ChangeEstimatedFeeSheet/
│ │ │ │ │ ├── ChangeEstimatedFeeSheet.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ └── ChangeEstimatedFeeForm/
│ │ │ │ │ │ ├── ChangeEstimatedFeeForm.tsx
│ │ │ │ │ │ ├── helpers.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── schema.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── ChangeSignerSheet/
│ │ │ │ │ ├── ChangeSignerSheet.container.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── useAvailableSigners.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── ConfirmTx/
│ │ │ │ │ ├── ConfirmTx.container.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── CanNotSign/
│ │ │ │ │ │ │ ├── CanNotSign.test.tsx
│ │ │ │ │ │ │ ├── CanNotSign.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── ConfirmTxForm/
│ │ │ │ │ │ │ ├── ConfirmTxForm.test.tsx
│ │ │ │ │ │ │ ├── ConfirmTxForm.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── ConfirmationView/
│ │ │ │ │ │ │ ├── ConfirmationView.tsx
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── types.ts
│ │ │ │ │ │ ├── ConfirmationsInfo/
│ │ │ │ │ │ │ ├── ConfirmationsInfo.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── ExecuteForm/
│ │ │ │ │ │ │ ├── ExecuteForm.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── ListTable/
│ │ │ │ │ │ │ ├── ListTable.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── LoadingTx/
│ │ │ │ │ │ │ ├── LoadingTx.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── PendingTx/
│ │ │ │ │ │ │ ├── PendingTx.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── PendingTxInfo/
│ │ │ │ │ │ │ ├── PendingTxInfo.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── ReviewAndConfirm/
│ │ │ │ │ │ │ ├── ReviewAndConfirmContainer.tsx
│ │ │ │ │ │ │ ├── ReviewAndConfirmView.tsx
│ │ │ │ │ │ │ ├── ReviewFooter.test.tsx
│ │ │ │ │ │ │ ├── ReviewFooter.tsx
│ │ │ │ │ │ │ ├── ReviewHeader.tsx
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── tabs/
│ │ │ │ │ │ │ ├── DataTab.tsx
│ │ │ │ │ │ │ ├── HashesTab.tsx
│ │ │ │ │ │ │ └── JSONTab.tsx
│ │ │ │ │ │ ├── SignForm/
│ │ │ │ │ │ │ ├── SignForm.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── SignTransaction/
│ │ │ │ │ │ │ ├── SignError.tsx
│ │ │ │ │ │ │ ├── SignSuccess.tsx
│ │ │ │ │ │ │ └── hooks/
│ │ │ │ │ │ │ ├── useTransactionSigning.test.ts
│ │ │ │ │ │ │ └── useTransactionSigning.ts
│ │ │ │ │ │ ├── TransactionChecks/
│ │ │ │ │ │ │ ├── TransactionChecks.tsx
│ │ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ │ └── TransactionChecks.test.tsx
│ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ ├── TransactionChecksBottomContent.tsx
│ │ │ │ │ │ │ │ ├── TransactionChecksLeftNode.tsx
│ │ │ │ │ │ │ │ └── __tests__/
│ │ │ │ │ │ │ │ ├── TransactionChecksBottomContent.test.tsx
│ │ │ │ │ │ │ │ └── TransactionChecksLeftNode.test.tsx
│ │ │ │ │ │ │ ├── hooks/
│ │ │ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ │ │ └── useTransactionSecurity.test.ts
│ │ │ │ │ │ │ │ └── useTransactionSecurity.ts
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── utils/
│ │ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ │ └── transactionChecksUtils.test.ts
│ │ │ │ │ │ │ └── transactionChecksUtils.ts
│ │ │ │ │ │ ├── TransactionHeader/
│ │ │ │ │ │ │ ├── TransactionHeader.tsx
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── TransactionInfo/
│ │ │ │ │ │ │ ├── TransactionInfo.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ └── confirmation-views/
│ │ │ │ │ │ ├── AddSigner/
│ │ │ │ │ │ │ ├── AddSigner.tsx
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── utils.tsx
│ │ │ │ │ │ ├── AlreadySigned/
│ │ │ │ │ │ │ ├── AlreadySigned.test.tsx
│ │ │ │ │ │ │ ├── AlreadySigned.tsx
│ │ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ │ └── AlreadySigned.test.tsx.snap
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── BridgeTransaction/
│ │ │ │ │ │ │ ├── BridgeTransaction.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── CancelTx/
│ │ │ │ │ │ │ ├── CancelTx.tsx
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── utils.tsx
│ │ │ │ │ │ ├── Contract/
│ │ │ │ │ │ │ ├── Contract.tsx
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── utils.tsx
│ │ │ │ │ │ ├── GenericView/
│ │ │ │ │ │ │ ├── GenericView.tsx
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── utils.tsx
│ │ │ │ │ │ ├── LifiSwapTransaction/
│ │ │ │ │ │ │ ├── LifiSwapHeader.tsx
│ │ │ │ │ │ │ ├── LifiSwapTransaction.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── RemoveSigner/
│ │ │ │ │ │ │ ├── RemoveSigner.tsx
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── utils.tsx
│ │ │ │ │ │ ├── SendNFT/
│ │ │ │ │ │ │ ├── SendNFT.tsx
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── utils.tsx
│ │ │ │ │ │ ├── Stake/
│ │ │ │ │ │ │ ├── Deposit/
│ │ │ │ │ │ │ │ ├── Deposit.stories.tsx
│ │ │ │ │ │ │ │ ├── Deposit.test.tsx
│ │ │ │ │ │ │ │ ├── Deposit.tsx
│ │ │ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ │ │ └── Deposit.test.tsx.snap
│ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ ├── Exit/
│ │ │ │ │ │ │ │ ├── Exit.stories.tsx
│ │ │ │ │ │ │ │ ├── Exit.test.tsx
│ │ │ │ │ │ │ │ ├── Exit.tsx
│ │ │ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ │ │ └── Exit.test.tsx.snap
│ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ ├── WithdrawRequest/
│ │ │ │ │ │ │ │ ├── WithdrawRequest.stories.tsx
│ │ │ │ │ │ │ │ ├── WithdrawRequest.test.tsx
│ │ │ │ │ │ │ │ ├── WithdrawRequest.tsx
│ │ │ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ │ │ └── WithdrawRequest.test.tsx.snap
│ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ ├── utils.test.tsx
│ │ │ │ │ │ │ └── utils.tsx
│ │ │ │ │ │ ├── SwapOrder/
│ │ │ │ │ │ │ ├── StatusLabel/
│ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ ├── SwapOrder.tsx
│ │ │ │ │ │ │ ├── SwapOrderHeader.test.tsx
│ │ │ │ │ │ │ ├── SwapOrderHeader.tsx
│ │ │ │ │ │ │ ├── TwapFallbackHandlerWarning.tsx
│ │ │ │ │ │ │ ├── hooks/
│ │ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ │ ├── useRecipientItem.test.tsx
│ │ │ │ │ │ │ │ ├── useRecipientItem.tsx
│ │ │ │ │ │ │ │ └── useRecipientItems.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── TokenTransfer/
│ │ │ │ │ │ │ ├── TokenTransfer.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── VaultDeposit/
│ │ │ │ │ │ │ ├── VaultDeposit.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ └── utils.tsx
│ │ │ │ │ │ └── VaultRedeem/
│ │ │ │ │ │ ├── VaultRedeem.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── utils.tsx
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ ├── useOpenExplorer/
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── useOpenExplorer.ts
│ │ │ │ │ │ ├── useTransactionData.test.ts
│ │ │ │ │ │ ├── useTransactionData.ts
│ │ │ │ │ │ ├── useTransactionSigner.test.ts
│ │ │ │ │ │ ├── useTransactionSigner.ts
│ │ │ │ │ │ ├── useTxSignerActions.test.ts
│ │ │ │ │ │ ├── useTxSignerActions.ts
│ │ │ │ │ │ ├── useTxSignerAutoSelection.test.ts
│ │ │ │ │ │ ├── useTxSignerAutoSelection.ts
│ │ │ │ │ │ ├── useTxSignerState.test.ts
│ │ │ │ │ │ └── useTxSignerState.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── ConfirmationsSheet/
│ │ │ │ │ ├── ConfirmationsSheet.container.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── ConflictTxSheet/
│ │ │ │ │ ├── ConflictTxSheet.container.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── DataImport/
│ │ │ │ │ ├── DataTransfer.container.tsx
│ │ │ │ │ ├── EnterPassword.container.tsx
│ │ │ │ │ ├── FileSelection.container.tsx
│ │ │ │ │ ├── HelpImport.container.tsx
│ │ │ │ │ ├── ImportError.container.tsx
│ │ │ │ │ ├── ImportProgressScreen.container.tsx
│ │ │ │ │ ├── ImportSuccessScreen.container.tsx
│ │ │ │ │ ├── ReviewData.container.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── EnterPassword.test.tsx
│ │ │ │ │ │ ├── FileSelection.test.tsx
│ │ │ │ │ │ ├── ImportProgressScreen.test.tsx
│ │ │ │ │ │ ├── ReviewData.test.tsx
│ │ │ │ │ │ └── useLegacyImport.test.ts
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── DataTransferView.tsx
│ │ │ │ │ │ ├── EnterPasswordView.tsx
│ │ │ │ │ │ ├── FileSelectionView.tsx
│ │ │ │ │ │ ├── HelpImportView.tsx
│ │ │ │ │ │ ├── ImportErrorView.tsx
│ │ │ │ │ │ ├── ImportProgressScreenView.tsx
│ │ │ │ │ │ ├── ImportSuccessScreenView.tsx
│ │ │ │ │ │ └── ReviewDataView.tsx
│ │ │ │ │ ├── context/
│ │ │ │ │ │ └── DataImportProvider.tsx
│ │ │ │ │ ├── helpers/
│ │ │ │ │ │ ├── transforms.test.ts
│ │ │ │ │ │ └── transforms.ts
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ └── useLegacyImport.ts
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Developer/
│ │ │ │ │ ├── Developer.container.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ └── Developer.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── types.ts
│ │ │ │ ├── ExecuteTx/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── CanNotEstimate/
│ │ │ │ │ │ │ ├── CanNotEstimate.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── CanNotExecute/
│ │ │ │ │ │ │ ├── CanNotExecute.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── EstimatedNetworkFee/
│ │ │ │ │ │ │ ├── EstimatedNetworkFee.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── ExecuteError.tsx
│ │ │ │ │ │ ├── ExecuteSuccess.tsx
│ │ │ │ │ │ ├── RelayFee/
│ │ │ │ │ │ │ ├── RelayFee.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── ReviewAndExecute/
│ │ │ │ │ │ │ ├── ReviewAndExecuteContainer.tsx
│ │ │ │ │ │ │ ├── ReviewExecuteFooter.tsx
│ │ │ │ │ │ │ ├── ReviewExecuteFooterSkeleton.tsx
│ │ │ │ │ │ │ ├── helpers.test.ts
│ │ │ │ │ │ │ └── helpers.ts
│ │ │ │ │ │ └── SignerFee/
│ │ │ │ │ │ ├── SignerFee.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ └── hooks/
│ │ │ │ │ ├── useClearEstimatedFeeOnMount.ts
│ │ │ │ │ ├── useExecutionFlow.test.ts
│ │ │ │ │ ├── useExecutionFlow.ts
│ │ │ │ │ ├── useExecutionFunds.test.tsx
│ │ │ │ │ ├── useExecutionFunds.ts
│ │ │ │ │ ├── useGasFee.test.ts
│ │ │ │ │ ├── useGasFee.ts
│ │ │ │ │ └── useTransactionExecution.ts
│ │ │ │ ├── GetStarted/
│ │ │ │ │ ├── GetStarted.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── HistoryTransactionDetails/
│ │ │ │ │ ├── HistoryTransactionDetails.container.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── HistoryAdvancedDetailsButton/
│ │ │ │ │ │ │ ├── HistoryAdvancedDetailsButton.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── HistoryConfirmationsInfo/
│ │ │ │ │ │ │ ├── HistoryConfirmationsInfo.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── HistoryTransactionHeader/
│ │ │ │ │ │ │ ├── HistoryTransactionHeader.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── HistoryTransactionInfo/
│ │ │ │ │ │ │ ├── HistoryTransactionInfo.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── HistoryTransactionView/
│ │ │ │ │ │ │ ├── HistoryTransactionView.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── ViewOnExplorerButton/
│ │ │ │ │ │ │ ├── ViewOnExplorerButton.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── history-views/
│ │ │ │ │ │ │ ├── CancelTx.tsx
│ │ │ │ │ │ │ ├── HistoryAddSigner.tsx
│ │ │ │ │ │ │ ├── HistoryChangeThreshold.tsx
│ │ │ │ │ │ │ ├── HistoryContract.tsx
│ │ │ │ │ │ │ ├── HistoryGenericView.tsx
│ │ │ │ │ │ │ ├── HistoryRemoveSigner.tsx
│ │ │ │ │ │ │ ├── HistoryStakeDeposit.tsx
│ │ │ │ │ │ │ ├── HistoryStakeWithdraw.tsx
│ │ │ │ │ │ │ ├── HistoryStakeWithdrawRequest.tsx
│ │ │ │ │ │ │ ├── HistorySwapOrder.tsx
│ │ │ │ │ │ │ ├── HistorySwapSigner.tsx
│ │ │ │ │ │ │ ├── HistoryTokenTransfer.tsx
│ │ │ │ │ │ │ ├── HistoryTransactionBase.tsx
│ │ │ │ │ │ │ ├── HistoryVaultDeposit.tsx
│ │ │ │ │ │ │ ├── HistoryVaultRedeem.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ └── shared/
│ │ │ │ │ │ ├── NetworkDisplay.tsx
│ │ │ │ │ │ ├── ThresholdChangeDisplay.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── utils/
│ │ │ │ │ ├── header.test.ts
│ │ │ │ │ └── header.ts
│ │ │ │ ├── HowToExecuteSheet/
│ │ │ │ │ ├── HowToExecuteSheet.container.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── RelayAvailable/
│ │ │ │ │ │ │ ├── RelayAvailable.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ └── RelayUnavailable/
│ │ │ │ │ │ ├── RelayUnavailable.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── ImportReadOnly/
│ │ │ │ │ ├── AddSignersForm.container.tsx
│ │ │ │ │ ├── ImportAccountForm.container.tsx
│ │ │ │ │ ├── NetworkBadge.container.tsx
│ │ │ │ │ ├── ScanQrAccount.container.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── AddSignersFormView.tsx
│ │ │ │ │ │ ├── AvailableNetworks.tsx
│ │ │ │ │ │ ├── ImportAccountFormView.tsx
│ │ │ │ │ │ ├── ScanQrAccountView.tsx
│ │ │ │ │ │ └── VerificationStatus.tsx
│ │ │ │ │ ├── helpers/
│ │ │ │ │ │ ├── safes.test.tsx
│ │ │ │ │ │ └── safes.tsx
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ └── useScan/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── useScan.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── schema.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── ImportSigner/
│ │ │ │ │ ├── ImportSigner.container.tsx
│ │ │ │ │ ├── ImportSigner.test.tsx
│ │ │ │ │ ├── SeedPhraseAddresses.container.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── ConnectSignerError/
│ │ │ │ │ │ │ ├── ConnectSignerError.tsx
│ │ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ │ └── ConnectSignerError.test.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── ImportError/
│ │ │ │ │ │ │ ├── ImportError.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── ImportSuccess/
│ │ │ │ │ │ │ ├── ImportSuccess.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── LoadingImport/
│ │ │ │ │ │ │ ├── LoadingImport.container.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── NameSigner/
│ │ │ │ │ │ │ ├── NameSigner.container.tsx
│ │ │ │ │ │ │ ├── NameSignerView.tsx
│ │ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ │ ├── NameSigner.test.tsx
│ │ │ │ │ │ │ │ └── buildDefaultName.test.ts
│ │ │ │ │ │ │ ├── buildDefaultName.ts
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ └── ReconnectError/
│ │ │ │ │ │ ├── ReconnectError.tsx
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ └── ReconnectError.test.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── useImportPrivateKey.test.ts
│ │ │ │ │ │ │ ├── useImportSeedPhraseAddress.test.ts
│ │ │ │ │ │ │ ├── useSeedPhraseAddresses.test.ts
│ │ │ │ │ │ │ └── useSignerCollisionGuard.test.ts
│ │ │ │ │ │ ├── useImportPrivateKey.ts
│ │ │ │ │ │ ├── useImportSeedPhraseAddress.ts
│ │ │ │ │ │ ├── useSeedPhraseAddresses.ts
│ │ │ │ │ │ └── useSignerCollisionGuard.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── utils/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── findCollidingSigner.test.ts
│ │ │ │ │ ├── findCollidingSigner.ts
│ │ │ │ │ └── showCollisionAlert.ts
│ │ │ │ ├── ImportSigners/
│ │ │ │ │ ├── ImportSigners.container.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── ImportSigners.container.test.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── Ledger/
│ │ │ │ │ ├── LedgerAddresses.container.tsx
│ │ │ │ │ ├── LedgerConnect.container.tsx
│ │ │ │ │ ├── LedgerIntro.container.tsx
│ │ │ │ │ ├── LedgerPairing.container.tsx
│ │ │ │ │ ├── LedgerSuccess.container.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── AddressItem.tsx
│ │ │ │ │ │ ├── AddressesEmptyState.tsx
│ │ │ │ │ │ ├── BluetoothError.tsx
│ │ │ │ │ │ ├── DeviceList.tsx
│ │ │ │ │ │ ├── EmptyState.tsx
│ │ │ │ │ │ ├── LedgerConnect.tsx
│ │ │ │ │ │ ├── LedgerError.tsx
│ │ │ │ │ │ ├── LedgerImportError.tsx
│ │ │ │ │ │ ├── LedgerPairing.tsx
│ │ │ │ │ │ ├── LedgerProgress.tsx
│ │ │ │ │ │ ├── LedgerSignerBadge.tsx
│ │ │ │ │ │ ├── LedgerSuccess.tsx
│ │ │ │ │ │ ├── LoadMoreButton.tsx
│ │ │ │ │ │ ├── PairingError.tsx
│ │ │ │ │ │ ├── PairingProgress.tsx
│ │ │ │ │ │ └── ScanningProgress.tsx
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ ├── useBluetoothStatus.test.ts
│ │ │ │ │ │ ├── useBluetoothStatus.ts
│ │ │ │ │ │ ├── useImportLedgerAddress.test.ts
│ │ │ │ │ │ ├── useImportLedgerAddress.ts
│ │ │ │ │ │ ├── useLedgerAddresses.test.ts
│ │ │ │ │ │ ├── useLedgerAddresses.ts
│ │ │ │ │ │ ├── useLedgerConnection.test.ts
│ │ │ │ │ │ ├── useLedgerConnection.ts
│ │ │ │ │ │ ├── useLedgerDeviceScanning.test.ts
│ │ │ │ │ │ └── useLedgerDeviceScanning.ts
│ │ │ │ │ ├── icons/
│ │ │ │ │ │ ├── BluetoothIcon.tsx
│ │ │ │ │ │ ├── DashIcon.tsx
│ │ │ │ │ │ ├── LedgerIcon.tsx
│ │ │ │ │ │ ├── PhoneIcon.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── LedgerExecute/
│ │ │ │ │ ├── LedgerConnect.container.tsx
│ │ │ │ │ ├── LedgerPairing.container.tsx
│ │ │ │ │ ├── LedgerReview.container.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── LedgerSign/
│ │ │ │ │ ├── LedgerConnect.container.tsx
│ │ │ │ │ ├── LedgerPairing.container.tsx
│ │ │ │ │ ├── LedgerReview.container.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── NetworksSheet/
│ │ │ │ │ ├── NetworksSheet.container.tsx
│ │ │ │ │ ├── NetworksSheetFooter.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── NetworksSheetFooter.test.tsx
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ └── useScanForNewNetworks.test.ts
│ │ │ │ │ │ └── useScanForNewNetworks.ts
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Notifications/
│ │ │ │ │ ├── NotificationsCenter.container.tsx
│ │ │ │ │ ├── NotificationsSettings.container.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── EmptyBell.tsx
│ │ │ │ │ │ ├── NotificationPermissions.tsx
│ │ │ │ │ │ ├── NotificationsScreenEmpty.tsx
│ │ │ │ │ │ └── NotificationsSettingsView.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Onboarding/
│ │ │ │ │ ├── Onboarding.container.test.tsx
│ │ │ │ │ ├── Onboarding.container.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── OnboardingCarousel/
│ │ │ │ │ │ │ ├── CarouselFeedback.test.tsx
│ │ │ │ │ │ │ ├── CarouselFeedback.tsx
│ │ │ │ │ │ │ ├── CarouselItem.test.tsx
│ │ │ │ │ │ │ ├── CarouselItem.tsx
│ │ │ │ │ │ │ ├── OnboardingCarousel.native.stories.tsx
│ │ │ │ │ │ │ ├── OnboardingCarousel.test.tsx
│ │ │ │ │ │ │ ├── OnboardingCarousel.tsx
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── items.tsx
│ │ │ │ │ │ └── OnboardingHeader/
│ │ │ │ │ │ ├── OnboardingHeader.test.tsx
│ │ │ │ │ │ ├── OnboardingHeader.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── PendingTx/
│ │ │ │ │ ├── PendingTx.container.test.tsx
│ │ │ │ │ ├── PendingTx.container.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ └── PendingTxList/
│ │ │ │ │ │ ├── PendingTxList.container.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── utils.tsx
│ │ │ │ ├── PrivateKey/
│ │ │ │ │ ├── PrivateKey.container.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── PrivateKeyView.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SafeShield/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── AnalysisDetails/
│ │ │ │ │ │ │ ├── AnalysisDetails.stories.tsx
│ │ │ │ │ │ │ ├── AnalysisDetails.test.tsx
│ │ │ │ │ │ │ ├── AnalysisDetails.tsx
│ │ │ │ │ │ │ ├── AnalysisDetailsContent.test.tsx
│ │ │ │ │ │ │ ├── AnalysisDetailsContent.tsx
│ │ │ │ │ │ │ ├── AnalysisDetailsHeader.test.tsx
│ │ │ │ │ │ │ ├── AnalysisDetailsHeader.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── AnalysisGroup/
│ │ │ │ │ │ │ ├── AnalysisDisplay/
│ │ │ │ │ │ │ │ ├── AnalysisDisplay.test.tsx
│ │ │ │ │ │ │ │ ├── AnalysisDisplay.tsx
│ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ ├── AddressChanges.test.tsx
│ │ │ │ │ │ │ │ │ ├── AddressChanges.tsx
│ │ │ │ │ │ │ │ │ ├── AddressListItem.test.tsx
│ │ │ │ │ │ │ │ │ ├── AddressListItem.tsx
│ │ │ │ │ │ │ │ │ ├── AnalysisDetailsDropdown.test.tsx
│ │ │ │ │ │ │ │ │ ├── AnalysisDetailsDropdown.tsx
│ │ │ │ │ │ │ │ │ ├── AnalysisDisplay.stories.tsx
│ │ │ │ │ │ │ │ │ ├── AnalysisIssuesDisplay.test.tsx
│ │ │ │ │ │ │ │ │ ├── AnalysisIssuesDisplay.tsx
│ │ │ │ │ │ │ │ │ ├── ShowAllAddress.test.tsx
│ │ │ │ │ │ │ │ │ └── ShowAllAddress.tsx
│ │ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ │ ├── AnalysisGroup.stories.tsx
│ │ │ │ │ │ │ ├── AnalysisGroup.test.tsx
│ │ │ │ │ │ │ ├── AnalysisGroup.tsx
│ │ │ │ │ │ │ ├── DelegateCallItem.tsx
│ │ │ │ │ │ │ ├── FallbackHandlerItem.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── AnalysisLabel/
│ │ │ │ │ │ │ ├── AnalysisLabel.stories.tsx
│ │ │ │ │ │ │ ├── AnalysisLabel.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── AnalysisPaper/
│ │ │ │ │ │ │ ├── AnalysisPaper.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── BalanceChange/
│ │ │ │ │ │ │ ├── BalanceChange.stories.tsx
│ │ │ │ │ │ │ ├── BalanceChangeBlock.test.tsx
│ │ │ │ │ │ │ ├── BalanceChangeBlock.tsx
│ │ │ │ │ │ │ ├── BalanceChangeItem.test.tsx
│ │ │ │ │ │ │ ├── BalanceChangeItem.tsx
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── utils/
│ │ │ │ │ │ │ ├── utils.test.ts
│ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ ├── SafeShieldDetailsSheet/
│ │ │ │ │ │ │ ├── SafeShieldDetailsSheet.container.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── SafeShieldHeadline/
│ │ │ │ │ │ │ ├── SafeShieldHeadline.stories.tsx
│ │ │ │ │ │ │ ├── SafeShieldHeadline.test.tsx
│ │ │ │ │ │ │ ├── SafeShieldHeadline.tsx
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ ├── theme.ts
│ │ │ │ │ │ │ └── variants.ts
│ │ │ │ │ │ ├── SafeShieldIcons/
│ │ │ │ │ │ │ ├── SafeShieldInfo.tsx
│ │ │ │ │ │ │ ├── SafeShieldIssues.tsx
│ │ │ │ │ │ │ ├── SafeShieldNeutral.tsx
│ │ │ │ │ │ │ ├── SafeShieldOk.tsx
│ │ │ │ │ │ │ ├── SafeShieldWarning.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── SafeShieldWidget/
│ │ │ │ │ │ │ ├── SafeShieldWidget.stories.tsx
│ │ │ │ │ │ │ ├── SafeShieldWidget.tsx
│ │ │ │ │ │ │ ├── WidgetAction/
│ │ │ │ │ │ │ │ ├── WidgetAction.stories.tsx
│ │ │ │ │ │ │ │ ├── WidgetAction.tsx
│ │ │ │ │ │ │ │ ├── constants.tsx
│ │ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ │ ├── WidgetDisplay/
│ │ │ │ │ │ │ │ ├── ErrorWidget/
│ │ │ │ │ │ │ │ │ ├── ErrorWidget.test.tsx
│ │ │ │ │ │ │ │ │ ├── ErrorWidget.tsx
│ │ │ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ │ │ ├── LoadingWidget/
│ │ │ │ │ │ │ │ │ ├── LoadingWidget.tsx
│ │ │ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ │ │ ├── WidgetDisplay.stories.tsx
│ │ │ │ │ │ │ │ ├── WidgetDisplay.tsx
│ │ │ │ │ │ │ │ ├── WidgetDisplayWrapper.tsx
│ │ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── theme.ts
│ │ │ │ │ │ └── TransactionSimulation/
│ │ │ │ │ │ ├── TransactionSimulation.tsx
│ │ │ │ │ │ ├── hooks/
│ │ │ │ │ │ │ └── useTransactionSimulation.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── useAnalysisAddress.ts
│ │ │ │ │ │ ├── useCounterpartyAnalysis.ts
│ │ │ │ │ │ ├── useSafeShieldSeverity.ts
│ │ │ │ │ │ └── useThreatAnalysis.ts
│ │ │ │ │ └── theme.ts
│ │ │ │ ├── Send/
│ │ │ │ │ ├── EnterAmount.container.tsx
│ │ │ │ │ ├── ScanQrSend.container.tsx
│ │ │ │ │ ├── SelectRecipient.container.tsx
│ │ │ │ │ ├── SelectToken.container.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── AddToAddressBookModal.tsx
│ │ │ │ │ │ ├── AmountDisplay.tsx
│ │ │ │ │ │ ├── CustomNonceModal.tsx
│ │ │ │ │ │ ├── DialogModal.tsx
│ │ │ │ │ │ ├── FooterAction.tsx
│ │ │ │ │ │ ├── KnownOtherChainWarning.tsx
│ │ │ │ │ │ ├── NonceBottomSheet.tsx
│ │ │ │ │ │ ├── ProposerBottomSheet.tsx
│ │ │ │ │ │ ├── RecipientDisplay.tsx
│ │ │ │ │ │ ├── RecipientHeader.tsx
│ │ │ │ │ │ ├── RecipientInput.tsx
│ │ │ │ │ │ ├── RecipientSections.tsx
│ │ │ │ │ │ ├── RecipientValidationBadge.tsx
│ │ │ │ │ │ ├── SelectProposer.tsx
│ │ │ │ │ │ ├── SuspiciousAddressComparison.tsx
│ │ │ │ │ │ ├── TokenListItem.tsx
│ │ │ │ │ │ └── TokenPill.tsx
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ ├── useAmountInput.test.ts
│ │ │ │ │ │ ├── useAmountInput.ts
│ │ │ │ │ │ ├── useEnsureActiveSigner.test.ts
│ │ │ │ │ │ ├── useEnsureActiveSigner.ts
│ │ │ │ │ │ ├── useFiatConversion.test.tsx
│ │ │ │ │ │ ├── useFiatConversion.ts
│ │ │ │ │ │ ├── useKeyboardVisible.ts
│ │ │ │ │ │ ├── useMaxAmount.test.ts
│ │ │ │ │ │ ├── useMaxAmount.ts
│ │ │ │ │ │ ├── useNonce.test.ts
│ │ │ │ │ │ ├── useNonce.ts
│ │ │ │ │ │ ├── useNonceSelection.ts
│ │ │ │ │ │ ├── useProposerSheet.ts
│ │ │ │ │ │ ├── useRecipientSearch.ts
│ │ │ │ │ │ ├── useRecipientValidation.test.ts
│ │ │ │ │ │ ├── useRecipientValidation.ts
│ │ │ │ │ │ ├── useSendTransaction.ts
│ │ │ │ │ │ ├── useSuspiciousAddressDetection.ts
│ │ │ │ │ │ └── useTokenBalance.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── services/
│ │ │ │ │ │ ├── proposeSendTransaction.test.ts
│ │ │ │ │ │ ├── proposeSendTransaction.ts
│ │ │ │ │ │ ├── tokenTransferParams.test.ts
│ │ │ │ │ │ └── tokenTransferParams.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── Settings/
│ │ │ │ │ ├── Settings.container.tsx
│ │ │ │ │ ├── Settings.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── Settings.test.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── AppSettings/
│ │ │ │ │ │ │ ├── AppSettings.container.tsx
│ │ │ │ │ │ │ ├── AppSettings.tsx
│ │ │ │ │ │ │ ├── AppSettings.types.ts
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── Currency/
│ │ │ │ │ │ │ ├── Currency.container.tsx
│ │ │ │ │ │ │ ├── Currency.types.ts
│ │ │ │ │ │ │ ├── CurrencyItem/
│ │ │ │ │ │ │ │ ├── CurrencyItem.tsx
│ │ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ │ ├── CurrencySection/
│ │ │ │ │ │ │ │ ├── CurrencySection.tsx
│ │ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ │ ├── CurrencyView.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── FloatingMenu.tsx
│ │ │ │ │ │ └── Navbar/
│ │ │ │ │ │ ├── Navbar.tsx
│ │ │ │ │ │ ├── SettingsButton.tsx
│ │ │ │ │ │ ├── SettingsMenu.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Share/
│ │ │ │ │ ├── Share.container.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── ShareView.test.tsx
│ │ │ │ │ │ ├── ShareView.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── Signer/
│ │ │ │ │ ├── Signer.container.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── SignerHeader.tsx
│ │ │ │ │ │ ├── SignerView.test.tsx
│ │ │ │ │ │ └── SignerView.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── schema.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── Signers/
│ │ │ │ │ ├── Signers.container.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ └── SignersList/
│ │ │ │ │ │ ├── ImportedBadge.tsx
│ │ │ │ │ │ ├── SignersList.tsx
│ │ │ │ │ │ ├── SignersListHeader.tsx
│ │ │ │ │ │ ├── SignersListItem.tsx
│ │ │ │ │ │ ├── hooks/
│ │ │ │ │ │ │ └── useSignersActions.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── constants.ts
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ ├── useSignersGroupService.test.ts
│ │ │ │ │ │ └── useSignersGroupService.ts
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TransactionActions/
│ │ │ │ │ ├── TransactionActions.container.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ └── TxActionsList.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── TransactionChecks/
│ │ │ │ │ ├── TransactionChecks.container.tsx
│ │ │ │ │ ├── blockaid/
│ │ │ │ │ │ └── useBlockaid.ts
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── TransactionChecksView.tsx
│ │ │ │ │ │ └── blockaid/
│ │ │ │ │ │ ├── PoweredByBlockaid.tsx
│ │ │ │ │ │ ├── ResultDescription.tsx
│ │ │ │ │ │ ├── balance/
│ │ │ │ │ │ │ ├── BalanceChange.tsx
│ │ │ │ │ │ │ ├── BlockaidBalanceChanges.tsx
│ │ │ │ │ │ │ ├── FungibleBalanceChange.tsx
│ │ │ │ │ │ │ └── NFTBalanceChange.tsx
│ │ │ │ │ │ └── scans/
│ │ │ │ │ │ ├── BlockaidError.tsx
│ │ │ │ │ │ ├── BlockaidHint.tsx
│ │ │ │ │ │ ├── BlockaidMessage.tsx
│ │ │ │ │ │ ├── BlockaidWarning.tsx
│ │ │ │ │ │ └── ContractChangeWarning.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── tenderly/
│ │ │ │ │ ├── useSimulation.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── TxHistory/
│ │ │ │ │ ├── TxHistory.container.test.tsx
│ │ │ │ │ ├── TxHistory.container.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── TransactionHeader/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ └── TxHistoryList/
│ │ │ │ │ │ ├── TxHistoryList.test.tsx
│ │ │ │ │ │ ├── TxHistoryList.tsx
│ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ ├── DateHeaderItem.tsx
│ │ │ │ │ │ │ ├── ErrorComponent.tsx
│ │ │ │ │ │ │ ├── GroupedTransactionItem.tsx
│ │ │ │ │ │ │ ├── LoadingComponents.tsx
│ │ │ │ │ │ │ └── TransactionListItem.tsx
│ │ │ │ │ │ ├── constants.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── utils.ts
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── utils.tsx
│ │ │ │ └── WalletConnect/
│ │ │ │ ├── appKit.ts
│ │ │ │ ├── components/
│ │ │ │ │ ├── AppKitInitializer/
│ │ │ │ │ │ ├── AppKitInitializer.tsx
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ └── AppKitInitializer.test.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── WalletConnectBadge/
│ │ │ │ │ │ ├── WalletConnectBadge.test.tsx
│ │ │ │ │ │ ├── WalletConnectBadge.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ └── WalletConnectGate/
│ │ │ │ │ ├── WalletConnectGate.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── WalletConnectGate.test.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── context/
│ │ │ │ │ ├── WalletConnectContext.e2e.tsx
│ │ │ │ │ ├── WalletConnectContext.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── WalletConnectContext.test.tsx
│ │ │ │ │ ├── types.ts
│ │ │ │ │ └── walletConnectE2eState.ts
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── useChainSync.test.ts
│ │ │ │ │ │ ├── useConnect.test.ts
│ │ │ │ │ │ ├── useImportSignerFlow.test.ts
│ │ │ │ │ │ ├── useReconnectFlow.test.ts
│ │ │ │ │ │ ├── useStableAppKitEvent.test.ts
│ │ │ │ │ │ ├── useSwitchNetwork.test.ts
│ │ │ │ │ │ ├── useWalletConnectSigning.test.ts
│ │ │ │ │ │ └── useWalletConnectStatus.test.ts
│ │ │ │ │ ├── useChainSync.ts
│ │ │ │ │ ├── useConnect.ts
│ │ │ │ │ ├── useImportSignerFlow.ts
│ │ │ │ │ ├── useReconnectFlow.ts
│ │ │ │ │ ├── useStableAppKitEvent.ts
│ │ │ │ │ ├── useSwitchNetwork.ts
│ │ │ │ │ ├── useWalletConnectSigning.ts
│ │ │ │ │ └── useWalletConnectStatus.ts
│ │ │ │ └── utils/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── chains.test.ts
│ │ │ │ └── chains.ts
│ │ │ ├── hooks/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── useAddressOwnershipValidation.test.ts
│ │ │ │ │ ├── useDatadogConsent.test.ts
│ │ │ │ │ ├── useDisplayName.test.ts
│ │ │ │ │ ├── useNotificationHandler.test.ts
│ │ │ │ │ ├── useScreenProtection.test.ts
│ │ │ │ │ └── useShareTransaction.test.ts
│ │ │ │ ├── coreSDK/
│ │ │ │ │ ├── safeCoreSDK.test.ts
│ │ │ │ │ ├── safeCoreSDK.ts
│ │ │ │ │ ├── useInitSafeCoreSDK.test.ts
│ │ │ │ │ └── useInitSafeCoreSDK.ts
│ │ │ │ ├── services/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── useLazySafeOverviews.test.ts
│ │ │ │ │ │ └── useSafeKnownChainsOverview.test.ts
│ │ │ │ │ ├── overviewQueryArgs.ts
│ │ │ │ │ ├── useLazySafeOverviews.ts
│ │ │ │ │ ├── useSafeKnownChainsOverview.ts
│ │ │ │ │ └── useSafeOverviewsQuery.ts
│ │ │ │ ├── useAddressOwnershipValidation.ts
│ │ │ │ ├── useAddresses.ts
│ │ │ │ ├── useAnalytics.ts
│ │ │ │ ├── useBalances.ts
│ │ │ │ ├── useBiometrics.test.ts
│ │ │ │ ├── useBiometrics.ts
│ │ │ │ ├── useCopyAndDispatchToast/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── useCopyAndDisptachToast.test.tsx
│ │ │ │ ├── useCurrencies.ts
│ │ │ │ ├── useDatadogConsent.ts
│ │ │ │ ├── useDelegate.test.ts
│ │ │ │ ├── useDelegate.ts
│ │ │ │ ├── useDelegateCleanup/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── utils.test.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── useDelegateCleanup.ts
│ │ │ │ ├── useDisplayName.ts
│ │ │ │ ├── useFeeParams/
│ │ │ │ │ ├── useFeeParams.test.ts
│ │ │ │ │ └── useFeeParams.ts
│ │ │ │ ├── useHasFeature.ts
│ │ │ │ ├── useHasSigner.ts
│ │ │ │ ├── useHeaderHeight.ts
│ │ │ │ ├── useInitWeb3.ts
│ │ │ │ ├── useIsMounted.ts
│ │ │ │ ├── useIsNextTx.ts
│ │ │ │ ├── useMakeSafesWithChainId/
│ │ │ │ │ ├── useMakeSafesWithChainId.test.ts
│ │ │ │ │ └── useMakeSafesWithChainId.ts
│ │ │ │ ├── useNotificationCleanup.ts
│ │ │ │ ├── useNotificationGTWPermissions.test.ts
│ │ │ │ ├── useNotificationGTWPermissions.ts
│ │ │ │ ├── useNotificationHandler.ts
│ │ │ │ ├── useNotificationManager.test.ts
│ │ │ │ ├── useNotificationManager.ts
│ │ │ │ ├── useNotificationPayload.test.ts
│ │ │ │ ├── useNotificationPayload.ts
│ │ │ │ ├── usePendingTxs/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── usePendingTxsMonitor.ts
│ │ │ │ ├── usePreventLeaveScreen/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── useRegisterForNotifications.ts
│ │ │ │ ├── useSafeCreationData.ts
│ │ │ │ ├── useSafeInfo.ts
│ │ │ │ ├── useSafeTx.test.ts
│ │ │ │ ├── useSafeTx.ts
│ │ │ │ ├── useScreenProtection.e2e.ts
│ │ │ │ ├── useScreenProtection.ts
│ │ │ │ ├── useScreenTracking.ts
│ │ │ │ ├── useShareTransaction.ts
│ │ │ │ ├── useSign/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── useSign.test.ts
│ │ │ │ │ └── useSign.ts
│ │ │ │ ├── useSiwe.ts
│ │ │ │ ├── useTokenDetails/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── useTokenDetails.ts
│ │ │ │ ├── useTotalBalances.ts
│ │ │ │ ├── useTransactionProcessingState.test.tsx
│ │ │ │ ├── useTransactionProcessingState.ts
│ │ │ │ ├── useTransactionSigningState.ts
│ │ │ │ ├── useTransactionType/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── useTransactionType.test.tsx
│ │ │ │ └── wallets/
│ │ │ │ ├── web3.test.ts
│ │ │ │ └── web3.ts
│ │ │ ├── navigation/
│ │ │ │ ├── NavigationGuardHOC.tsx
│ │ │ │ ├── dismissToConfirmTransaction.ts
│ │ │ │ ├── hooks/
│ │ │ │ │ └── utils.tsx
│ │ │ │ └── useScrollableHeader.tsx
│ │ │ ├── platform/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── fetch.test.ts
│ │ │ │ ├── crypto-shims.ts
│ │ │ │ ├── fetch.ts
│ │ │ │ ├── intl-polyfills.ts
│ │ │ │ └── security.ts
│ │ │ ├── providers/
│ │ │ │ └── DatadogWrapper.tsx
│ │ │ ├── react-app-env.d.ts
│ │ │ ├── services/
│ │ │ │ ├── analytics/
│ │ │ │ │ ├── constants.ts
│ │ │ │ │ ├── datadogAnalytics.ts
│ │ │ │ │ ├── events/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── copy.test.ts
│ │ │ │ │ │ │ └── overview.test.ts
│ │ │ │ │ │ ├── addressBook.ts
│ │ │ │ │ │ ├── copy.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── nativeIntent.ts
│ │ │ │ │ │ ├── overview.ts
│ │ │ │ │ │ ├── safes.ts
│ │ │ │ │ │ ├── settings.ts
│ │ │ │ │ │ ├── signers.ts
│ │ │ │ │ │ └── transactions.ts
│ │ │ │ │ ├── firebaseAnalytics.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── types.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── bluetooth/
│ │ │ │ │ └── bluetooth.service.ts
│ │ │ │ ├── contracts/
│ │ │ │ │ └── safeContracts.ts
│ │ │ │ ├── delegate-cleanup/
│ │ │ │ │ ├── DelegateCleanupService.test.ts
│ │ │ │ │ ├── DelegateCleanupService.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── key-storage/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── key-storage.service.test.ts
│ │ │ │ │ ├── key-storage.service.ts
│ │ │ │ │ ├── types.ts
│ │ │ │ │ └── wallet.service.ts
│ │ │ │ ├── ledger/
│ │ │ │ │ ├── ledger-dmk.service.test.ts
│ │ │ │ │ ├── ledger-dmk.service.ts
│ │ │ │ │ ├── ledger-ethereum.service.test.ts
│ │ │ │ │ ├── ledger-ethereum.service.ts
│ │ │ │ │ ├── ledger-execution.service.test.ts
│ │ │ │ │ ├── ledger-execution.service.ts
│ │ │ │ │ ├── ledger-safe-signing.service.test.ts
│ │ │ │ │ └── ledger-safe-signing.service.ts
│ │ │ │ ├── notifications/
│ │ │ │ │ ├── BadgeManager.ts
│ │ │ │ │ ├── FCMService.ts
│ │ │ │ │ ├── NotificationService.test.ts
│ │ │ │ │ ├── NotificationService.ts
│ │ │ │ │ ├── SubscriptionManager.ts
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── backend.test.ts
│ │ │ │ │ │ └── notificationNavigationHandler.test.ts
│ │ │ │ │ ├── backend.ts
│ │ │ │ │ ├── backgroundHandlers.ts
│ │ │ │ │ ├── notificationNavigationHandler.ts
│ │ │ │ │ ├── notificationParser.test.ts
│ │ │ │ │ ├── notificationParser.ts
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ ├── registration.ts
│ │ │ │ │ ├── store-sync/
│ │ │ │ │ │ ├── const.ts
│ │ │ │ │ │ ├── read.ts
│ │ │ │ │ │ └── sync.ts
│ │ │ │ │ └── utils/
│ │ │ │ │ ├── messageDeduplication.test.ts
│ │ │ │ │ └── messageDeduplication.ts
│ │ │ │ ├── remoteConfig/
│ │ │ │ │ ├── remoteConfigService.e2e.ts
│ │ │ │ │ └── remoteConfigService.ts
│ │ │ │ ├── tx/
│ │ │ │ │ ├── extractTx.test.ts
│ │ │ │ │ ├── extractTx.ts
│ │ │ │ │ ├── fetchTransactionDetails.ts
│ │ │ │ │ ├── proposeNewTransaction.ts
│ │ │ │ │ └── tx-sender/
│ │ │ │ │ ├── create.test.ts
│ │ │ │ │ ├── create.ts
│ │ │ │ │ ├── execute.test.ts
│ │ │ │ │ ├── execute.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── sign.test.ts
│ │ │ │ │ └── sign.ts
│ │ │ │ ├── tx-execution/
│ │ │ │ │ ├── ledgerExecutor.test.ts
│ │ │ │ │ ├── ledgerExecutor.ts
│ │ │ │ │ ├── privateKeyExecutor.test.ts
│ │ │ │ │ ├── privateKeyExecutor.ts
│ │ │ │ │ ├── relayExecutor.test.ts
│ │ │ │ │ ├── relayExecutor.ts
│ │ │ │ │ ├── walletConnectExecutor.test.ts
│ │ │ │ │ └── walletConnectExecutor.ts
│ │ │ │ ├── walletconnect/
│ │ │ │ │ ├── walletconnect-signing.service.test.ts
│ │ │ │ │ └── walletconnect-signing.service.ts
│ │ │ │ └── web3/
│ │ │ │ └── index.ts
│ │ │ ├── store/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── activeSafeSlice.test.ts
│ │ │ │ │ ├── addressBookSlice.selector.test.ts
│ │ │ │ │ ├── addressBookSlice.test.ts
│ │ │ │ │ ├── migrations.test.ts
│ │ │ │ │ ├── persistConfig.test.ts
│ │ │ │ │ ├── persistMigrations.test.ts
│ │ │ │ │ ├── safesSlice.test.ts
│ │ │ │ │ ├── sanitizePendingQueriesTransform.test.ts
│ │ │ │ │ ├── settingsSlice.test.ts
│ │ │ │ │ └── signersSlice.test.ts
│ │ │ │ ├── activeSafeSlice.ts
│ │ │ │ ├── activeSignerSlice.ts
│ │ │ │ ├── addressBookSlice.ts
│ │ │ │ ├── biometricsSlice.ts
│ │ │ │ ├── chains/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── constants.ts
│ │ │ │ ├── delegatesSlice.ts
│ │ │ │ ├── estimatedFeeSlice.ts
│ │ │ │ ├── executingStateSlice.test.ts
│ │ │ │ ├── executingStateSlice.ts
│ │ │ │ ├── executionMethodSlice.ts
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── activeSafe.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── storeHooks.test.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── middleware/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── notificationSync.test.ts
│ │ │ │ │ │ └── pendingTxs.test.ts
│ │ │ │ │ ├── analytics/
│ │ │ │ │ │ ├── AnalyticsStrategyManager.ts
│ │ │ │ │ │ └── strategies/
│ │ │ │ │ │ ├── AddressBookTrackingStrategy.ts
│ │ │ │ │ │ ├── SafeManagementStrategy.ts
│ │ │ │ │ │ ├── SafeViewedStrategy.ts
│ │ │ │ │ │ ├── SettingsStrategy.ts
│ │ │ │ │ │ ├── SignerTrackingStrategy.ts
│ │ │ │ │ │ ├── TransactionConfirmationStrategy.ts
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── AddressBookTrackingStrategy.test.ts
│ │ │ │ │ │ │ ├── SafeManagementStrategy.test.ts
│ │ │ │ │ │ │ ├── SafeViewedStrategy.test.ts
│ │ │ │ │ │ │ ├── SettingsStrategy.test.ts
│ │ │ │ │ │ │ ├── SignerTrackingStrategy.test.ts
│ │ │ │ │ │ │ └── TransactionConfirmationStrategy.test.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── analytics.ts
│ │ │ │ │ ├── notificationSync.ts
│ │ │ │ │ ├── notifications/
│ │ │ │ │ │ ├── NotificationStrategyManager.ts
│ │ │ │ │ │ └── strategies/
│ │ │ │ │ │ ├── AddDelegateStrategy.ts
│ │ │ │ │ │ ├── AddSafeStrategy.ts
│ │ │ │ │ │ ├── RemoveSafeStrategy.ts
│ │ │ │ │ │ ├── ToggleAppNotificationsStrategy.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── notifications.ts
│ │ │ │ │ └── pendingTxs.ts
│ │ │ │ ├── migrations.ts
│ │ │ │ ├── myAccountsSlice.ts
│ │ │ │ ├── notificationsSlice.ts
│ │ │ │ ├── pendingTxsSlice.ts
│ │ │ │ ├── resetE2EState.test.ts
│ │ │ │ ├── resetE2EState.ts
│ │ │ │ ├── safeSubscriptionsSlice.ts
│ │ │ │ ├── safesSettingsSlice.test.ts
│ │ │ │ ├── safesSettingsSlice.ts
│ │ │ │ ├── safesSlice.ts
│ │ │ │ ├── settingsSlice.test.ts
│ │ │ │ ├── settingsSlice.ts
│ │ │ │ ├── signerImportFlowSlice.ts
│ │ │ │ ├── signerThunks.ts
│ │ │ │ ├── signersBalance.ts
│ │ │ │ ├── signersSlice.ts
│ │ │ │ ├── signingStateSlice.test.ts
│ │ │ │ ├── signingStateSlice.ts
│ │ │ │ ├── storage.ts
│ │ │ │ ├── txHistorySlice.ts
│ │ │ │ └── utils/
│ │ │ │ ├── cookieHandling.test.ts
│ │ │ │ ├── cookieHandling.ts
│ │ │ │ ├── singletonStore.ts
│ │ │ │ └── strategy/
│ │ │ │ ├── Strategy.ts
│ │ │ │ └── StrategyManager.ts
│ │ │ ├── tests/
│ │ │ │ ├── e2e-maestro/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── TestCtrls.e2e.tsx
│ │ │ │ │ │ └── TestCtrls.tsx
│ │ │ │ │ └── setup/
│ │ │ │ │ ├── assetsSetup.ts
│ │ │ │ │ ├── connectSignerSetup.ts
│ │ │ │ │ ├── historySetup.ts
│ │ │ │ │ ├── mockData.ts
│ │ │ │ │ ├── onboardingSetup.ts
│ │ │ │ │ ├── pendingTxSetup.ts
│ │ │ │ │ ├── positionsSetup.ts
│ │ │ │ │ └── setupHelpers.ts
│ │ │ │ ├── factories/
│ │ │ │ │ └── transaction.ts
│ │ │ │ ├── jest.setup.tsx
│ │ │ │ ├── mocks.ts
│ │ │ │ ├── server.ts
│ │ │ │ └── test-utils.tsx
│ │ │ ├── theme/
│ │ │ │ ├── SafeStatusBar.tsx
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── SafeStatusBar.test.tsx
│ │ │ │ ├── hooks/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── useTheme.test.tsx
│ │ │ │ │ ├── useSafeAreaPaddingBottom.tsx
│ │ │ │ │ └── useTheme.tsx
│ │ │ │ ├── navigation.ts
│ │ │ │ ├── provider/
│ │ │ │ │ ├── DataFetchProvider.tsx
│ │ │ │ │ ├── font.tsx
│ │ │ │ │ ├── safeTheme.tsx
│ │ │ │ │ ├── storybookTheme.tsx
│ │ │ │ │ └── toastProvider.tsx
│ │ │ │ ├── tamagui.config.ts
│ │ │ │ └── tokens.ts
│ │ │ ├── types/
│ │ │ │ ├── address.ts
│ │ │ │ ├── iconTypes.ts
│ │ │ │ ├── notifee.d.ts
│ │ │ │ ├── react-native-device-info.d.ts
│ │ │ │ ├── theme.ts
│ │ │ │ └── txType.ts
│ │ │ └── utils/
│ │ │ ├── balance.test.ts
│ │ │ ├── balance.ts
│ │ │ ├── chains.test.ts
│ │ │ ├── chains.ts
│ │ │ ├── currency.test.ts
│ │ │ ├── currency.ts
│ │ │ ├── date.test.ts
│ │ │ ├── date.ts
│ │ │ ├── delegate.ts
│ │ │ ├── errors/
│ │ │ │ ├── index.ts
│ │ │ │ └── standardErrors.ts
│ │ │ ├── feeParams.test.ts
│ │ │ ├── feeParams.ts
│ │ │ ├── formatters.test.ts
│ │ │ ├── formatters.ts
│ │ │ ├── inputDetection.test.ts
│ │ │ ├── inputDetection.ts
│ │ │ ├── legacyData.test.ts
│ │ │ ├── legacyData.ts
│ │ │ ├── logger.ts
│ │ │ ├── notifications/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── cleanup.test.ts
│ │ │ │ ├── accountType.test.ts
│ │ │ │ ├── accountType.ts
│ │ │ │ ├── cleanup.ts
│ │ │ │ └── index.ts
│ │ │ ├── retry.ts
│ │ │ ├── signer.test.ts
│ │ │ ├── signer.ts
│ │ │ ├── swapOrderUtils.test.tsx
│ │ │ ├── swapOrderUtils.tsx
│ │ │ ├── transaction-guards.test.ts
│ │ │ ├── transaction-guards.ts
│ │ │ ├── transactions.test.tsx
│ │ │ ├── transactions.tsx
│ │ │ ├── url.test.ts
│ │ │ ├── url.ts
│ │ │ ├── uuid.test.ts
│ │ │ └── uuid.ts
│ │ └── tsconfig.json
│ ├── tx-builder/
│ │ ├── README.md
│ │ ├── docs/
│ │ │ └── release-procedure.md
│ │ ├── eslint.config.mjs
│ │ ├── index.html
│ │ ├── jest.config.cjs
│ │ ├── package.json
│ │ ├── public/
│ │ │ └── manifest.json
│ │ ├── src/
│ │ │ ├── App.tsx
│ │ │ ├── __mocks__/
│ │ │ │ └── fileMock.js
│ │ │ ├── components/
│ │ │ │ ├── Accordion/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Button.tsx
│ │ │ │ ├── Card/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ChecksumWarning.tsx
│ │ │ │ ├── CreateNewBatchCard.tsx
│ │ │ │ ├── Divider.tsx
│ │ │ │ ├── Dot/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ETHHashInfo.tsx
│ │ │ │ ├── EditableLabel.tsx
│ │ │ │ ├── EllipsisMenu/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ErrorAlert.tsx
│ │ │ │ ├── FixedIcon/
│ │ │ │ │ ├── images/
│ │ │ │ │ │ ├── arrowReceived.tsx
│ │ │ │ │ │ ├── arrowReceivedWhite.tsx
│ │ │ │ │ │ ├── arrowSent.tsx
│ │ │ │ │ │ ├── arrowSentWhite.tsx
│ │ │ │ │ │ ├── arrowSort.tsx
│ │ │ │ │ │ ├── bullit.tsx
│ │ │ │ │ │ ├── chevronDown.tsx
│ │ │ │ │ │ ├── chevronLeft.tsx
│ │ │ │ │ │ ├── chevronRight.tsx
│ │ │ │ │ │ ├── chevronUp.tsx
│ │ │ │ │ │ ├── connectedRinkeby.tsx
│ │ │ │ │ │ ├── connectedWallet.tsx
│ │ │ │ │ │ ├── creatingInProgress.tsx
│ │ │ │ │ │ ├── dropdownArrowSmall.tsx
│ │ │ │ │ │ ├── networkError.tsx
│ │ │ │ │ │ ├── notConnected.tsx
│ │ │ │ │ │ ├── notOwner.tsx
│ │ │ │ │ │ ├── options.tsx
│ │ │ │ │ │ ├── plus.tsx
│ │ │ │ │ │ ├── settingsChange.tsx
│ │ │ │ │ │ └── threeDots.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── GenericModal.tsx
│ │ │ │ ├── Header.test.tsx
│ │ │ │ ├── Header.tsx
│ │ │ │ ├── Icon/
│ │ │ │ │ ├── images/
│ │ │ │ │ │ ├── alert.tsx
│ │ │ │ │ │ ├── bookmark.tsx
│ │ │ │ │ │ ├── bookmarkFilled.tsx
│ │ │ │ │ │ ├── check.tsx
│ │ │ │ │ │ ├── code.tsx
│ │ │ │ │ │ ├── copy.tsx
│ │ │ │ │ │ ├── cross.tsx
│ │ │ │ │ │ ├── delete.tsx
│ │ │ │ │ │ ├── edit.tsx
│ │ │ │ │ │ ├── externalLink.tsx
│ │ │ │ │ │ ├── import.tsx
│ │ │ │ │ │ ├── info.tsx
│ │ │ │ │ │ └── termsOfUse.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── IconText/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Link/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Loader/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── QuickTip.tsx
│ │ │ │ ├── ShowMoreText.tsx
│ │ │ │ ├── Switch.tsx
│ │ │ │ ├── Text.tsx
│ │ │ │ ├── Title.tsx
│ │ │ │ ├── Tooltip.tsx
│ │ │ │ ├── TransactionBatchListItem.tsx
│ │ │ │ ├── TransactionDetails.tsx
│ │ │ │ ├── TransactionsBatchList.tsx
│ │ │ │ ├── VirtualizedList.tsx
│ │ │ │ ├── Wrapper/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── buttons/
│ │ │ │ │ ├── ButtonLink/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── CopyToClipboardBtn/
│ │ │ │ │ │ ├── copyTextToClipboard.ts
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── ExplorerButton/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ └── Identicon/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── forms/
│ │ │ │ │ ├── AddNewTransactionForm.tsx
│ │ │ │ │ ├── SolidityForm.test.tsx
│ │ │ │ │ ├── SolidityForm.tsx
│ │ │ │ │ ├── fields/
│ │ │ │ │ │ ├── AddressContractField.tsx
│ │ │ │ │ │ ├── AddressInput.tsx
│ │ │ │ │ │ ├── Field.tsx
│ │ │ │ │ │ ├── JsonField.tsx
│ │ │ │ │ │ ├── SelectContractField.tsx
│ │ │ │ │ │ ├── TextContractField.tsx
│ │ │ │ │ │ ├── TextFieldInput.tsx
│ │ │ │ │ │ ├── TextareaContractField.tsx
│ │ │ │ │ │ ├── fields.test.ts
│ │ │ │ │ │ ├── fields.ts
│ │ │ │ │ │ └── styles.ts
│ │ │ │ │ └── validations/
│ │ │ │ │ ├── basicSolidityValidation.ts
│ │ │ │ │ ├── validateAddressField.ts
│ │ │ │ │ ├── validateAmountField.ts
│ │ │ │ │ ├── validateBooleanField.ts
│ │ │ │ │ ├── validateField.ts
│ │ │ │ │ ├── validateHexEncodedDataField.ts
│ │ │ │ │ └── validations.test.ts
│ │ │ │ └── modals/
│ │ │ │ ├── DeleteBatchFromLibrary.tsx
│ │ │ │ ├── DeleteBatchModal.tsx
│ │ │ │ ├── DeleteTransactionModal.tsx
│ │ │ │ ├── EditTransactionModal.tsx
│ │ │ │ ├── ImplementationABIDialog.tsx
│ │ │ │ ├── SaveBatchModal.tsx
│ │ │ │ ├── SuccessBatchCreationModal.tsx
│ │ │ │ └── WrongChainBatchModal.tsx
│ │ │ ├── global.ts
│ │ │ ├── hooks/
│ │ │ │ ├── useAbi.ts
│ │ │ │ ├── useAsync.ts
│ │ │ │ ├── useDebounce.ts
│ │ │ │ ├── useDropZone/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── useElementHeight/
│ │ │ │ │ └── useElementHeight.tsx
│ │ │ │ ├── useModal/
│ │ │ │ │ └── useModal.tsx
│ │ │ │ ├── useSimulation.ts
│ │ │ │ └── useThrottle.ts
│ │ │ ├── lib/
│ │ │ │ ├── analytics.ts
│ │ │ │ ├── batches/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── checksum.test.ts
│ │ │ │ ├── checksum.ts
│ │ │ │ ├── getAbi.test.ts
│ │ │ │ ├── getAbi.ts
│ │ │ │ ├── interfaceRepository.ts
│ │ │ │ ├── local-storage/
│ │ │ │ │ ├── Storage.ts
│ │ │ │ │ └── local.ts
│ │ │ │ ├── simulation/
│ │ │ │ │ ├── multisend.ts
│ │ │ │ │ ├── simulation.ts
│ │ │ │ │ └── types.ts
│ │ │ │ └── storage.ts
│ │ │ ├── main.tsx
│ │ │ ├── mocks/
│ │ │ │ └── handlers.ts
│ │ │ ├── pages/
│ │ │ │ ├── CreateTransactions.tsx
│ │ │ │ ├── Dashboard.tsx
│ │ │ │ ├── EditTransactionLibrary.tsx
│ │ │ │ ├── ReviewAndConfirm.tsx
│ │ │ │ ├── SaveTransactionLibrary.tsx
│ │ │ │ └── TransactionLibrary.tsx
│ │ │ ├── routes/
│ │ │ │ └── routes.ts
│ │ │ ├── setupTests.ts
│ │ │ ├── store/
│ │ │ │ ├── index.tsx
│ │ │ │ ├── networkContext.tsx
│ │ │ │ ├── transactionLibraryContext.tsx
│ │ │ │ └── transactionsContext.tsx
│ │ │ ├── test-utils.tsx
│ │ │ ├── theme/
│ │ │ │ ├── SafeThemeProvider.tsx
│ │ │ │ ├── darkPalette.ts
│ │ │ │ ├── lightPalette.ts
│ │ │ │ ├── safeTheme.ts
│ │ │ │ └── typography.ts
│ │ │ ├── typings/
│ │ │ │ ├── custom.d.ts
│ │ │ │ ├── errors.ts
│ │ │ │ ├── fonts.d.ts
│ │ │ │ └── models.ts
│ │ │ ├── utils/
│ │ │ │ ├── __mocks__/
│ │ │ │ │ └── env.ts
│ │ │ │ ├── address.ts
│ │ │ │ ├── env.ts
│ │ │ │ └── strings.ts
│ │ │ ├── utils.test.ts
│ │ │ ├── utils.ts
│ │ │ └── vite-env.d.ts
│ │ ├── tsconfig.json
│ │ ├── tsconfig.node.json
│ │ └── vite.config.ts
│ └── web/
│ ├── .dockerignore
│ ├── .gitignore
│ ├── .storybook/
│ │ ├── AGENTS.md
│ │ ├── COVERAGE.md
│ │ ├── decorators/
│ │ │ ├── LayoutDecorator.tsx
│ │ │ ├── MockProviderDecorator.tsx
│ │ │ └── index.ts
│ │ ├── main.ts
│ │ ├── mocks/
│ │ │ ├── nextImage.js
│ │ │ ├── querystring.ts
│ │ │ ├── svgMock.tsx
│ │ │ └── useIsOfficialHost.ts
│ │ ├── preview-head.html
│ │ ├── preview.tsx
│ │ ├── shadcn-stories.css
│ │ ├── shadcn.ts
│ │ └── test-runner.mjs
│ ├── .storybook-vite/
│ │ ├── main.ts
│ │ ├── preview-head.html
│ │ └── preview.tsx
│ ├── AGENTS.md
│ ├── Dockerfile
│ ├── LICENSE
│ ├── README.md
│ ├── chromatic.config.json
│ ├── components.json
│ ├── cypress/
│ │ ├── AGENTS.md
│ │ ├── CLAUDE.md
│ │ ├── COVERAGE.md
│ │ ├── ci.json
│ │ ├── e2e/
│ │ │ ├── happypath/
│ │ │ │ ├── recovery_hp_1.cy.js
│ │ │ │ ├── recovery_hp_2.cy.js
│ │ │ │ ├── recovery_hp_3.cy.js
│ │ │ │ ├── recovery_hp_4.cy.js
│ │ │ │ ├── sendfunds_connected_wallet.cy.js
│ │ │ │ ├── sendfunds_queue_1.cy.js
│ │ │ │ ├── sendfunds_relay.cy.js
│ │ │ │ ├── tx_history_filter_hp_1.cy.js
│ │ │ │ └── tx_history_filter_hp_2.cy.js
│ │ │ ├── happypath_2/
│ │ │ │ ├── add_owner.cy.js
│ │ │ │ ├── create_safe_cf.cy.js
│ │ │ │ ├── mass_payouts.cy.js
│ │ │ │ ├── multichain_create_safe.cy.js
│ │ │ │ ├── nested_safes.cy.js
│ │ │ │ ├── proposers.cy.js
│ │ │ │ ├── swaps.cy.js
│ │ │ │ └── tx-builder.cy.js
│ │ │ ├── pages/
│ │ │ │ ├── accounts_modal.pages.js
│ │ │ │ ├── address_book.page.js
│ │ │ │ ├── assets.pages.js
│ │ │ │ ├── batches.pages.js
│ │ │ │ ├── bridge.pages.js
│ │ │ │ ├── copilot.js
│ │ │ │ ├── create_tx.pages.js
│ │ │ │ ├── create_wallet.pages.js
│ │ │ │ ├── dashboard.pages.js
│ │ │ │ ├── header.page.js
│ │ │ │ ├── import_export.pages.js
│ │ │ │ ├── load_safe.pages.js
│ │ │ │ ├── main.page.js
│ │ │ │ ├── messages.pages.js
│ │ │ │ ├── modals/
│ │ │ │ │ └── message_confirmation.pages.js
│ │ │ │ ├── modals.page.js
│ │ │ │ ├── modules.page.js
│ │ │ │ ├── navigation.page.js
│ │ │ │ ├── nestedsafes.pages.js
│ │ │ │ ├── network.pages.js
│ │ │ │ ├── nfts.pages.js
│ │ │ │ ├── notifications.page.js
│ │ │ │ ├── owners.pages.js
│ │ │ │ ├── portfolio.pages.js
│ │ │ │ ├── proposers.pages.js
│ │ │ │ ├── recovery.pages.js
│ │ │ │ ├── safe_navigation.pages.js
│ │ │ │ ├── safeapps.pages.js
│ │ │ │ ├── sidebar.pages.js
│ │ │ │ ├── spaces.page.js
│ │ │ │ ├── spending_limits.pages.js
│ │ │ │ ├── staking.page.js
│ │ │ │ ├── swaps.pages.js
│ │ │ │ ├── tables.page.js
│ │ │ │ ├── transactions.page.js
│ │ │ │ └── walletconnect.page.js
│ │ │ ├── prodhealthcheck/
│ │ │ │ ├── add_owner.cy.js
│ │ │ │ ├── create_tx.cy.js
│ │ │ │ ├── load_safe.cy.js
│ │ │ │ ├── messages_onchain.cy.js
│ │ │ │ ├── multichain_network.cy.js
│ │ │ │ ├── nfts.cy.js
│ │ │ │ ├── recovery.cy.js
│ │ │ │ ├── remove_owner.cy.js
│ │ │ │ ├── sidebar.cy.js
│ │ │ │ ├── sidebar_3.cy.js
│ │ │ │ ├── spending_limits.cy.js
│ │ │ │ ├── swaps_history_2.cy.js
│ │ │ │ ├── swaps_tokens.cy.js
│ │ │ │ ├── tokens.cy.js
│ │ │ │ ├── tx_history.cy.js
│ │ │ │ └── tx_history_2.cy.js
│ │ │ ├── regression/
│ │ │ │ ├── add_owner.cy.js
│ │ │ │ ├── address_book.cy.js
│ │ │ │ ├── address_book_2.cy.js
│ │ │ │ ├── address_book_3.cy.js
│ │ │ │ ├── assets.cy.js
│ │ │ │ ├── assets_2.cy.js
│ │ │ │ ├── balances_pagination.cy.js
│ │ │ │ ├── batch_tx.cy.js
│ │ │ │ ├── bulk_execution.cy.js
│ │ │ │ ├── copilot.cy.js
│ │ │ │ ├── create_safe_cf.cy.js
│ │ │ │ ├── create_safe_simple.cy.js
│ │ │ │ ├── create_safe_simple_2.cy.js
│ │ │ │ ├── create_safe_simple_3.cy.js
│ │ │ │ ├── create_tx.cy.js
│ │ │ │ ├── create_tx_2.cy.js
│ │ │ │ ├── dashboard.cy.js
│ │ │ │ ├── import_export_data_2.cy.js
│ │ │ │ ├── limit_order.cy.js
│ │ │ │ ├── limit_order_history.cy.js
│ │ │ │ ├── limit_order_queue.cy.js
│ │ │ │ ├── load_safe.cy.js
│ │ │ │ ├── load_safe_2.cy.js
│ │ │ │ ├── load_safe_3.cy.js
│ │ │ │ ├── mass_payouts.cy.js
│ │ │ │ ├── messages_offchain.cy.js
│ │ │ │ ├── messages_onchain.cy.js
│ │ │ │ ├── messages_popup.cy.js
│ │ │ │ ├── multichain_create_safe.cy.js
│ │ │ │ ├── multichain_create_safe_flow.cy.js
│ │ │ │ ├── multichain_network.cy.js
│ │ │ │ ├── multichain_networkswitch.cy.js
│ │ │ │ ├── multichain_safe_selector.cy.js
│ │ │ │ ├── multichain_setup.cy.js
│ │ │ │ ├── multichain_setup_new.cy.js
│ │ │ │ ├── multichain_sidebar.cy.js
│ │ │ │ ├── nested_safes.cy.js
│ │ │ │ ├── nested_safes_curation.cy.js
│ │ │ │ ├── nested_safes_fund_asset.cy.js
│ │ │ │ ├── nested_safes_review.cy.js
│ │ │ │ ├── nfts.cy.js
│ │ │ │ ├── nfts_2.cy.js
│ │ │ │ ├── notifications.cy.js
│ │ │ │ ├── portfolio.cy.js
│ │ │ │ ├── proposers.cy.js
│ │ │ │ ├── proposers_2.cy.js
│ │ │ │ ├── recovery.cy.js
│ │ │ │ ├── recovery_2.cy.js
│ │ │ │ ├── remove_owner.cy.js
│ │ │ │ ├── replace_owner.cy.js
│ │ │ │ ├── safe_selector.cy.js
│ │ │ │ ├── sidebar.cy.js
│ │ │ │ ├── sidebar_2.cy.js
│ │ │ │ ├── sidebar_3.cy.js
│ │ │ │ ├── sidebar_4.cy.js
│ │ │ │ ├── sidebar_5.cy.js
│ │ │ │ ├── sidebar_6.cy.js
│ │ │ │ ├── sidebar_7.cy.js
│ │ │ │ ├── sidebar_8.cy.js
│ │ │ │ ├── sidebar_9.cy.js
│ │ │ │ ├── sidebar_new.cy.js
│ │ │ │ ├── sidebar_nonowner.cy.js
│ │ │ │ ├── spaces_basicflow.cy.js
│ │ │ │ ├── spaces_dashboard.cy.js
│ │ │ │ ├── spending_limits.cy.js
│ │ │ │ ├── spending_limits_nonowner.cy.js
│ │ │ │ ├── staking_history.cy.js
│ │ │ │ ├── swaps.cy.js
│ │ │ │ ├── swaps_2.cy.js
│ │ │ │ ├── swaps_history.cy.js
│ │ │ │ ├── swaps_history_2.cy.js
│ │ │ │ ├── swaps_queue.cy.js
│ │ │ │ ├── swaps_tokens.cy.js
│ │ │ │ ├── tokens.cy.js
│ │ │ │ ├── twaps_history.cy.js
│ │ │ │ ├── twaps_integration.cy.js
│ │ │ │ ├── twaps_queue.cy.js
│ │ │ │ ├── tx_details_createtx.cy.js
│ │ │ │ ├── tx_details_queue.cy.js
│ │ │ │ ├── tx_history.cy.js
│ │ │ │ ├── tx_history_2.cy.js
│ │ │ │ ├── tx_history_3.cy.js
│ │ │ │ ├── tx_history_4.cy.js
│ │ │ │ ├── tx_history_5.cy.js
│ │ │ │ ├── tx_history_6.cy.js
│ │ │ │ ├── tx_history_filter.cy.js
│ │ │ │ ├── tx_history_filter_2.cy.js
│ │ │ │ ├── tx_notes.cy.js
│ │ │ │ ├── tx_queue.cy.js
│ │ │ │ ├── tx_queue_delete_btn.cy.js
│ │ │ │ ├── tx_queue_reject_btn.cy.js
│ │ │ │ ├── tx_queue_replace_btn.cy.js
│ │ │ │ ├── tx_share_block.cy.js
│ │ │ │ ├── walletconnect.cy.js
│ │ │ │ └── walletconnect_2.cy.js
│ │ │ ├── safe-apps/
│ │ │ │ ├── apps_list.cy.js
│ │ │ │ ├── browser_permissions.cy.js
│ │ │ │ ├── constants.js
│ │ │ │ ├── drain_account.spec.cy.js
│ │ │ │ ├── info_modal.cy.js
│ │ │ │ ├── permissions_settings.cy.js
│ │ │ │ ├── preview_drawer.cy.js
│ │ │ │ ├── safe_permissions.cy.js
│ │ │ │ ├── tx-builder.cy.js
│ │ │ │ ├── tx-builder_2.cy.js
│ │ │ │ └── tx-builder_3.cy.js
│ │ │ ├── smoke/
│ │ │ │ ├── add_owner.cy.js
│ │ │ │ ├── address_book.cy.js
│ │ │ │ ├── assets.cy.js
│ │ │ │ ├── balances_endpoints.cy.js
│ │ │ │ ├── batch_tx.cy.js
│ │ │ │ ├── create_tx.cy.js
│ │ │ │ ├── dashboard.cy.js
│ │ │ │ ├── import_export_data.cy.js
│ │ │ │ ├── import_export_data_2.cy.js
│ │ │ │ ├── landing.cy.js
│ │ │ │ ├── load_safe.cy.js
│ │ │ │ ├── messages_offchain.cy.js
│ │ │ │ ├── nfts.cy.js
│ │ │ │ ├── replace_owner.cy.js
│ │ │ │ ├── safe_selector.cy.js
│ │ │ │ ├── sidebar.cy.js
│ │ │ │ ├── spending_limits.cy.js
│ │ │ │ ├── tokens.cy.js
│ │ │ │ └── tx_history.cy.js
│ │ │ └── visual/
│ │ │ ├── address_book.cy.js
│ │ │ ├── apps_custom.cy.js
│ │ │ ├── balances.cy.js
│ │ │ ├── batch_tx.cy.js
│ │ │ ├── bridge.cy.js
│ │ │ ├── create_tx_flow.cy.js
│ │ │ ├── dashboard.cy.js
│ │ │ ├── earn.cy.js
│ │ │ ├── env_variables.cy.js
│ │ │ ├── error_pages.cy.js
│ │ │ ├── legal_pages.cy.js
│ │ │ ├── messages.cy.js
│ │ │ ├── msg_details.cy.js
│ │ │ ├── new_safe.cy.js
│ │ │ ├── new_safe_advanced.cy.js
│ │ │ ├── nfts.cy.js
│ │ │ ├── owner_management.cy.js
│ │ │ ├── positions.cy.js
│ │ │ ├── safe_apps.cy.js
│ │ │ ├── settings_cookies.cy.js
│ │ │ ├── settings_data_security.cy.js
│ │ │ ├── settings_pages.cy.js
│ │ │ ├── settings_safe_apps.cy.js
│ │ │ ├── sidebar.cy.js
│ │ │ ├── spaces.cy.js
│ │ │ ├── spending_limits.cy.js
│ │ │ ├── stake.cy.js
│ │ │ ├── swap.cy.js
│ │ │ ├── tx_details.cy.js
│ │ │ ├── tx_history.cy.js
│ │ │ ├── tx_queue.cy.js
│ │ │ ├── user_settings.cy.js
│ │ │ └── welcome.cy.js
│ │ ├── fixtures/
│ │ │ ├── address_book_addedsafes.csv
│ │ │ ├── address_book_duplicated.csv
│ │ │ ├── address_book_empty_test.csv
│ │ │ ├── address_book_networks.csv
│ │ │ ├── address_book_test.csv
│ │ │ ├── balances.json
│ │ │ ├── data_import.json
│ │ │ ├── history/
│ │ │ │ └── history_tx_1.json
│ │ │ ├── messages/
│ │ │ │ └── messages.json
│ │ │ ├── nfts/
│ │ │ │ └── nfts.json
│ │ │ ├── pending_tx/
│ │ │ │ ├── pending_tx.json
│ │ │ │ └── pending_tx_order.json
│ │ │ ├── safe-app.html
│ │ │ ├── safes/
│ │ │ │ ├── funds.json
│ │ │ │ ├── nfts.json
│ │ │ │ ├── recovery.json
│ │ │ │ ├── safeapps.json
│ │ │ │ └── static.js
│ │ │ ├── spaces/
│ │ │ │ ├── address_book.json
│ │ │ │ ├── members.json
│ │ │ │ ├── staticSpaces.js
│ │ │ │ ├── user.json
│ │ │ │ └── visualSpacesApiMock.js
│ │ │ ├── staking_data.json
│ │ │ ├── swaps/
│ │ │ │ ├── quoteresponse1.json
│ │ │ │ └── quoteresponse2.json
│ │ │ ├── swaps_data.json
│ │ │ ├── test-empty-batch.json
│ │ │ ├── test-invalid-batch.json
│ │ │ ├── test-mainnet-batch.json
│ │ │ ├── test-modified-batch.json
│ │ │ ├── test-working-batch.json
│ │ │ ├── txhistory_data_data.json
│ │ │ ├── txhistory_incoming_data.json
│ │ │ └── txmessages_data.json
│ │ ├── plugins/
│ │ │ └── index.js
│ │ └── support/
│ │ ├── api/
│ │ │ ├── contracts.js
│ │ │ ├── utils_ether.js
│ │ │ └── utils_protocolkit.js
│ │ ├── commands.js
│ │ ├── constants.js
│ │ ├── e2e.js
│ │ ├── localstorage_data.js
│ │ ├── safe-apps-commands.js
│ │ ├── safes/
│ │ │ └── safesHandler.js
│ │ ├── utils/
│ │ │ ├── checkers.js
│ │ │ ├── ethers.js
│ │ │ ├── gtag.js
│ │ │ ├── txquery.js
│ │ │ └── wallet.js
│ │ └── visual-mocks.js
│ ├── cypress.config.js
│ ├── docs/
│ │ ├── TESTING.md
│ │ ├── code-style.md
│ │ ├── environments.md
│ │ ├── feature-architecture.md
│ │ ├── release-procedure-automated.md
│ │ ├── release-procedure.md
│ │ ├── spaces-accounts-architecture.md
│ │ ├── storybook-snapshots.md
│ │ ├── update-patch.md
│ │ └── update-terms.md
│ ├── eslint.config.mjs
│ ├── jest.config.cjs
│ ├── jest.setup.js
│ ├── knip.json
│ ├── mocks/
│ │ └── svg.js
│ ├── next-env.d.ts
│ ├── next.config.mjs
│ ├── package.json
│ ├── plugins/
│ │ └── sri-manifest-webpack-plugin.mjs
│ ├── postcss.config.mjs
│ ├── public/
│ │ ├── .well-known/
│ │ │ └── apple-app-site-association
│ │ ├── beamer-embed.css
│ │ ├── beamer-embed.js
│ │ ├── fonts/
│ │ │ └── fonts.css
│ │ ├── mockServiceWorker.js
│ │ └── safe.webmanifest
│ ├── scripts/
│ │ ├── cmp.sh
│ │ ├── css-vars.ts
│ │ ├── fetch-chains.ts
│ │ ├── generate-routes.js
│ │ ├── generate-storybook-tests.cjs
│ │ ├── github/
│ │ │ ├── prepare_production_deployment.sh
│ │ │ └── s3_upload.sh
│ │ ├── integrity-hashes.cjs
│ │ ├── release/
│ │ │ ├── README.md
│ │ │ ├── generate-changelog.sh
│ │ │ └── notify-slack.sh
│ │ └── release-notes.sh
│ ├── src/
│ │ ├── components/
│ │ │ ├── address-book/
│ │ │ │ ├── AddressBookHeader/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── AddressBookTable/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── EntryDialog/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ExportDialog/
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ImportDialog/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── validation.test.ts
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.module.css
│ │ │ │ │ └── validation.ts
│ │ │ │ ├── RemoveDialog/
│ │ │ │ │ └── index.tsx
│ │ │ │ └── index.stories.tsx
│ │ │ ├── balances/
│ │ │ │ ├── AssetsHeader/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── AssetsTable/
│ │ │ │ │ ├── ActionButtons.tsx
│ │ │ │ │ ├── AssetRowContent.tsx
│ │ │ │ │ ├── FiatBalance.tsx
│ │ │ │ │ ├── FiatChange.test.tsx
│ │ │ │ │ ├── FiatChange.tsx
│ │ │ │ │ ├── HiddenTokensInfo.tsx
│ │ │ │ │ ├── PromoButtons.tsx
│ │ │ │ │ ├── SendButton.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── index.stories.test.tsx.snap
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── AssetsTable.test.tsx
│ │ │ │ │ ├── index.stories.test.tsx
│ │ │ │ │ ├── index.stories.tsx
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.module.css
│ │ │ │ │ └── useHideAssets.ts
│ │ │ │ ├── CurrencySelect/
│ │ │ │ │ ├── CurrencySelect.stories.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── index.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── useCurrencies.ts
│ │ │ │ ├── HiddenTokenButton/
│ │ │ │ │ ├── HiddenTokenButton.stories.tsx
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── ManageTokensButton/
│ │ │ │ │ ├── ManageTokensMenu.module.css
│ │ │ │ │ ├── ManageTokensMenu.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── index.stories.test.tsx.snap
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── ManageTokensButton.test.tsx
│ │ │ │ │ ├── index.stories.test.tsx
│ │ │ │ │ ├── index.stories.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── TokenMenu/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ └── TotalAssetValue/
│ │ │ │ ├── TotalAssetValue.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── common/
│ │ │ │ ├── ActionCard/
│ │ │ │ │ ├── ActionCard.stories.tsx
│ │ │ │ │ ├── ActionCard.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── AddFunds/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── AddressBookInput/
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── AddressBookSourceProvider/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── AddressInput/
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.module.css
│ │ │ │ │ └── useNameResolver.ts
│ │ │ │ ├── AddressInputReadOnly/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── AssetActionButton/
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── AuditLog/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── BackLink/
│ │ │ │ │ ├── BackLink.stories.tsx
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── BlockedAddress/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── Breadcrumbs/
│ │ │ │ │ ├── BreadcrumbItem.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── Captcha/
│ │ │ │ │ ├── CaptchaModal.tsx
│ │ │ │ │ ├── CaptchaProvider.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── CaptchaProvider.test.tsx
│ │ │ │ │ │ ├── captchaHeadersInit.test.ts
│ │ │ │ │ │ └── useCaptchaToken.test.ts
│ │ │ │ │ ├── captchaHeadersInit.ts
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── useCaptchaToken.ts
│ │ │ │ ├── ChainIndicator/
│ │ │ │ │ ├── ChainIndicator.stories.test.tsx
│ │ │ │ │ ├── ChainIndicator.stories.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── ChainIndicator.stories.test.tsx.snap
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── ChainSwitcher/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── CheckWallet/
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── CheckWalletWithPermission/
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Chip/
│ │ │ │ │ ├── Chip.stories.test.tsx
│ │ │ │ │ ├── Chip.stories.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── Chip.stories.test.tsx.snap
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ChoiceButton/
│ │ │ │ │ ├── ChoiceButton.stories.test.tsx
│ │ │ │ │ ├── ChoiceButton.stories.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── ChoiceButton.stories.test.tsx.snap
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── ConnectWallet/
│ │ │ │ │ ├── AccountCenter.tsx
│ │ │ │ │ ├── ConnectWalletButton.tsx
│ │ │ │ │ ├── ConnectionCenter.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── AccountCenter.test.tsx
│ │ │ │ │ │ └── ConnectionCenter.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.module.css
│ │ │ │ │ └── useConnectWallet.ts
│ │ │ │ ├── ContextMenu/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── CookieAndTermBanner/
│ │ │ │ │ ├── CookieBannerActions.tsx
│ │ │ │ │ ├── CookieOptionsList.tsx
│ │ │ │ │ ├── IntroText.tsx
│ │ │ │ │ ├── WarningMessage.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── index.test.tsx
│ │ │ │ │ ├── constants.ts
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── CooldownButton/
│ │ │ │ │ ├── CooldownButton.stories.test.tsx
│ │ │ │ │ ├── CooldownButton.stories.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── CooldownButton.stories.test.tsx.snap
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── CopyAddressButton/
│ │ │ │ │ ├── CopyAddressButton.stories.test.tsx
│ │ │ │ │ ├── CopyAddressButton.stories.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── CopyAddressButton.stories.test.tsx.snap
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── CopyButton/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── index.stories.test.tsx.snap
│ │ │ │ │ ├── index.stories.test.tsx
│ │ │ │ │ ├── index.stories.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── CopyTooltip/
│ │ │ │ │ ├── ConfirmCopyModal.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── Countdown/
│ │ │ │ │ ├── Countdown.stories.test.tsx
│ │ │ │ │ ├── Countdown.stories.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── Countdown.stories.test.tsx.snap
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── CustomLink/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── CustomTooltip/
│ │ │ │ │ ├── CustomTooltip.stories.test.tsx
│ │ │ │ │ ├── CustomTooltip.stories.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── CustomTooltip.stories.test.tsx.snap
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── DatePickerInput/
│ │ │ │ │ ├── DatePickerInput.stories.test.tsx
│ │ │ │ │ ├── DatePickerInput.stories.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── DatePickerInput.stories.test.tsx.snap
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── DateTime/
│ │ │ │ │ ├── DateTime.stories.test.tsx
│ │ │ │ │ ├── DateTime.stories.tsx
│ │ │ │ │ ├── DateTime.tsx
│ │ │ │ │ ├── DateTimeContainer.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── DateTime.stories.test.tsx.snap
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Disclaimer/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── index.stories.test.tsx.snap
│ │ │ │ │ ├── index.stories.test.tsx
│ │ │ │ │ ├── index.stories.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── EnhancedTable/
│ │ │ │ │ ├── EnhancedTable.stories.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── ErrorBoundary/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── EthHashInfo/
│ │ │ │ │ ├── SrcEthHashInfo/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── index.stories.test.tsx.snap
│ │ │ │ │ │ ├── index.stories.test.tsx
│ │ │ │ │ │ ├── index.stories.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── index.stories.test.tsx.snap
│ │ │ │ │ ├── index.stories.test.tsx
│ │ │ │ │ ├── index.stories.tsx
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ExplorerButton/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ExternalLink/
│ │ │ │ │ ├── ExternalLink.stories.test.tsx
│ │ │ │ │ ├── ExternalLink.stories.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── ExternalLink.stories.test.tsx.snap
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── FiatValue/
│ │ │ │ │ ├── FiatValue.stories.test.tsx
│ │ │ │ │ ├── FiatValue.stories.tsx
│ │ │ │ │ ├── FiatValue.test.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── FiatValue.stories.test.tsx.snap
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── FileUpload/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── Footer/
│ │ │ │ │ ├── footer.type.ts
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── GeoblockingProvider/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── GradientCircularProgress/
│ │ │ │ │ ├── GradientCircularProgress.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── Header/
│ │ │ │ │ ├── Topbar/
│ │ │ │ │ │ ├── NotificationsPopover.test.tsx
│ │ │ │ │ │ ├── NotificationsPopover.tsx
│ │ │ │ │ │ ├── SafenetStakingButton.tsx
│ │ │ │ │ │ ├── hooks/
│ │ │ │ │ │ │ ├── useNotificationsPopover.test.ts
│ │ │ │ │ │ │ └── useNotificationsPopover.ts
│ │ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── HelpMenu/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── Identicon/
│ │ │ │ │ ├── Identicon.stories.test.tsx
│ │ │ │ │ ├── Identicon.stories.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── Identicon.stories.test.tsx.snap
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── IframeIcon/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ImageFallback/
│ │ │ │ │ ├── ImageFallback.stories.test.tsx
│ │ │ │ │ ├── ImageFallback.stories.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── ImageFallback.stories.test.tsx.snap
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── InfiniteScroll/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── InfoTooltip/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── InlineRetryError/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── LazyWeb3Init/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── LegalDisclaimerContent/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── MarkdownContent/
│ │ │ │ │ ├── index.module.css
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── MetaTags/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ModalDialog/
│ │ │ │ │ ├── ModalDialog.stories.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── Mui/
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── NameInput/
│ │ │ │ │ ├── NameInput.stories.test.tsx
│ │ │ │ │ ├── NameInput.stories.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── NameInput.stories.test.tsx.snap
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── NamedAddressInfo/
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── NavTabs/
│ │ │ │ │ ├── NavTabs.stories.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── Navigate/
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── NestedSafeBreadcrumbs/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── NetworkInput/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── NetworkSelector/
│ │ │ │ │ ├── NetworkMultiSelectorInput.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── Notifications/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.module.css
│ │ │ │ │ └── useCounter.ts
│ │ │ │ ├── NumberField/
│ │ │ │ │ ├── index.test.ts
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ObservabilityErrorBoundary/
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── OnboardingTooltip/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── OnboardingTooltip.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── OnlyOwnerOrProposer/
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── PageHeader/
│ │ │ │ │ ├── PageHeader.stories.test.tsx
│ │ │ │ │ ├── PageHeader.stories.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── PageHeader.stories.test.tsx.snap
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── PageLayout/
│ │ │ │ │ ├── SideDrawer.tsx
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── PagePlaceholder/
│ │ │ │ │ ├── PagePlaceholder.stories.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── PaginatedTxns/
│ │ │ │ │ ├── SkeletonTxList.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── PaperViewToggle/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Popup/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ProgressBar/
│ │ │ │ │ ├── ProgressBar.stories.test.tsx
│ │ │ │ │ ├── ProgressBar.stories.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── ProgressBar.stories.test.tsx.snap
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── PromoBanner/
│ │ │ │ │ ├── PromoBanner.stories.test.tsx
│ │ │ │ │ ├── PromoBanner.stories.tsx
│ │ │ │ │ ├── PromoBanner.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── PromoBanner.stories.test.tsx.snap
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── QRCode/
│ │ │ │ │ ├── QRCode.stories.test.tsx
│ │ │ │ │ ├── QRCode.stories.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── QRCode.stories.test.tsx.snap
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SafeIcon/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── SafeLoadingError/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SafeLogo/
│ │ │ │ │ ├── SafeLogo.module.css
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── SafeLogo.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SafenetStakingWidget/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── SignerSelector/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── index.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── SpaceSafeBar/
│ │ │ │ │ ├── AccountsModal/
│ │ │ │ │ │ ├── MultiSafeItemCard.test.tsx
│ │ │ │ │ │ ├── MultiSafeItemCard.tsx
│ │ │ │ │ │ ├── PinnedMultiSafeItem.tsx
│ │ │ │ │ │ ├── PinnedSafeContextMenu.tsx
│ │ │ │ │ │ ├── PinnedSafeItem.tsx
│ │ │ │ │ │ ├── SafeItemCard.test.tsx
│ │ │ │ │ │ ├── SafeItemCard.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── shared.tsx
│ │ │ │ │ ├── SpaceBackLink.test.tsx
│ │ │ │ │ ├── SpaceBackLink.tsx
│ │ │ │ │ ├── SpaceChainSelector.stories.tsx
│ │ │ │ │ ├── SpaceChainSelector.test.tsx
│ │ │ │ │ ├── SpaceChainSelector.tsx
│ │ │ │ │ ├── SpaceNestedSafesButton.stories.tsx
│ │ │ │ │ ├── SpaceNestedSafesButton.test.tsx
│ │ │ │ │ ├── SpaceNestedSafesButton.tsx
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── useSafeBarSafes.test.ts
│ │ │ │ │ │ │ ├── useSpaceBackLink.test.ts
│ │ │ │ │ │ │ ├── useSpaceChainSelector.test.ts
│ │ │ │ │ │ │ └── useSpaceSafeSelectorItems.test.ts
│ │ │ │ │ │ ├── useSafeBarSafes.ts
│ │ │ │ │ │ ├── useSpaceBackLink.ts
│ │ │ │ │ │ ├── useSpaceChainSelector.ts
│ │ │ │ │ │ └── useSpaceSafeSelectorItems.ts
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SpendingLimitLabel/
│ │ │ │ │ ├── SpendingLimitLabel.stories.test.tsx
│ │ │ │ │ ├── SpendingLimitLabel.stories.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── SpendingLimitLabel.stories.test.tsx.snap
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SplitMenuButton/
│ │ │ │ │ ├── SplitMenuButton.stories.test.tsx
│ │ │ │ │ ├── SplitMenuButton.stories.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── SplitMenuButton.stories.test.tsx.snap
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Sticky/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Table/
│ │ │ │ │ ├── DataRow.stories.test.tsx
│ │ │ │ │ ├── DataRow.stories.tsx
│ │ │ │ │ ├── DataRow.tsx
│ │ │ │ │ ├── DataTable.stories.test.tsx
│ │ │ │ │ ├── DataTable.stories.tsx
│ │ │ │ │ ├── DataTable.tsx
│ │ │ │ │ ├── EmptyRow.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ ├── DataRow.stories.test.tsx.snap
│ │ │ │ │ │ └── DataTable.stories.test.tsx.snap
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── ToggleButtonGroup/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TokenAmount/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── index.stories.test.tsx.snap
│ │ │ │ │ ├── index.stories.test.tsx
│ │ │ │ │ ├── index.stories.tsx
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── TokenAmountInput/
│ │ │ │ │ ├── TokenAmountInput.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── TokenIcon/
│ │ │ │ │ ├── TokenIcon.stories.test.tsx
│ │ │ │ │ ├── TokenIcon.stories.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── TokenIcon.stories.test.tsx.snap
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── Track/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TxModalDialog/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── UnreadBadge/
│ │ │ │ │ ├── UnreadBadge.stories.test.tsx
│ │ │ │ │ ├── UnreadBadge.stories.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── UnreadBadge.stories.test.tsx.snap
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── WalletBalance/
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── WalletIcon/
│ │ │ │ │ ├── WalletIcon.stories.test.tsx
│ │ │ │ │ ├── WalletIcon.stories.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── WalletIcon.stories.test.tsx.snap
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── WalletInfo/
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── WalletOverview/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── WalletProvider/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── WidgetDisclaimer/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ └── icons/
│ │ │ │ └── CircularIcon/
│ │ │ │ ├── index.tsx
│ │ │ │ └── styles.module.css
│ │ │ ├── dashboard/
│ │ │ │ ├── ActionRequiredPanel/
│ │ │ │ │ ├── ActionRequiredPanel.test.tsx
│ │ │ │ │ ├── ActionRequiredPanel.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.module.css
│ │ │ │ │ └── useWarningCount.ts
│ │ │ │ ├── AddFundsBanner/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Assets/
│ │ │ │ │ ├── Assets.stories.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── ExplorePossibleWidget/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── index.stories.test.tsx.snap
│ │ │ │ │ ├── index.stories.test.tsx
│ │ │ │ │ ├── index.stories.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── FirstSteps/
│ │ │ │ │ ├── FirstSteps.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.module.css
│ │ │ │ │ ├── utils.test.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── NewsCarousel/
│ │ │ │ │ ├── NewsDisclaimers.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── utils.test.ts
│ │ │ │ │ ├── banners/
│ │ │ │ │ │ ├── EarnBanner.stories.test.tsx
│ │ │ │ │ │ ├── EarnBanner.stories.tsx
│ │ │ │ │ │ ├── EarnBanner.tsx
│ │ │ │ │ │ ├── EurcvBoostBanner.stories.test.tsx
│ │ │ │ │ │ ├── EurcvBoostBanner.stories.tsx
│ │ │ │ │ │ ├── EurcvBoostBanner.tsx
│ │ │ │ │ │ ├── SpacesBanner.stories.test.tsx
│ │ │ │ │ │ ├── SpacesBanner.stories.tsx
│ │ │ │ │ │ ├── SpacesBanner.tsx
│ │ │ │ │ │ ├── StakeBanner.stories.test.tsx
│ │ │ │ │ │ ├── StakeBanner.stories.tsx
│ │ │ │ │ │ ├── StakeBanner.tsx
│ │ │ │ │ │ └── __snapshots__/
│ │ │ │ │ │ ├── EarnBanner.stories.test.tsx.snap
│ │ │ │ │ │ ├── EurcvBoostBanner.stories.test.tsx.snap
│ │ │ │ │ │ ├── SpacesBanner.stories.test.tsx.snap
│ │ │ │ │ │ └── StakeBanner.stories.test.tsx.snap
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.module.css
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── Overview/
│ │ │ │ │ ├── Overview.stories.tsx
│ │ │ │ │ ├── Overview.tsx
│ │ │ │ │ └── OverviewSkeleton.tsx
│ │ │ │ ├── PendingTxs/
│ │ │ │ │ ├── PendingRecoveryListItem.tsx
│ │ │ │ │ ├── PendingTxList.test.ts
│ │ │ │ │ ├── PendingTxListItem.tsx
│ │ │ │ │ ├── PendingTxsList.stories.tsx
│ │ │ │ │ ├── PendingTxsList.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── SafeAppsDashboardSection/
│ │ │ │ │ ├── SafeAppsDashboardSection.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── SafeAppsDashboardSection.test.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── StakingBanner/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.module.css
│ │ │ │ │ ├── useIsStakingBannerVisible.test.ts
│ │ │ │ │ └── useIsStakingBannerVisible.ts
│ │ │ │ ├── index.tsx
│ │ │ │ ├── styled.stories.tsx
│ │ │ │ ├── styled.tsx
│ │ │ │ └── styles.module.css
│ │ │ ├── new-safe/
│ │ │ │ ├── CardStepper/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.module.css
│ │ │ │ │ └── useCardStepper.ts
│ │ │ │ ├── OwnerRow/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── ReviewRow/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── create/
│ │ │ │ │ ├── AdvancedCreateSafe.tsx
│ │ │ │ │ ├── CreateSafeInfos/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── InfoWidget/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ ├── NetworkWarning/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── NoWalletConnectedWarning/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── OverviewWidget/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── useEstimateSafeCreationGas.test.ts
│ │ │ │ │ │ └── useSyncSafeCreationStep.test.ts
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── logic/
│ │ │ │ │ │ ├── address-book.ts
│ │ │ │ │ │ ├── index.test.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── utils.test.ts
│ │ │ │ │ │ └── utils.ts
│ │ │ │ │ ├── steps/
│ │ │ │ │ │ ├── AdvancedOptionsStep/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── OwnerPolicyStep/
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ └── useSafeSetupHints.ts
│ │ │ │ │ │ ├── ReviewStep/
│ │ │ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── styles.module.css
│ │ │ │ │ │ │ ├── utils.test.ts
│ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ ├── SetNameStep/
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ │ └── StatusStep/
│ │ │ │ │ │ ├── LoadingSpinner/
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ │ ├── StatusMessage.tsx
│ │ │ │ │ │ ├── StatusStep.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── styles.module.css
│ │ │ │ │ │ └── useUndeployedSafe.ts
│ │ │ │ │ ├── styles.module.css
│ │ │ │ │ ├── types.d.ts
│ │ │ │ │ ├── useEstimateSafeCreationGas.ts
│ │ │ │ │ └── useSyncSafeCreationStep.ts
│ │ │ │ ├── index.stories.tsx
│ │ │ │ └── load/
│ │ │ │ ├── index.tsx
│ │ │ │ └── steps/
│ │ │ │ ├── SafeOwnerStep/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SafeReviewStep/
│ │ │ │ │ └── index.tsx
│ │ │ │ └── SetAddressStep/
│ │ │ │ └── index.tsx
│ │ │ ├── notification-center/
│ │ │ │ ├── NotificationCenter/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── NotificationCenterItem/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── NotificationCenterList/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── NotificationRenewal/
│ │ │ │ │ └── index.tsx
│ │ │ │ └── index.stories.tsx
│ │ │ ├── safe-apps/
│ │ │ │ ├── AddCustomAppModal/
│ │ │ │ │ ├── CustomApp.tsx
│ │ │ │ │ ├── CustomAppPlaceholder.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── AddCustomSafeAppCard/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── AppFrame/
│ │ │ │ │ ├── SafeAppIframe.tsx
│ │ │ │ │ ├── ThirdPartyCookiesWarning.tsx
│ │ │ │ │ ├── TransactionQueueBar/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── AppFrame.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.module.css
│ │ │ │ │ ├── useAppCommunicator.ts
│ │ │ │ │ ├── useAppIsLoading.ts
│ │ │ │ │ ├── useFromAppAnalytics.ts
│ │ │ │ │ ├── useGetSafeInfo.ts
│ │ │ │ │ ├── useThirdPartyCookies.test.ts
│ │ │ │ │ ├── useThirdPartyCookies.ts
│ │ │ │ │ └── useTransactionQueueBarState.ts
│ │ │ │ ├── NativeSwapsCard/
│ │ │ │ │ ├── index.stories.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── PermissionCheckbox.tsx
│ │ │ │ ├── PermissionsPrompt.tsx
│ │ │ │ ├── RemoveCustomAppModal.tsx
│ │ │ │ ├── SafeAppActionButtons/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SafeAppCard/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── SafeAppIconCard/
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SafeAppLandingPage/
│ │ │ │ │ ├── AppActions.tsx
│ │ │ │ │ ├── SafeAppDetails.tsx
│ │ │ │ │ ├── TryDemo.tsx
│ │ │ │ │ ├── constants.ts
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SafeAppList/
│ │ │ │ │ ├── SafeAppList.stories.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── SafeAppPreviewDrawer/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── SafeAppSocialLinksCard/
│ │ │ │ │ ├── SafeAppSocialLinksCard.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── SafeAppTags/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── SafeAppsErrorBoundary/
│ │ │ │ │ ├── SafeAppsLoadError.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── SafeAppsFilters/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── SafeAppsHeader/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── SafeAppsInfoModal/
│ │ │ │ │ ├── AllowedFeaturesList.tsx
│ │ │ │ │ ├── Domain.tsx
│ │ │ │ │ ├── Slider.tsx
│ │ │ │ │ ├── UnknownAppWarning.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.module.css
│ │ │ │ │ └── useSafeAppsInfoModal.ts
│ │ │ │ ├── SafeAppsListHeader/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── SafeAppsSDKLink/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── SafeAppsZeroResultsPlaceholder/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── hooks/
│ │ │ │ │ └── useShareSafeAppUrl.ts
│ │ │ │ ├── types.ts
│ │ │ │ └── utils.ts
│ │ │ ├── safe-messages/
│ │ │ │ ├── DecodedMsg/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── InfoBox/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── Msg/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── MsgAuditLog/
│ │ │ │ │ ├── MsgAuditLog.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── MsgDetails/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── MsgList/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── MsgListItem/
│ │ │ │ │ ├── ExpandableMsgItem.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── MsgShareLink/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── MsgSigners/
│ │ │ │ │ ├── MsgSigners.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── MsgSummary/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── MsgType/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── PaginatedMsgs/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SignMsgButton/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SingleMsg/
│ │ │ │ │ ├── SingleMsg.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ └── index.stories.tsx
│ │ │ ├── settings/
│ │ │ │ ├── ClearPendingTxs/
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ContractVersion/
│ │ │ │ │ ├── ContractVersion.stories.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── DataManagement/
│ │ │ │ │ ├── FileListCard.tsx
│ │ │ │ │ ├── ImportDialog.tsx
│ │ │ │ │ ├── ImportFileUpload.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── useGlobalImportFileParser.test.ts
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.module.css
│ │ │ │ │ └── useGlobalImportFileParser.ts
│ │ │ │ ├── EnvironmentVariables/
│ │ │ │ │ ├── EnvHintButton/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ ├── RpcProviderSection.tsx
│ │ │ │ │ ├── TenderlySection.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── FallbackHandler/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── FeeTokenPreference/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── NestedSafesList/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ProposersList/
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── PushNotifications/
│ │ │ │ │ ├── GlobalPushNotifications.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── GlobalPushNotifications.test.ts
│ │ │ │ │ │ └── logic.test.ts
│ │ │ │ │ ├── constants.ts
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── useNotificationPreferences.test.ts
│ │ │ │ │ │ │ ├── useNotificationRegistrations.test.ts
│ │ │ │ │ │ │ ├── useNotificationTracking.test.ts
│ │ │ │ │ │ │ ├── useNotificationsRenewal.test.ts
│ │ │ │ │ │ │ ├── useNotificationsTokenVersion.test.ts
│ │ │ │ │ │ │ └── useShowNotificationsRenewalMessage.test.ts
│ │ │ │ │ │ ├── useNotificationPreferences.ts
│ │ │ │ │ │ ├── useNotificationRegistrations.ts
│ │ │ │ │ │ ├── useNotificationTracking.ts
│ │ │ │ │ │ ├── useNotificationsRenewal.ts
│ │ │ │ │ │ ├── useNotificationsTokenVersion.ts
│ │ │ │ │ │ └── useShowNotificationsRenewalMessage.ts
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── logic.ts
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── RequiredConfirmations/
│ │ │ │ │ ├── RequiredConfirmations.stories.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SafeAppsPermissions/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SafeAppsSigningMethod/
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SafeModules/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── SafeModules.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SecurityLogin/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SecuritySettings/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SettingsHeader/
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TransactionGuards/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── TransactionGuards.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── SecurityLogin.test.tsx
│ │ │ │ └── owner/
│ │ │ │ ├── EditOwnerDialog/
│ │ │ │ │ └── index.tsx
│ │ │ │ └── OwnerList/
│ │ │ │ ├── OwnerList.stories.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── sidebar/
│ │ │ │ ├── DebugToggle/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── IndexingStatus/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── NestedSafeInfo/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── NestedSafeIntro/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── NestedSafesButton/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── NestedSafesList/
│ │ │ │ │ ├── SimilarityConfirmDialog.tsx
│ │ │ │ │ ├── SimilarityGroupContainer.tsx
│ │ │ │ │ ├── SimilarityWarning.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── useManageNestedSafes.ts
│ │ │ │ ├── NestedSafesPopover/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.module.css
│ │ │ │ │ ├── utils.test.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── NewTxButton/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── QrCodeButton/
│ │ │ │ │ ├── QrModal.stories.tsx
│ │ │ │ │ ├── QrModal.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SafeListContextMenu/
│ │ │ │ │ ├── MultiAccountContextMenu.stories.tsx
│ │ │ │ │ ├── MultiAccountContextMenu.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SafeListRemoveDialog/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Sidebar/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── SidebarFooter/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SidebarHeader/
│ │ │ │ │ ├── SafeHeaderInfo.stories.tsx
│ │ │ │ │ ├── SafeHeaderInfo.test.tsx
│ │ │ │ │ ├── SafeHeaderInfo.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── SidebarList/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ └── SidebarNavigation/
│ │ │ │ ├── config.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── terms/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── safe-labs-terms.test.tsx
│ │ │ │ ├── safe-labs-terms.tsx
│ │ │ │ └── styles.module.css
│ │ │ ├── theme/
│ │ │ │ ├── SafeThemeProvider.tsx
│ │ │ │ ├── mui.d.ts
│ │ │ │ └── safeTheme.ts
│ │ │ ├── transactions/
│ │ │ │ ├── BatchExecuteButton/
│ │ │ │ │ ├── BatchExecuteHoverProvider.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── BulkTxListGroup/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── CsvTxExportButton/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── CsvTxExportModal/
│ │ │ │ │ ├── CsvTxExportModal.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ExecuteTxButton/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── GroupLabel/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── GroupedTxListItems/
│ │ │ │ │ ├── ReplaceTxHoverProvider.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── HexEncodedData/
│ │ │ │ │ ├── HexEncodedData.test.tsx
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── HexEncodedData.test.tsx.snap
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── ImitationTransactionWarning/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── InfoDetails/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── MaliciousTxWarning/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── QueuedTxSimulation/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── RejectTxButton/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SafeCreationTx/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── SignTxButton/
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── SignedMessagesHelpLink/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SingleTx/
│ │ │ │ │ ├── SingleTx.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TrustedToggle/
│ │ │ │ │ ├── TrustedToggleButton.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TxConfirmations/
│ │ │ │ │ ├── TxConfirmations.stories.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TxDateLabel/
│ │ │ │ │ ├── TxDateLabel.stories.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── TxDetails/
│ │ │ │ │ ├── Summary/
│ │ │ │ │ │ ├── DecoderLinks.tsx
│ │ │ │ │ │ ├── SafeTxHashDataRow/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── TxDataRow/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── TxData/
│ │ │ │ │ │ ├── DecodedData/
│ │ │ │ │ │ │ ├── MethodCall.tsx
│ │ │ │ │ │ │ ├── MethodDetails/
│ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ ├── Multisend/
│ │ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ │ │ ├── SingleTxDecoded/
│ │ │ │ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ │ ├── styles.module.css
│ │ │ │ │ │ │ │ ├── useTransferTokenInfo.test.ts
│ │ │ │ │ │ │ │ └── useTransferTokenInfo.ts
│ │ │ │ │ │ │ ├── ValueArray/
│ │ │ │ │ │ │ │ ├── ValueArray.test.tsx
│ │ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── MigrationToL2TxData/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── NestedTransaction/
│ │ │ │ │ │ │ ├── ExecTransaction/
│ │ │ │ │ │ │ │ ├── ExecTransaction.stories.tsx
│ │ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ │ └── mockData.ts
│ │ │ │ │ │ │ ├── NestedTransaction.tsx
│ │ │ │ │ │ │ ├── OnChainConfirmation/
│ │ │ │ │ │ │ │ ├── OnChainConfirmation.stories.tsx
│ │ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ │ └── mockData.ts
│ │ │ │ │ │ │ └── useSignedHash.tsx
│ │ │ │ │ │ ├── Rejection/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── SafeUpdate/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── SettingsChange/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── SpendingLimits/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── Staking/
│ │ │ │ │ │ │ ├── StakingConfirmationTxDeposit.tsx
│ │ │ │ │ │ │ ├── StakingConfirmationTxWithdraw.tsx
│ │ │ │ │ │ │ ├── StakingStatus.tsx
│ │ │ │ │ │ │ ├── StakingTxDepositDetails.tsx
│ │ │ │ │ │ │ ├── StakingTxExitDetails.tsx
│ │ │ │ │ │ │ ├── StakingTxWithdrawDetails.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── Transfer/
│ │ │ │ │ │ │ ├── TransferActions.tsx
│ │ │ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── useTransferFiatValue.test.ts
│ │ │ │ │ │ │ └── useTransferFiatValue.ts
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── TxFilterForm/
│ │ │ │ │ ├── TxFilterForm.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── TxHeader/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── TxInfo/
│ │ │ │ │ ├── Staking/
│ │ │ │ │ │ ├── StakingTxDepositInfo.tsx
│ │ │ │ │ │ ├── StakingTxExitInfo.tsx
│ │ │ │ │ │ ├── StakingTxWithdrawInfo.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── SwapTx.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── TxList/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── TxListItem/
│ │ │ │ │ ├── ExpandableTransactionItem.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── TxNavigation/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TxShareLink/
│ │ │ │ │ ├── TxShareLink.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TxSigners/
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── TxStatusChip/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── index.stories.test.tsx.snap
│ │ │ │ │ ├── index.stories.test.tsx
│ │ │ │ │ ├── index.stories.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TxStatusLabel/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TxSummary/
│ │ │ │ │ ├── QueueActions.tsx
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── TxType/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ └── Warning/
│ │ │ │ ├── Warning.stories.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── styles.module.css
│ │ │ ├── tx/
│ │ │ │ ├── AdvancedParams/
│ │ │ │ │ ├── AdvancedParamsForm.tsx
│ │ │ │ │ ├── GasLimitInput.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── types.ts
│ │ │ │ │ ├── useAdvancedParams.ts
│ │ │ │ │ └── useUserNonce.ts
│ │ │ │ ├── ApprovalEditor/
│ │ │ │ │ ├── ApprovalEditor.test.tsx
│ │ │ │ │ ├── ApprovalEditorForm.test.tsx
│ │ │ │ │ ├── ApprovalEditorForm.tsx
│ │ │ │ │ ├── ApprovalItem.tsx
│ │ │ │ │ ├── ApprovalValueField.tsx
│ │ │ │ │ ├── Approvals.tsx
│ │ │ │ │ ├── EditableApprovalItem.tsx
│ │ │ │ │ ├── SpenderField.test.tsx
│ │ │ │ │ ├── SpenderField.tsx
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ ├── useApprovalInfos.test.ts
│ │ │ │ │ │ └── useApprovalInfos.ts
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── styles.module.css
│ │ │ │ │ └── utils/
│ │ │ │ │ └── approvals.ts
│ │ │ │ ├── BalanceInfo/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── ColorCodedTxAccordion/
│ │ │ │ │ ├── HelpTooltip.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ConfirmTxDetails/
│ │ │ │ │ ├── JsonView.tsx
│ │ │ │ │ ├── NameChip.test.tsx
│ │ │ │ │ ├── NameChip.tsx
│ │ │ │ │ ├── Receipt.tsx
│ │ │ │ │ └── TxDetailsRow.tsx
│ │ │ │ ├── ConfirmTxReceipt/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ConfirmationOrder/
│ │ │ │ │ └── ConfirmationOrderHeader.tsx
│ │ │ │ ├── ErrorMessage/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── ExecuteCheckbox/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── ExecutionMethodSelector/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── FieldsGrid/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── GasParams/
│ │ │ │ │ ├── GasParams.test.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── RemainingRelays/
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ReviewTransactionV2/
│ │ │ │ │ ├── ErrorTransactionPreview.tsx
│ │ │ │ │ ├── ReviewTransactionContent.tsx
│ │ │ │ │ ├── ReviewTransactionSkeleton.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ │ │ └── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SendFromBlock/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── SendToBlock/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SponsoredBy/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── SuccessMessage/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── confirmation-views/
│ │ │ │ │ ├── BatchTransactions/
│ │ │ │ │ │ ├── BatchTransactions.stories.test.tsx
│ │ │ │ │ │ ├── BatchTransactions.stories.tsx
│ │ │ │ │ │ ├── BatchTransactions.test.tsx
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ ├── BatchTransactions.stories.test.tsx.snap
│ │ │ │ │ │ │ └── BatchTransactions.test.tsx.snap
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── mockData.ts
│ │ │ │ │ ├── BridgeTransaction/
│ │ │ │ │ │ ├── BridgeTransaction.stories.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── mockData.ts
│ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ ├── ChangeThreshold/
│ │ │ │ │ │ ├── ChangeThreshold.stories.test.tsx
│ │ │ │ │ │ ├── ChangeThreshold.stories.tsx
│ │ │ │ │ │ ├── ChangeThreshold.test.tsx
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ ├── ChangeThreshold.stories.test.tsx.snap
│ │ │ │ │ │ │ └── ChangeThreshold.test.tsx.snap
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── LifiSwapTransaction/
│ │ │ │ │ │ ├── LifiSwapTransaction.stories.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── mockData.ts
│ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ ├── ManageSigners/
│ │ │ │ │ │ ├── ManageSigners.stories.tsx
│ │ │ │ │ │ ├── get-new-safe-setup.test.ts
│ │ │ │ │ │ ├── get-new-safe-setup.ts
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── mockData.ts
│ │ │ │ │ ├── MigrateToL2Information/
│ │ │ │ │ │ ├── MigrateToL2Information.stories.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── NestedSafeCreation/
│ │ │ │ │ │ ├── NestedSafeCreation.stories.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── mockData.ts
│ │ │ │ │ ├── SettingsChange/
│ │ │ │ │ │ ├── SettingsChange.stories.test.tsx
│ │ │ │ │ │ ├── SettingsChange.stories.tsx
│ │ │ │ │ │ ├── SettingsChange.test.tsx
│ │ │ │ │ │ ├── UntrustedFallbackHandlerTxAlert.tsx
│ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ ├── SettingsChange.stories.test.tsx.snap
│ │ │ │ │ │ │ └── SettingsChange.test.tsx.snap
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── mockData.ts
│ │ │ │ │ ├── StakingTx/
│ │ │ │ │ │ ├── StakingTx.stories.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── mockData.ts
│ │ │ │ │ ├── SwapOrder/
│ │ │ │ │ │ ├── SwapOrder.stories.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── mockData.ts
│ │ │ │ │ ├── UpdateSafe/
│ │ │ │ │ │ ├── UpdateSafe.stories.tsx
│ │ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── mockData.ts
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── types.d.ts
│ │ │ │ │ ├── useTxPreview.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── security/
│ │ │ │ │ ├── BalanceChanges/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ └── tenderly/
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── useSimulation.test.ts
│ │ │ │ │ │ └── utils.test.ts
│ │ │ │ │ ├── useSimulation.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ └── shared/
│ │ │ │ ├── ConfirmationTitle.tsx
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── hooks.test.ts
│ │ │ │ ├── errors/
│ │ │ │ │ ├── NonOwnerError.tsx
│ │ │ │ │ ├── RiskConfirmationError.tsx
│ │ │ │ │ ├── UnknownContractError.tsx
│ │ │ │ │ └── WalletRejectionError.tsx
│ │ │ │ ├── hooks.ts
│ │ │ │ ├── styles.module.css
│ │ │ │ ├── tracking.test.ts
│ │ │ │ ├── tracking.ts
│ │ │ │ └── types.ts
│ │ │ ├── tx-flow/
│ │ │ │ ├── SafeTxProvider.tsx
│ │ │ │ ├── TxFlow.tsx
│ │ │ │ ├── TxFlowProvider.tsx
│ │ │ │ ├── TxFlowStep.tsx
│ │ │ │ ├── TxInfoProvider.tsx
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── SafeTxProvider.test.tsx
│ │ │ │ ├── actions/
│ │ │ │ │ ├── Batching/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── ComboSubmit.tsx
│ │ │ │ │ ├── Counterfactual.tsx
│ │ │ │ │ ├── Execute/
│ │ │ │ │ │ ├── ExecuteForm.tsx
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ └── ExecuteForm.test.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ ├── ExecuteThroughRole/
│ │ │ │ │ │ ├── ExecuteThroughRoleForm/
│ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ ├── ExecuteThroughRoleForm.test.tsx
│ │ │ │ │ │ │ │ └── hooks.test.ts
│ │ │ │ │ │ │ ├── hooks.ts
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── Propose/
│ │ │ │ │ │ ├── ProposerForm.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── Sign/
│ │ │ │ │ │ ├── SignForm.tsx
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ └── SignForm.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ ├── ComboSubmit.test.tsx
│ │ │ │ │ │ └── ExecuteThroughRoleSlot.test.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── common/
│ │ │ │ │ ├── OwnerList/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ ├── SafeInfo/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── TxButton.tsx
│ │ │ │ │ ├── TxCard/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── TxFlowContent/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ ├── TxLayout/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ ├── TxNonce/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ └── TxNonce.test.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ ├── TxStatusWidget/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ ├── constants.ts
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── features/
│ │ │ │ │ ├── BalanceChanges.tsx
│ │ │ │ │ ├── ExecuteCheckbox.tsx
│ │ │ │ │ ├── FeeInfoBanner.tsx
│ │ │ │ │ ├── FeesPreview.tsx
│ │ │ │ │ ├── RiskConfirmation.tsx
│ │ │ │ │ ├── SignerSelect/
│ │ │ │ │ │ ├── SignerForm/
│ │ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ │ └── index.test.tsx
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── TxNote.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── flows/
│ │ │ │ │ ├── AddOwner/
│ │ │ │ │ │ ├── ChooseOwner.tsx
│ │ │ │ │ │ ├── ReviewOwner.tsx
│ │ │ │ │ │ ├── context.ts
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── CancelRecovery/
│ │ │ │ │ │ ├── CancelRecoveryFlowReview.tsx
│ │ │ │ │ │ ├── CancelRecoveryOverview.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ ├── ChangeThreshold/
│ │ │ │ │ │ ├── ChooseThreshold.tsx
│ │ │ │ │ │ ├── ReviewChangeThreshold.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── ConfirmBatch/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── ConfirmTx/
│ │ │ │ │ │ ├── ConfirmProposedTx.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── CreateNestedSafe/
│ │ │ │ │ │ ├── ReviewNestedSafe.tsx
│ │ │ │ │ │ ├── SetupNestedSafe.tsx
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ └── index.test.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ ├── ExecuteBatch/
│ │ │ │ │ │ ├── DecodedTxs.tsx
│ │ │ │ │ │ ├── ReviewBatch.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── useMultiSendContract.ts
│ │ │ │ │ ├── ManagerSigners/
│ │ │ │ │ │ ├── ReviewSigners.tsx
│ │ │ │ │ │ ├── SignersStructure.tsx
│ │ │ │ │ │ ├── SignersStructureView.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── MigrateSafeL2/
│ │ │ │ │ │ ├── MigrateSafeL2Review.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── NestedTxSuccessScreen/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ ├── NewSpendingLimit/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ └── SpendingLimitForm.test.ts
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── NewTx/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ ├── NftTransfer/
│ │ │ │ │ │ ├── ReviewNftBatch.tsx
│ │ │ │ │ │ ├── SendNftBatch.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── RecoverAccount/
│ │ │ │ │ │ ├── RecoverAccountFlowReview.tsx
│ │ │ │ │ │ ├── RecoverAccountFlowSetup.tsx
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ └── RecoverAccountFlowSetup.test.ts
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── RecoveryAttempt/
│ │ │ │ │ │ ├── RecoveryAttemptReview.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── RejectTx/
│ │ │ │ │ │ ├── RejectTx.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── RemoveGuard/
│ │ │ │ │ │ ├── ReviewRemoveGuard.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── RemoveModule/
│ │ │ │ │ │ ├── ReviewRemoveModule.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── RemoveOwner/
│ │ │ │ │ │ ├── ReviewRemoveOwner.tsx
│ │ │ │ │ │ ├── SetThreshold.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ ├── RemoveRecovery/
│ │ │ │ │ │ ├── RemoveRecoveryFlowOverview.tsx
│ │ │ │ │ │ ├── RemoveRecoveryFlowReview.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── RemoveSpendingLimit/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── ReplaceOwner/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── ReplaceTx/
│ │ │ │ │ │ ├── DeleteTxModal.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ ├── SafeAppsTx/
│ │ │ │ │ │ ├── ReviewSafeAppsTx.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── SignMessage/
│ │ │ │ │ │ ├── SignMessage.test.tsx
│ │ │ │ │ │ ├── SignMessage.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── SignMessageOnChain/
│ │ │ │ │ │ ├── ReviewSignMessageOnChain.test.tsx
│ │ │ │ │ │ ├── ReviewSignMessageOnChain.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── SuccessScreen/
│ │ │ │ │ │ ├── StatusStepper.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── statuses/
│ │ │ │ │ │ │ ├── DefaultStatus.tsx
│ │ │ │ │ │ │ ├── IndexingStatus.tsx
│ │ │ │ │ │ │ └── ProcessingStatus.tsx
│ │ │ │ │ │ └── styles.module.css
│ │ │ │ │ ├── TokenTransfer/
│ │ │ │ │ │ ├── CSVAirdropAppModal/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── CreateTokenTransfer.tsx
│ │ │ │ │ │ ├── RecipientRow/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── ReviewRecipientRow.tsx
│ │ │ │ │ │ ├── ReviewTokenTransfer.tsx
│ │ │ │ │ │ ├── ReviewTokenTx.tsx
│ │ │ │ │ │ ├── SendAmountBlock.stories.tsx
│ │ │ │ │ │ ├── SendAmountBlock.tsx
│ │ │ │ │ │ ├── SpendingLimitRow/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── CreateTokenTransfer.test.tsx
│ │ │ │ │ │ │ ├── ReviewTokenTransfer.test.tsx
│ │ │ │ │ │ │ ├── SendAmountBlock.test.tsx
│ │ │ │ │ │ │ └── utils.test.ts
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── types.ts
│ │ │ │ │ │ └── utils.ts
│ │ │ │ │ ├── UpdateSafe/
│ │ │ │ │ │ ├── UpdateSafeReview.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── UpsertRecovery/
│ │ │ │ │ │ ├── RecovererSmartContractWarning.tsx
│ │ │ │ │ │ ├── UpsertRecoveryFlowIntro.tsx
│ │ │ │ │ │ ├── UpsertRecoveryFlowReview.tsx
│ │ │ │ │ │ ├── UpsertRecoveryFlowSettings.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── styles.module.css
│ │ │ │ │ │ ├── useRecoveryPeriods.ts
│ │ │ │ │ │ └── utils.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.stories.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── slots/
│ │ │ │ │ ├── Slot.tsx
│ │ │ │ │ ├── SlotProvider.tsx
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── useRegisterSlot.ts
│ │ │ │ │ │ ├── useSlot.ts
│ │ │ │ │ │ ├── useSlotContext.ts
│ │ │ │ │ │ └── useSlotIds.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── withSlot.tsx
│ │ │ │ └── useTxStepper.tsx
│ │ │ ├── ui/
│ │ │ │ ├── README.md
│ │ │ │ ├── ShadcnProvider.tsx
│ │ │ │ ├── accordion.tsx
│ │ │ │ ├── alert-dialog.tsx
│ │ │ │ ├── alert.tsx
│ │ │ │ ├── aspect-ratio.tsx
│ │ │ │ ├── avatar.tsx
│ │ │ │ ├── badge.tsx
│ │ │ │ ├── breadcrumb.tsx
│ │ │ │ ├── button.tsx
│ │ │ │ ├── card.tsx
│ │ │ │ ├── checkbox.tsx
│ │ │ │ ├── collapsible.tsx
│ │ │ │ ├── combobox.tsx
│ │ │ │ ├── context-menu.tsx
│ │ │ │ ├── dialog.tsx
│ │ │ │ ├── docs/
│ │ │ │ │ └── figma-code-connect.md
│ │ │ │ ├── drawer.tsx
│ │ │ │ ├── dropdown-menu.tsx
│ │ │ │ ├── empty.tsx
│ │ │ │ ├── field.tsx
│ │ │ │ ├── hover-card.tsx
│ │ │ │ ├── input-group.tsx
│ │ │ │ ├── input-otp.tsx
│ │ │ │ ├── input.test.ts
│ │ │ │ ├── input.tsx
│ │ │ │ ├── kbd.tsx
│ │ │ │ ├── label.tsx
│ │ │ │ ├── native-select.tsx
│ │ │ │ ├── navigation-menu.tsx
│ │ │ │ ├── pagination.tsx
│ │ │ │ ├── popover.tsx
│ │ │ │ ├── progress.tsx
│ │ │ │ ├── radio-group.tsx
│ │ │ │ ├── resizable.tsx
│ │ │ │ ├── scroll-area.tsx
│ │ │ │ ├── select.tsx
│ │ │ │ ├── separator.tsx
│ │ │ │ ├── sheet.tsx
│ │ │ │ ├── sidebar.tsx
│ │ │ │ ├── skeleton.tsx
│ │ │ │ ├── slider.tsx
│ │ │ │ ├── sonner.tsx
│ │ │ │ ├── spinner.tsx
│ │ │ │ ├── stories/
│ │ │ │ │ ├── accordion.stories.tsx
│ │ │ │ │ ├── alert-dialog.stories.tsx
│ │ │ │ │ ├── alert.stories.tsx
│ │ │ │ │ ├── aspect-ratio.stories.tsx
│ │ │ │ │ ├── avatar.stories.tsx
│ │ │ │ │ ├── badge.stories.tsx
│ │ │ │ │ ├── breadcrumb.stories.tsx
│ │ │ │ │ ├── button.stories.tsx
│ │ │ │ │ ├── card.stories.tsx
│ │ │ │ │ ├── checkbox.stories.tsx
│ │ │ │ │ ├── collapsible.stories.tsx
│ │ │ │ │ ├── combobox.stories.tsx
│ │ │ │ │ ├── context-menu.stories.tsx
│ │ │ │ │ ├── drawer.stories.tsx
│ │ │ │ │ ├── dropdown-menu.stories.tsx
│ │ │ │ │ ├── empty.stories.tsx
│ │ │ │ │ ├── field.stories.tsx
│ │ │ │ │ ├── hover-card.stories.tsx
│ │ │ │ │ ├── input-group.stories.tsx
│ │ │ │ │ ├── input-otp.stories.tsx
│ │ │ │ │ ├── input.stories.tsx
│ │ │ │ │ ├── kbd.stories.tsx
│ │ │ │ │ ├── label.stories.tsx
│ │ │ │ │ ├── native-select.stories.tsx
│ │ │ │ │ ├── navigation-menu.stories.tsx
│ │ │ │ │ ├── pagination.stories.tsx
│ │ │ │ │ ├── popover.stories.tsx
│ │ │ │ │ ├── progress.stories.tsx
│ │ │ │ │ ├── radio-group.stories.tsx
│ │ │ │ │ ├── resizable.stories.tsx
│ │ │ │ │ ├── scroll-area.stories.tsx
│ │ │ │ │ ├── select.stories.tsx
│ │ │ │ │ ├── separator.stories.tsx
│ │ │ │ │ ├── sheet.stories.tsx
│ │ │ │ │ ├── sidebar.stories.tsx
│ │ │ │ │ ├── skeleton.stories.tsx
│ │ │ │ │ ├── slider.stories.tsx
│ │ │ │ │ ├── sonner.stories.tsx
│ │ │ │ │ ├── spinner.stories.tsx
│ │ │ │ │ ├── switch.stories.tsx
│ │ │ │ │ ├── table.stories.tsx
│ │ │ │ │ ├── tabs.stories.tsx
│ │ │ │ │ ├── textarea.stories.tsx
│ │ │ │ │ ├── toggle.stories.tsx
│ │ │ │ │ ├── tooltip.stories.tsx
│ │ │ │ │ └── typography.stories.tsx
│ │ │ │ ├── switch.tsx
│ │ │ │ ├── table.tsx
│ │ │ │ ├── tabs.tsx
│ │ │ │ ├── textarea.tsx
│ │ │ │ ├── toggle.tsx
│ │ │ │ ├── tooltip.tsx
│ │ │ │ └── typography.tsx
│ │ │ ├── welcome/
│ │ │ │ ├── NewSafe.tsx
│ │ │ │ ├── WelcomeLogin/
│ │ │ │ │ ├── WalletLogin.tsx
│ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ └── WalletLogin.test.tsx
│ │ │ │ │ ├── hooks/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── useHomeAuth.test.ts
│ │ │ │ │ │ │ └── useSignInRedirect.test.ts
│ │ │ │ │ │ ├── useHomeAuth.ts
│ │ │ │ │ │ └── useSignInRedirect.ts
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── styles.module.css
│ │ │ │ ├── index.stories.tsx
│ │ │ │ ├── styles.module.css
│ │ │ │ └── welcomeFooter.module.css
│ │ │ └── wrappers/
│ │ │ ├── DisclaimerWrapper/
│ │ │ │ ├── index.test.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── FeatureWrapper/
│ │ │ │ ├── index.test.tsx
│ │ │ │ └── index.tsx
│ │ │ └── SanctionWrapper/
│ │ │ ├── index.test.tsx
│ │ │ └── index.tsx
│ │ ├── config/
│ │ │ ├── constants.ts
│ │ │ ├── eurcv.ts
│ │ │ ├── gateway.ts
│ │ │ ├── routes.ts
│ │ │ ├── securityHeaders.ts
│ │ │ └── version.ts
│ │ ├── definitions.d.ts
│ │ ├── features/
│ │ │ ├── __core__/
│ │ │ │ ├── __tests__/
│ │ │ │ │ └── useLoadFeature.test.ts
│ │ │ │ ├── createFeatureHandle.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── types.ts
│ │ │ │ ├── useLoadFeature.ts
│ │ │ │ └── withS
================================================
FILE CONTENTS
================================================
================================================
FILE: .claude/commands/speckit.analyze.md
================================================
---
description: Perform a non-destructive cross-artifact consistency and quality analysis across spec.md, plan.md, and tasks.md after task generation.
---
## User Input
```text
$ARGUMENTS
```
You **MUST** consider the user input before proceeding (if not empty).
## Goal
Identify inconsistencies, duplications, ambiguities, and underspecified items across the three core artifacts (`spec.md`, `plan.md`, `tasks.md`) before implementation. This command MUST run only after `/speckit.tasks` has successfully produced a complete `tasks.md`.
## Operating Constraints
**STRICTLY READ-ONLY**: Do **not** modify any files. Output a structured analysis report. Offer an optional remediation plan (user must explicitly approve before any follow-up editing commands would be invoked manually).
**Constitution Authority**: The project constitution (`.specify/memory/constitution.md`) is **non-negotiable** within this analysis scope. Constitution conflicts are automatically CRITICAL and require adjustment of the spec, plan, or tasks—not dilution, reinterpretation, or silent ignoring of the principle. If a principle itself needs to change, that must occur in a separate, explicit constitution update outside `/speckit.analyze`.
## Execution Steps
### 1. Initialize Analysis Context
Run `.specify/scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks` once from repo root and parse JSON for FEATURE_DIR and AVAILABLE_DOCS. Derive absolute paths:
- SPEC = FEATURE_DIR/spec.md
- PLAN = FEATURE_DIR/plan.md
- TASKS = FEATURE_DIR/tasks.md
Abort with an error message if any required file is missing (instruct the user to run missing prerequisite command).
For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot").
### 2. Load Artifacts (Progressive Disclosure)
Load only the minimal necessary context from each artifact:
**From spec.md:**
- Overview/Context
- Functional Requirements
- Non-Functional Requirements
- User Stories
- Edge Cases (if present)
**From plan.md:**
- Architecture/stack choices
- Data Model references
- Phases
- Technical constraints
**From tasks.md:**
- Task IDs
- Descriptions
- Phase grouping
- Parallel markers [P]
- Referenced file paths
**From constitution:**
- Load `.specify/memory/constitution.md` for principle validation
### 3. Build Semantic Models
Create internal representations (do not include raw artifacts in output):
- **Requirements inventory**: Each functional + non-functional requirement with a stable key (derive slug based on imperative phrase; e.g., "User can upload file" → `user-can-upload-file`)
- **User story/action inventory**: Discrete user actions with acceptance criteria
- **Task coverage mapping**: Map each task to one or more requirements or stories (inference by keyword / explicit reference patterns like IDs or key phrases)
- **Constitution rule set**: Extract principle names and MUST/SHOULD normative statements
### 4. Detection Passes (Token-Efficient Analysis)
Focus on high-signal findings. Limit to 50 findings total; aggregate remainder in overflow summary.
#### A. Duplication Detection
- Identify near-duplicate requirements
- Mark lower-quality phrasing for consolidation
#### B. Ambiguity Detection
- Flag vague adjectives (fast, scalable, secure, intuitive, robust) lacking measurable criteria
- Flag unresolved placeholders (TODO, TKTK, ???, `<placeholder>`, etc.)
#### C. Underspecification
- Requirements with verbs but missing object or measurable outcome
- User stories missing acceptance criteria alignment
- Tasks referencing files or components not defined in spec/plan
#### D. Constitution Alignment
- Any requirement or plan element conflicting with a MUST principle
- Missing mandated sections or quality gates from constitution
#### E. Coverage Gaps
- Requirements with zero associated tasks
- Tasks with no mapped requirement/story
- Non-functional requirements not reflected in tasks (e.g., performance, security)
#### F. Inconsistency
- Terminology drift (same concept named differently across files)
- Data entities referenced in plan but absent in spec (or vice versa)
- Task ordering contradictions (e.g., integration tasks before foundational setup tasks without dependency note)
- Conflicting requirements (e.g., one requires Next.js while other specifies Vue)
### 5. Severity Assignment
Use this heuristic to prioritize findings:
- **CRITICAL**: Violates constitution MUST, missing core spec artifact, or requirement with zero coverage that blocks baseline functionality
- **HIGH**: Duplicate or conflicting requirement, ambiguous security/performance attribute, untestable acceptance criterion
- **MEDIUM**: Terminology drift, missing non-functional task coverage, underspecified edge case
- **LOW**: Style/wording improvements, minor redundancy not affecting execution order
### 6. Produce Compact Analysis Report
Output a Markdown report (no file writes) with the following structure:
## Specification Analysis Report
| ID | Category | Severity | Location(s) | Summary | Recommendation |
| --- | ----------- | -------- | ---------------- | ---------------------------- | ------------------------------------ |
| A1 | Duplication | HIGH | spec.md:L120-134 | Two similar requirements ... | Merge phrasing; keep clearer version |
(Add one row per finding; generate stable IDs prefixed by category initial.)
**Coverage Summary Table:**
| Requirement Key | Has Task? | Task IDs | Notes |
| --------------- | --------- | -------- | ----- |
**Constitution Alignment Issues:** (if any)
**Unmapped Tasks:** (if any)
**Metrics:**
- Total Requirements
- Total Tasks
- Coverage % (requirements with >=1 task)
- Ambiguity Count
- Duplication Count
- Critical Issues Count
### 7. Provide Next Actions
At end of report, output a concise Next Actions block:
- If CRITICAL issues exist: Recommend resolving before `/speckit.implement`
- If only LOW/MEDIUM: User may proceed, but provide improvement suggestions
- Provide explicit command suggestions: e.g., "Run /speckit.specify with refinement", "Run /speckit.plan to adjust architecture", "Manually edit tasks.md to add coverage for 'performance-metrics'"
### 8. Offer Remediation
Ask the user: "Would you like me to suggest concrete remediation edits for the top N issues?" (Do NOT apply them automatically.)
## Operating Principles
### Context Efficiency
- **Minimal high-signal tokens**: Focus on actionable findings, not exhaustive documentation
- **Progressive disclosure**: Load artifacts incrementally; don't dump all content into analysis
- **Token-efficient output**: Limit findings table to 50 rows; summarize overflow
- **Deterministic results**: Rerunning without changes should produce consistent IDs and counts
### Analysis Guidelines
- **NEVER modify files** (this is read-only analysis)
- **NEVER hallucinate missing sections** (if absent, report them accurately)
- **Prioritize constitution violations** (these are always CRITICAL)
- **Use examples over exhaustive rules** (cite specific instances, not generic patterns)
- **Report zero issues gracefully** (emit success report with coverage statistics)
## Context
$ARGUMENTS
================================================
FILE: .claude/commands/speckit.checklist.md
================================================
---
description: Generate a custom checklist for the current feature based on user requirements.
---
## Checklist Purpose: "Unit Tests for English"
**CRITICAL CONCEPT**: Checklists are **UNIT TESTS FOR REQUIREMENTS WRITING** - they validate the quality, clarity, and completeness of requirements in a given domain.
**NOT for verification/testing**:
- ❌ NOT "Verify the button clicks correctly"
- ❌ NOT "Test error handling works"
- ❌ NOT "Confirm the API returns 200"
- ❌ NOT checking if code/implementation matches the spec
**FOR requirements quality validation**:
- ✅ "Are visual hierarchy requirements defined for all card types?" (completeness)
- ✅ "Is 'prominent display' quantified with specific sizing/positioning?" (clarity)
- ✅ "Are hover state requirements consistent across all interactive elements?" (consistency)
- ✅ "Are accessibility requirements defined for keyboard navigation?" (coverage)
- ✅ "Does the spec define what happens when logo image fails to load?" (edge cases)
**Metaphor**: If your spec is code written in English, the checklist is its unit test suite. You're testing whether the requirements are well-written, complete, unambiguous, and ready for implementation - NOT whether the implementation works.
## User Input
```text
$ARGUMENTS
```
You **MUST** consider the user input before proceeding (if not empty).
## Execution Steps
1. **Setup**: Run `.specify/scripts/bash/check-prerequisites.sh --json` from repo root and parse JSON for FEATURE_DIR and AVAILABLE_DOCS list.
- All file paths must be absolute.
- For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot").
2. **Clarify intent (dynamic)**: Derive up to THREE initial contextual clarifying questions (no pre-baked catalog). They MUST:
- Be generated from the user's phrasing + extracted signals from spec/plan/tasks
- Only ask about information that materially changes checklist content
- Be skipped individually if already unambiguous in `$ARGUMENTS`
- Prefer precision over breadth
Generation algorithm:
1. Extract signals: feature domain keywords (e.g., auth, latency, UX, API), risk indicators ("critical", "must", "compliance"), stakeholder hints ("QA", "review", "security team"), and explicit deliverables ("a11y", "rollback", "contracts").
2. Cluster signals into candidate focus areas (max 4) ranked by relevance.
3. Identify probable audience & timing (author, reviewer, QA, release) if not explicit.
4. Detect missing dimensions: scope breadth, depth/rigor, risk emphasis, exclusion boundaries, measurable acceptance criteria.
5. Formulate questions chosen from these archetypes:
- Scope refinement (e.g., "Should this include integration touchpoints with X and Y or stay limited to local module correctness?")
- Risk prioritization (e.g., "Which of these potential risk areas should receive mandatory gating checks?")
- Depth calibration (e.g., "Is this a lightweight pre-commit sanity list or a formal release gate?")
- Audience framing (e.g., "Will this be used by the author only or peers during PR review?")
- Boundary exclusion (e.g., "Should we explicitly exclude performance tuning items this round?")
- Scenario class gap (e.g., "No recovery flows detected—are rollback / partial failure paths in scope?")
Question formatting rules:
- If presenting options, generate a compact table with columns: Option | Candidate | Why It Matters
- Limit to A–E options maximum; omit table if a free-form answer is clearer
- Never ask the user to restate what they already said
- Avoid speculative categories (no hallucination). If uncertain, ask explicitly: "Confirm whether X belongs in scope."
Defaults when interaction impossible:
- Depth: Standard
- Audience: Reviewer (PR) if code-related; Author otherwise
- Focus: Top 2 relevance clusters
Output the questions (label Q1/Q2/Q3). After answers: if ≥2 scenario classes (Alternate / Exception / Recovery / Non-Functional domain) remain unclear, you MAY ask up to TWO more targeted follow‑ups (Q4/Q5) with a one-line justification each (e.g., "Unresolved recovery path risk"). Do not exceed five total questions. Skip escalation if user explicitly declines more.
3. **Understand user request**: Combine `$ARGUMENTS` + clarifying answers:
- Derive checklist theme (e.g., security, review, deploy, ux)
- Consolidate explicit must-have items mentioned by user
- Map focus selections to category scaffolding
- Infer any missing context from spec/plan/tasks (do NOT hallucinate)
4. **Load feature context**: Read from FEATURE_DIR:
- spec.md: Feature requirements and scope
- plan.md (if exists): Technical details, dependencies
- tasks.md (if exists): Implementation tasks
**Context Loading Strategy**:
- Load only necessary portions relevant to active focus areas (avoid full-file dumping)
- Prefer summarizing long sections into concise scenario/requirement bullets
- Use progressive disclosure: add follow-on retrieval only if gaps detected
- If source docs are large, generate interim summary items instead of embedding raw text
5. **Generate checklist** - Create "Unit Tests for Requirements":
- Create `FEATURE_DIR/checklists/` directory if it doesn't exist
- Generate unique checklist filename:
- Use short, descriptive name based on domain (e.g., `ux.md`, `api.md`, `security.md`)
- Format: `[domain].md`
- If file exists, append to existing file
- Number items sequentially starting from CHK001
- Each `/speckit.checklist` run creates a NEW file (never overwrites existing checklists)
**CORE PRINCIPLE - Test the Requirements, Not the Implementation**:
Every checklist item MUST evaluate the REQUIREMENTS THEMSELVES for:
- **Completeness**: Are all necessary requirements present?
- **Clarity**: Are requirements unambiguous and specific?
- **Consistency**: Do requirements align with each other?
- **Measurability**: Can requirements be objectively verified?
- **Coverage**: Are all scenarios/edge cases addressed?
**Category Structure** - Group items by requirement quality dimensions:
- **Requirement Completeness** (Are all necessary requirements documented?)
- **Requirement Clarity** (Are requirements specific and unambiguous?)
- **Requirement Consistency** (Do requirements align without conflicts?)
- **Acceptance Criteria Quality** (Are success criteria measurable?)
- **Scenario Coverage** (Are all flows/cases addressed?)
- **Edge Case Coverage** (Are boundary conditions defined?)
- **Non-Functional Requirements** (Performance, Security, Accessibility, etc. - are they specified?)
- **Dependencies & Assumptions** (Are they documented and validated?)
- **Ambiguities & Conflicts** (What needs clarification?)
**HOW TO WRITE CHECKLIST ITEMS - "Unit Tests for English"**:
❌ **WRONG** (Testing implementation):
- "Verify landing page displays 3 episode cards"
- "Test hover states work on desktop"
- "Confirm logo click navigates home"
✅ **CORRECT** (Testing requirements quality):
- "Are the exact number and layout of featured episodes specified?" [Completeness]
- "Is 'prominent display' quantified with specific sizing/positioning?" [Clarity]
- "Are hover state requirements consistent across all interactive elements?" [Consistency]
- "Are keyboard navigation requirements defined for all interactive UI?" [Coverage]
- "Is the fallback behavior specified when logo image fails to load?" [Edge Cases]
- "Are loading states defined for asynchronous episode data?" [Completeness]
- "Does the spec define visual hierarchy for competing UI elements?" [Clarity]
**ITEM STRUCTURE**:
Each item should follow this pattern:
- Question format asking about requirement quality
- Focus on what's WRITTEN (or not written) in the spec/plan
- Include quality dimension in brackets [Completeness/Clarity/Consistency/etc.]
- Reference spec section `[Spec §X.Y]` when checking existing requirements
- Use `[Gap]` marker when checking for missing requirements
**EXAMPLES BY QUALITY DIMENSION**:
Completeness:
- "Are error handling requirements defined for all API failure modes? [Gap]"
- "Are accessibility requirements specified for all interactive elements? [Completeness]"
- "Are mobile breakpoint requirements defined for responsive layouts? [Gap]"
Clarity:
- "Is 'fast loading' quantified with specific timing thresholds? [Clarity, Spec §NFR-2]"
- "Are 'related episodes' selection criteria explicitly defined? [Clarity, Spec §FR-5]"
- "Is 'prominent' defined with measurable visual properties? [Ambiguity, Spec §FR-4]"
Consistency:
- "Do navigation requirements align across all pages? [Consistency, Spec §FR-10]"
- "Are card component requirements consistent between landing and detail pages? [Consistency]"
Coverage:
- "Are requirements defined for zero-state scenarios (no episodes)? [Coverage, Edge Case]"
- "Are concurrent user interaction scenarios addressed? [Coverage, Gap]"
- "Are requirements specified for partial data loading failures? [Coverage, Exception Flow]"
Measurability:
- "Are visual hierarchy requirements measurable/testable? [Acceptance Criteria, Spec §FR-1]"
- "Can 'balanced visual weight' be objectively verified? [Measurability, Spec §FR-2]"
**Scenario Classification & Coverage** (Requirements Quality Focus):
- Check if requirements exist for: Primary, Alternate, Exception/Error, Recovery, Non-Functional scenarios
- For each scenario class, ask: "Are [scenario type] requirements complete, clear, and consistent?"
- If scenario class missing: "Are [scenario type] requirements intentionally excluded or missing? [Gap]"
- Include resilience/rollback when state mutation occurs: "Are rollback requirements defined for migration failures? [Gap]"
**Traceability Requirements**:
- MINIMUM: ≥80% of items MUST include at least one traceability reference
- Each item should reference: spec section `[Spec §X.Y]`, or use markers: `[Gap]`, `[Ambiguity]`, `[Conflict]`, `[Assumption]`
- If no ID system exists: "Is a requirement & acceptance criteria ID scheme established? [Traceability]"
**Surface & Resolve Issues** (Requirements Quality Problems):
Ask questions about the requirements themselves:
- Ambiguities: "Is the term 'fast' quantified with specific metrics? [Ambiguity, Spec §NFR-1]"
- Conflicts: "Do navigation requirements conflict between §FR-10 and §FR-10a? [Conflict]"
- Assumptions: "Is the assumption of 'always available podcast API' validated? [Assumption]"
- Dependencies: "Are external podcast API requirements documented? [Dependency, Gap]"
- Missing definitions: "Is 'visual hierarchy' defined with measurable criteria? [Gap]"
**Content Consolidation**:
- Soft cap: If raw candidate items > 40, prioritize by risk/impact
- Merge near-duplicates checking the same requirement aspect
- If >5 low-impact edge cases, create one item: "Are edge cases X, Y, Z addressed in requirements? [Coverage]"
**🚫 ABSOLUTELY PROHIBITED** - These make it an implementation test, not a requirements test:
- ❌ Any item starting with "Verify", "Test", "Confirm", "Check" + implementation behavior
- ❌ References to code execution, user actions, system behavior
- ❌ "Displays correctly", "works properly", "functions as expected"
- ❌ "Click", "navigate", "render", "load", "execute"
- ❌ Test cases, test plans, QA procedures
- ❌ Implementation details (frameworks, APIs, algorithms)
**✅ REQUIRED PATTERNS** - These test requirements quality:
- ✅ "Are [requirement type] defined/specified/documented for [scenario]?"
- ✅ "Is [vague term] quantified/clarified with specific criteria?"
- ✅ "Are requirements consistent between [section A] and [section B]?"
- ✅ "Can [requirement] be objectively measured/verified?"
- ✅ "Are [edge cases/scenarios] addressed in requirements?"
- ✅ "Does the spec define [missing aspect]?"
6. **Structure Reference**: Generate the checklist following the canonical template in `.specify/templates/checklist-template.md` for title, meta section, category headings, and ID formatting. If template is unavailable, use: H1 title, purpose/created meta lines, `##` category sections containing `- [ ] CHK### <requirement item>` lines with globally incrementing IDs starting at CHK001.
7. **Report**: Output full path to created checklist, item count, and remind user that each run creates a new file. Summarize:
- Focus areas selected
- Depth level
- Actor/timing
- Any explicit user-specified must-have items incorporated
**Important**: Each `/speckit.checklist` command invocation creates a checklist file using short, descriptive names unless file already exists. This allows:
- Multiple checklists of different types (e.g., `ux.md`, `test.md`, `security.md`)
- Simple, memorable filenames that indicate checklist purpose
- Easy identification and navigation in the `checklists/` folder
To avoid clutter, use descriptive types and clean up obsolete checklists when done.
## Example Checklist Types & Sample Items
**UX Requirements Quality:** `ux.md`
Sample items (testing the requirements, NOT the implementation):
- "Are visual hierarchy requirements defined with measurable criteria? [Clarity, Spec §FR-1]"
- "Is the number and positioning of UI elements explicitly specified? [Completeness, Spec §FR-1]"
- "Are interaction state requirements (hover, focus, active) consistently defined? [Consistency]"
- "Are accessibility requirements specified for all interactive elements? [Coverage, Gap]"
- "Is fallback behavior defined when images fail to load? [Edge Case, Gap]"
- "Can 'prominent display' be objectively measured? [Measurability, Spec §FR-4]"
**API Requirements Quality:** `api.md`
Sample items:
- "Are error response formats specified for all failure scenarios? [Completeness]"
- "Are rate limiting requirements quantified with specific thresholds? [Clarity]"
- "Are authentication requirements consistent across all endpoints? [Consistency]"
- "Are retry/timeout requirements defined for external dependencies? [Coverage, Gap]"
- "Is versioning strategy documented in requirements? [Gap]"
**Performance Requirements Quality:** `performance.md`
Sample items:
- "Are performance requirements quantified with specific metrics? [Clarity]"
- "Are performance targets defined for all critical user journeys? [Coverage]"
- "Are performance requirements under different load conditions specified? [Completeness]"
- "Can performance requirements be objectively measured? [Measurability]"
- "Are degradation requirements defined for high-load scenarios? [Edge Case, Gap]"
**Security Requirements Quality:** `security.md`
Sample items:
- "Are authentication requirements specified for all protected resources? [Coverage]"
- "Are data protection requirements defined for sensitive information? [Completeness]"
- "Is the threat model documented and requirements aligned to it? [Traceability]"
- "Are security requirements consistent with compliance obligations? [Consistency]"
- "Are security failure/breach response requirements defined? [Gap, Exception Flow]"
## Anti-Examples: What NOT To Do
**❌ WRONG - These test implementation, not requirements:**
```markdown
- [ ] CHK001 - Verify landing page displays 3 episode cards [Spec §FR-001]
- [ ] CHK002 - Test hover states work correctly on desktop [Spec §FR-003]
- [ ] CHK003 - Confirm logo click navigates to home page [Spec §FR-010]
- [ ] CHK004 - Check that related episodes section shows 3-5 items [Spec §FR-005]
```
**✅ CORRECT - These test requirements quality:**
```markdown
- [ ] CHK001 - Are the number and layout of featured episodes explicitly specified? [Completeness, Spec §FR-001]
- [ ] CHK002 - Are hover state requirements consistently defined for all interactive elements? [Consistency, Spec §FR-003]
- [ ] CHK003 - Are navigation requirements clear for all clickable brand elements? [Clarity, Spec §FR-010]
- [ ] CHK004 - Is the selection criteria for related episodes documented? [Gap, Spec §FR-005]
- [ ] CHK005 - Are loading state requirements defined for asynchronous episode data? [Gap]
- [ ] CHK006 - Can "visual hierarchy" requirements be objectively measured? [Measurability, Spec §FR-001]
```
**Key Differences:**
- Wrong: Tests if the system works correctly
- Correct: Tests if the requirements are written correctly
- Wrong: Verification of behavior
- Correct: Validation of requirement quality
- Wrong: "Does it do X?"
- Correct: "Is X clearly specified?"
================================================
FILE: .claude/commands/speckit.clarify.md
================================================
---
description: Identify underspecified areas in the current feature spec by asking up to 5 highly targeted clarification questions and encoding answers back into the spec.
handoffs:
- label: Build Technical Plan
agent: speckit.plan
prompt: Create a plan for the spec. I am building with...
---
## User Input
```text
$ARGUMENTS
```
You **MUST** consider the user input before proceeding (if not empty).
## Outline
Goal: Detect and reduce ambiguity or missing decision points in the active feature specification and record the clarifications directly in the spec file.
Note: This clarification workflow is expected to run (and be completed) BEFORE invoking `/speckit.plan`. If the user explicitly states they are skipping clarification (e.g., exploratory spike), you may proceed, but must warn that downstream rework risk increases.
Execution steps:
1. Run `.specify/scripts/bash/check-prerequisites.sh --json --paths-only` from repo root **once** (combined `--json --paths-only` mode / `-Json -PathsOnly`). Parse minimal JSON payload fields:
- `FEATURE_DIR`
- `FEATURE_SPEC`
- (Optionally capture `IMPL_PLAN`, `TASKS` for future chained flows.)
- If JSON parsing fails, abort and instruct user to re-run `/speckit.specify` or verify feature branch environment.
- For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot").
2. Load the current spec file. Perform a structured ambiguity & coverage scan using this taxonomy. For each category, mark status: Clear / Partial / Missing. Produce an internal coverage map used for prioritization (do not output raw map unless no questions will be asked).
Functional Scope & Behavior:
- Core user goals & success criteria
- Explicit out-of-scope declarations
- User roles / personas differentiation
Domain & Data Model:
- Entities, attributes, relationships
- Identity & uniqueness rules
- Lifecycle/state transitions
- Data volume / scale assumptions
Interaction & UX Flow:
- Critical user journeys / sequences
- Error/empty/loading states
- Accessibility or localization notes
Non-Functional Quality Attributes:
- Performance (latency, throughput targets)
- Scalability (horizontal/vertical, limits)
- Reliability & availability (uptime, recovery expectations)
- Observability (logging, metrics, tracing signals)
- Security & privacy (authN/Z, data protection, threat assumptions)
- Compliance / regulatory constraints (if any)
Integration & External Dependencies:
- External services/APIs and failure modes
- Data import/export formats
- Protocol/versioning assumptions
Edge Cases & Failure Handling:
- Negative scenarios
- Rate limiting / throttling
- Conflict resolution (e.g., concurrent edits)
Constraints & Tradeoffs:
- Technical constraints (language, storage, hosting)
- Explicit tradeoffs or rejected alternatives
Terminology & Consistency:
- Canonical glossary terms
- Avoided synonyms / deprecated terms
Completion Signals:
- Acceptance criteria testability
- Measurable Definition of Done style indicators
Misc / Placeholders:
- TODO markers / unresolved decisions
- Ambiguous adjectives ("robust", "intuitive") lacking quantification
For each category with Partial or Missing status, add a candidate question opportunity unless:
- Clarification would not materially change implementation or validation strategy
- Information is better deferred to planning phase (note internally)
3. Generate (internally) a prioritized queue of candidate clarification questions (maximum 5). Do NOT output them all at once. Apply these constraints:
- Maximum of 10 total questions across the whole session.
- Each question must be answerable with EITHER:
- A short multiple‑choice selection (2–5 distinct, mutually exclusive options), OR
- A one-word / short‑phrase answer (explicitly constrain: "Answer in <=5 words").
- Only include questions whose answers materially impact architecture, data modeling, task decomposition, test design, UX behavior, operational readiness, or compliance validation.
- Ensure category coverage balance: attempt to cover the highest impact unresolved categories first; avoid asking two low-impact questions when a single high-impact area (e.g., security posture) is unresolved.
- Exclude questions already answered, trivial stylistic preferences, or plan-level execution details (unless blocking correctness).
- Favor clarifications that reduce downstream rework risk or prevent misaligned acceptance tests.
- If more than 5 categories remain unresolved, select the top 5 by (Impact \* Uncertainty) heuristic.
4. Sequential questioning loop (interactive):
- Present EXACTLY ONE question at a time.
- For multiple‑choice questions:
- **Analyze all options** and determine the **most suitable option** based on:
- Best practices for the project type
- Common patterns in similar implementations
- Risk reduction (security, performance, maintainability)
- Alignment with any explicit project goals or constraints visible in the spec
- Present your **recommended option prominently** at the top with clear reasoning (1-2 sentences explaining why this is the best choice).
- Format as: `**Recommended:** Option [X] - <reasoning>`
- Then render all options as a Markdown table:
| Option | Description |
| ------ | --------------------------------------------------------------------------------------------------- |
| A | <Option A description> |
| B | <Option B description> |
| C | <Option C description> (add D/E as needed up to 5) |
| Short | Provide a different short answer (<=5 words) (Include only if free-form alternative is appropriate) |
- After the table, add: `You can reply with the option letter (e.g., "A"), accept the recommendation by saying "yes" or "recommended", or provide your own short answer.`
- For short‑answer style (no meaningful discrete options):
- Provide your **suggested answer** based on best practices and context.
- Format as: `**Suggested:** <your proposed answer> - <brief reasoning>`
- Then output: `Format: Short answer (<=5 words). You can accept the suggestion by saying "yes" or "suggested", or provide your own answer.`
- After the user answers:
- If the user replies with "yes", "recommended", or "suggested", use your previously stated recommendation/suggestion as the answer.
- Otherwise, validate the answer maps to one option or fits the <=5 word constraint.
- If ambiguous, ask for a quick disambiguation (count still belongs to same question; do not advance).
- Once satisfactory, record it in working memory (do not yet write to disk) and move to the next queued question.
- Stop asking further questions when:
- All critical ambiguities resolved early (remaining queued items become unnecessary), OR
- User signals completion ("done", "good", "no more"), OR
- You reach 5 asked questions.
- Never reveal future queued questions in advance.
- If no valid questions exist at start, immediately report no critical ambiguities.
5. Integration after EACH accepted answer (incremental update approach):
- Maintain in-memory representation of the spec (loaded once at start) plus the raw file contents.
- For the first integrated answer in this session:
- Ensure a `## Clarifications` section exists (create it just after the highest-level contextual/overview section per the spec template if missing).
- Under it, create (if not present) a `### Session YYYY-MM-DD` subheading for today.
- Append a bullet line immediately after acceptance: `- Q: <question> → A: <final answer>`.
- Then immediately apply the clarification to the most appropriate section(s):
- Functional ambiguity → Update or add a bullet in Functional Requirements.
- User interaction / actor distinction → Update User Stories or Actors subsection (if present) with clarified role, constraint, or scenario.
- Data shape / entities → Update Data Model (add fields, types, relationships) preserving ordering; note added constraints succinctly.
- Non-functional constraint → Add/modify measurable criteria in Non-Functional / Quality Attributes section (convert vague adjective to metric or explicit target).
- Edge case / negative flow → Add a new bullet under Edge Cases / Error Handling (or create such subsection if template provides placeholder for it).
- Terminology conflict → Normalize term across spec; retain original only if necessary by adding `(formerly referred to as "X")` once.
- If the clarification invalidates an earlier ambiguous statement, replace that statement instead of duplicating; leave no obsolete contradictory text.
- Save the spec file AFTER each integration to minimize risk of context loss (atomic overwrite).
- Preserve formatting: do not reorder unrelated sections; keep heading hierarchy intact.
- Keep each inserted clarification minimal and testable (avoid narrative drift).
6. Validation (performed after EACH write plus final pass):
- Clarifications session contains exactly one bullet per accepted answer (no duplicates).
- Total asked (accepted) questions ≤ 5.
- Updated sections contain no lingering vague placeholders the new answer was meant to resolve.
- No contradictory earlier statement remains (scan for now-invalid alternative choices removed).
- Markdown structure valid; only allowed new headings: `## Clarifications`, `### Session YYYY-MM-DD`.
- Terminology consistency: same canonical term used across all updated sections.
7. Write the updated spec back to `FEATURE_SPEC`.
8. Report completion (after questioning loop ends or early termination):
- Number of questions asked & answered.
- Path to updated spec.
- Sections touched (list names).
- Coverage summary table listing each taxonomy category with Status: Resolved (was Partial/Missing and addressed), Deferred (exceeds question quota or better suited for planning), Clear (already sufficient), Outstanding (still Partial/Missing but low impact).
- If any Outstanding or Deferred remain, recommend whether to proceed to `/speckit.plan` or run `/speckit.clarify` again later post-plan.
- Suggested next command.
Behavior rules:
- If no meaningful ambiguities found (or all potential questions would be low-impact), respond: "No critical ambiguities detected worth formal clarification." and suggest proceeding.
- If spec file missing, instruct user to run `/speckit.specify` first (do not create a new spec here).
- Never exceed 5 total asked questions (clarification retries for a single question do not count as new questions).
- Avoid speculative tech stack questions unless the absence blocks functional clarity.
- Respect user early termination signals ("stop", "done", "proceed").
- If no questions asked due to full coverage, output a compact coverage summary (all categories Clear) then suggest advancing.
- If quota reached with unresolved high-impact categories remaining, explicitly flag them under Deferred with rationale.
Context for prioritization: $ARGUMENTS
================================================
FILE: .claude/commands/speckit.constitution.md
================================================
---
description: Create or update the project constitution from interactive or provided principle inputs, ensuring all dependent templates stay in sync.
handoffs:
- label: Build Specification
agent: speckit.specify
prompt: Implement the feature specification based on the updated constitution. I want to build...
---
## User Input
```text
$ARGUMENTS
```
You **MUST** consider the user input before proceeding (if not empty).
## Outline
You are updating the project constitution at `.specify/memory/constitution.md`. This file is a TEMPLATE containing placeholder tokens in square brackets (e.g. `[PROJECT_NAME]`, `[PRINCIPLE_1_NAME]`). Your job is to (a) collect/derive concrete values, (b) fill the template precisely, and (c) propagate any amendments across dependent artifacts.
Follow this execution flow:
1. Load the existing constitution template at `.specify/memory/constitution.md`.
- Identify every placeholder token of the form `[ALL_CAPS_IDENTIFIER]`.
**IMPORTANT**: The user might require less or more principles than the ones used in the template. If a number is specified, respect that - follow the general template. You will update the doc accordingly.
2. Collect/derive values for placeholders:
- If user input (conversation) supplies a value, use it.
- Otherwise infer from existing repo context (README, docs, prior constitution versions if embedded).
- For governance dates: `RATIFICATION_DATE` is the original adoption date (if unknown ask or mark TODO), `LAST_AMENDED_DATE` is today if changes are made, otherwise keep previous.
- `CONSTITUTION_VERSION` must increment according to semantic versioning rules:
- MAJOR: Backward incompatible governance/principle removals or redefinitions.
- MINOR: New principle/section added or materially expanded guidance.
- PATCH: Clarifications, wording, typo fixes, non-semantic refinements.
- If version bump type ambiguous, propose reasoning before finalizing.
3. Draft the updated constitution content:
- Replace every placeholder with concrete text (no bracketed tokens left except intentionally retained template slots that the project has chosen not to define yet—explicitly justify any left).
- Preserve heading hierarchy and comments can be removed once replaced unless they still add clarifying guidance.
- Ensure each Principle section: succinct name line, paragraph (or bullet list) capturing non‑negotiable rules, explicit rationale if not obvious.
- Ensure Governance section lists amendment procedure, versioning policy, and compliance review expectations.
4. Consistency propagation checklist (convert prior checklist into active validations):
- Read `.specify/templates/plan-template.md` and ensure any "Constitution Check" or rules align with updated principles.
- Read `.specify/templates/spec-template.md` for scope/requirements alignment—update if constitution adds/removes mandatory sections or constraints.
- Read `.specify/templates/tasks-template.md` and ensure task categorization reflects new or removed principle-driven task types (e.g., observability, versioning, testing discipline).
- Read each command file in `.specify/templates/commands/*.md` (including this one) to verify no outdated references (agent-specific names like CLAUDE only) remain when generic guidance is required.
- Read any runtime guidance docs (e.g., `README.md`, `docs/quickstart.md`, or agent-specific guidance files if present). Update references to principles changed.
5. Produce a Sync Impact Report (prepend as an HTML comment at top of the constitution file after update):
- Version change: old → new
- List of modified principles (old title → new title if renamed)
- Added sections
- Removed sections
- Templates requiring updates (✅ updated / ⚠ pending) with file paths
- Follow-up TODOs if any placeholders intentionally deferred.
6. Validation before final output:
- No remaining unexplained bracket tokens.
- Version line matches report.
- Dates ISO format YYYY-MM-DD.
- Principles are declarative, testable, and free of vague language ("should" → replace with MUST/SHOULD rationale where appropriate).
7. Write the completed constitution back to `.specify/memory/constitution.md` (overwrite).
8. Output a final summary to the user with:
- New version and bump rationale.
- Any files flagged for manual follow-up.
- Suggested commit message (e.g., `docs: amend constitution to vX.Y.Z (principle additions + governance update)`).
Formatting & Style Requirements:
- Use Markdown headings exactly as in the template (do not demote/promote levels).
- Wrap long rationale lines to keep readability (<100 chars ideally) but do not hard enforce with awkward breaks.
- Keep a single blank line between sections.
- Avoid trailing whitespace.
If the user supplies partial updates (e.g., only one principle revision), still perform validation and version decision steps.
If critical info missing (e.g., ratification date truly unknown), insert `TODO(<FIELD_NAME>): explanation` and include in the Sync Impact Report under deferred items.
Do not create a new template; always operate on the existing `.specify/memory/constitution.md` file.
================================================
FILE: .claude/commands/speckit.implement.md
================================================
---
description: Execute the implementation plan by processing and executing all tasks defined in tasks.md
---
## User Input
```text
$ARGUMENTS
```
You **MUST** consider the user input before proceeding (if not empty).
## Outline
1. Run `.specify/scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot").
2. **Check checklists status** (if FEATURE_DIR/checklists/ exists):
- Scan all checklist files in the checklists/ directory
- For each checklist, count:
- Total items: All lines matching `- [ ]` or `- [X]` or `- [x]`
- Completed items: Lines matching `- [X]` or `- [x]`
- Incomplete items: Lines matching `- [ ]`
- Create a status table:
```text
| Checklist | Total | Completed | Incomplete | Status |
|-----------|-------|-----------|------------|--------|
| ux.md | 12 | 12 | 0 | ✓ PASS |
| test.md | 8 | 5 | 3 | ✗ FAIL |
| security.md | 6 | 6 | 0 | ✓ PASS |
```
- Calculate overall status:
- **PASS**: All checklists have 0 incomplete items
- **FAIL**: One or more checklists have incomplete items
- **If any checklist is incomplete**:
- Display the table with incomplete item counts
- **STOP** and ask: "Some checklists are incomplete. Do you want to proceed with implementation anyway? (yes/no)"
- Wait for user response before continuing
- If user says "no" or "wait" or "stop", halt execution
- If user says "yes" or "proceed" or "continue", proceed to step 3
- **If all checklists are complete**:
- Display the table showing all checklists passed
- Automatically proceed to step 3
3. Load and analyze the implementation context:
- **REQUIRED**: Read tasks.md for the complete task list and execution plan
- **REQUIRED**: Read plan.md for tech stack, architecture, and file structure
- **IF EXISTS**: Read data-model.md for entities and relationships
- **IF EXISTS**: Read contracts/ for API specifications and test requirements
- **IF EXISTS**: Read research.md for technical decisions and constraints
- **IF EXISTS**: Read quickstart.md for integration scenarios
4. **Project Setup Verification**:
- **REQUIRED**: Create/verify ignore files based on actual project setup:
**Detection & Creation Logic**:
- Check if the following command succeeds to determine if the repository is a git repo (create/verify .gitignore if so):
```sh
git rev-parse --git-dir 2>/dev/null
```
- Check if Dockerfile\* exists or Docker in plan.md → create/verify .dockerignore
- Check if .eslintrc\* exists → create/verify .eslintignore
- Check if eslint.config.\* exists → ensure the config's `ignores` entries cover required patterns
- Check if .prettierrc\* exists → create/verify .prettierignore
- Check if .npmrc or package.json exists → create/verify .npmignore (if publishing)
- Check if terraform files (\*.tf) exist → create/verify .terraformignore
- Check if .helmignore needed (helm charts present) → create/verify .helmignore
**If ignore file already exists**: Verify it contains essential patterns, append missing critical patterns only
**If ignore file missing**: Create with full pattern set for detected technology
**Common Patterns by Technology** (from plan.md tech stack):
- **Node.js/JavaScript/TypeScript**: `node_modules/`, `dist/`, `build/`, `*.log`, `.env*`
- **Python**: `__pycache__/`, `*.pyc`, `.venv/`, `venv/`, `dist/`, `*.egg-info/`
- **Java**: `target/`, `*.class`, `*.jar`, `.gradle/`, `build/`
- **C#/.NET**: `bin/`, `obj/`, `*.user`, `*.suo`, `packages/`
- **Go**: `*.exe`, `*.test`, `vendor/`, `*.out`
- **Ruby**: `.bundle/`, `log/`, `tmp/`, `*.gem`, `vendor/bundle/`
- **PHP**: `vendor/`, `*.log`, `*.cache`, `*.env`
- **Rust**: `target/`, `debug/`, `release/`, `*.rs.bk`, `*.rlib`, `*.prof*`, `.idea/`, `*.log`, `.env*`
- **Kotlin**: `build/`, `out/`, `.gradle/`, `.idea/`, `*.class`, `*.jar`, `*.iml`, `*.log`, `.env*`
- **C++**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.so`, `*.a`, `*.exe`, `*.dll`, `.idea/`, `*.log`, `.env*`
- **C**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.a`, `*.so`, `*.exe`, `Makefile`, `config.log`, `.idea/`, `*.log`, `.env*`
- **Swift**: `.build/`, `DerivedData/`, `*.swiftpm/`, `Packages/`
- **R**: `.Rproj.user/`, `.Rhistory`, `.RData`, `.Ruserdata`, `*.Rproj`, `packrat/`, `renv/`
- **Universal**: `.DS_Store`, `Thumbs.db`, `*.tmp`, `*.swp`, `.vscode/`, `.idea/`
**Tool-Specific Patterns**:
- **Docker**: `node_modules/`, `.git/`, `Dockerfile*`, `.dockerignore`, `*.log*`, `.env*`, `coverage/`
- **ESLint**: `node_modules/`, `dist/`, `build/`, `coverage/`, `*.min.js`
- **Prettier**: `node_modules/`, `dist/`, `build/`, `coverage/`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`
- **Terraform**: `.terraform/`, `*.tfstate*`, `*.tfvars`, `.terraform.lock.hcl`
- **Kubernetes/k8s**: `*.secret.yaml`, `secrets/`, `.kube/`, `kubeconfig*`, `*.key`, `*.crt`
5. Parse tasks.md structure and extract:
- **Task phases**: Setup, Tests, Core, Integration, Polish
- **Task dependencies**: Sequential vs parallel execution rules
- **Task details**: ID, description, file paths, parallel markers [P]
- **Execution flow**: Order and dependency requirements
6. Execute implementation following the task plan:
- **Phase-by-phase execution**: Complete each phase before moving to the next
- **Respect dependencies**: Run sequential tasks in order, parallel tasks [P] can run together
- **Follow TDD approach**: Execute test tasks before their corresponding implementation tasks
- **File-based coordination**: Tasks affecting the same files must run sequentially
- **Validation checkpoints**: Verify each phase completion before proceeding
7. Implementation execution rules:
- **Setup first**: Initialize project structure, dependencies, configuration
- **Tests before code**: If you need to write tests for contracts, entities, and integration scenarios
- **Core development**: Implement models, services, CLI commands, endpoints
- **Integration work**: Database connections, middleware, logging, external services
- **Polish and validation**: Unit tests, performance optimization, documentation
8. Progress tracking and error handling:
- Report progress after each completed task
- Halt execution if any non-parallel task fails
- For parallel tasks [P], continue with successful tasks, report failed ones
- Provide clear error messages with context for debugging
- Suggest next steps if implementation cannot proceed
- **IMPORTANT** For completed tasks, make sure to mark the task off as [X] in the tasks file.
9. Completion validation:
- Verify all required tasks are completed
- Check that implemented features match the original specification
- Validate that tests pass and coverage meets requirements
- Confirm the implementation follows the technical plan
- Report final status with summary of completed work
Note: This command assumes a complete task breakdown exists in tasks.md. If tasks are incomplete or missing, suggest running `/speckit.tasks` first to regenerate the task list.
================================================
FILE: .claude/commands/speckit.plan.md
================================================
---
description: Execute the implementation planning workflow using the plan template to generate design artifacts.
handoffs:
- label: Create Tasks
agent: speckit.tasks
prompt: Break the plan into tasks
send: true
- label: Create Checklist
agent: speckit.checklist
prompt: Create a checklist for the following domain...
---
## User Input
```text
$ARGUMENTS
```
You **MUST** consider the user input before proceeding (if not empty).
## Outline
1. **Setup**: Run `.specify/scripts/bash/setup-plan.sh --json` from repo root and parse JSON for FEATURE_SPEC, IMPL_PLAN, SPECS_DIR, BRANCH. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot").
2. **Load context**: Read FEATURE_SPEC and `.specify/memory/constitution.md`. Load IMPL_PLAN template (already copied).
3. **Execute plan workflow**: Follow the structure in IMPL_PLAN template to:
- Fill Technical Context (mark unknowns as "NEEDS CLARIFICATION")
- Fill Constitution Check section from constitution
- Evaluate gates (ERROR if violations unjustified)
- Phase 0: Generate research.md (resolve all NEEDS CLARIFICATION)
- Phase 1: Generate data-model.md, contracts/, quickstart.md
- Phase 1: Update agent context by running the agent script
- Re-evaluate Constitution Check post-design
4. **Stop and report**: Command ends after Phase 2 planning. Report branch, IMPL_PLAN path, and generated artifacts.
## Phases
### Phase 0: Outline & Research
1. **Extract unknowns from Technical Context** above:
- For each NEEDS CLARIFICATION → research task
- For each dependency → best practices task
- For each integration → patterns task
2. **Generate and dispatch research agents**:
```text
For each unknown in Technical Context:
Task: "Research {unknown} for {feature context}"
For each technology choice:
Task: "Find best practices for {tech} in {domain}"
```
3. **Consolidate findings** in `research.md` using format:
- Decision: [what was chosen]
- Rationale: [why chosen]
- Alternatives considered: [what else evaluated]
**Output**: research.md with all NEEDS CLARIFICATION resolved
### Phase 1: Design & Contracts
**Prerequisites:** `research.md` complete
1. **Extract entities from feature spec** → `data-model.md`:
- Entity name, fields, relationships
- Validation rules from requirements
- State transitions if applicable
2. **Generate API contracts** from functional requirements:
- For each user action → endpoint
- Use standard REST/GraphQL patterns
- Output OpenAPI/GraphQL schema to `/contracts/`
3. **Agent context update**:
- Run `.specify/scripts/bash/update-agent-context.sh claude`
- These scripts detect which AI agent is in use
- Update the appropriate agent-specific context file
- Add only new technology from current plan
- Preserve manual additions between markers
**Output**: data-model.md, /contracts/\*, quickstart.md, agent-specific file
## Key rules
- Use absolute paths
- ERROR on gate failures or unresolved clarifications
================================================
FILE: .claude/commands/speckit.specify.md
================================================
---
description: Create or update the feature specification from a natural language feature description.
handoffs:
- label: Build Technical Plan
agent: speckit.plan
prompt: Create a plan for the spec. I am building with...
- label: Clarify Spec Requirements
agent: speckit.clarify
prompt: Clarify specification requirements
send: true
---
## User Input
```text
$ARGUMENTS
```
You **MUST** consider the user input before proceeding (if not empty).
## Outline
The text the user typed after `/speckit.specify` in the triggering message **is** the feature description. Assume you always have it available in this conversation even if `$ARGUMENTS` appears literally below. Do not ask the user to repeat it unless they provided an empty command.
Given that feature description, do this:
1. **Generate a concise short name** (2-4 words) for the branch:
- Analyze the feature description and extract the most meaningful keywords
- Create a 2-4 word short name that captures the essence of the feature
- Use action-noun format when possible (e.g., "add-user-auth", "fix-payment-bug")
- Preserve technical terms and acronyms (OAuth2, API, JWT, etc.)
- Keep it concise but descriptive enough to understand the feature at a glance
- Examples:
- "I want to add user authentication" → "user-auth"
- "Implement OAuth2 integration for the API" → "oauth2-api-integration"
- "Create a dashboard for analytics" → "analytics-dashboard"
- "Fix payment processing timeout bug" → "fix-payment-timeout"
2. **Check for existing branches before creating new one**:
a. First, fetch all remote branches to ensure we have the latest information:
```bash
git fetch --all --prune
```
b. Find the highest feature number across all sources for the short-name:
- Remote branches: `git ls-remote --heads origin | grep -E 'refs/heads/[0-9]+-<short-name>$'`
- Local branches: `git branch | grep -E '^[* ]*[0-9]+-<short-name>$'`
- Specs directories: Check for directories matching `specs/[0-9]+-<short-name>`
c. Determine the next available number:
- Extract all numbers from all three sources
- Find the highest number N
- Use N+1 for the new branch number
d. Run the script `.specify/scripts/bash/create-new-feature.sh --json "$ARGUMENTS"` with the calculated number and short-name:
- Pass `--number N+1` and `--short-name "your-short-name"` along with the feature description
- Bash example: `.specify/scripts/bash/create-new-feature.sh --json "$ARGUMENTS" --json --number 5 --short-name "user-auth" "Add user authentication"`
- PowerShell example: `.specify/scripts/bash/create-new-feature.sh --json "$ARGUMENTS" -Json -Number 5 -ShortName "user-auth" "Add user authentication"`
**IMPORTANT**:
- Check all three sources (remote branches, local branches, specs directories) to find the highest number
- Only match branches/directories with the exact short-name pattern
- If no existing branches/directories found with this short-name, start with number 1
- You must only ever run this script once per feature
- The JSON is provided in the terminal as output - always refer to it to get the actual content you're looking for
- The JSON output will contain BRANCH_NAME and SPEC_FILE paths
- For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot")
3. Load `.specify/templates/spec-template.md` to understand required sections.
4. Follow this execution flow:
1. Parse user description from Input
If empty: ERROR "No feature description provided"
2. Extract key concepts from description
Identify: actors, actions, data, constraints
3. For unclear aspects:
- Make informed guesses based on context and industry standards
- Only mark with [NEEDS CLARIFICATION: specific question] if:
- The choice significantly impacts feature scope or user experience
- Multiple reasonable interpretations exist with different implications
- No reasonable default exists
- **LIMIT: Maximum 3 [NEEDS CLARIFICATION] markers total**
- Prioritize clarifications by impact: scope > security/privacy > user experience > technical details
4. Fill User Scenarios & Testing section
If no clear user flow: ERROR "Cannot determine user scenarios"
5. Generate Functional Requirements
Each requirement must be testable
Use reasonable defaults for unspecified details (document assumptions in Assumptions section)
6. Define Success Criteria
Create measurable, technology-agnostic outcomes
Include both quantitative metrics (time, performance, volume) and qualitative measures (user satisfaction, task completion)
Each criterion must be verifiable without implementation details
7. Identify Key Entities (if data involved)
8. Return: SUCCESS (spec ready for planning)
5. Write the specification to SPEC_FILE using the template structure, replacing placeholders with concrete details derived from the feature description (arguments) while preserving section order and headings.
6. **Specification Quality Validation**: After writing the initial spec, validate it against quality criteria:
a. **Create Spec Quality Checklist**: Generate a checklist file at `FEATURE_DIR/checklists/requirements.md` using the checklist template structure with these validation items:
```markdown
# Specification Quality Checklist: [FEATURE NAME]
**Purpose**: Validate specification completeness and quality before proceeding to planning
**Created**: [DATE]
**Feature**: [Link to spec.md]
## Content Quality
- [ ] No implementation details (languages, frameworks, APIs)
- [ ] Focused on user value and business needs
- [ ] Written for non-technical stakeholders
- [ ] All mandatory sections completed
## Requirement Completeness
- [ ] No [NEEDS CLARIFICATION] markers remain
- [ ] Requirements are testable and unambiguous
- [ ] Success criteria are measurable
- [ ] Success criteria are technology-agnostic (no implementation details)
- [ ] All acceptance scenarios are defined
- [ ] Edge cases are identified
- [ ] Scope is clearly bounded
- [ ] Dependencies and assumptions identified
## Feature Readiness
- [ ] All functional requirements have clear acceptance criteria
- [ ] User scenarios cover primary flows
- [ ] Feature meets measurable outcomes defined in Success Criteria
- [ ] No implementation details leak into specification
## Notes
- Items marked incomplete require spec updates before `/speckit.clarify` or `/speckit.plan`
```
b. **Run Validation Check**: Review the spec against each checklist item:
- For each item, determine if it passes or fails
- Document specific issues found (quote relevant spec sections)
c. **Handle Validation Results**:
- **If all items pass**: Mark checklist complete and proceed to step 6
- **If items fail (excluding [NEEDS CLARIFICATION])**:
1. List the failing items and specific issues
2. Update the spec to address each issue
3. Re-run validation until all items pass (max 3 iterations)
4. If still failing after 3 iterations, document remaining issues in checklist notes and warn user
- **If [NEEDS CLARIFICATION] markers remain**:
1. Extract all [NEEDS CLARIFICATION: ...] markers from the spec
2. **LIMIT CHECK**: If more than 3 markers exist, keep only the 3 most critical (by scope/security/UX impact) and make informed guesses for the rest
3. For each clarification needed (max 3), present options to user in this format:
```markdown
## Question [N]: [Topic]
**Context**: [Quote relevant spec section]
**What we need to know**: [Specific question from NEEDS CLARIFICATION marker]
**Suggested Answers**:
| Option | Answer | Implications |
| ------ | ------------------------- | ------------------------------------- |
| A | [First suggested answer] | [What this means for the feature] |
| B | [Second suggested answer] | [What this means for the feature] |
| C | [Third suggested answer] | [What this means for the feature] |
| Custom | Provide your own answer | [Explain how to provide custom input] |
**Your choice**: _[Wait for user response]_
```
4. **CRITICAL - Table Formatting**: Ensure markdown tables are properly formatted:
- Use consistent spacing with pipes aligned
- Each cell should have spaces around content: `| Content |` not `|Content|`
- Header separator must have at least 3 dashes: `|--------|`
- Test that the table renders correctly in markdown preview
5. Number questions sequentially (Q1, Q2, Q3 - max 3 total)
6. Present all questions together before waiting for responses
7. Wait for user to respond with their choices for all questions (e.g., "Q1: A, Q2: Custom - [details], Q3: B")
8. Update the spec by replacing each [NEEDS CLARIFICATION] marker with the user's selected or provided answer
9. Re-run validation after all clarifications are resolved
d. **Update Checklist**: After each validation iteration, update the checklist file with current pass/fail status
7. Report completion with branch name, spec file path, checklist results, and readiness for the next phase (`/speckit.clarify` or `/speckit.plan`).
**NOTE:** The script creates and checks out the new branch and initializes the spec file before writing.
## General Guidelines
## Quick Guidelines
- Focus on **WHAT** users need and **WHY**.
- Avoid HOW to implement (no tech stack, APIs, code structure).
- Written for business stakeholders, not developers.
- DO NOT create any checklists that are embedded in the spec. That will be a separate command.
### Section Requirements
- **Mandatory sections**: Must be completed for every feature
- **Optional sections**: Include only when relevant to the feature
- When a section doesn't apply, remove it entirely (don't leave as "N/A")
### For AI Generation
When creating this spec from a user prompt:
1. **Make informed guesses**: Use context, industry standards, and common patterns to fill gaps
2. **Document assumptions**: Record reasonable defaults in the Assumptions section
3. **Limit clarifications**: Maximum 3 [NEEDS CLARIFICATION] markers - use only for critical decisions that:
- Significantly impact feature scope or user experience
- Have multiple reasonable interpretations with different implications
- Lack any reasonable default
4. **Prioritize clarifications**: scope > security/privacy > user experience > technical details
5. **Think like a tester**: Every vague requirement should fail the "testable and unambiguous" checklist item
6. **Common areas needing clarification** (only if no reasonable default exists):
- Feature scope and boundaries (include/exclude specific use cases)
- User types and permissions (if multiple conflicting interpretations possible)
- Security/compliance requirements (when legally/financially significant)
**Examples of reasonable defaults** (don't ask about these):
- Data retention: Industry-standard practices for the domain
- Performance targets: Standard web/mobile app expectations unless specified
- Error handling: User-friendly messages with appropriate fallbacks
- Authentication method: Standard session-based or OAuth2 for web apps
- Integration patterns: RESTful APIs unless specified otherwise
### Success Criteria Guidelines
Success criteria must be:
1. **Measurable**: Include specific metrics (time, percentage, count, rate)
2. **Technology-agnostic**: No mention of frameworks, languages, databases, or tools
3. **User-focused**: Describe outcomes from user/business perspective, not system internals
4. **Verifiable**: Can be tested/validated without knowing implementation details
**Good examples**:
- "Users can complete checkout in under 3 minutes"
- "System supports 10,000 concurrent users"
- "95% of searches return results in under 1 second"
- "Task completion rate improves by 40%"
**Bad examples** (implementation-focused):
- "API response time is under 200ms" (too technical, use "Users see results instantly")
- "Database can handle 1000 TPS" (implementation detail, use user-facing metric)
- "React components render efficiently" (framework-specific)
- "Redis cache hit rate above 80%" (technology-specific)
================================================
FILE: .claude/commands/speckit.tasks.md
================================================
---
description: Generate an actionable, dependency-ordered tasks.md for the feature based on available design artifacts.
handoffs:
- label: Analyze For Consistency
agent: speckit.analyze
prompt: Run a project analysis for consistency
send: true
- label: Implement Project
agent: speckit.implement
prompt: Start the implementation in phases
send: true
---
## User Input
```text
$ARGUMENTS
```
You **MUST** consider the user input before proceeding (if not empty).
## Outline
1. **Setup**: Run `.specify/scripts/bash/check-prerequisites.sh --json` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot").
2. **Load design documents**: Read from FEATURE_DIR:
- **Required**: plan.md (tech stack, libraries, structure), spec.md (user stories with priorities)
- **Optional**: data-model.md (entities), contracts/ (API endpoints), research.md (decisions), quickstart.md (test scenarios)
- Note: Not all projects have all documents. Generate tasks based on what's available.
3. **Execute task generation workflow**:
- Load plan.md and extract tech stack, libraries, project structure
- Load spec.md and extract user stories with their priorities (P1, P2, P3, etc.)
- If data-model.md exists: Extract entities and map to user stories
- If contracts/ exists: Map endpoints to user stories
- If research.md exists: Extract decisions for setup tasks
- Generate tasks organized by user story (see Task Generation Rules below)
- Generate dependency graph showing user story completion order
- Create parallel execution examples per user story
- Validate task completeness (each user story has all needed tasks, independently testable)
4. **Generate tasks.md**: Use `.specify/templates/tasks-template.md` as structure, fill with:
- Correct feature name from plan.md
- Phase 1: Setup tasks (project initialization)
- Phase 2: Foundational tasks (blocking prerequisites for all user stories)
- Phase 3+: One phase per user story (in priority order from spec.md)
- Each phase includes: story goal, independent test criteria, tests (if requested), implementation tasks
- Final Phase: Polish & cross-cutting concerns
- All tasks must follow the strict checklist format (see Task Generation Rules below)
- Clear file paths for each task
- Dependencies section showing story completion order
- Parallel execution examples per story
- Implementation strategy section (MVP first, incremental delivery)
5. **Report**: Output path to generated tasks.md and summary:
- Total task count
- Task count per user story
- Parallel opportunities identified
- Independent test criteria for each story
- Suggested MVP scope (typically just User Story 1)
- Format validation: Confirm ALL tasks follow the checklist format (checkbox, ID, labels, file paths)
Context for task generation: $ARGUMENTS
The tasks.md should be immediately executable - each task must be specific enough that an LLM can complete it without additional context.
## Task Generation Rules
**CRITICAL**: Tasks MUST be organized by user story to enable independent implementation and testing.
**Tests are OPTIONAL**: Only generate test tasks if explicitly requested in the feature specification or if user requests TDD approach.
### Checklist Format (REQUIRED)
Every task MUST strictly follow this format:
```text
- [ ] [TaskID] [P?] [Story?] Description with file path
```
**Format Components**:
1. **Checkbox**: ALWAYS start with `- [ ]` (markdown checkbox)
2. **Task ID**: Sequential number (T001, T002, T003...) in execution order
3. **[P] marker**: Include ONLY if task is parallelizable (different files, no dependencies on incomplete tasks)
4. **[Story] label**: REQUIRED for user story phase tasks only
- Format: [US1], [US2], [US3], etc. (maps to user stories from spec.md)
- Setup phase: NO story label
- Foundational phase: NO story label
- User Story phases: MUST have story label
- Polish phase: NO story label
5. **Description**: Clear action with exact file path
**Examples**:
- ✅ CORRECT: `- [ ] T001 Create project structure per implementation plan`
- ✅ CORRECT: `- [ ] T005 [P] Implement authentication middleware in src/middleware/auth.py`
- ✅ CORRECT: `- [ ] T012 [P] [US1] Create User model in src/models/user.py`
- ✅ CORRECT: `- [ ] T014 [US1] Implement UserService in src/services/user_service.py`
- ❌ WRONG: `- [ ] Create User model` (missing ID and Story label)
- ❌ WRONG: `T001 [US1] Create model` (missing checkbox)
- ❌ WRONG: `- [ ] [US1] Create User model` (missing Task ID)
- ❌ WRONG: `- [ ] T001 [US1] Create model` (missing file path)
### Task Organization
1. **From User Stories (spec.md)** - PRIMARY ORGANIZATION:
- Each user story (P1, P2, P3...) gets its own phase
- Map all related components to their story:
- Models needed for that story
- Services needed for that story
- Endpoints/UI needed for that story
- If tests requested: Tests specific to that story
- Mark story dependencies (most stories should be independent)
2. **From Contracts**:
- Map each contract/endpoint → to the user story it serves
- If tests requested: Each contract → contract test task [P] before implementation in that story's phase
3. **From Data Model**:
- Map each entity to the user story(ies) that need it
- If entity serves multiple stories: Put in earliest story or Setup phase
- Relationships → service layer tasks in appropriate story phase
4. **From Setup/Infrastructure**:
- Shared infrastructure → Setup phase (Phase 1)
- Foundational/blocking tasks → Foundational phase (Phase 2)
- Story-specific setup → within that story's phase
### Phase Structure
- **Phase 1**: Setup (project initialization)
- **Phase 2**: Foundational (blocking prerequisites - MUST complete before user stories)
- **Phase 3+**: User Stories in priority order (P1, P2, P3...)
- Within each story: Tests (if requested) → Models → Services → Endpoints → Integration
- Each phase should be a complete, independently testable increment
- **Final Phase**: Polish & Cross-Cutting Concerns
================================================
FILE: .claude/commands/speckit.taskstoissues.md
================================================
---
description: Convert existing tasks into actionable, dependency-ordered GitHub issues for the feature based on available design artifacts.
tools: ['github/github-mcp-server/issue_write']
---
## User Input
```text
$ARGUMENTS
```
You **MUST** consider the user input before proceeding (if not empty).
## Outline
1. Run `.specify/scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot").
1. From the executed script, extract the path to **tasks**.
1. Get the Git remote by running:
```bash
git config --get remote.origin.url
```
> [!CAUTION]
> ONLY PROCEED TO NEXT STEPS IF THE REMOTE IS A GITHUB URL
1. For each task in the list, use the GitHub MCP server to create a new issue in the repository that is representative of the Git remote.
> [!CAUTION]
> UNDER NO CIRCUMSTANCES EVER CREATE ISSUES IN REPOSITORIES THAT DO NOT MATCH THE REMOTE URL
================================================
FILE: .claude/skills/cypress-e2e/SKILL.md
================================================
---
name: cypress-e2e
description: Write or refactor Cypress E2E tests following Page Object Model, action/assertion separation, and project conventions. Use when creating new tests, refactoring existing ones, or adding page object functions.
argument-hint: '[test-description-or-file-path]'
allowed-tools:
- Read
- Edit
- Write
- Bash
- Grep
- Glob
- Agent
---
# Cypress E2E Test Automation
Write or refactor Cypress E2E tests for **$ARGUMENTS**.
Read `apps/web/cypress/CLAUDE.md` and `apps/web/cypress/AGENTS.md` for project-specific conventions before proceeding.
## Phase 1: Understand Context
1. Read the relevant test file(s) and page object(s) in `apps/web/cypress/e2e/pages/`
2. Read `apps/web/cypress/CLAUDE.md` for conventions
3. Identify which page object file to use (or create)
4. Check existing functions in ALL `*.page*.js` files and `main.page.js` before creating anything new
5. Check the actual React component DOM to understand what `data-testid` attributes exist and which component renders them
## Phase 2: Page Object Structure
Organize page object files in clear sections with this order:
```js
// 1. Imports
// 2. Selectors — grouped by feature area, with comments
// 3. Labels & regex patterns
// 4. Internal helpers (selector builders, lookups)
// 5. Action functions (exported)
// 6. Verify functions (exported)
// 7. Composite flows (exported — multi-step sequences like onboarding)
```
### Selector Rules
- Use `data-testid` (preferred), `aria-label`, or semantic HTML — never class names
- If a component lacks a `data-testid`, add one to the React component
- Selectors only used within the page object: `const` (no `export`)
- Selectors used by test files: `export const`
- Before adding a new `data-testid`, check if one already exists on the element
### data-testid Rules
- **Every `data-testid` must be unique** — never reuse the same value across different components
- When similar UI elements exist in different contexts (e.g. single-chain vs multichain rows), use distinct prefixes:
```
single-account-name (AccountWidgetItem — single-chain)
multichain-account-name (AccountItemContent — expandable multichain)
```
- **Verify before adding**: read the React component source to confirm the element renders in the DOM where Cypress will look for it. An expandable/accordion row has different DOM structure than a flat row.
- **Every `data-testid` added to source must be referenced** in at least one Cypress page object selector. After adding test-ids, run a cross-reference check.
- **Never hardcode values in regex patterns or counts** — use format-only checks (e.g. `/\$[\s]*[1-9][\d,]*/` not `/\$875/`) since live data changes
### Function Rules
- **Action functions** (`click*`, `open*`, `expand*`, `type*`, `visit*`): perform one user action AND wait for the result to be ready. An action that opens a popover must wait for the popover to appear. An action that navigates must wait for the target page to load. This prevents flaky tests where the next step runs before the UI has settled:
```js
// ✅ Good: action waits for result
export function clickOnExpandWalletBtn() {
cy.get(expandWalletBtn).should('be.visible').click()
cy.get(sentinelStart).next().should('exist') // wait for popover
}
// ❌ Bad: action with no wait — next step may fail
export function clickOnExpandWalletBtn() {
cy.get(expandWalletBtn).click()
}
```
- **Verify functions** (`verify*`): assert state only, no user actions
- Functions used only within the page object: no `export`
- Functions used by test files: `export`
- General functions (3+ page files): put in `main.page.js`
- Page-specific functions: put in that page's `.pages.js`
- **Wallet/navigation functions belong in `navigation.page.js`** — not in feature page objects. Feature page objects import and call them. When the same action has different UI across contexts (e.g. legacy vs spaces wallet button), create separate functions in `navigation.page.js` rather than duplicating selectors in feature page objects:
```js
// navigation.page.js — both wallet expand variants
export function clickOnWalletExpandMoreIcon() { ... } // legacy
export function clickOnExpandWalletBtn() { ... } // spaces
// spaces.page.js — uses navigation, no local wallet selector
export function disconnectFromSpaceLevel() {
navigation.clickOnExpandWalletBtn()
navigation.clickOnDisconnectBtn()
}
```
- **Prefer one parameterized function over multiple similar functions** — use a type/variant parameter with a selector lookup table when the same verification applies to different component variants:
```js
const selectors = {
single: { name: singleName, address: singleAddress },
multichain: { name: multichainName, address: multichainAddress },
}
export function verifyAccountRowDetails(type, rowIndex, details) {
const sel = selectors[type]
// ... use sel.name, sel.address etc.
}
```
- **Check `main.page.js` first** for general utilities like `verifyElementsCount`, `verifyMinimumElementsCount`, `verifyValuesExist`, `verifyElementsIsVisible` — use them instead of writing custom versions
### Composite Flows
Multi-step flows (onboarding, account creation, member invite) should be split into small private helper functions and composed into one exported function:
```js
// Private step functions — not exported
function navigateToCreateSpacePage() { ... }
function submitSpaceName(name) { ... }
function skipSelectSafesStep() { ... }
function skipInviteMembersStep() { ... }
function verifySpaceDashboardLoaded() { ... }
// Exported composite flow — reads like a clear sequence
export function createSpaceViaOnboardingWithSkip(name) {
navigateToCreateSpacePage()
submitSpaceName(name)
skipSelectSafesStep()
skipInviteMembersStep()
verifySpaceDashboardLoaded()
}
```
Rules for composite flows:
- Each step is a private function with a descriptive name
- The exported function reads as a plain-language sequence
- Step functions handle their own waits (URL checks, element visibility)
- When a page can be reached from multiple entry points, use a resilient pattern that waits for either state:
```js
// Wait for EITHER the list page OR the form page to appear
cy.get(`${listPageBtn}, ${formPageInput}`, { timeout: 30000 })
.filter(':visible')
.first()
.then(($el) => {
if (!$el.is(formPageInput)) {
cy.wrap($el).click()
}
})
```
### Function Naming Convention
| Prefix | Purpose | Example |
| --------- | ------------------------------ | ---------------------------------- |
| `click*` | Click an element | `clickAccountItemByIndex(index)` |
| `open*` | Open a dropdown/modal/panel | `openSpaceSelector()` |
| `expand*` | Expand a collapsible section | `expandAccountRow(index)` |
| `type*` | Type into an input | `typeSpaceName(name)` |
| `visit*` | Navigate to a URL | `visitSpaceDashboard(id)` |
| `verify*` | Assert state (visibility, URL) | `verifySpaceSidebarItemsVisible()` |
## Phase 3: Write Tests
### Test Structure
```js
it('Verify that [expected behavior]', () => {
// 1. Preconditions — verify page is ready
space.verifySpaceDashboardWidgetVisible('Accounts')
// 2. Actions — user interactions
space.clickAccountItemByIndex(0)
// 3. Assertions — verify outcomes (grouped at the end)
space.verifyAccountRowDetails('single', 0, { name: 'My Safe', address: '0x...' })
})
```
### Rules
- **Test names**: always `'Verify that [expected behavior]'`
- **No raw Cypress commands in test files**: every `cy.get()`, `cy.url().should()`, `cy.contains().click()` must be in a page object function
- **No hardcoded selectors in test files**: import from page objects
- **No `cy.wait(N)` hard waits**: use assertion-based waits (`cy.get(sel, { timeout: 30000 }).should('be.visible')`) or `waitFor*` functions
- **No `.only`**: never commit `it.only` or `describe.only`
- **No hardcoded amounts or counts in regex**: use format-only validation (e.g. `nonZeroBalanceRegex` not `$875Regex`)
- **Test data in fixtures**: put static data in `cypress/fixtures/`, not inline in tests. Use `staticSpaces`, `getSafes(CATEGORIES.static)`, etc.
- **Separate actions from assertions**: blank line between action block and assertion block
- **Reuse `main.verifyElementsCount`** for counting elements instead of inline `.should('have.length', N)`
- **Extract repeated data access**: if the same fixture path is referenced multiple times, extract to a `const` at the top of the test (e.g. `const safeData = staticSpaces.dashboardWithSafes.pendingTxAccount`)
### Test Data
- Safe addresses: `getSafes(CATEGORIES.static)` — never hardcode
- Static space data: `cypress/fixtures/spaces/staticSpaces.js`
- localStorage: payloads in `support/localstorage_data.js`, keys in `support/constants.js`
- API mocks: `cy.intercept()` + `cy.fixture()` from `fixtures/`
## Phase 4: Adding data-testid to Components
When a component needs a `data-testid` for E2E tests:
1. **Read the component source** to understand the DOM structure — especially for accordion/collapsible/expandable patterns where the trigger and content have different structures
2. **Check if different component variants exist** (e.g. `AccountWidgetItem` for single-chain vs `ExpandableAccountItem` for multichain) — they need distinct test-ids
3. **Add the `data-testid`** to the correct element in the correct component
4. **Verify the element will be visible** when Cypress looks for it — collapsed accordion content won't be found until expanded
5. **Add the corresponding selector** to the page object file
6. **Cross-reference**: after all changes, verify every new `data-testid` in source is referenced in at least one page object selector
## Phase 5: Data Separation
Keep test data and UI selectors in separate places — never mix them.
### Fixture files (`cypress/fixtures/`) — test data only
- Space IDs, names
- Account addresses, names, chain info, row indices
- Counts (row counts, sub-accounts)
- Sub-account chain details (chainId, query params)
- Any data that varies per environment or test scenario
### Page object files (`e2e/pages/`) — UI selectors and labels only
- `data-testid` selectors
- `aria-label` selectors
- Static UI text labels ("Getting started", "Add member", etc.)
- Regex patterns for format validation
- Functions (actions, verifiers)
### Rules
- **Never duplicate fixture data in page objects** — if an address or name is in a fixture, don't also define it as a `const` in the page object
- **Never put selectors in fixtures** — selectors belong in page objects
- **Never re-export fixtures from page objects** — tests should import fixtures directly (`import staticSpaces from '../../fixtures/spaces/staticSpaces.js'`)
- **Never import fixtures in page objects** unless a function internally needs the data (rare — prefer passing as parameters)
- **Regex patterns belong in page objects** not fixtures — they validate UI format, not test data
## Phase 6: Cleanup Checklist
After writing or refactoring tests, verify:
- [ ] No raw selectors in test files — all in page objects
- [ ] No unused `export` keywords — only export what test files import
- [ ] No dead exports — remove functions/consts not used anywhere
- [ ] Internal-only selectors and helpers are `const`/`function` (not `export`)
- [ ] No `cy.wait(N)` hard waits (except in legacy flows pending refactor)
- [ ] No `.only` left in tests
- [ ] No commented-out code left behind
- [ ] All `data-testid` added to source components are referenced in Cypress page objects
- [ ] No duplicate `data-testid` values across different components
- [ ] Test names follow "Verify that" format
- [ ] Parameterized functions with selector lookups used instead of duplicated functions
- [ ] No hardcoded amounts/counts in regex — format-only checks
- [ ] Page object file is organized in clear sections (selectors, labels, helpers, actions, verifiers, flows)
- [ ] No fixture data duplicated in page objects (addresses, names, counts)
- [ ] No fixture re-exports from page objects — tests import fixtures directly
- [ ] No unused imports in page objects or test files
================================================
FILE: .claude/skills/design.figma-to-code/SKILL.md
================================================
---
name: design.figma-to-code
description: Implement a Figma design using shadcn/ui components. Use when converting Figma URLs to React code.
argument-hint: '[figma-url]'
allowed-tools:
- mcp__figma-remote-mcp__get_design_context
- mcp__figma-remote-mcp__get_screenshot
- mcp__figma-remote-mcp__get_variable_defs
- mcp__figma-remote-mcp__get_metadata
- Read
- Write
- Edit
- Bash
- Glob
- Grep
---
# Figma to Code Implementation
Implement the Figma design at **$ARGUMENTS** using shadcn/ui components.
**Note:** All shadcn/ui components are already installed and available at `apps/web/src/components/ui/`. Import them directly (e.g., `import { Button } from '@/components/ui/button'`). Avoid other components.
## Step 1: Parse Figma URL
Extract from URL `https://figma.com/design/:fileKey/:fileName?node-id=:nodeId`:
- `fileKey`: The file identifier
- `nodeId`: Convert `123-456` to `123:456` format
## Step 2: Fetch Design Context
```
mcp__figma-remote-mcp__get_design_context(
fileKey: "<fileKey>",
nodeId: "<nodeId>",
clientLanguages: "typescript",
clientFrameworks: "react,nextjs"
)
```
Also get screenshot and metadata:
```
mcp__figma-remote-mcp__get_screenshot(fileKey, nodeId)
mcp__figma-remote-mcp__get_metadata(fileKey, nodeId)
```
## Step 3: Analyze Component Types (CRITICAL)
**Check `data-name` attributes in Figma output - don't assume from visuals!**
| Visual Appearance | Check `data-name` for | Likely Component |
| ------------------------------- | --------------------- | ---------------- |
| Grouped buttons with one active | `Tabs`, `Tab` | `<Tabs>` |
| Toggle between options | `Switch`, `Toggle` | `<Switch>` |
| Button group | `ButtonGroup` | `<ToggleGroup>` |
| Dropdown trigger | `Select`, `Dropdown` | `<Select>` |
**Red Flags - Verify Before Coding:**
- Multiple similar elements in a row (could be Tabs, not Buttons)
- Elements sharing a container background (grouped component)
- Active/inactive states (selection component)
## Step 4: Extract Variants & Props
For shadcn Figma libraries, extract props from **attributes only**:
**What to LOOK AT:**
- CSS variable **names**: `--general/primary`, `--general/secondary`
- `data-name` for component type
- **Text:** Use `get_variable_defs` — map Figma text styles (e.g. `heading 2`, `paragraph/regular`) to Typography variants (see reference.md)
**What to IGNORE:**
- Pixel values in generated code (px, py, gap, rounded)
- These are internal implementation details
**Priority Order:**
1. `data-name` with variant (e.g., "Button/Secondary/sm")
2. CSS variable names → variant (`--general/secondary` → `variant="secondary"`)
3. **Omitted = default**
**Typography:** NEVER use hardcoded Tailwind for text. Always use `<Typography variant="…" />` from `@/components/ui/typography`. Map Figma variable names (e.g. `heading 2`, `paragraph-bold`) to Typography variants (e.g. `h2`, `paragraph-bold`).
## Step 5: Build the Component
```tsx
import { Button } from '@/components/ui/button'
import { Card, CardContent } from '@/components/ui/card'
type MyComponentProps = {
// typed props
}
export function MyComponent({ ...props }: MyComponentProps) {
return (
// Implementation
)
}
```
**Styling Guidelines:**
DO:
- Use shadcn variants (`variant="outline"`, `size="sm"`)
- Use **Typography** with variants for all text — never raw Tailwind for typography
- Use Tailwind for layout only: `flex`, `grid`, `gap-*`, `p-*`
- Match layout ratios from Figma exactly (e.g., `grid-cols-2` for 50/50 split, or specific column ratios)
- Prefer using wrapper classes for layout, to use pure shadcn components without added tailwind classes
- Use CSS variables from shadcn for colors
DON'T:
- Add custom colors (`bg-blue-500`)
- Override shadcn styles
- Hardcode pixel values
- Wrap icons in divs inside buttons (icons should be direct children)
- Hardcode Tailwind for text
## Step 6: Create Storybook Stories
**Place story files next to the component they document** (e.g., `MyComponent.stories.tsx` next to `MyComponent.tsx`).
### Simple Component Stories
For shadcn/ui components and simple UI components that don't need API mocking:
```tsx
import type { Meta, StoryObj } from '@storybook/react'
import { MyComponent } from './MyComponent'
const meta = {
title: 'Components/MyComponent',
component: MyComponent,
} satisfies Meta<typeof MyComponent>
export default meta
type Story = StoryObj<typeof meta>
export const Default: Story = {
args: {
// component props
},
}
```
### Story Guidelines
- Use descriptive story names (Default, WithError, Loading, etc.)
- Include all important component states and variations
- Extract and apply the Figma frame's background color to the story wrapper for visual consistency, ideally using tailwind classes
- **For screens with subcomponents**, create stories for each:
```
MyScreen/
├── MyScreen.stories.tsx
├── HeaderCard.stories.tsx
└── DataTable.stories.tsx
```
**Note:** For pages/widgets that need Redux state and API mocking, use `createMockStory` from `@/stories/mocks` (see `AGENTS.md` for details).
## Step 7: Verify
```bash
yarn workspace @safe-global/web type-check
yarn workspace @safe-global/web storybook
```
## Project Notes
- **Components Path**: `apps/web/src/components/ui/`
- **Utility Path**: `apps/web/src/utils/cn.ts`
- **Icon Library**: `lucide-react`
See [reference.md](reference.md) for detailed component mappings and patterns.
================================================
FILE: .claude/skills/design.figma-to-code/reference.md
================================================
# Figma to Code Reference
## Typography (CRITICAL)
**Never hardcode Tailwind classes for text.** Always use the `Typography` component with variants.
```tsx
import { Typography } from '@/components/ui/typography'
// ✅ Correct
<Typography variant="h2" align="center">Invite team members</Typography>
<Typography variant="paragraph">Body text here.</Typography>
<Typography variant="paragraph-medium">Emphasized text.</Typography>
// ❌ Wrong — no raw Tailwind for text
<p className="text-[30px] font-semibold">Invite team members</p>
<h2 className="text-3xl font-semibold">Heading</h2>
```
### How to get the Figma style and map to Typography
1. **Get style from node**: Call `get_variable_defs(fileKey, nodeId)` — returns variables used by that text node.
2. **Extract style name**: Look for keys whose value is `Font(...)` — that key is the Figma style name.
- Example: `"heading 2": "Font(family: ...)"` → style name is `heading 2`
- Example: `"paragraph small/medium": "Font(...)"` → style name is `paragraph small/medium`
3. **Map to variant**: Use the table below.
### Figma style name → Typography variant mapping
| Figma variable / style | Typography variant |
| ------------------------ | ---------------------------------- |
| heading 1 | `variant="h1"` |
| heading 2 | `variant="h2"` |
| heading 3 | `variant="h3"` |
| heading 4 | `variant="h4"` |
| paragraph/regular | `variant="paragraph"` |
| paragraph/medium | `variant="paragraph-medium"` |
| paragraph/bold | `variant="paragraph-bold"` |
| paragraph/small | `variant="paragraph-small"` |
| paragraph/small + medium | `variant="paragraph-small-medium"` |
| paragraph/mini | `variant="paragraph-mini"` |
| paragraph/mini + medium | `variant="paragraph-mini-medium"` |
| paragraph/mini + bold | `variant="paragraph-mini-bold"` |
| monospaced | `variant="code"` |
**Align:** Use `align="center"` or `align="right"` when the design has centered/right-aligned text.
**Color:** Use `color="muted"` for muted/secondary text (e.g. `text-muted-foreground`).
## Component Mappings
| Figma Element | shadcn Component |
| ----------------- | ------------------ |
| Text Input | `<Input>` |
| Select/Dropdown | `<Select>` |
| Checkbox | `<Checkbox>` |
| Radio | `<RadioGroup>` |
| Toggle/Switch | `<Switch>` |
| Card/Container | `<Card>` |
| Dialog/Modal | `<Dialog>` |
| Tabs | `<Tabs>` |
| Table | `<Table>` |
| Tooltip | `<Tooltip>` |
| Badge/Tag | `<Badge>` |
| Avatar | `<Avatar>` |
| Separator/Divider | `<Separator>` |
| Skeleton/Loading | `<Skeleton>` |
| Alert/Banner | `<Alert>` |
| Accordion | `<Accordion>` |
| Navigation Menu | `<NavigationMenu>` |
| Breadcrumb | `<Breadcrumb>` |
| Pagination | `<Pagination>` |
## Component Properties (shadcn Libraries)
| Component | Key Properties |
| --------- | ----------------------------------------------- |
| Button | `variant`, `size`, `icon`, `disabled` |
| Input | `size`, `disabled`, `error` |
| Select | `size`, `disabled` |
| Avatar | `size`, `src`, `fallback` |
| Badge | `variant` |
| Tabs | `defaultValue`, individual `TabsTrigger` values |
| Card | `size` (if available) |
## Layout Patterns
```tsx
// Vertical stack with gap
<div className="flex flex-col gap-4">
// Horizontal layout
<div className="flex items-center gap-2">
// Grid layout
<div className="grid grid-cols-2 gap-4 md:grid-cols-3">
// Container with padding
<div className="p-4 md:p-6">
// Full width with max constraint
<div className="w-full max-w-md mx-auto">
```
## Complex Screen Implementation
### Component Decomposition
1. **Identify logical sections** - Each card, panel becomes a subcomponent
2. **Extract reusable patterns** - If pattern appears 2+ times, extract it
3. **Create main orchestrator** - Screen component imports and composes subcomponents
Example structure:
```
showcase/
├── AssetValueCard.tsx
├── PendingTransactionsCard.tsx
├── PortfolioCard.tsx
├── WalletSidebar.tsx
├── WalletDashboard.tsx # Main orchestrator
└── WalletDashboard.stories.tsx
```
### Data Prop Patterns
```tsx
interface Transaction {
id: string
title: string
date: string
}
interface Props {
transactions: Transaction[]
onViewAll?: () => void
onItemClick?: (id: string) => void
}
```
### Component Dependencies
Some shadcn components have hidden dependencies:
- `sidebar` requires `use-mobile` hook, `sheet`, `skeleton`, `tooltip`
- Always run type-check after installing
- Install missing: `npx shadcn@latest add <dep>`
### Naming Conventions
- `*Card` - Self-contained card components
- `*Sidebar` / `*Nav` - Navigation components
- `*Dashboard` / `*Screen` / `*Page` - Full page orchestrators
- Use `PascalCase` for component names
## Validation Checklist
**Before starting:**
- [ ] Checked `data-name` attributes for component types
- [ ] Verified grouped elements aren't Tabs mistaken for Buttons
- [ ] Extracted variant from CSS variable names
- [ ] Compared similar components to identify size differences
**Before completing:**
- [ ] All UI uses shadcn components (no custom primitives)
- [ ] Custom Tailwind limited to layout/spacing
- [ ] No hardcoded colors - uses theme variables
- [ ] Component is typed with TypeScript
- [ ] Storybook story created
- [ ] Import paths fixed (`@/utils/cn`)
================================================
FILE: .claude/skills/design.prototype/SKILL.md
================================================
---
name: design.prototype
description: Creates a Storybook UI prototype from a PRD-style input using existing shadcn/ui components, subtle visual tone, and a clear hierarchy. Use when the user invokes /design.prototype or asks for a prototype Storybook story.
argument-hint: '[prd-description]'
allowed-tools:
- Read
- Write
- Edit
- Glob
- Grep
- Bash
- mcp__cursor-browser-extension__browser_navigate
- mcp__cursor-browser-extension__browser_wait_for
- mcp__cursor-browser-extension__browser_take_screenshot
---
# Design Prototype (Storybook)
Create a Storybook prototype from **$ARGUMENTS** using only shadcn/ui components.
**Note:** All shadcn/ui components are already installed and available at `apps/web/src/components/ui/`. Import them directly (e.g., `import { Button } from '@/components/ui/button'`).
## Step 1: Gather Requirements
If missing, ask:
- Target story name (short, Title Case)
- Storybook port (default: 6006)
- Desired variants (single Default or multiple states)
- Component constraints beyond shadcn/ui
## Step 2: Design Process
1. **Intent**: Summarize what the page must achieve in one sentence
2. **Hierarchy**: Define 3–4 priority levels (hero, primary clusters, secondary clusters, info)
3. **Clustering**: Group related settings into sections with headings
4. **Patterns**: Use hero summary, grid clusters, and consistent actions
5. **Tone**: Subtle, calm, non-alarming. Use muted backgrounds and secondary/outline badges
## Step 3: Create Component
**Location**: `apps/web/src/features/design-system/prototypes/<Name>.tsx`
**Rules**:
- Use only shadcn/ui components from `apps/web/src/components/ui/`
- No custom styling on components
- Use layout-only Tailwind classes on wrapper `div`s
**Styling Guidelines:**
DO:
- Use shadcn variants (`variant="outline"`, `size="sm"`)
- Use Tailwind for layout: `flex`, `grid`, `gap-*`, `p-*`
- Prefer using wrapper classes for layout, to use pure shadcn components without added Tailwind classes
- Use CSS variables from shadcn for colors
DON'T:
- Add custom colors (`bg-blue-500`)
- Override shadcn styles
- Hardcode pixel values
**Template**:
```tsx
import * as React from 'react'
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card'
// ... other shadcn imports
export const MyPrototype = (): React.ReactElement => {
return (
<div className="flex flex-col gap-6 p-6">
<h2 className="text-xl font-semibold">Page Title</h2>
{/* Layout with shadcn components */}
</div>
)
}
```
## Step 4: Create Story
**Location**: `apps/web/src/features/design-system/stories/prototypes/<Name>.stories.tsx`
**Template**:
```tsx
import type { Meta, StoryObj } from '@storybook/react'
import { MyPrototype } from '../../prototypes/MyPrototype'
const meta = {
title: 'Design System/Prototypes/My Prototype',
component: MyPrototype,
parameters: {
layout: 'fullscreen',
},
} satisfies Meta<typeof MyPrototype>
export default meta
type Story = StoryObj<typeof meta>
export const Default: Story = {
args: {
// component props if any
},
}
```
## Step 5: Screenshot Workflow
After writing the story:
```
browser_navigate("http://localhost:<port>/?path=/story/design-system-prototypes-<slug>--default")
browser_wait_for(time: 2)
browser_take_screenshot(fullPage: true)
```
If variants exist, capture each variant.
## Step 6: Verify
```bash
yarn workspace @safe-global/web type-check
yarn workspace @safe-global/web storybook
```
## Naming Convention
| Item | Format | Example |
| --------- | ------------------------------------------ | ------------------------------------------------ |
| Component | `<Name>.tsx` | `SecurityHub.tsx` |
| Story | `<Name>.stories.tsx` | `SecurityHub.stories.tsx` |
| Title | `Design System/Prototypes/<Name>` | `Design System/Prototypes/Security Hub` |
| Slug | `design-system-prototypes-<name>--default` | `design-system-prototypes-security-hub--default` |
## Project Notes
- **Components Path**: `apps/web/src/components/ui/`
- **Utility Path**: `apps/web/src/utils/cn.ts`
- **Icon Library**: `lucide-react`
- **Prototypes Path**: `apps/web/src/features/design-system/prototypes/`
- **Stories Path**: `apps/web/src/features/design-system/stories/prototypes/`
- **Storybook**: `yarn workspace @safe-global/web storybook`
================================================
FILE: .claude/skills/design.sync-component/SKILL.md
================================================
---
name: design.sync-component
description: Sync a UI component from Figma to code using the component sync workflow. Use when updating components to match Figma designs.
argument-hint: '[component-name]'
allowed-tools:
- mcp__figma-remote-mcp__get_design_context
- mcp__figma-remote-mcp__get_screenshot
- Read
- Edit
- Bash
- Grep
---
# Sync Component from Figma
Sync the **$ARGUMENTS** component from Figma to code.
## Source Files
- **Figma File**: `trBVcpjZslO63zxiNUI9io` (Obra shadcn-ui safe)
- **Component Mapping**: `apps/web/src/components/ui/docs/figma-code-connect.md`
- **Target**: `apps/web/src/components/ui/<component>.tsx`
## Process
### 1. Find Node ID
Look up the component in `figma-code-connect.md` to get the Figma node ID.
### 2. Fetch Design Context
```
mcp__figma-remote-mcp__get_design_context(
fileKey: "trBVcpjZslO63zxiNUI9io",
nodeId: "<node-id>",
disableCodeConnect: true
)
```
Also get a screenshot for visual reference:
```
mcp__figma-remote-mcp__get_screenshot(fileKey, nodeId)
```
**Check for changelog comments**: Look for comments on the Figma component page that document changes (e.g., "removed shadow and border", "updated spacing", "changed variant names"). These comments indicate intentional design changes that should be synced to code.
### 3. Compare & Document
**First, check Figma comments for changelog** - Look for documented changes in component comments that describe what was modified (e.g., "removed shadow", "updated border radius", "changed color scheme").
Then compare:
| Check | What to Compare |
| -------- | --------------------------------------------------------------- |
| Sizes | Verify px values match (size-6=24px, size-8=32px, size-10=40px) |
| Colors | Fill colors → bg-_, text-_ classes |
| Border | border-_, rounded-_ classes |
| Shadow | shadow-\* classes (Figma often has none) |
| Variants | CVA variants object keys |
**Prioritize changelog items** - If changelog comments exist, sync those changes first before doing a full comparison.
### 4. Update Code
**Only sync when Figma actually changed.** Don't remove code defaults that improve DX.
Add/update component header comment:
```tsx
/**
* ComponentName
*
* Figma: https://www.figma.com/design/trBVcpjZslO63zxiNUI9io/?node-id=XX:XXXX
*
* Intentional differences from Figma:
* - property: reason for difference
*
* Changelog (from Figma comments):
* - YYYY-MM-DD: Description of changes from Figma changelog comment
* - YYYY-MM-DD: Additional sync changes made
*/
```
**Note**: The changelog should reflect changes documented in Figma component comments. If Figma has a changelog comment, include those changes in the code changelog.
### 5. Verify
Run type-check:
```bash
yarn workspace @safe-global/web type-check
```
## Rules
1. **Check Figma changelog first** - Always look for changelog comments on the Figma component page that document design changes
2. **Document the delta** - Note intentional differences, only sync breaking changes
3. **Preserve code patterns** - Keep CVA structure, only update classes/variants
4. **Keep existing functionality** - Don't remove event handlers, refs, or accessibility
5. **Verify sizes match** - Check actual pixel values, not just naming conventions
6. **Sync changelog items** - If Figma comments document changes (e.g., "removed shadow", "updated border"), ensure those changes are reflected in code
================================================
FILE: .claude/skills/design.sync-variables/SKILL.md
================================================
---
name: design.sync-variables
description: Sync CSS variables from Figma plugin export to globals.css. Use when updating design tokens/colors from Figma.
disable-model-invocation: true
allowed-tools:
- Read
- Edit
- Bash
- Grep
---
# Sync Variables from Figma
Sync CSS variables from Figma plugin [variables2css](https://www.figma.com/community/plugin/1261234393153346915) export to `globals.css`.
## Rules
1. **Only update existing variables** - Never add new variables
2. **Keep code order** - Only change values, not structure
3. **Direct mappings only** - Only update if Figma has a matching variable
4. **Use Figma plugin export** - Do NOT use Figma MCP for variables (incomplete data)
## Source Files
- **Source of truth**: Figma plugin export (user provides)
- **Target**: `apps/web/src/styles/globals.css`
## Process
1. Ask user for Figma CSS Variables plugin export
2. Compare Figma values vs `globals.css` existing variables
3. Update only values that differ (use direct hex values)
4. Verify: `yarn workspace @safe-global/web type-check`
## Variable Mapping
| Figma Export | CSS Variable |
| -------------------------------------- | ------------------------------ |
| `--general-background` | `--background` |
| `--general-foreground` | `--foreground` |
| `--general-primary` | `--primary` |
| `--general-primary-foreground` | `--primary-foreground` |
| `--general-secondary` | `--secondary` |
| `--general-secondary-foreground` | `--secondary-foreground` |
| `--general-muted` | `--muted` |
| `--general-muted-foreground` | `--muted-foreground` |
| `--general-accent` | `--accent` |
| `--general-accent-foreground` | `--accent-foreground` |
| `--general-destructive` | `--destructive` |
| `--general-border` | `--border` |
| `--general-input` | `--input` |
| `--card-card` | `--card` |
| `--card-card-foreground` | `--card-foreground` |
| `--popover-popover` | `--popover` |
| `--popover-popover-foreground` | `--popover-foreground` |
| `--focus-ring` | `--ring` |
| `--sidebar-sidebar` | `--sidebar` |
| `--sidebar-sidebar-foreground` | `--sidebar-foreground` |
| `--sidebar-sidebar-primary` | `--sidebar-primary` |
| `--sidebar-sidebar-primary-foreground` | `--sidebar-primary-foreground` |
| `--sidebar-sidebar-accent` | `--sidebar-accent` |
| `--sidebar-sidebar-accent-foreground` | `--sidebar-accent-foreground` |
| `--sidebar-sidebar-border` | `--sidebar-border` |
| `--sidebar-sidebar-ring` | `--sidebar-ring` |
## Example
User provides export:
```css
--general-background: #ffffff;
--general-primary: #12ff80;
```
Update in globals.css:
```css
--background: #ffffff;
--primary: #12ff80;
```
================================================
FILE: .claude/skills/design.verify/SKILL.md
================================================
---
name: design.verify
description: Verify Figma implementation is pixel-perfect. Use after implementing Figma designs to catch and fix discrepancies.
argument-hint: '[figma-url-or-node-id]'
allowed-tools:
- mcp__figma-remote-mcp__get_design_context
- mcp__figma-remote-mcp__get_screenshot
- Read
- Edit
- Bash
- Grep
---
# Figma-to-Code Verification
Verify the implementation of **$ARGUMENTS** matches Figma specs.
## The 5-Phase Verification Process
### Phase 1: Component Inventory
**Goal:** Create a complete list of all components to verify.
1. Fetch design context from Figma
2. **Check for changelog comments** - Look for documented changes in Figma component comments
3. Extract all unique node IDs and types
4. Create a checklist
```
mcp__figma-remote-mcp__get_design_context(fileKey, nodeId)
```
**Output format:**
```markdown
## Component Checklist
- [ ] Sidebar (node: 1:3236)
- [ ] Header with workspace switcher
- [ ] Navigation items
- [ ] Main content area
- [ ] TotalValueCard (node: 5:1620)
- [ ] AssetsCard (node: 5:1624)
```
### Phase 2: Visual Comparison
**Goal:** Compare Figma screenshot vs implementation.
```
mcp__figma-remote-mcp__get_screenshot(fileKey, nodeId)
```
**Comparison Checklist:**
- [ ] Overall layout matches
- [ ] Spacing between elements
- [ ] Component sizes (width/height)
- [ ] Colors and backgrounds
- [ ] Typography (font size, weight, line height)
- [ ] Border radius
- [ ] Shadows and elevation
- [ ] Icons (size, color, alignment) - verify button icons are direct children, not wrapped in divs, ignore visual description and stick to data for icons
### Phase 3: Attribute-by-Attribute Verification
**For each component, verify:**
#### Layout & Spacing
| Attribute | Figma | Implementation | Match? |
| ------------- | ----- | -------------- | ------ |
| width | | | |
| height | | | |
| padding | | | |
| gap | | | |
| layout ratios | | | |
**Important:** Verify layout ratios match Figma (e.g., 2-column grid with 50/50 split, or specific width ratios). Custom Tailwind classes are only allowed for layout, not for styling shadcn components.
#### Typography
| Attribute | Figma | Implementation | Match? |
| ----------- | ----- | -------------- | ------ |
| font-size | | | |
| font-weight | | | |
| line-height | | | |
| text-color | | | |
#### Visual Styling
| Attribute | Figma | Implementation | Match? |
| ------------- | ----- | -------------- | ------ |
| background | | | |
| border | | | |
| border-radius | | | |
| box-shadow | | | |
### Phase 4: Interactive States
**States to verify:**
- [ ] Default/resting state
- [ ] Hover state
- [ ] Active/pressed state
- [ ] Focus state
- [ ] Disabled state
- [ ] Selected/active state
### Phase 5: Edge Cases
- [ ] Min/max width behavior
- [ ] Long text (truncation/wrapping)
- [ ] Empty states
- [ ] Loading states
## Verification Report Template
```markdown
# Verification Report: [Component Name]
## Figma Reference
- Node ID: [ID]
- Screenshot: [attached]
## Discrepancies Found
### 1. [Issue Title]
- **Location:** [element]
- **Expected:** [Figma value]
- **Actual:** [Implementation value]
- **Fix:** [what to change]
## Summary
- Layout: ✅/❌
- Typography: ✅/❌
- Colors: ✅/❌
- Components: ✅/❌
```
## Quick Commands
```bash
# Run Storybook for visual testing
yarn workspace @safe-global/web storybook
# Type-check
yarn workspace @safe-global/web type-check
```
## Project Notes
- **Components Path**: `apps/web/src/components/ui/`
- **Utility Path**: `apps/web/src/utils/cn.ts`
- **Icon Library**: `lucide-react`
**Component Usage Rules:**
- Must use existing shadcn components from `/ui/` - do not alter or override them
- Custom styling/Tailwind is only allowed for layout (flex, grid, gap, padding, width/height ratios)
- Verify layout ratios match Figma exactly (e.g., grid column ratios, flex proportions)
================================================
FILE: .codescene.yml
================================================
# CodeScene Configuration
# https://docs.enterprise.codescene.io/latest/configuration/code-health-configuration.html
version: 2
# Exclude paths from code health analysis
exclude:
- pattern: 'apps/web/src/components/ui/**'
reason: 'shadcn UI components are semi-auto generated from templates'
- pattern: 'apps/web/src/components/ui/stories/**'
reason: 'Storybook stories for shadcn UI components'
================================================
FILE: .cursor/rules/cypress-e2e.mdc
================================================
---
description: Cypress E2E test automation rules and best practices for Safe Wallet
globs:
- "**/cypress/**/*.cy.js"
- "**/cypress/**/*.pages.js"
- "**/cypress/support/localstorage_data.js"
- "**/cypress/support/constants.js"
- "**/cypress/support/e2e.js"
- "**/cypress/support/commands.js"
- "**/cypress/support/safe-apps-commands.js"
- "**/cypress/support/safes/safesHandler.js"
- "**/cypress/e2e/pages/main.page.js"
alwaysApply: false
---
# Cypress E2E Automation Rules
**Quick reference:** Test names = "Verify that …". Selectors only in `.pages.js`; use existing support (constants, localstorage_data.js, getSafes, addToLocalStorage/addToAppLocalStorage) — do not add new setup helpers. See **Implementation Checklist** at the end.
## Test Structure and Naming
### Test Names
- **MANDATORY**: All test names MUST use "Verify that" format
- **MANDATORY**: Each test suite can contain only ONE describe block
- **FORMAT**: `it('Verify that [expected behavior]', () => {})`
- **EXAMPLES**:
- ✅ `'Verify that user can create a new transaction'`
- ✅ `'Verify that total asset value is displayed correctly'`
- ❌ `'Create a new transaction'`
- ❌ `'Test transaction creation'`
### Test Suite Structure
```jsx
describe('Feature Name tests', () => {
before(() => {
// Setup code that runs once before all tests
})
beforeEach(() => {
// Setup code that runs before each test
})
it('Verify that [specific behavior]', () => {
// Test implementation
})
it('Verify that [another specific behavior]', () => {
// Test implementation
})
})
```
## Page Object Model (POM)
### Element Definition
- **MANDATORY**: ALL element selectors MUST be defined in `.page.js` files
- **MANDATORY**: NEVER use element selectors directly in test files
- **MANDATORY**: Each page file MUST have corresponding functions to interact with elements
### Page File Structure
```jsx
// dashboard.pages.js
const overviewSection = '[data-testid="overview-section"]'
const totalAssetValueAmount = '[data-testid="total-asset-value-amount"]'
const sendButton = '[data-testid="overview-send-btn"]'
export function verifyTotalAssetValueIsDisplayed() {
cy.get(overviewSection).should('be.visible')
cy.get(totalAssetValueAmount).should('be.visible')
}
export function clickSendButton() {
cy.get(sendButton).click()
}
```
### Test File Implementation
```jsx
// dashboard.cy.js
import * as dashboard from '../pages/dashboard.pages'
describe('Dashboard tests', () => {
it('Verify that total asset value is displayed', () => {
dashboard.verifyTotalAssetValueIsDisplayed()
})
it('Verify that send button is clickable', () => {
dashboard.clickSendButton()
})
})
```
## Element Selection Strategy
### Prohibited Selectors
- **NEVER** use class names: `'[class*="MuiTypography"]'`
- **NEVER** use CSS selectors based on styling: `'.red-button'`
- **NEVER** use element position: `'button:nth-child(2)'`
- **NEVER** use generic selectors: `'div'`, `'span'`, `'button'`
- **NEVER** select links by tag and then assert URL/target: e.g. `cy.contains('a', 'Get CLI')`, `.should('have.attr', 'href', url)`, `.and('have.attr', 'target', '_blank')`. Use **data-testid** on the link in the component and select by that in the page object instead.
### Preferred Selectors (in order of preference)
1. **data-testid attributes**: `'[data-testid="send-button"]'`, `'[data-testid="get-cli-link"]'` — use for links and CTAs as well; add `data-testid` (or `actionTestId` on ActionCard) in the component when missing.
2. **Semantic HTML**: `'[role="button"]'`, `'[type="submit"]'`
3. **Text content**: `cy.contains('Send')` (for non-link elements when no testid exists)
4. **ARIA labels**: `'[aria-label="Send transaction"]'`
### Links and external CTAs
- **Prefer data-testid**: For links (e.g. "Get CLI", "Learn more", external docs), add a `data-testid` (or `actionTestId` when using ActionCard) in the React component and use `cy.get('[data-testid="…"]')` in the page object. Verify visibility or behavior via the testid, not via `href`/`target`.
- **Avoid**: `cy.contains('a', 'Label')`, `.should('have.attr', 'href', ...)`, `.and('have.attr', 'target', '_blank')` and similar tag/attribute patterns. If you need to assert a link, add a testid and assert the element is visible (or that the correct flow runs after click).
### Reuse existing test IDs
- **MANDATORY**: If an element or its container already has a `data-testid` (or the component already passes `testId` / `actionTestId`), **do not add a new one**. Reuse the existing testid in the page object and in assertions. Add new test IDs only when the element currently has none.
### Adding Test IDs to Components
When test IDs are missing, add them to React components. If a testid already exists on the element or a parent, use that instead of adding another.
```jsx
// Component.tsx
<Button data-testid="send-button">Send</Button>
<Typography data-testid="total-amount">$1,234.56</Typography>
```
## Function Organization and Reusability
### Function Placement Rules
- **MANDATORY**: Before creating any new function, check if a similar one exists in other page files; reuse it.
- **MANDATORY**: General (used by 3+ page files) → `main.page.js`. Page-specific and helpers used only in one page → that page's `.pages.js`.
### General Functions (main.page.js)
- **Purpose**: Truly generic, reusable functions used across multiple pages
- **Examples**:
- Button clicks: `clickButton()`, `clickButtonByText()`
- Input interactions: `typeInInput()`, `clearInput()`
- Visibility checks: `verifyElementVisible()`, `verifyElementExists()`
- Text verification: `verifyTextContent()`, `verifyTextExists()`
- Navigation: `navigateToPage()`, `goBack()`
- Wait utilities: `waitForElement()`, `waitForPageLoad()`
- **Rule**: Only functions that are used by 3+ different page files should be in `main.page.js`
### Page-Specific Functions and Helpers (feature.pages.js)
- **Purpose**: Functions and helpers used only in one page/feature (business logic, complex interactions, validation, internal utilities). Place in that page's `.pages.js`, not in main.page.js.
### Helper Function Placement Guidelines
```jsx
// ✅ CORRECT: Helper function in the appropriate page file
// dashboard.pages.js
import * as main from './main.page'
const totalAssetValueAmount = '[data-testid="total-asset-value-amount"]'
const sendButton = '[data-testid="send-button"]'
const assetList = '[data-testid="asset-list"]'
// Helper function - only used within dashboard.pages.js
function formatAssetValue(value) {
return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' })
}
// Helper function - only used for dashboard-specific validation
function verifyAssetListNotEmpty() {
cy.get(assetList).should('have.length.greaterThan', 0)
}
// Public function that uses the helper
export function verifyTotalAssetValueIsDisplayed() {
main.verifyElementVisible(totalAssetValueAmount)
verifyAssetListNotEmpty() // Uses page-specific helper
}
export function clickSendButton() {
main.clickButton(sendButton)
}
// ❌ INCORRECT: Helper function in main.page.js when it's page-specific
// main.page.js - WRONG
export function formatAssetValue(value) { // ❌ Only used in dashboard, shouldn't be here
return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' })
}
```
### Decision Tree for Function Placement
1. **Is the function used by 3+ different page files?**
- ✅ YES → Place in `main.page.js`
- ❌ NO → Continue to step 2
2. **Is the function specific to one page/feature?**
- ✅ YES → Place in that page's `.pages.js` file
- ❌ NO → Check if it's a helper for a specific page
3. **Is the function a helper that supports a specific page's functionality?**
- ✅ YES → Place in that page's `.pages.js` file (even if it's a "helper")
- ❌ NO → Re-evaluate - might need to be split or refactored
### Function Naming Convention
```jsx
// main.page.js - General functions
export function clickButton(selector) {
cy.get(selector).click()
}
export function verifyElementVisible(selector) {
cy.get(selector).should('be.visible')
}
export function verifyTextContent(selector, expectedText) {
cy.get(selector).should('contain.text', expectedText)
}
// dashboard.pages.js - Page-specific functions and helpers
import * as main from './main.page'
const totalAssetValueAmount = '[data-testid="total-asset-value-amount"]'
const dashboardTab = '[data-testid="dashboard-tab"]'
// Helper function - only used within this page file
function verifyAmountFormat(amount) {
return amount.match(/^\\$[\\d,]+\\.\\d{2}$/)
}
export function verifyDashboardTotalAmount() {
main.verifyElementVisible(totalAssetValueAmount)
main.verifyTextContent(totalAssetValueAmount, '$')
// Helper function used internally
cy.get(totalAssetValueAmount).then(($el) => {
const amount = $el.text()
expect(verifyAmountFormat(amount)).to.be.true
})
}
export function navigateToDashboardTab() {
main.clickButton(dashboardTab)
}
```
### Function Reusability
Before adding a function: search page files for similar logic. If it exists, import and reuse. If new: 3+ pages → main.page.js; otherwise → that feature's `.pages.js`.
## Test Organization
### File Structure (actual layout)
Use this structure to find or place code. Do not invent new folders or helpers that duplicate support modules.
```
cypress/
├── e2e/ # Test specs and page objects
│ ├── smoke/ # Critical path tests (functional)
│ │ └── visual/ # Visual regression tests (Chromatic E2E only)
│ ├── regression/ # Feature tests
│ ├── happypath/ # User journey tests
│ ├── safe-apps/ # Safe Apps tests
│ ├── pages/ # Page Object Model (*.pages.js), main.page.js
│ └── ...
├── fixtures/ # Static test data (JSON, CSV, static.js safes)
│ └── safes/ # getSafes() loads from here (static.js, *.json)
├── plugins/
│ └── index.js # Cypress plugins
└── support/ # Shared config, data, commands — check here before adding new helpers
├── api/ # Contract/protocol utilities (utils_ether.js, etc.)
├── commands.js # Custom Cypress commands (e.g. saveLocalStorageCache)
├── constants.js # URLs, localStorage key names (localStorageKeys), test constants
├── e2e.js # Global support (imports commands, safe-apps-commands, constants, ls)
├── localstorage_data.js # All localStorage payloads: addedSafes, addressBookData, undeployedSafe, batchData, etc.
├── safe-apps-commands.js # Safe Apps–specific Cypress commands
├── safes/
│ └── safesHandler.js # getSafes(CATEGORIES.static|funds|nfts|...) — safe addresses for tests
└── utils/ # wallet.js, ethers.js, checkers.js, gtag.js, txquery.js
```
**Where to find things (use these; do not reinvent):**
| Need | Location |
|------|----------|
| Safe addresses for tests | `support/safes/safesHandler.js` → `getSafes(CATEGORIES.static)`; fixtures in `fixtures/safes/` |
| URL paths, localStorage key strings | `support/constants.js` (e.g. `constants.BALANCE_URL`, `constants.localStorageKeys.SAFE_v2__addedSafes`) |
| localStorage data (addedSafes, addressBook, etc.) | `support/localstorage_data.js` — add new scenarios as named consts here |
| Wallet connect / signing | `support/utils/wallet.js` |
| Custom Cypress commands | `support/commands.js`, `support/safe-apps-commands.js` |
| Page selectors and flows | `e2e/pages/*.pages.js`, `e2e/pages/main.page.js` |
Test categories:
- **smoke/** — critical path, functional (runs on every PR)
- **smoke/visual/** — visual regression for Chromatic (only runs in Chromatic E2E workflow, not in smoke CI)
- **regression/** — feature tests
- **happypath/** — user journeys
- **safe-apps/** — Safe Apps tests
## Data Management
### General principle: use existing support, do not add new setup helpers
For **any** test data or setup (localStorage, API mocks, addresses, etc.):
- **Check first:** Look in `support/` and `fixtures/` for existing constants, keys, and helpers that already provide or set that data. Use the "Where to find things" table in the File Structure section.
- **Use existing helpers:** Use the existing functions and commands (e.g. `addToLocalStorage`, `addToAppLocalStorage`, `getSafes`, `cy.fixture`). Do **not** create new helper functions in `main.page.js` or page objects that duplicate or replace this (e.g. a new "add X to Y" or "set up Z" function). If the need is "set data the app reads", the pattern is: existing helper + data from support/fixtures.
- **Data in support/fixtures:** Put new scenario data as named constants in the appropriate support file (e.g. `localstorage_data.js`) or fixtures. Do not inline large payloads in tests or page objects, and do not add functions that build or merge such data elsewhere.
When in doubt, search existing tests for the same kind of setup and copy that pattern instead of inventing a new function.
### localStorage Setup
Always use existing localStorage setup patterns:
```jsx
// Use existing safe data from safesHandler
import { getSafes, CATEGORIES } from '../../support/safes/safesHandler.js'
let staticSafes = []
describe('Test Suite', () => {
before(async () => {
staticSafes = await getSafes(CATEGORIES.static)
})
beforeEach(() => {
cy.visit(constants.homeUrl + staticSafes.SEP_STATIC_SAFE_2)
})
})
```
### localStorage Data (addedSafes, addressBook, undeployedSafes, etc.)
**Rule (application of the general principle above):** Use existing support only. Do **not** create new helper functions that set or build localStorage (e.g. custom "add X" or "set Y" helpers). Put payloads in `support/localstorage_data.js` and use the existing `main.addToLocalStorage` or `main.addToAppLocalStorage` with keys from `support/constants.js`. Do not inline large localStorage objects in tests or page objects.
- **MANDATORY — Check structure first:** Before setting localStorage in tests:
- **Keys (string names):** Use `support/constants.js` → `constants.localStorageKeys` (e.g. `SAFE_v2__addedSafes`, `SAFE_v2__addressBook`, `SAFE_v2__undeployedSafes`).
- **Data shape and payloads:** Use `support/localstorage_data.js` (exports: `addedSafes`, `addressBookData`, `undeployedSafe`, `batchData`, etc.). For `addedSafes`, shape is chainId → address → `{ owners, threshold, ethBalance? }`.
- **MANDATORY — Use only existing helpers:** Do **not** add new functions in `main.page.js` or page objects that set or build localStorage. Use the existing pair:
- **`main.addToLocalStorage(key, value)`** — Writes to the **runner's** window. Use when you set data **before** the first `cy.visit()` (e.g. multichain sidebar with `set5WithSingleSafe` set then visit).
- **`main.addToAppLocalStorage(key, value)`** — Writes to the **app's** window (via `cy.window()`). Use when the app must read the data. Call after `cy.visit()`, then `cy.reload()` so the app picks it up.
- **MANDATORY — Data in one place:** Define new scenarios as **named constants** in `support/localstorage_data.js` (e.g. under `addedSafes`, `addressBookData`). Do **not** inline large objects in `*.cy.js` or `*.pages.js`, and do **not** add new helpers that build or merge localStorage content.
- **Before adding a constant:** Check for an existing set in `localstorage_data.js` that already fits (e.g. `set1`–`set6`, or other named entries) to avoid duplicates.
- **When unsure:** Search existing tests for the same key (e.g. `SAFE_v2__addedSafes`) and copy the pattern (import `ls` from `localstorage_data.js`, use `constants.localStorageKeys`).
**Examples:**
```js
import * as constants from '../../support/constants.js'
import * as main from '../pages/main.page.js'
import * as ls from '../../support/localstorage_data.js'
// Pattern A — app must see data: visit → addToAppLocalStorage → reload
cy.visit(constants.BALANCE_URL + staticSafes.SEP_STATIC_SAFE_9)
main.addToAppLocalStorage(constants.localStorageKeys.SAFE_v2__addedSafes, ls.addedSafes.sidebarTrustedSafe1)
cy.reload()
// Pattern B — data before first load: addToLocalStorage → visit (no reload)
main.addToLocalStorage(constants.localStorageKeys.SAFE_v2__addedSafes, ls.addedSafes.set5WithSingleSafe)
cy.visit(constants.BALANCE_URL + staticSafes.MATIC_STATIC_SAFE_28)
```
**localStorage seeding — low risk, but watch for flakiness:** Test-only and docs changes are low risk. The main risk is E2E flakiness if (1) **reload ordering** is wrong (e.g. using `addToLocalStorage` when the app must see data → use Pattern A with `addToAppLocalStorage` after visit then reload), or (2) **scenario data is mismatched** (e.g. fixture has different chainId/address than the visited safe). If a test fails only when using a new fixture: check that the fixture’s chainId and safe addresses match the URL/safe under test, and that addressBook/undeployedSafes are set when the test expects them.
### Test Data
See **Where to find things** table. In addition: use `getSafes(CATEGORIES.static)` for safe addresses (do not hardcode); use `cy.fixture()` for JSON/CSV; put new localStorage scenarios in `support/localstorage_data.js`.
## Error Handling
### Wait Strategies
- **AVOID**: `cy.wait(1000)` - hard coded waits
- **PREFER**: `cy.get(selector, { timeout: 30000 })` - explicit waits
- **USE**: `cy.should('be.visible')` - assertion-based waits
### Error Recovery
```jsx
// ✅ Good error handling - selectors defined in page file
// transactions.pages.js
const transactionItem = '[data-testid="transaction-item"]'
export function waitForTransactionToLoad() {
cy.get(transactionItem, { timeout: 30000 })
.should('be.visible')
.and('contain.text', 'Transaction')
}
// main.page.js
export function waitForElementWithText(selector, text, timeout = 30000) {
cy.get(selector, { timeout })
.should('be.visible')
.and('contain.text', text)
}
// Handle network issues
cy.intercept('GET', '/api/transactions', { fixture: 'transactions.json' })
```
## Performance Guidelines
### Parallel Execution
- Tests should be independent
- Use `before()` for expensive setup
- Use `beforeEach()` for test isolation
### Resource Management
- Clean up after tests
- Use appropriate timeouts
- Minimize network requests
## Copilot-Specific Patterns
### Setup Functions
For Copilot tests, use these setup functions:
```jsx
// General Copilot setup (for Threat, Contract, Tenderly tests)
shield.navigateToTransactionAndSetupCopilot(transactionId, signer, addressBookData?, safeAddress?)
// Recipient Analysis setup (includes card expansion)
shield.setupRecipientAnalysis(transactionId, signer, addressBookData?, safeAddress?)
```
### Transaction IDs
- Use `shield.testTransactions.*` constants
- Extract from URL: `&id=multisig_0x..._0x...`
- Add new transaction IDs to `copilot.js` testTransactions object
### Text Constants
- Use `shield.*Str` constants for text verification
- Add new constants to `copilot.js` and export them
- Use `main.verifyTextVisibility([shield.textConstant1, shield.textConstant2])`
### Test Template
```jsx
it('[Category] Verify that [behavior] - [ID]', () => {
shield.navigateToTransactionAndSetupCopilot(
shield.testTransactions.[transactionKey],
signer
)
shield.verify[Element]()
main.verifyTextVisibility([shield.[textConstant]])
})
```
## Common Mistakes
1. **Hardcoded selectors in test files** — Never use raw `data-testid` strings or CSS selectors directly in `.cy.js` files. Always use page object constants/functions from `cypress/e2e/pages/*.pages.js`. If a selector doesn't exist yet, add it to the correct page object file first.
- `cy.get('[data-testid="safe-list-item"]')` → `cy.get(sideBar.sideSafeListItem)`
- `cy.get('[data-testid="apps-list"]')` → `cy.get(safeapps.safeAppsList)`
- `cy.get('input[id="search-by-name"]').type(...)` → `safeapps.typeAppName(...)`
2. **Test naming** — Smoke tests: `[SMOKE] Verify that ...`. Visual tests: `[VISUAL] Screenshot ...`.
3. **Visual tests in wrong folder** — Visual regression tests go in `smoke/visual/`, not `smoke/`. They only run in Chromatic E2E workflow, not in smoke CI.
4. **Import paths after moving** — Tests in `smoke/visual/` need an extra `../` level for relative imports to pages and support.
## Implementation Checklist
When creating or updating tests, ensure:
- [ ] Test name uses "Verify that" format
- [ ] Only one describe block per test suite
- [ ] All element selectors are in page files
- [ ] Functions are created for element interactions
- [ ] No direct selector usage in test files
- [ ] No class-based selectors used
- [ ] data-testid: reuse existing test IDs; add new ones only when the element has none (including links/CTAs; do not use `cy.contains('a', ...)` or `.should('have.attr', 'href'/'target')`)
- [ ] **Functions: search page files first; reuse. New: 3+ pages → main.page.js; else → that page's .pages.js**
- [ ] **Reuse existing functions instead of creating duplicates**
- [ ] **Test data/setup: use support + fixtures (constants, localstorage_data.js, getSafes, addToLocalStorage/addToAppLocalStorage); do not add new setup helpers or inline large payloads**
- [ ] Appropriate wait strategies (no hard-coded waits)
- [ ] Test data loaded from fixtures or constants
- [ ] Error handling implemented
- [ ] Comments added for complex logic
## Examples
### ✅ Good Test Structure with Function Reusability
```jsx
// main.page.js
export function clickButton(selector) {
cy.get(selector).click()
}
export function verifyElementVisible(selector) {
cy.get(selector).should('be.visible')
}
// dashboard.pages.js
import * as main from './main.page'
const totalAssetValueAmount = '[data-testid="total-asset-value-amount"]'
const sendButton = '[data-testid="send-button"]'
const assetList = '[data-testid="asset-list"]'
// Helper function - page-specific, located in this page file
function verifyAssetListLoaded() {
cy.get(assetList).should('be.visible').and('have.length.greaterThan', 0)
}
export function verifyTotalAssetValueIsDisplayed() {
main.verifyElementVisible(totalAssetValueAmount)
verifyAssetListLoaded() // Uses page-specific helper
}
export function clickSendButton() {
main.clickButton(sendButton)
}
// dashboard.cy.js
import * as dashboard from '../pages/dashboard.pages'
import { getSafes, CATEGORIES } from '../../support/safes/safesHandler.js'
let staticSafes = []
describe('Dashboard tests', () => {
before(async () => {
staticSafes = await getSafes(CATEGORIES.static)
})
beforeEach(() => {
cy.visit(constants.homeUrl + staticSafes.SEP_STATIC_SAFE_2)
})
it('Verify that total asset value is displayed correctly', () => {
dashboard.verifyTotalAssetValueIsDisplayed()
})
it('Verify that send button is clickable', () => {
dashboard.clickSendButton()
})
})
```
### ❌ Bad Test Structure
```jsx
// ❌ Multiple describe blocks; wrong test name; class selector; direct selector in test
describe('Dashboard tests', () => {
describe('Asset values', () => {
it('Check total value', () => {
cy.get('[class*="MuiTypography"]').should('be.visible')
cy.get('[data-testid="total-amount"]').click()
})
})
})
// ❌ Page-specific helper in main.page.js → move to that page's .pages.js (see Helper Function Placement above)
```
## Migration Guide
When updating existing tests:
1. **Update test names**: Add "Verify that" prefix
2. **Consolidate describe blocks**: One per file
3. **Move selectors to page files**: Create functions for interactions
4. **Check for existing functions**: Search all page files before creating new ones
5. **Function placement**: General (3+ pages) → main.page.js; page-specific and helpers → that page's `.pages.js`
6. **Add missing test IDs**: Update React components
7. **Test data/setup**: Use existing support; do not add new setup helpers
8. **Remove hard waits**: Replace with proper assertions
9. **Add error handling**: Implement timeout strategies
================================================
FILE: .cursor/rules/safe-monorepo.mdc
================================================
---
description:
globs:
alwaysApply: true
---
You are an expert developer proficient in TypeScript, Web3/Blockchain(ethers.js, Safe Ecosystem (formally known as Gnosis Safe)), React and Next.js, Expo (React Native), Tamagui, Zod, Yarn v4 (Monorepo Management), Redux, RTK.
Project Structure and Environment
- Follow the established project structure
- Use the `apps` directory for Next.js and Expo applications.
- Utilize the `packages` directory for shared code and components.
- use `expo-plugins` directory for custom expo config plugins
- Use `dotenv` for environment variable management.
- Follow patterns for environment-specific configurations in `eas.json` and `next.config.js`.
Code Style and Structure
- Depending on the part of the code you work on, follow the code style document in the respective docs folder.
- Write concise, technical TypeScript code with accurate examples.
- Use functional and declarative programming patterns; avoid classes.
- Prefer iteration and modularization over code duplication.
- Use descriptive variable names with auxiliary verbs (e.g., `isLoading`, `hasError`).
- Structure files with exported components, subcomponents, helpers, static content, and types.
- Favor named exports for components and functions.
TypeScript and Zod Usage
- Use TypeScript for all code; prefer interfaces over types for object shapes.
- Utilize Zod for schema validation and type inference.
- Avoid enums; use literal types or maps instead.
- Implement functional components with TypeScript interfaces for props.
- follow the lint rules and don't use ts "any" type
Syntax and Formatting
- Use the `const` instead of `function` for pure functions.
- Write declarative JSX with clear and readable structure.
UI and Styling
- in the mobile project utilise Tamagui for UI compoentns and styling
- in the nextjs project use Mui
- Implement responsive design with a mobile-first approach.
- Ensure styling consistency between web and native applications.
State Management and Data Fetching
- Use Redux for state management.
- Use Redux RTK for data fetching, caching, and synchronization.
- Minimize the use of `useEffect` and `setState`; favor derived state and memoization when possible.
Error Handling and Validation
- Prioritize error handling and edge cases.
- Handle errors and edge cases at the beginning of functions.
- Use early returns for error conditions to avoid deep nesting.
- Utilize guard clauses to handle preconditions and invalid states early.
- Implement proper error logging and user-friendly error messages.
- Use custom error types or factories for consistent error handling.
Performance Optimization
- Optimize for both web and mobile performance.
- Use dynamic imports for code splitting in Next.js.
- Implement lazy loading for non-critical components.
- Optimize images use appropriate formats, include size data, and implement lazy loading.
Monorepo Management
- Follow best practices using Yarn v4 for monorepo setups.
- Ensure packages are properly isolated and dependencies are correctly managed.
- Use shared configurations and scripts where appropriate.
- Utilize the workspace structure as defined in the root `package.json`.
Testing and Quality Assurance
- use faker to create test data
- Write unit and integration tests for critical components.
- Use jest and the testing libraries specified in each package
- Ensure code coverage and quality metrics meet the project's requirements.
- when testing Redux code prefer actual state changes test over mock calls
- when testing functions that call network endpoints prefer Mock Service Worker (MSW) over mocking function calls
Key Conventions
- Use descriptive and meaningful commit messages.
- Ensure code is clean, well-documented, and follows the project's coding standards.
- Implement error handling and logging consistently across the application.
Follow Official Documentation
- Adhere to the official documentation for each technology used.
- For Next.js, focus on data fetching methods and routing conventions.
- Stay updated with the latest best practices and updates, especially for Expo, React-Native and Tamagui.
Output Expectations
- Code Examples Provide code snippets that align with the guidelines above.
- Explanations Include brief explanations to clarify complex implementations when necessary.
- Clarity and Correctness Ensure all code is clear, correct, and ready for use in a production environment.
- Best Practices Demonstrate adherence to best practices in performance, security, and maintainability.
================================================
FILE: .editorconfig
================================================
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
# TypeScript, JavaScript, JSX, TSX
[*.{ts,tsx,js,jsx,mjs,cjs}]
indent_style = space
indent_size = 2
max_line_length = 120
# JSON files
[*.json]
indent_style = space
indent_size = 2
# YAML files
[*.{yml,yaml}]
indent_style = space
indent_size = 2
# Markdown files
[*.md]
indent_style = space
indent_size = 2
trim_trailing_whitespace = false
# Package.json
[package.json]
indent_style = space
indent_size = 2
================================================
FILE: .gitattributes
================================================
* text=auto eol=lf
================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.md
================================================
---
name: Bug report
about: Create an issue to fix a bug
type: 'bug'
---
<!--
BEFORE SUBMITTING: Please search to make sure this issue hasn't been reported already
-->
## Bug description
## Environment
- Browser: Chrome
- Wallet: MetaMask
- Chain: Ethereum mainnet
## Steps to reproduce
1. Go to
## Expected result
## Obtained result
## Screenshots
================================================
FILE: .github/ISSUE_TEMPLATE/feature-request.md
================================================
---
name: Feature request
about: Create a feature request for the Safe UI
---
<!--
NB: this repository is ONLY for the React frontend of the Safe.
Please make sure your feature request is related specifically to the frontend.
For general technical QUESTIONS about the Safe, we recommend StackExchange:
https://ethereum.stackexchange.com/questions/tagged/gnosis-safe
Thank you!
-->
## What is the feature about
## The list of requirements
## Designs/sketches
## Links
================================================
FILE: .github/ISSUE_TEMPLATE/task.md
================================================
---
name: Task
about: Internal implementation task – only for the Safe team!
type: 'task'
---
## Links
Epic on Notion:
## What must be done
## Designs/sketches
## How to test it
================================================
FILE: .github/ISSUE_TEMPLATE/tech-debt.md
================================================
---
name: Tech debt task
about: Internal tech debt task – only for the Safe team!
type: 'task'
labels: 'tech debt'
---
## Problem
## Proposed solution
## Dependencies & risks
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
## What it solves
Resolves:
## How this PR fixes it
## How to test it
## Affected flows
<!-- The primary user journey(s) this PR intentionally changes. One bullet per flow. Example: "Owner adds a new signer from Settings > Signers". -->
## Blast radius
<!--
List the surfaces touched by this change and who else depends on them. Think in dependency terms, not files.
Include where relevant:
- Shared hooks / components / selectors / slices touched and their known consumers
- RTK Query endpoints / API contracts
- Feature flags / chain configs
- Persistence / cache / migration implications
- Routes or layouts affected indirectly
- Mobile impact (shared packages)
-->
## Risks / not checked
<!--
Be explicit about what you did NOT verify. This exposes false confidence and helps reviewers target their attention.
Example:
- Did not verify behavior with feature flag X disabled
- Did not test on mobile
- Did not exercise the retry / error path manually
-->
## Visual summary
<!-- REQUIRED for AI-authored PRs. Include a Mermaid diagram for architecture/logic changes, a screenshot for UI changes, or both. See AGENTS.md for examples. -->
## Checklist
- [ ] I've tested the branch on mobile 📱
- [ ] I've documented how it affects the analytics (if at all) 📊
- [ ] I've written a unit/e2e test for it (if applicable) 🧑💻
- [ ] I've listed affected flows and blast radius, and named what I did not verify 🎯
---
## CLA signature
With the submission of this Pull Request, I confirm that I have read and agree to the terms of the [Contributor License Agreement](https://safe.global/cla).
================================================
FILE: .github/actions/branch-slug/action.yml
================================================
name: 'Branch Slug'
description: 'Sanitize branch name into a DNS-safe slug for preview subdomains'
inputs:
max-length:
description: 'Max slug length (default 50, keeps branch--walletweb under 63-char DNS limit)'
required: false
default: '50'
outputs:
slug:
description: 'DNS-safe branch slug'
value: ${{ steps.slugify.outputs.slug }}
runs:
using: 'composite'
steps:
- name: Slugify branch name
id: slugify
shell: bash
run: |
raw="$(echo "$GITHUB_HEAD_REF" | sed 's|refs/heads/||')"
safe="$(echo "$raw" | sed 's/[^a-zA-Z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//' | sed 's/[A-Z]/\L&/g' | cut -c1-${{ inputs.max-length }} | sed 's/-$//')"
echo "slug=$safe" >> $GITHUB_OUTPUT
================================================
FILE: .github/actions/build/action.yml
================================================
name: 'Build'
description: 'Build the app'
inputs:
secrets:
required: true
description: 'GitHub secrets as JSON'
prod: # id of input
description: 'Production build flag'
required: false
runs:
using: 'composite'
steps:
- name: Restore Next.js Build Cache & Cypress cache
id: restore-nc
uses: ./.github/actions/cache-deps
with:
mode: restore-nc
- name: Export NEXT_PUBLIC secrets to env
shell: bash
env:
SECRETS_JSON: ${{ inputs.secrets }}
run: |
set -euo pipefail
# Auto-export all NEXT_PUBLIC_* secrets.
# New secrets with this prefix are picked up automatically.
# Uses per-key heredoc delimiters to safely handle multi-line values
# (e.g. NEXT_PUBLIC_FIREBASE_OPTIONS_* are JSON strings).
EXPORTED=$(echo "$SECRETS_JSON" | jq -r '
to_entries[]
| select(.key | startswith("NEXT_PUBLIC_"))
| select(.value != null and .value != "")
| "\(.key)<<EOF_\(.key)\n\(.value)\nEOF_\(.key)"
')
if [ -n "$EXPORTED" ]; then
echo "$EXPORTED" >> "$GITHUB_ENV"
# Log exported key names (values masked)
echo "$EXPORTED" | grep -oP '^[A-Z0-9_]+(?=<<)' | while read -r key; do
echo " Exported: $key"
done
else
echo "Warning: No NEXT_PUBLIC_* secrets found to export"
fi
- name: Set environment variables
shell: bash
run: |
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
echo "NEXT_PUBLIC_COMMIT_HASH=$SHORT_SHA" >> $GITHUB_ENV
# Datadog RUM env:
# - can be overridden by setting NEXT_PUBLIC_DATADOG_RUM_ENV in repo secrets
# - otherwise set to "production" or "development" based on prod flag
DATADOG_RUM_ENV="${{ fromJSON(inputs.secrets).NEXT_PUBLIC_DATADOG_RUM_ENV }}"
if [ -z "$DATADOG_RUM_ENV" ]; then
if [ "${{ inputs.prod }}" = "true" ]; then
DATADOG_RUM_ENV="production"
else
DATADOG_RUM_ENV="development"
fi
fi
echo "NEXT_PUBLIC_DATADOG_RUM_ENV=$DATADOG_RUM_ENV" >> $GITHUB_ENV
if [ "${{ inputs.prod }}" = "true" ]; then
echo "NEXT_PUBLIC_INFURA_TOKEN=${{ fromJSON(inputs.secrets).NEXT_PUBLIC_INFURA_TOKEN }}" >> $GITHUB_ENV
echo "NEXT_PUBLIC_SAFE_APPS_INFURA_TOKEN=${{ fromJSON(inputs.secrets).NEXT_PUBLIC_SAFE_APPS_INFURA_TOKEN }}" >> $GITHUB_ENV
else
echo "NEXT_PUBLIC_INFURA_TOKEN=${{ fromJSON(inputs.secrets).NEXT_PUBLIC_INFURA_TOKEN_DEVSTAGING }}" >> $GITHUB_ENV
echo "NEXT_PUBLIC_SAFE_APPS_INFURA_TOKEN=${{ fromJSON(inputs.secrets).NEXT_PUBLIC_SAFE_APPS_INFURA_TOKEN_DEVSTAGING }}" >> $GITHUB_ENV
fi
- name: Build
shell: bash
run: yarn workspace @safe-global/web build
env:
NEXT_PUBLIC_IS_PRODUCTION: ${{ inputs.prod }}
- name: Upload source maps to Datadog
if: ${{ fromJSON(inputs.secrets).DATADOG_API_KEY }}
shell: bash
working-directory: apps/web
run: |
RELEASE_VERSION="${NEXT_PUBLIC_COMMIT_HASH:-$(echo "${{ github.sha }}" | cut -c1-7)}"
DATADOG_SERVICE="${NEXT_PUBLIC_DATADOG_RUM_SERVICE:-safe-wallet-web}"
echo "Uploading Datadog sourcemaps:"
echo "- env: ${NEXT_PUBLIC_DATADOG_RUM_ENV:-unset}"
echo "- service: $DATADOG_SERVICE"
echo "- release-version: $RELEASE_VERSION"
echo "- minified-path-prefix: /_next/static"
echo "- sourcemaps-dir: ./out/_next/static"
npx @datadog/datadog-ci sourcemaps upload ./out/_next/static \
--service="$DATADOG_SERVICE" \
--release-version="$RELEASE_VERSION" \
--minified-path-prefix=/_next/static
env:
DATADOG_API_KEY: ${{ fromJSON(inputs.secrets).DATADOG_API_KEY }}
DATADOG_SITE: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_DATADOG_RUM_SITE || 'datadoghq.eu' }}
- name: Generate SRI for static scripts
shell: bash
# Skip SRI for Cypress test builds (NODE_ENV=cypress)
run: |
if [ "$NODE_ENV" != "cypress" ]; then
yarn workspace @safe-global/web integrity
else
echo "Skipping SRI generation for Cypress test environment"
fi
- name: Save Next.js Build Cache & Cypress cache
if: steps.restore-nc.outputs.cache-hit-nc != 'true'
uses: ./.github/actions/cache-deps
with:
mode: save-nc
key: ${{ steps.restore-nc.outputs.computed-cache-key-nc }}
================================================
FILE: .github/actions/build-storybook/action.yml
================================================
name: 'Build Storybook'
description: 'Build the storybook'
inputs:
secrets:
required: true
runs:
using: 'composite'
steps:
- name: Build Storybook
shell: bash
run: yarn workspace @safe-global/web build-storybook -o ./out/storybook
================================================
FILE: .github/actions/cache-deps/action.yml
================================================
name: 'Cache Yarn Dependencies'
description: 'Restore or save yarn dependencies'
inputs:
mode:
description: 'restore-yarn | save-yarn | restore-nc | save-nc'
required: true
key:
description: 'The cache key to use to safe. Attention! Make sure to use the correct computed cache key depending on the mode'
required: false
outputs:
cache-hit-yarn:
value: ${{ steps.restore.outputs.cache-hit }}
description: 'Whether the cache was hit or not'
computed-cache-key-yarn:
value: ${{ steps.restore.outputs.cache-primary-key }}
description: 'The computed cache key for yarn'
cache-hit-nc:
value: ${{ steps.restore-nc.outputs.cache-hit }}
description: 'Whether the cache was hit or not'
computed-cache-key-nc:
value: ${{ steps.restore-nc.outputs.cache-primary-key }}
description: 'The computed cache key for nextjs/cypress'
runs:
using: 'composite'
steps:
- name: Restore Yarn Cache
if: ${{ inputs.mode == 'restore-yarn' }}
id: restore
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: |
**/node_modules
/home/runner/.cache/Cypress
~/.yarn/berry/cache
${{ github.workspace }}/.yarn/install-state.gz
${{ github.workspace }}/packages/utils/src/types
key: ${{ runner.os }}-web-core-modules-${{ hashFiles('**/package.json','**/yarn.lock') }}
- name: Set composite outputs yarn
if: ${{ inputs.mode == 'restore-yarn' }}
shell: bash
run: |
echo "cache-hit-yarn=${{ steps.restore.outputs.cache-hit }}" >> $GITHUB_OUTPUT
echo "computed-cache-key-yarn=${{ steps.restore.outputs.cache-primary-key }}" >> $GITHUB_OUTPUT
- name: Save Yarn Cache
if: ${{ inputs.mode == 'save-yarn' }}
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: |
**/node_modules
/home/runner/.cache/Cypress
~/.yarn/berry/cache
${{ github.workspace }}/.yarn/install-state.gz
${{ github.workspace }}/packages/utils/src/types
key: ${{inputs.key}}
- name: Restore Next.js
if: ${{ inputs.mode == 'restore-nc' }}
id: restore-nc
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: |
${{ github.workspace }}/apps/web/.next/cache
key: ${{ runner.os }}-nextjs-cypress-${{ hashFiles('apps/web/package.json', 'apps/web/yarn.lock') }}-${{ hashFiles('apps/web/src/**/*', 'apps/web/public/**/*', 'apps/web/*.{js,jsx,cjs,ts,mjs,tsx,json}') }}
- name: Set composite outputs nc
if: ${{ inputs.mode == 'restore-nc' }}
shell: bash
run: |
echo "cache-hit-nc=${{ steps.restore-nc.outputs.cache-hit }}" >> $GITHUB_OUTPUT
echo "computed-cache-key-nc=${{ steps.restore-nc.outputs.cache-primary-key }}" >> $GITHUB_OUTPUT
- name: Save Next.js
if: ${{ inputs.mode == 'save-nc' }}
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: |
${{ github.workspace }}/apps/web/.next/cache
key: ${{inputs.key}}
================================================
FILE: .github/actions/corepack/action.yml
================================================
name: 'Enable corepack'
runs:
using: 'composite'
steps:
- name: 'Enable Corepack'
shell: bash
run: corepack enable
================================================
FILE: .github/actions/cypress/action.yml
================================================
name: 'Cypress'
description: 'Run Cypress'
inputs:
secrets:
description: 'GitHub secrets as JSON'
required: true
spec:
description: 'A glob pattern for which tests to run'
required: true
group:
description: 'The name of the group (e.g. "smoke")'
required: true
project_id:
description: 'Cypress cloud project id'
required: false
record_key:
description: 'Cypress cloud record key'
required: false
tag:
description: 'Cypress cloud tag key'
required: false
parallel:
description: 'Enable Cypress Cloud parallel mode'
required: false
default: 'true'
record:
description: 'Record results to Cypress Cloud'
required: false
default: 'true'
container-index:
description: 'Container index for parallel runs (used for artifact naming)'
required: false
default: '0'
runs:
using: 'composite'
steps:
- uses: ./.github/actions/yarn
- name: Install Chrome
uses: browser-actions/setup-chrome@c785b87e244131f27c9f19c1a33e2ead956ab7ce # v1.7.3
with:
chrome-version: '134'
id: setup-chrome
- uses: ./.github/actions/build
with:
secrets: ${{ inputs.secrets }}
env:
NODE_ENV: cypress
- uses: cypress-io/github-action@f790eee7a50d9505912f50c2095510be7de06aa7 # v6.10.9
with:
spec: ${{ inputs.spec }}
group: ${{ inputs.record == 'true' && inputs.group || '' }}
parallel: ${{ inputs.record == 'true' && inputs.parallel == 'true' }}
browser: ${{ steps.setup-chrome.outputs.chrome-path }}
record: ${{ inputs.record == 'true' }}
tag: ${{ inputs.record == 'true' && inputs.tag || '' }}
config: baseUrl=http://localhost:8080
install: false
start: yarn workspace @safe-global/web serve
wait-on: 'http://localhost:8080'
wait-on-timeout: 120
working-directory: apps/web
env:
NODE_ENV: cypress
CYPRESS_RECORD_KEY: ${{ inputs.record_key || fromJSON(inputs.secrets).CYPRESS_RECORD_KEY }}
GITHUB_TOKEN: ${{ fromJSON(inputs.secrets).GITHUB_TOKEN }}
CYPRESS_PROJECT_ID: ${{ inputs.project_id }}
CYPRESS_WALLET_CREDENTIALS: ${{ fromJSON(inputs.secrets).CYPRESS_WALLET_CREDENTIALS }}
BEAMER_DATA_E2E: ${{ fromJSON(inputs.secrets).BEAMER_DATA_E2E }}
================================================
FILE: .github/actions/upload-coverage/action.yml
================================================
name: 'Upload Coverage to Datadog'
description: 'Upload LCOV coverage report to Datadog Code Coverage'
inputs:
api-key:
required: true
description: 'Datadog API key'
site:
required: false
default: 'datadoghq.eu'
description: 'Datadog site'
coverage-path:
required: true
description: 'Path to coverage directory containing lcov.info'
base-path:
required: true
description: 'Workspace root relative to repo root (e.g., apps/web)'
flag:
required: true
description: 'Flag to identify the workspace (e.g., workspace:web)'
runs:
using: 'composite'
steps:
- name: Upload coverage to Datadog
shell: bash
continue-on-error: true
run: |
npx @datadog/datadog-ci coverage upload \
--flags "${{ inputs.flag }}" \
--base-path "${{ inputs.base-path }}" \
"${{ inputs.coverage-path }}"
env:
DD_API_KEY: ${{ inputs.api-key }}
DD_SITE: ${{ inputs.site }}
================================================
FILE: .github/actions/upload-to-storage-branch/action.yml
================================================
name: 'Upload to Storage Branch'
description: 'Uploads files to a separate storage branch (creates orphan branch if needed)'
inputs:
storage_branch:
description: 'Name of the storage branch'
required: true
source_dir:
description: 'Source directory containing files to upload'
required: true
target_dir:
description: 'Target directory within the storage branch (optional, defaults to root)'
required: false
default: ''
file_pattern:
description: 'Glob pattern for files to copy (e.g., "*.png")'
required: false
default: '*'
commit_message:
description: 'Commit message for the upload'
required: true
readme_title:
description: 'Title for the README.md if creating new branch'
required: false
default: 'Storage Branch'
github_token:
description: 'GitHub token for authentication'
required: true
outputs:
uploaded:
description: 'Whether files were uploaded (true/false)'
value: ${{ steps.upload.outputs.uploaded }}
files_count:
description: 'Number of files uploaded'
value: ${{ steps.upload.outputs.files_count }}
runs:
using: 'composite'
steps:
- name: Upload to storage branch
id: upload
shell: bash
env:
GH_TOKEN: ${{ inputs.github_token }}
STORAGE_BRANCH: ${{ inputs.storage_branch }}
SOURCE_DIR: ${{ inputs.source_dir }}
TARGET_DIR: ${{ inputs.target_dir }}
FILE_PATTERN: ${{ inputs.file_pattern }}
COMMIT_MESSAGE: ${{ inputs.commit_message }}
README_TITLE: ${{ inputs.readme_title }}
run: |
set -euo pipefail
# Constrain storage_branch to a known shape so callers cannot pass
# paths or unexpected refs. A follow-up will tighten this to
# `^pr-\d+(-storybook)?-screenshots$` once all callers pass a
# PR-number-based branch name.
if ! [[ "$STORAGE_BRANCH" =~ ^[a-z0-9_-]+-screenshots$ ]]; then
echo "::error::Invalid storage_branch: '$STORAGE_BRANCH'"
exit 1
fi
# Check if source directory exists and has files
if [ ! -d "$SOURCE_DIR" ]; then
echo "Source directory does not exist: $SOURCE_DIR"
echo "uploaded=false" >> $GITHUB_OUTPUT
echo "files_count=0" >> $GITHUB_OUTPUT
exit 0
fi
FILES_COUNT=$(find "$SOURCE_DIR" -maxdepth 1 -name "$FILE_PATTERN" -type f 2>/dev/null | wc -l)
if [ "$FILES_COUNT" -eq 0 ]; then
echo "No files matching pattern '$FILE_PATTERN' in $SOURCE_DIR"
echo "uploaded=false" >> $GITHUB_OUTPUT
echo "files_count=0" >> $GITHUB_OUTPUT
exit 0
fi
echo "Found $FILES_COUNT file(s) to upload"
# Configure git
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
cd /tmp
rm -rf storage-upload
# Clone or create storage branch. `--heads <name>` is an exact-match
# filter server-side, so a non-empty result means the branch exists.
if [ -n "$(git ls-remote --heads origin "$STORAGE_BRANCH")" ]; then
echo "Cloning existing storage branch: $STORAGE_BRANCH"
git clone --depth 1 --branch "$STORAGE_BRANCH" \
"https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git" storage-upload
cd storage-upload
else
echo "Creating new orphan storage branch: $STORAGE_BRANCH"
git clone --depth 1 \
"https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git" storage-upload
cd storage-upload
git checkout --orphan "$STORAGE_BRANCH"
git rm -rf . 2>/dev/null || true
echo "# $README_TITLE" > README.md
git add README.md
git commit -m "Initialize $STORAGE_BRANCH branch"
fi
# Determine target path
if [ -n "$TARGET_DIR" ]; then
mkdir -p "$TARGET_DIR"
DEST_PATH="$TARGET_DIR"
else
DEST_PATH="."
fi
# Copy files. The caller has already validated file count > 0 and the
# filenames in the artifact, so any cp failure here is a real bug —
# let it fail loudly.
cp "$GITHUB_WORKSPACE/$SOURCE_DIR"/$FILE_PATTERN "$DEST_PATH/"
# Commit and push with retry logic for concurrent runs
git add .
if git commit -m "$COMMIT_MESSAGE"; then
MAX_RETRIES=3
RETRY_COUNT=0
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
if git push origin "$STORAGE_BRANCH"; then
echo "Successfully uploaded to $STORAGE_BRANCH"
echo "uploaded=true" >> $GITHUB_OUTPUT
break
else
RETRY_COUNT=$((RETRY_COUNT + 1))
if [ $RETRY_COUNT -lt $MAX_RETRIES ]; then
echo "Push failed, pulling latest changes and retrying ($RETRY_COUNT/$MAX_RETRIES)..."
git pull --rebase origin "$STORAGE_BRANCH"
else
echo "Push failed after $MAX_RETRIES attempts"
echo "uploaded=false" >> $GITHUB_OUTPUT
exit 1
fi
fi
done
else
echo "No changes to commit"
echo "uploaded=false" >> $GITHUB_OUTPUT
fi
echo "files_count=$FILES_COUNT" >> $GITHUB_OUTPUT
================================================
FILE: .github/actions/yarn/action.yml
================================================
name: 'Yarn'
description: 'Set up Node.js and install dependencies'
inputs:
after-install:
description: 'Run web after-install step to generate contract types'
required: false
default: 'true'
turbo-token:
description: 'Turborepo remote cache token (Vercel PAT)'
required: false
default: ''
turbo-team:
description: 'Turborepo remote cache team slug'
required: false
default: ''
runs:
using: 'composite'
steps:
- uses: ./.github/actions/corepack
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: '24.14.0'
cache: 'yarn'
- name: Export Turbo remote cache env
if: inputs.turbo-token != ''
shell: bash
run: |
echo "TURBO_TOKEN=${{ inputs.turbo-token }}" >> "$GITHUB_ENV"
echo "TURBO_TEAM=${{ inputs.turbo-team }}" >> "$GITHUB_ENV"
echo "TURBO_REMOTE_ONLY=false" >> "$GITHUB_ENV"
- name: Restore Yarn Cache & Types
id: restore-yarn-types
uses: ./.github/actions/cache-deps
with:
mode: restore-yarn
- name: Echo cache hit
shell: bash
run: |
echo "Yarn cache hit: ${{ steps.restore-yarn-types.outputs.cache-hit-yarn }}"
- name: Yarn install
if: steps.restore-yarn-types.outputs.cache-hit-yarn != 'true'
shell: bash
run: yarn install --immutable
- name: Yarn after-install to generate contracts types
if: steps.restore-yarn-types.outputs.cache-hit-yarn != 'true' && inputs.after-install == 'true'
shell: bash
run: yarn workspace @safe-global/web after-install
- name: Save Yarn Cache & Types
if: steps.restore-yarn-types.outputs.cache-hit-yarn != 'true'
uses: ./.github/actions/cache-deps
with:
mode: save-yarn
key: ${{ steps.restore-yarn-types.outputs.computed-cache-key-yarn }}
================================================
FILE: .github/dependabot.yml
================================================
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
- package-ecosystem: 'npm'
directory: '/'
schedule:
interval: 'weekly'
groups:
ledger:
patterns:
- '@ledgerhq/*'
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: 'weekly'
================================================
FILE: .github/scripts/capture-mobile-screenshots.js
================================================
/**
* Capture screenshots of Mobile Storybook stories using Playwright
*
* This script serves the built Storybook locally and captures screenshots
*/
const fs = require('fs')
const path = require('path')
const http = require('http')
const { chromium } = require('playwright')
// Simple static file server
function createServer(staticDir, port) {
const resolvedStaticDir = path.resolve(staticDir)
return new Promise((resolve) => {
const server = http.createServer((req, res) => {
// Parse URL and remove query string
const urlPath = (req.url || '/').split('?')[0]
// Resolve the file path and ensure it stays within staticDir (prevent path traversal)
const requestedPath = path.normalize(urlPath).replace(/^(\.\.[/\\])+/, '')
let filePath = path.join(resolvedStaticDir, requestedPath === '/' ? 'index.html' : requestedPath)
filePath = path.resolve(filePath)
// Security: Ensure the resolved path is within the static directory
if (!filePath.startsWith(resolvedStaticDir)) {
res.writeHead(403)
res.end('Forbidden')
return
}
const extname = path.extname(filePath)
const contentTypes = {
'.html': 'text/html',
'.js': 'text/javascript',
'.css': 'text/css',
'.json': 'application/json',
'.png': 'image/png',
'.jpg': 'image/jpg',
'.gif': 'image/gif',
'.svg': 'image/svg+xml',
'.woff': 'font/woff',
'.woff2': 'font/woff2',
'.ttf': 'font/ttf',
}
const contentType = contentTypes[extname] || 'application/octet-stream'
// Text-based content types that should use utf-8 encoding
const textTypes = ['.html', '.js', '.css', '.json', '.svg']
const isTextContent = textTypes.includes(extname)
fs.readFile(filePath, (error, content) => {
if (error) {
if (error.code === 'ENOENT') {
// Try index.html for SPA routing
fs.readFile(path.join(resolvedStaticDir, 'index.html'), (err, indexContent) => {
if (err) {
res.writeHead(404)
res.end('Not Found')
} else {
res.writeHead(200, { 'Content-Type': 'text/html' })
res.end(indexContent, 'utf-8')
}
})
} else {
res.writeHead(500)
res.end(`Server Error: ${error.code}`)
}
} else {
res.writeHead(200, { 'Content-Type': contentType })
// Only use utf-8 encoding for text content, not binary files
if (isTextContent) {
res.end(content, 'utf-8')
} else {
res.end(content)
}
}
})
})
server.listen(port, () => {
console.log(`Static server running at http://localhost:${port}`)
resolve(server)
})
})
}
async function captureScreenshots() {
const storyUrlsFile = 'mobile-screenshots/story-urls.json'
if (!fs.existsSync(storyUrlsFile)) {
console.log('No story URLs file found')
return
}
const storyUrls = JSON.parse(fs.readFileSync(storyUrlsFile, 'utf-8'))
if (storyUrls.length === 0) {
console.log('No story URLs to capture')
return
}
// Start local server for built Storybook
const storybookDir = path.join(process.cwd(), 'apps/mobile/storybook-static')
if (!fs.existsSync(storybookDir)) {
console.error('Storybook build not found at:', storybookDir)
process.exit(1)
}
const server = await createServer(storybookDir, 6006)
console.log(`Capturing ${storyUrls.length} screenshots...`)
const browser = await chromium.launch()
// Use mobile viewport for more authentic screenshots
const context = await browser.newContext({
viewport: { width: 390, height: 844 }, // iPhone 14 Pro dimensions
})
const page = await context.newPage()
for (let i = 0; i < storyUrls.length; i++) {
const { url, componentName, storyName } = storyUrls[i]
console.log(`[${i + 1}/${storyUrls.length}] Capturing: ${componentName} - ${storyName}`)
const cleanComponentName = componentName.replace(/[/\\]/g, '-').replace(/\s+/g, '')
const modes = ['light', 'dark']
for (const mode of modes) {
try {
// Add theme global parameter to URL
const separator = url.includes('?') ? '&' : '?'
const modeUrl = `${url}${separator}globals=theme:${mode}`
console.log(` 📸 Capturing ${mode} mode...`)
await page.goto(modeUrl, {
waitUntil: 'networkidle',
timeout: 30000,
})
// Check if we're on iframe.html (direct story view) or the main Storybook page
const isDirectIframe = url.includes('iframe.html')
let targetPage = page
if (!isDirectIframe) {
// We're on the main Storybook page with iframe wrapper
const iframeElement = await page.waitForSelector('iframe#storybook-preview-iframe', { timeout: 10000 })
const frame = await iframeElement.contentFrame()
if (!frame) {
throw new Error('Could not access Storybook iframe')
}
await frame.waitForLoadState('load', { timeout: 10000 })
targetPage = frame
}
// Additional wait for React Native Web to render
await page.waitForTimeout(3000)
await page.waitForLoadState('networkidle', { timeout: 5000 }).catch(() => {
console.log(` ⚠ Network not fully idle, continuing anyway`)
})
const screenshotPath = path.join('mobile-screenshots', `${cleanComponentName}--${storyName}--${mode}.png`)
// Try to find the story content - React Native Web may render in different containers
// Priority: #storybook-root, body > div, or fallback to body
let screenshotTarget = null
const storyRoot = targetPage.locator('#storybook-root').first()
const bodyContent = targetPage.locator('body > div').first()
if ((await storyRoot.count()) > 0) {
const rootContent = await targetPage.locator('#storybook-root > *').first()
if ((await rootContent.count()) > 0) {
screenshotTarget = storyRoot
console.log(` Using #storybook-root`)
}
}
if (!screenshotTarget && (await bodyContent.count()) > 0) {
screenshotTarget = bodyContent
console.log(` Using body > div`)
}
if (screenshotTarget) {
await screenshotTarget.screenshot({
path: screenshotPath,
animations: 'disabled',
})
console.log(` ✓ Saved: ${screenshotPath}`)
} else {
// Fallback to full page screenshot
await page.screenshot({
path: screenshotPath,
animations: 'disabled',
fullPage: true,
})
console.log(` ✓ Saved (full page): ${screenshotPath}`)
}
} catch (error) {
console.error(` ✗ Error capturing ${mode} mode for ${componentName} - ${storyName}:`, error.message)
try {
const errorPath = path.join('mobile-screenshots', `${cleanComponentName}--${storyName}--${mode}-ERROR.png`)
await page.screenshot({ path: errorPath, fullPage: true })
console.log(` ⚠ Error screenshot saved: ${errorPath}`)
} catch (screenshotError) {
console.error(` ✗ Could not capture error screenshot:`, screenshotError.message)
}
}
}
}
await browser.close()
server.close()
console.log('\n✓ Mobile screenshot capture complete!')
}
captureScreenshots().catch((error) => {
console.error('Fatal error:', error)
process.exit(1)
})
================================================
FILE: .github/scripts/capture-page-screenshots.js
================================================
/**
* Capture screenshots of web app pages using Playwright
*
* This script reads route URLs and captures screenshots of each page
*/
const fs = require('fs')
const path = require('path')
// Playwright is installed into an isolated directory outside the workspace by
// the build workflow. Resolve by absolute path so a stray local `node_modules`
// can never shadow the pinned install.
const playwrightPath = process.env.PLAYWRIGHT_PATH
if (!playwrightPath) {
console.error('PLAYWRIGHT_PATH env var is required')
process.exit(1)
}
const { chromium } = require(playwrightPath)
// LocalStorage values to dismiss modals/banners (from Cypress e2e setup)
const COOKIE_CONSENT = JSON.stringify({
necessary: true,
updates: true,
analytics: true,
terms: true,
termsVersion: '1.1',
})
async function capturePageScreenshots() {
// Read routes file
const routesFile = 'page-screenshots/routes.json'
if (!fs.existsSync(routesFile)) {
console.log('No routes file found')
return
}
const routes = JSON.parse(fs.readFileSync(routesFile, 'utf-8'))
if (routes.length === 0) {
console.log('No routes to capture')
return
}
console.log(`Capturing ${routes.length} page screenshots...`)
// Launch browser
const browser = await chromium.launch()
const context = await browser.newContext({
viewport: { width: 1440, height: 900 },
// Ignore HTTPS errors for preview deployments
ignoreHTTPSErrors: true,
})
// Set a longer default timeout
context.setDefaultTimeout(60000)
// Add script to set localStorage before page loads to dismiss modals
await context.addInitScript(() => {
// Accept Safe Labs terms
localStorage.setItem('SAFE_v2__safe-labs-terms', 'true')
// Accept cookies
localStorage.setItem(
'SAFE_v2__cookies_terms',
JSON.stringify({
necessary: true,
updates: true,
analytics: true,
terms: true,
termsVersion: '1.3',
}),
)
// Dismiss outreach popup
sessionStorage.setItem('SAFE_v2__outreachPopup_session_v2', Date.now().toString())
})
const page = await context.newPage()
// Capture each route. Filenames follow the strict convention
// `<routeSlug>__<viewport>.png` where routeSlug matches [a-z0-9_]+ and
// viewport is `desktop` or `mobile`. The publish workflow validates this
// shape and rejects anything that doesn't match.
for (let i = 0; i < routes.length; i++) {
const { url, route, name, waitForSelector } = routes[i]
const routeSlug = name
.toLowerCase()
.replace(/[^a-z0-9]+/g, '_')
.replace(/^_+|_+$/g, '')
if (!routeSlug) {
console.log(`[${i + 1}/${routes.length}] Skipping: empty slug for "${name}"`)
continue
}
const screenshotName = `${routeSlug}__desktop`
console.log(`[${i + 1}/${routes.length}] Capturing: ${name} (${route})`)
try {
// Navigate to page
await page.goto(url, {
waitUntil: 'networkidle',
timeout: 60000,
})
// Wait for specific selector if configured
if (waitForSelector) {
try {
await page.locator(waitForSelector).first().waitFor({
state: 'visible',
timeout: 15000,
})
console.log(` Found selector: ${waitForSelector}`)
} catch (error) {
console.log(` Selector not found: ${waitForSelector}, continuing anyway`)
}
}
// Wait for network to settle
await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {
console.log(' Network not fully idle, continuing')
})
// Additional wait for any lazy-loaded content
await page.waitForTimeout(2000)
// Take screenshot
const screenshotPath = path.join('page-screenshots', `${screenshotName}.png`)
await page.screenshot({
path: screenshotPath,
fullPage: false, // Viewport only for consistency
animations: 'disabled',
})
console.log(` Saved: ${screenshotPath}`)
} catch (error) {
console.error(` Error capturing ${name}:`, error.message)
// Try to capture error screenshot
try {
// Error screenshots use the same convention so they pass the
// publish-side filename validation. Suffix the slug, not the viewport.
const errorPath = path.join('page-screenshots', `${routeSlug}_error__desktop.png`)
// Viewport-only to stay within the publish-side size cap.
await page.screenshot({ path: errorPath, fullPage: false })
console.log(` Error screenshot saved: ${errorPath}`)
} catch (screenshotError) {
console.error(' Could not capture error screenshot:', screenshotError.message)
}
}
}
await browser.close()
console.log('\nScreenshot capture complete!')
}
capturePageScreenshots().catch((error) => {
console.error('Fatal error:', error)
process.exit(1)
})
================================================
FILE: .github/scripts/capture-web-storybook-screenshots.js
================================================
/**
* Capture screenshots of Web Storybook stories using Playwright
*
* This script captures screenshots from the deployed Storybook preview
*/
const fs = require('fs')
const path = require('path')
const { chromium } = require('playwright')
async function captureScreenshots() {
const storyUrlsFile = 'web-storybook-screenshots/story-urls.json'
if (!fs.existsSync(storyUrlsFile)) {
console.log('No story URLs file found')
return
}
const storyUrls = JSON.parse(fs.readFileSync(storyUrlsFile, 'utf-8'))
if (storyUrls.length === 0) {
console.log('No story URLs to capture')
return
}
console.log(`Capturing ${storyUrls.length} screenshots from deployed Storybook...`)
const browser = await chromium.launch()
const context = await browser.newContext({
viewport: { width: 1280, height: 720 },
})
const page = await context.newPage()
for (let i = 0; i < storyUrls.length; i++) {
const { url, componentName, storyName } = storyUrls[i]
console.log(`[${i + 1}/${storyUrls.length}] Capturing: ${componentName} - ${storyName}`)
const cleanComponentName = componentName.replace(/[/\\]/g, '-').replace(/\s+/g, '')
try {
console.log(` 📸 Loading: ${url}`)
await page.goto(url, {
waitUntil: 'domcontentloaded',
timeout: 30000,
})
// Wait for story content to render
await page.waitForTimeout(2000)
await page.waitForLoadState('networkidle', { timeout: 5000 }).catch(() => {
console.log(` ⚠ Network not fully idle, continuing anyway`)
})
const screenshotPath = path.join('web-storybook-screenshots', `${cleanComponentName}--${storyName}.png`)
// Try to find the story content
let screenshotTarget = null
const storyRoot = page.locator('#storybook-root').first()
if ((await storyRoot.count()) > 0) {
const rootContent = await page.locator('#storybook-root > *').first()
if ((await rootContent.count()) > 0) {
screenshotTarget = storyRoot
console.log(` Using #storybook-root`)
}
}
if (screenshotTarget) {
await screenshotTarget.screenshot({
path: screenshotPath,
animations: 'disabled',
})
console.log(` ✓ Saved: ${screenshotPath}`)
} else {
// Fallback to full page screenshot
await page.screenshot({
path: screenshotPath,
animations: 'disabled',
fullPage: true,
})
console.log(` ✓ Saved (full page): ${screenshotPath}`)
}
} catch (error) {
console.error(` ✗ Error capturing ${componentName} - ${storyName}:`, error.message)
try {
const errorPath = path.join('web-storybook-screenshots', `${cleanComponentName}--${storyName}-ERROR.png`)
await page.screenshot({ path: errorPath, fullPage: true })
console.log(` ⚠ Error screenshot saved: ${errorPath}`)
} catch (screenshotError) {
console.error(` ✗ Could not capture error screenshot:`, screenshotError.message)
}
}
}
await browser.close()
console.log('\n✓ Web Storybook screenshot capture complete!')
}
captureScreenshots().catch((error) => {
console.error('Fatal error:', error)
process.exit(1)
})
================================================
FILE: .github/scripts/generate-mobile-story-urls.js
================================================
/**
* Generate Storybook URLs from changed mobile story files
*
* This script takes changed story files and converts them to Storybook preview URLs
* for the mobile app's web Storybook build
*/
const fs = require('fs')
const path = require('path')
const changedFiles = process.env.CHANGED_FILES || ''
if (!changedFiles) {
console.log('No changed files provided')
process.exit(0)
}
// Mobile Storybook is served locally from the built output
const baseUrl = 'http://localhost:6006'
const files = changedFiles.split('\n').filter(Boolean)
console.log('Processing mobile story files:', files)
/**
* Extract the title from the story file's meta export
*/
function extractTitleFromFile(filePath) {
try {
const fullPath = path.join(process.cwd(), filePath)
if (!fs.existsSync(fullPath)) {
return null
}
const content = fs.readFileSync(fullPath, 'utf-8')
// Match title with proper quote handling (separate patterns for single/double quotes)
const titleMatch = content.match(/title:\s*(?:"([^"]+)"|'([^']+)')/)
if (titleMatch) {
return titleMatch[1] || titleMatch[2]
}
return null
} catch (error) {
console.error(`Error extracting title from ${filePath}:`, error.message)
return null
}
}
/**
* Convert title to Storybook story ID
*/
function titleToStoryId(title) {
return title.replace(/\//g, '-').replace(/\s+/g, '-').toLowerCase()
}
/**
* Fallback: Convert file path to story ID
*/
function filePathToStoryId(filePath) {
let normalized = filePath.replace(/^apps\/mobile\//, '')
normalized = normalized.replace(/^src\//, '')
normalized = normalized.replace(/\.(stories|story)\.(tsx?|jsx?)$/, '')
normalized = normalized.replace(/\/index$/, '')
// Get just the component name (last part of path)
const parts = normalized.split('/')
return parts[parts.length - 1].toLowerCase()
}
/**
* Parse story file to extract story names
*/
function extractStoryNames(filePath) {
try {
const fullPath = path.join(process.cwd(), filePath)
if (!fs.existsSync(fullPath)) {
return []
}
const content = fs.readFileSync(fullPath, 'utf-8')
const stories = []
const namedExportRegex = /export\s+const\s+(\w+)\s*[:=]/g
let match
while ((match = namedExportRegex.exec(content)) !== null) {
const name = match[1]
if (name !== 'default' && name !== 'meta' && name !== 'Meta') {
stories.push(name)
}
}
if (stories.length === 0) {
stories.push('Default')
}
return stories
} catch (error) {
console.error(`Error parsing ${filePath}:`, error.message)
return ['Default']
}
}
const storyUrls = []
for (const file of files) {
// Skip native-only stories (they won't work in web Storybook)
if (file.includes('.native.stories.')) {
console.log(`Skipping native-only story: ${file}`)
continue
}
const title = extractTitleFromFile(file)
const storyId = title ? titleToStoryId(title) : filePathToStoryId(file)
const storyNames = extractStoryNames(file)
console.log(`File: ${file}`)
console.log(`Title: ${title || '(not found, using file path)'}`)
console.log(`Story ID: ${storyId}`)
console.log(`Stories: ${storyNames.join(', ')}`)
for (const storyName of storyNames) {
const storySlug = storyName.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()
const url = `${baseUrl}/iframe.html?id=${storyId}--${storySlug}&viewMode=story`
storyUrls.push({
url,
file,
componentName: title || storyId,
storyName,
})
}
}
console.log('\nGenerated URLs:')
console.log(JSON.stringify(storyUrls, null, 2))
fs.mkdirSync('mobile-screenshots', { recursive: true })
fs.writeFileSync('mobile-screenshots/story-urls.json', JSON.stringify(storyUrls, null, 2))
const outputFile = process.env.GITHUB_OUTPUT
if (outputFile) {
fs.appendFileSync(outputFile, `urls=${JSON.stringify(storyUrls)}\n`)
}
console.log(`\nGenerated ${storyUrls.length} mobile story URLs`)
================================================
FILE: .github/scripts/generate-web-story-urls.js
================================================
/**
* Generate Storybook URLs from changed web story files
*
* This script takes changed story files and converts them to Storybook preview URLs
* for the deployed web Storybook
*/
const fs = require('fs')
const path = require('path')
const changedFiles = process.env.CHANGED_FILES || ''
const baseUrl = process.env.STORYBOOK_BASE_URL || 'http://localhost:6006'
if (!changedFiles) {
console.log('No changed files provided')
process.exit(0)
}
const files = changedFiles.split('\n').filter(Boolean)
console.log('Processing web story files:', files)
/**
* Extract the title from the story file's meta export
*/
function extractTitleFromFile(filePath) {
try {
const fullPath = path.join(process.cwd(), filePath)
if (!fs.existsSync(fullPath)) {
return null
}
const content = fs.readFileSync(fullPath, 'utf-8')
// Match title with proper quote handling (separate patterns for single/double quotes)
// Use word boundary \b to ensure we match 'title:' and not 'Subtitle:' or other fields
const titleMatch = content.match(/\btitle:\s*(?:"([^"]+)"|'([^']+)')/)
if (titleMatch) {
return titleMatch[1] || titleMatch[2]
}
return null
} catch (error) {
console.error(`Error extracting title from ${filePath}:`, error.message)
return null
}
}
/**
* Convert title to Storybook story ID
*/
function titleToStoryId(title) {
return title.replace(/\//g, '-').replace(/\s+/g, '-').toLowerCase()
}
/**
* Fallback: Convert file path to story ID
* Storybook auto-generates titles from file paths like:
* apps/web/src/components/common/Chip/Chip.stories.tsx -> Components/Common/Chip
* Which becomes story ID: components-common-chip
*/
function filePathToStoryId(filePath) {
let normalized = filePath.replace(/^apps\/web\//, '')
normalized = normalized.replace(/^src\//, '')
normalized = normalized.replace(/\.(stories|story)\.(tsx?|jsx?)$/, '')
normalized = normalized.replace(/\/index$/, '')
// Remove duplicate filename if it matches parent directory (e.g., Chip/Chip -> Chip)
const parts = normalized.split('/')
if (parts.length >= 2 && parts[parts.length - 1].toLowerCase() === parts[parts.length - 2].toLowerCase()) {
parts.pop()
}
// Convert path to story ID format (path/to/Component -> path-to-component)
return parts.join('-').toLowerCase()
}
/**
* Parse story file to extract story names
*/
function extractStoryNames(filePath) {
try {
const fullPath = path.join(process.cwd(), filePath)
if (!fs.existsSync(fullPath)) {
return []
}
const content = fs.readFileSync(fullPath, 'utf-8')
const stories = []
const namedExportRegex = /export\s+const\s+(\w+)\s*[:=]/g
let match
while ((match = namedExportRegex.exec(content)) !== null) {
const name = match[1]
if (name !== 'default' && name !== 'meta' && name !== 'Meta') {
stories.push(name)
}
}
if (stories.length === 0) {
stories.push('Default')
}
return stories
} catch (error) {
console.error(`Error parsing ${filePath}:`, error.message)
return ['Default']
}
}
const storyUrls = []
for (const file of files) {
const title = extractTitleFromFile(file)
const storyId = title ? titleToStoryId(title) : filePathToStoryId(file)
const storyNames = extractStoryNames(file)
console.log(`File: ${file}`)
console.log(`Title: ${title || '(not found, using file path)'}`)
console.log(`Story ID: ${storyId}`)
console.log(`Stories: ${storyNames.join(', ')}`)
for (const storyName of storyNames) {
const storySlug = storyName.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()
const url = `${baseUrl}/iframe.html?id=${storyId}--${storySlug}&viewMode=story`
storyUrls.push({
url,
file,
componentName: title || storyId,
storyName,
})
}
}
console.log('\nGenerated URLs:')
console.log(JSON.stringify(storyUrls, null, 2))
fs.mkdirSync('web-storybook-screenshots', { recursive: true })
fs.writeFileSync('web-storybook-screenshots/story-urls.json', JSON.stringify(storyUrls, null, 2))
const outputFile = process.env.GITHUB_OUTPUT
if (outputFile) {
fs.appendFileSync(outputFile, `urls=${JSON.stringify(storyUrls)}\n`)
fs.appendFileSync(outputFile, `has_urls=${storyUrls.length > 0 ? 'true' : 'false'}\n`)
}
console.log(`\nGenerated ${storyUrls.length} web story URLs`)
================================================
FILE: .github/scripts/map-files-to-routes.js
================================================
/**
* Map changed files to affected routes by analyzing import dependencies
*
* This script builds a dependency graph from the codebase and traces
* which page files are affected by changed source files.
*/
const fs = require('fs')
const path = require('path')
// Test Safe account for screenshots
const TEST_SAFE = 'eth:0xA77DE01e157f9f57C7c4A326eeE9C4874D0598b6'
// Routes to exclude from screenshots (error pages, internal pages, pages requiring specific params)
const EXCLUDED_ROUTES = [
'/403',
'/404',
'/_offline',
'/wc', // WalletConnect - requires specific session
'/transactions/tx', // Requires specific tx id
'/transactions/msg', // Requires specific msg id
'/apps/open', // Requires specific app
'/share/safe-app', // Requires specific app
'/addOwner', // Requires specific flow
'/settings/cookies', // Just shows cookie banner
'/settings/environment-variables', // Dev settings
'/', // Redirects to /welcome or /home
]
const changedFiles = process.env.CHANGED_FILES || ''
const branchName = process.env.BRANCH_NAME || ''
if (!changedFiles) {
console.log('No changed files provided')
process.exit(0)
}
const files = changedFiles.split('\n').filter(Boolean)
console.log('Processing changed files:', files.length)
const cwd = process.cwd()
const webAppRoot = path.join(cwd, 'apps/web')
const packagesRoot = path.join(cwd, 'packages')
/**
* Parse the AppRoutes object from routes.ts to get all available routes
*/
function parseRoutesFromFile() {
const routesFile = path.join(webAppRoot, 'src/config/routes.ts')
const content = fs.readFileSync(routesFile, 'utf-8')
const routes = []
// Match all route strings in the file: '/some/path'
const routeRegex = /['"](\/([\w-]+\/)*[\w-]*)['"]/g
let match
while ((match = routeRegex.exec(content)) !== null) {
const route = match[1]
// Skip duplicates and excluded routes
if (!routes.includes(route) && !EXCLUDED_ROUTES.includes(route)) {
routes.push(route)
}
}
console.log(`Parsed ${routes.length} routes from routes.ts`)
return routes
}
/**
* Convert route to a human-readable name
*/
function routeToName(route) {
return (
route
.split('/')
.filter(Boolean)
.map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1).replace(/-/g, ' '))
.join(' ') || 'Home'
)
}
/**
* Parse import statements from a TypeScript/JavaScript file
* Returns an array of imported module paths
*/
function parseImports(filePath) {
try {
const content = fs.readFileSync(filePath, 'utf-8')
const imports = []
// Match various import patterns:
// import X from 'path'
// import { X } from 'path'
// import * as X from 'path'
// import 'path'
// export { X } from 'path'
// export * from 'path'
const importRegex = /(?:import|export)\s+(?:(?:\{[^}]*\}|[\w*\s,]+)\s+from\s+)?['"]([^'"]+)['"]/g
let match
while ((match = importRegex.exec(content)) !== null) {
imports.push(match[1])
}
// Also match dynamic imports: import('path')
const dynamicImportRegex = /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g
while ((match = dynamicImportRegex.exec(content)) !== null) {
imports.push(match[1])
}
// Also match require statements: require('path')
const requireRegex = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g
while ((match = requireRegex.exec(content)) !== null) {
imports.push(match[1])
}
return imports
} catch (error) {
return []
}
}
/**
* Try to resolve a path to an actual file (handling index files and extensions)
*/
function resolveToFile(basePath) {
const extensions = ['.tsx', '.ts', '.jsx', '.js']
// Try exact path with extensions
for (const ext of extensions) {
const withExt = basePath + ext
if (fs.existsSync(withExt)) {
return withExt
}
}
// Try as directory with index file
for (const ext of extensions) {
const indexPath = path.join(basePath, `index${ext}`)
if (fs.existsSync(indexPath)) {
return indexPath
}
}
// Already has extension
if (fs.existsSync(basePath)) {
return basePath
}
return null
}
/**
* Resolve an import path to an absolute file path
*/
function resolveImportPath(importPath, fromFile) {
const fromDir = path.dirname(fromFile)
// Handle alias paths (e.g., @/components/...)
if (importPath.startsWith('@/')) {
const resolved = path.join(webAppRoot, 'src', importPath.slice(2))
return resolveToFile(resolved)
}
if (importPath.startsWith('@/public/')) {
// Skip public assets
return null
}
// Handle workspace packages
if (importPath.startsWith('@safe-global/store/')) {
const resolved = path.join(packagesRoot, 'store/src', importPath.replace('@safe-global/store/', ''))
return resolveToFile(resolved)
}
if (importPath.startsWith('@safe-global/store')) {
const resolved = path.join(packagesRoot, 'store/src')
return resolveToFile(resolved)
}
if (importPath.startsWith('@safe-global/utils/')) {
const resolved = path.join(packagesRoot, 'utils/src', importPath.replace('@safe-global/utils/', ''))
return resolveToFile(resolved)
}
if (importPath.startsWith('@safe-global/utils')) {
const resolved = path.join(packagesRoot, 'utils/src')
return resolveToFile(resolved)
}
// Handle relative imports
if (importPath.startsWith('.')) {
const resolved = path.resolve(fromDir, importPath)
return resolveToFile(resolved)
}
// External package - skip
return null
}
/**
* Get all source files in a directory recursively
*/
function getAllSourceFiles(dir, files = []) {
if (!fs.existsSync(dir)) {
return files
}
const entries = fs.readdirSync(dir, { withFileTypes: true })
for (const e
Showing preview only (461K chars total). Download the full file or copy to clipboard to get everything.
gitextract_0zone9s6/ ├── .claude/ │ ├── commands/ │ │ ├── speckit.analyze.md │ │ ├── speckit.checklist.md │ │ ├── speckit.clarify.md │ │ ├── speckit.constitution.md │ │ ├── speckit.implement.md │ │ ├── speckit.plan.md │ │ ├── speckit.specify.md │ │ ├── speckit.tasks.md │ │ └── speckit.taskstoissues.md │ └── skills/ │ ├── cypress-e2e/ │ │ └── SKILL.md │ ├── design.figma-to-code/ │ │ ├── SKILL.md │ │ └── reference.md │ ├── design.prototype/ │ │ └── SKILL.md │ ├── design.sync-component/ │ │ └── SKILL.md │ ├── design.sync-variables/ │ │ └── SKILL.md │ └── design.verify/ │ └── SKILL.md ├── .codescene.yml ├── .cursor/ │ └── rules/ │ ├── cypress-e2e.mdc │ └── safe-monorepo.mdc ├── .editorconfig ├── .gitattributes ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug-report.md │ │ ├── feature-request.md │ │ ├── task.md │ │ └── tech-debt.md │ ├── PULL_REQUEST_TEMPLATE.md │ ├── actions/ │ │ ├── branch-slug/ │ │ │ └── action.yml │ │ ├── build/ │ │ │ └── action.yml │ │ ├── build-storybook/ │ │ │ └── action.yml │ │ ├── cache-deps/ │ │ │ └── action.yml │ │ ├── corepack/ │ │ │ └── action.yml │ │ ├── cypress/ │ │ │ └── action.yml │ │ ├── upload-coverage/ │ │ │ └── action.yml │ │ ├── upload-to-storage-branch/ │ │ │ └── action.yml │ │ └── yarn/ │ │ └── action.yml │ ├── dependabot.yml │ ├── scripts/ │ │ ├── capture-mobile-screenshots.js │ │ ├── capture-page-screenshots.js │ │ ├── capture-web-storybook-screenshots.js │ │ ├── generate-mobile-story-urls.js │ │ ├── generate-web-story-urls.js │ │ ├── map-files-to-routes.js │ │ └── publish/ │ │ ├── download-artifact.js │ │ ├── post-comment.js │ │ └── resolve-pr.js │ └── workflows/ │ ├── claude-code-review.yml │ ├── mobile-checks.yml │ ├── mobile-dev-release.yml │ ├── mobile-e2e.yml │ ├── mobile-storybook-screenshots.yml │ ├── mobile-unit-tests.yml │ ├── package-utils-unit-tests.yml │ ├── page-screenshots-build.yml │ ├── page-screenshots-publish.yml │ ├── store-codegen-check.yml │ ├── store-codegen-drift.yml │ ├── tx-builder-checks.yml │ ├── tx-builder-deploy.yml │ ├── web-argos-e2e.yml │ ├── web-checks.yml │ ├── web-chromatic.yml │ ├── web-deploy-dev.yml │ ├── web-deploy-dockerhub.yml │ ├── web-e2e-full-ondemand.yml │ ├── web-e2e-hp-ondemand.yml │ ├── web-e2e-prod-ondemand.yml │ ├── web-e2e-smoke.yml │ ├── web-nextjs-bundle-analysis.yml │ ├── web-release-start.yml │ ├── web-storybook-screenshots-build.yml │ ├── web-storybook-screenshots-publish.yml │ ├── web-storybook-tests.yml │ ├── web-tag-release.yml │ └── web-unit-tests.yml ├── .gitignore ├── .husky/ │ ├── commit-msg │ ├── pre-commit │ └── pre-push ├── .lintstagedrc.mjs ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── .specify/ │ ├── memory/ │ │ └── constitution.md │ ├── scripts/ │ │ └── bash/ │ │ ├── check-prerequisites.sh │ │ ├── common.sh │ │ ├── create-new-feature.sh │ │ ├── setup-plan.sh │ │ └── update-agent-context.sh │ └── templates/ │ ├── agent-file-template.md │ ├── checklist-template.md │ ├── plan-template.md │ ├── spec-template.md │ └── tasks-template.md ├── .vscode/ │ └── settings.json ├── .yarn/ │ └── patches/ │ ├── @tamagui-image-npm-2.0.0-rc.26-04087a216c.patch │ ├── next-npm-15.5.8-7d525d02b9.patch │ ├── react-native-ble-plx+3.5.0.patch │ ├── react-native-device-crypto-npm-0.1.7-dbd2698fc4.patch │ ├── react-native-npm-0.83.4-77634a290c.patch │ └── react-native-qrcode-styled-npm-0.3.3-b5336fc77c.patch ├── .yarnrc.yml ├── AGENTS.md ├── CLAUDE.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── README.md ├── apps/ │ ├── mobile/ │ │ ├── .eas/ │ │ │ └── build/ │ │ │ └── build-and-maestro-test.yml │ │ ├── .easignore │ │ ├── .gitignore │ │ ├── .storybook/ │ │ │ ├── index.ts │ │ │ ├── main.ts │ │ │ ├── mocks/ │ │ │ │ ├── expo-fast-refresh.js │ │ │ │ ├── react-native-quick-crypto.js │ │ │ │ ├── react-native-reanimated.js │ │ │ │ ├── react-native-worklets/ │ │ │ │ │ ├── index.js │ │ │ │ │ └── package.json │ │ │ │ └── react-refresh.js │ │ │ ├── preview.tsx │ │ │ ├── storybook.requires.d.ts │ │ │ └── tsconfig.json │ │ ├── AGENTS.md │ │ ├── README.md │ │ ├── __mocks__/ │ │ │ ├── fileMock.js │ │ │ ├── react-native-capture-protection.js │ │ │ └── react-native-collapsible-tab-view.tsx │ │ ├── app.config.ts │ │ ├── assets/ │ │ │ ├── android/ │ │ │ │ └── drawable/ │ │ │ │ ├── baseline_arrow_outward_24.xml │ │ │ │ ├── baseline_auto_awesome_motion_24.xml │ │ │ │ ├── baseline_content_copy_24.xml │ │ │ │ ├── baseline_create_24.xml │ │ │ │ ├── baseline_delete_24.xml │ │ │ │ ├── baseline_explore_24.xml │ │ │ │ └── ic_notification.xml │ │ │ └── fonts/ │ │ │ └── safe-icons/ │ │ │ └── safe-icons.icomoon.json │ │ ├── babel.config.js │ │ ├── docs/ │ │ │ ├── analytics.md │ │ │ ├── code-style.md │ │ │ ├── e2e-tests-guidelines.md │ │ │ ├── push-notifications.md │ │ │ └── release-procedure.md │ │ ├── e2e/ │ │ │ ├── README.md │ │ │ ├── config.yaml │ │ │ ├── tests/ │ │ │ │ ├── app-update/ │ │ │ │ │ ├── force-update.yml │ │ │ │ │ └── soft-update.yml │ │ │ │ ├── assets/ │ │ │ │ │ ├── __suite__.yml │ │ │ │ │ ├── change-currency.yml │ │ │ │ │ ├── view-positions.yml │ │ │ │ │ └── view-tokens-and-nfts.yml │ │ │ │ ├── connect-signer/ │ │ │ │ │ ├── __suite__.yml │ │ │ │ │ ├── connect-signer-collision.yml │ │ │ │ │ ├── connect-signer-not-owner.yml │ │ │ │ │ ├── connect-signer-success.yml │ │ │ │ │ ├── reconnect-wrong-wallet.yml │ │ │ │ │ ├── wc-gate-reconnect.yml │ │ │ │ │ └── wc-gate-switch-network.yml │ │ │ │ ├── onboarding/ │ │ │ │ │ ├── __suite__.yml │ │ │ │ │ ├── add-existing-safe.yml │ │ │ │ │ ├── add-safe-and-import-signer.yml │ │ │ │ │ ├── enhanced-onboarding-flow.yml │ │ │ │ │ ├── import-signer-private-key.yml │ │ │ │ │ ├── import-signer-seed-phrase.yml │ │ │ │ │ ├── import-signer.yml │ │ │ │ │ └── new-user-onboarding.yml │ │ │ │ ├── settings/ │ │ │ │ │ ├── __suite__.yml │ │ │ │ │ ├── address-book.yml │ │ │ │ │ ├── change-theme.yml │ │ │ │ │ ├── state-preservation.yml │ │ │ │ │ └── view-account-info.yml │ │ │ │ └── transactions/ │ │ │ │ ├── history/ │ │ │ │ │ ├── __suite__.yml │ │ │ │ │ ├── add-owner-threshold.yml │ │ │ │ │ ├── batch-transaction.yml │ │ │ │ │ ├── bulk-transactions.yml │ │ │ │ │ ├── change-threshold.yml │ │ │ │ │ ├── contract-interaction-delete-allowance.yml │ │ │ │ │ ├── contract-interaction-deposit.yml │ │ │ │ │ ├── disable-module.yml │ │ │ │ │ ├── limit-order.yml │ │ │ │ │ ├── received-transaction.yml │ │ │ │ │ ├── rejected-transaction.yml │ │ │ │ │ ├── remove-owner.yml │ │ │ │ │ ├── sent-transaction.yml │ │ │ │ │ ├── stake-claim.yml │ │ │ │ │ ├── stake-deposit.yml │ │ │ │ │ ├── swap-order.yml │ │ │ │ │ ├── swap-owner.yml │ │ │ │ │ └── view-transaction-history.yml │ │ │ │ └── pending/ │ │ │ │ ├── batch-transaction.yml │ │ │ │ ├── conflicting-transactions.yml │ │ │ │ ├── limit-order.yml │ │ │ │ ├── on-chain-rejection.yml │ │ │ │ ├── safe-shield/ │ │ │ │ │ ├── approve-malicious.yml │ │ │ │ │ ├── batch-2-actions.yml │ │ │ │ │ ├── batch-3-actions-benign.yml │ │ │ │ │ ├── batch-3-actions-warn.yml │ │ │ │ │ ├── batch-malicious.yml │ │ │ │ │ ├── contract-interaction-malicious.yml │ │ │ │ │ ├── pending-bridge-unknown-network.yml │ │ │ │ │ ├── pending-bridge.yml │ │ │ │ │ ├── send-dai-malicious.yml │ │ │ │ │ ├── send-matic-benign.yml │ │ │ │ │ ├── send-matic-malicious.yml │ │ │ │ │ ├── settings-change-fallback-handler.yml │ │ │ │ │ └── settings-change.yml │ │ │ │ ├── send-transaction.yml │ │ │ │ ├── set-fallback-handler.yml │ │ │ │ ├── settings-change.yml │ │ │ │ ├── swap-order.yml │ │ │ │ └── twap-order.yml │ │ │ └── utils/ │ │ │ ├── assertions/ │ │ │ │ ├── verify-action-detail.yml │ │ │ │ ├── verify-actions-list.yml │ │ │ │ ├── verify-advanced-details.yml │ │ │ │ ├── verify-balance-change.yml │ │ │ │ ├── verify-clipboard-content.yml │ │ │ │ ├── verify-explorer-link.yml │ │ │ │ ├── verify-review-and-execute.yml │ │ │ │ ├── verify-safe-shield-sheet.yml │ │ │ │ ├── verify-safe-shield-widget.yml │ │ │ │ ├── verify-share-link.yml │ │ │ │ ├── verify-tx-checks.yml │ │ │ │ ├── verify-tx-confirmations.yml │ │ │ │ ├── verify-tx-details.yml │ │ │ │ ├── verify-tx-history-confirmations.yml │ │ │ │ ├── verify-tx-info.yml │ │ │ │ ├── verify-tx-network.yml │ │ │ │ ├── verify-tx-recipient.yml │ │ │ │ └── verify-tx-sender.yml │ │ │ ├── components/ │ │ │ │ ├── advanced-details/ │ │ │ │ │ ├── data.yml │ │ │ │ │ └── parameters.yml │ │ │ │ ├── pending-tx/ │ │ │ │ │ ├── batch-tx-card.yml │ │ │ │ │ ├── batch-tx.yml │ │ │ │ │ ├── conflicting-txs-card.yml │ │ │ │ │ ├── limit-order-tx-card.yml │ │ │ │ │ ├── limit-order-tx.yml │ │ │ │ │ ├── on-chain-rejection-tx-card.yml │ │ │ │ │ ├── on-chain-rejection-tx.yml │ │ │ │ │ ├── send-tx-card.yml │ │ │ │ │ ├── send-tx.yml │ │ │ │ │ ├── setFallbackHandler-tx-card.yml │ │ │ │ │ ├── setFallbackHandler-tx.yml │ │ │ │ │ ├── settings-change-new-signer-tx-card.yml │ │ │ │ │ ├── settings-change-new-signer-tx.yml │ │ │ │ │ ├── swap-order-tx-card.yml │ │ │ │ │ ├── swap-order-tx.yml │ │ │ │ │ ├── tap-tx-card.yml │ │ │ │ │ ├── twap-order-tx-card.yml │ │ │ │ │ └── twap-order-tx.yml │ │ │ │ └── tx-history/ │ │ │ │ ├── add-owner-with-threshold-tx-card.yml │ │ │ │ ├── add-owner-with-threshold-tx.yml │ │ │ │ ├── batch-tx-card.yml │ │ │ │ ├── batch-tx.yml │ │ │ │ ├── bulk-tx-card.yml │ │ │ │ ├── bulk-tx.yml │ │ │ │ ├── change-threshold-tx-card.yml │ │ │ │ ├── change-threshold-tx.yml │ │ │ │ ├── contract-interaction-tx-card.yml │ │ │ │ ├── contract-interaction-tx.yml │ │ │ │ ├── disable-module-tx-card.yml │ │ │ │ ├── disable-module-tx.yml │ │ │ │ ├── limit-order-tx-card.yml │ │ │ │ ├── limit-order-tx.yml │ │ │ │ ├── received-tx-card.yml │ │ │ │ ├── received-tx.yml │ │ │ │ ├── reject-tx-card.yml │ │ │ │ ├── reject-tx.yml │ │ │ │ ├── remove-owner-tx-card.yml │ │ │ │ ├── remove-owner-tx.yml │ │ │ │ ├── sent-tx-card.yml │ │ │ │ ├── sent-tx.yml │ │ │ │ ├── stake-claim-tx-card.yml │ │ │ │ ├── stake-claim-tx.yml │ │ │ │ ├── stake-deposit-tx-card.yml │ │ │ │ ├── stake-deposit-tx.yml │ │ │ │ ├── swap-order-tx-card.yml │ │ │ │ ├── swap-order-tx.yml │ │ │ │ ├── swap-owner-tx-card.yml │ │ │ │ └── swap-owner-tx.yml │ │ │ ├── scripts/ │ │ │ │ └── defaults.js │ │ │ └── setup/ │ │ │ ├── app-start.yml │ │ │ ├── open-review-and-execute.yml │ │ │ └── switch-safe.yml │ │ ├── eas.json │ │ ├── eslint.config.mjs │ │ ├── expo-plugins/ │ │ │ ├── ssl-pinning/ │ │ │ │ ├── README.md │ │ │ │ └── withSSLPinning.js │ │ │ ├── withDrawableAssets.js │ │ │ └── withNotificationIcons.js │ │ ├── firebase.json │ │ ├── index.js │ │ ├── jest.config.js │ │ ├── metro.config.js │ │ ├── openapi-config.ts │ │ ├── package.json │ │ ├── queries.js │ │ ├── resources/ │ │ │ └── icons/ │ │ │ ├── README.md │ │ │ └── safe-icons/ │ │ │ ├── font/ │ │ │ │ ├── demo.html │ │ │ │ └── style.css │ │ │ └── safe-icons.icomoon.json │ │ ├── scripts/ │ │ │ ├── generateIconTypes.js │ │ │ ├── getCertificates.js │ │ │ └── reset-project.js │ │ ├── src/ │ │ │ ├── app/ │ │ │ │ ├── (import-accounts)/ │ │ │ │ │ ├── _layout.tsx │ │ │ │ │ ├── form.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── signers.tsx │ │ │ │ ├── (send)/ │ │ │ │ │ ├── _layout.tsx │ │ │ │ │ ├── amount.tsx │ │ │ │ │ ├── recipient.tsx │ │ │ │ │ ├── scan-qr.tsx │ │ │ │ │ └── token.tsx │ │ │ │ ├── (tabs)/ │ │ │ │ │ ├── _layout.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── settings.tsx │ │ │ │ │ └── transactions.tsx │ │ │ │ ├── +html.tsx │ │ │ │ ├── +native-intent.tsx │ │ │ │ ├── +not-found.tsx │ │ │ │ ├── _layout.tsx │ │ │ │ ├── accounts-sheet.tsx │ │ │ │ ├── action-details.tsx │ │ │ │ ├── address-book.tsx │ │ │ │ ├── app-settings.tsx │ │ │ │ ├── biometrics-opt-in.tsx │ │ │ │ ├── change-estimated-fee-sheet.tsx │ │ │ │ ├── change-signer-sheet.tsx │ │ │ │ ├── confirm-transaction.tsx │ │ │ │ ├── confirmations-sheet.tsx │ │ │ │ ├── conflict-transaction-sheet.tsx │ │ │ │ ├── contact.tsx │ │ │ │ ├── currency.tsx │ │ │ │ ├── developer.tsx │ │ │ │ ├── execute-transaction/ │ │ │ │ │ ├── _layout.tsx │ │ │ │ │ ├── ledger-connect.tsx │ │ │ │ │ ├── ledger-pairing.tsx │ │ │ │ │ └── ledger-review.tsx │ │ │ │ ├── execution-error.tsx │ │ │ │ ├── execution-success.tsx │ │ │ │ ├── get-started.tsx │ │ │ │ ├── history-transaction-details.tsx │ │ │ │ ├── how-to-execute-sheet.tsx │ │ │ │ ├── import-data/ │ │ │ │ │ ├── _layout.tsx │ │ │ │ │ ├── enter-password.tsx │ │ │ │ │ ├── file-selection.tsx │ │ │ │ │ ├── help-import.tsx │ │ │ │ │ ├── import-error.tsx │ │ │ │ │ ├── import-progress.tsx │ │ │ │ │ ├── import-success.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── review-data.tsx │ │ │ │ ├── import-signers/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── _layout.test.tsx │ │ │ │ │ ├── _layout.tsx │ │ │ │ │ ├── connect-signer-error.tsx │ │ │ │ │ ├── connect-signer-success.tsx │ │ │ │ │ ├── hardware-devices.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── ledger-addresses.tsx │ │ │ │ │ ├── ledger-connect.tsx │ │ │ │ │ ├── ledger-error.tsx │ │ │ │ │ ├── ledger-pairing.tsx │ │ │ │ │ ├── ledger-success.tsx │ │ │ │ │ ├── loading.tsx │ │ │ │ │ ├── name-signer.tsx │ │ │ │ │ ├── private-key-error.tsx │ │ │ │ │ ├── private-key-success.tsx │ │ │ │ │ ├── private-key.tsx │ │ │ │ │ ├── reconnect-error.tsx │ │ │ │ │ ├── seed-phrase-addresses.tsx │ │ │ │ │ └── signer.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── manage-tokens-sheet.tsx │ │ │ │ ├── networks-sheet.tsx │ │ │ │ ├── notifications-center.tsx │ │ │ │ ├── notifications-opt-in.tsx │ │ │ │ ├── notifications-settings.tsx │ │ │ │ ├── onboarding.tsx │ │ │ │ ├── pending-transactions.tsx │ │ │ │ ├── protocol-detail-sheet.tsx │ │ │ │ ├── review-and-confirm.tsx │ │ │ │ ├── review-and-execute.tsx │ │ │ │ ├── safe-shield-details-sheet.tsx │ │ │ │ ├── share.tsx │ │ │ │ ├── sign-transaction/ │ │ │ │ │ ├── _layout.tsx │ │ │ │ │ ├── ledger-connect.tsx │ │ │ │ │ ├── ledger-pairing.tsx │ │ │ │ │ └── ledger-review.tsx │ │ │ │ ├── signers/ │ │ │ │ │ ├── [address]/ │ │ │ │ │ │ └── private-key.tsx │ │ │ │ │ ├── [address].tsx │ │ │ │ │ ├── _layout.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── signing-error.tsx │ │ │ │ ├── signing-success.tsx │ │ │ │ ├── transaction-actions.tsx │ │ │ │ ├── transaction-checks.tsx │ │ │ │ └── transaction-parameters/ │ │ │ │ ├── (tabs)/ │ │ │ │ │ ├── _layout.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── parameters.tsx │ │ │ │ └── _layout.tsx │ │ │ ├── components/ │ │ │ │ ├── ActionsRow/ │ │ │ │ │ ├── ActionsRow.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── Alert/ │ │ │ │ │ ├── Alert.stories.tsx │ │ │ │ │ ├── Alert.test.tsx │ │ │ │ │ ├── Alert.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── theme.ts │ │ │ │ ├── Badge/ │ │ │ │ │ ├── Badge.test.tsx │ │ │ │ │ ├── Badge.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── Badge.test.tsx.snap │ │ │ │ │ ├── badge.stories.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── theme.ts │ │ │ │ ├── BadgeWrapper/ │ │ │ │ │ ├── BadgeWrapper.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── BlurredIdenticonBackground/ │ │ │ │ │ ├── BlurredIdenticonBackground.stories.tsx │ │ │ │ │ ├── BlurredIdenticonBackground.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── Camera/ │ │ │ │ │ ├── QrCamera.test.tsx │ │ │ │ │ ├── QrCamera.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── useCameraPermissionFlow.test.ts │ │ │ │ │ └── useCameraPermissionFlow.ts │ │ │ │ ├── ChainIndicator/ │ │ │ │ │ ├── ChainIndicator.stories.tsx │ │ │ │ │ ├── ChainIndicator.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── ChainsDisplay/ │ │ │ │ │ ├── ChainsDisplay.stories.tsx │ │ │ │ │ ├── ChainsDisplay.test.tsx │ │ │ │ │ ├── ChainsDisplay.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── CloseButton/ │ │ │ │ │ ├── CloseButton.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── ComingSoon/ │ │ │ │ │ └── ComingSoon.tsx │ │ │ │ ├── Container/ │ │ │ │ │ ├── Container.stories.tsx │ │ │ │ │ ├── Container.test.tsx │ │ │ │ │ ├── Container.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── Container.test.tsx.snap │ │ │ │ │ └── index.ts │ │ │ │ ├── CopyButton/ │ │ │ │ │ ├── CopyButton.stories.tsx │ │ │ │ │ ├── CopyButton.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── DataRow/ │ │ │ │ │ ├── DataRow.stories.tsx │ │ │ │ │ ├── DataRow.test.tsx │ │ │ │ │ ├── DataRow.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── Dropdown/ │ │ │ │ │ ├── DropdownLabel.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── sheetComponents.tsx │ │ │ │ ├── EncodedData/ │ │ │ │ │ ├── EncodedData.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── ErrorBoundary/ │ │ │ │ │ ├── SilentErrorBoundary.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── EthAddress/ │ │ │ │ │ ├── ETHAddress.stories.tsx │ │ │ │ │ ├── ETHAddress.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── ExecutingMonitor/ │ │ │ │ │ ├── ExecutingMonitor.test.tsx │ │ │ │ │ ├── ExecutingMonitor.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── Fiat/ │ │ │ │ │ ├── Fiat.test.tsx │ │ │ │ │ ├── Fiat.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── FiatChange/ │ │ │ │ │ ├── FiatChange.tsx │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── FiatChange.test.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── FloatingContainer/ │ │ │ │ │ ├── FloatingContainer.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── GradientText/ │ │ │ │ │ ├── GradientText.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── HashDisplay/ │ │ │ │ │ ├── HashDisplay.tsx │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── HashDisplay.test.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── HexDataDisplay/ │ │ │ │ │ ├── HexDataDisplay.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── Identicon/ │ │ │ │ │ ├── Identicon.stories.tsx │ │ │ │ │ ├── Identicon.test.tsx │ │ │ │ │ ├── Identicon.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── InfoSheet/ │ │ │ │ │ ├── InfoSheet.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── InnerShadow/ │ │ │ │ │ ├── InnerShadow.test.tsx │ │ │ │ │ ├── InnerShadow.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── InnerShadow.test.tsx.snap │ │ │ │ │ └── index.ts │ │ │ │ ├── LinearGradient/ │ │ │ │ │ ├── LinearGradien.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── LoadableSwitch/ │ │ │ │ │ ├── LoadableSwitch.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── Loader/ │ │ │ │ │ ├── Loader.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── LoadingScreen/ │ │ │ │ │ ├── LoadingScreen.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── Logo/ │ │ │ │ │ ├── Logo.test.tsx │ │ │ │ │ ├── Logo.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── NetworkBadge/ │ │ │ │ │ ├── NetworkBadge.stories.tsx │ │ │ │ │ ├── NetworkBadge.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── theme.ts │ │ │ │ ├── NetworkRow/ │ │ │ │ │ ├── NetworkRow.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── OptIn/ │ │ │ │ │ ├── OptIn.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── ParametersButton/ │ │ │ │ │ ├── ParametersButton.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── ProposalBadge/ │ │ │ │ │ ├── ProposalBadge.stories.tsx │ │ │ │ │ ├── ProposalBadge.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── ReadOnlyWarningModal/ │ │ │ │ │ ├── ReadOnlyWarningModal.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── RiskAcknowledgmentCheckbox/ │ │ │ │ │ ├── RiskAcknowledgmentCheckbox.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── SVGs/ │ │ │ │ │ └── SafeWalletLogo.tsx │ │ │ │ ├── SafeAccountInput/ │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── useImportSafe.test.tsx │ │ │ │ │ │ └── useImportSafe.ts │ │ │ │ │ └── index.tsx │ │ │ │ ├── SafeAvatar/ │ │ │ │ │ ├── SafeAvatar.stories.tsx │ │ │ │ │ └── SafeAvatar.tsx │ │ │ │ ├── SafeBottomSheet/ │ │ │ │ │ ├── SafeBottomSheet.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── SafeButton/ │ │ │ │ │ ├── SafeButton.stories.tsx │ │ │ │ │ ├── SafeButton.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── SafeCard/ │ │ │ │ │ ├── SafeCard.stories.tsx │ │ │ │ │ ├── SafeCard.test.tsx │ │ │ │ │ ├── SafeCard.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── SafeFontIcon/ │ │ │ │ │ ├── SafeFontIcon.stories.tsx │ │ │ │ │ ├── SafeFontIcon.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── SafeInput/ │ │ │ │ │ ├── SafeInput.stories.tsx │ │ │ │ │ ├── SafeInput.test.tsx │ │ │ │ │ ├── SafeInput.tsx │ │ │ │ │ ├── SafeInputWithLabel.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── styled.ts │ │ │ │ │ ├── theme.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── SafeListItem/ │ │ │ │ │ ├── SafeListItem.test.tsx │ │ │ │ │ ├── SafeListItem.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── SafeListItem.test.tsx.snap │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── theme.ts │ │ │ │ ├── SafeSearchBar/ │ │ │ │ │ └── SafeSearchBar.tsx │ │ │ │ ├── SafeSkeleton/ │ │ │ │ │ ├── SafeSkeleton.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── SafeTab/ │ │ │ │ │ ├── SafeTab.tsx │ │ │ │ │ ├── SafeTabBar.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── theme.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── SelectExecutor/ │ │ │ │ │ ├── SelectExecutor.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── SelectSigner/ │ │ │ │ │ ├── SelectSigner.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── ShareButton/ │ │ │ │ │ ├── ShareButton.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── SignerTypeBadge/ │ │ │ │ │ ├── SignerTypeBadge.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── SigningMonitor/ │ │ │ │ │ ├── SigningMonitor.test.tsx │ │ │ │ │ ├── SigningMonitor.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── StatusBanners/ │ │ │ │ │ └── PendingTransactions/ │ │ │ │ │ ├── PendingTransactions.stories.tsx │ │ │ │ │ ├── PendingTransactions.test.tsx │ │ │ │ │ ├── PendingTransactions.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── PendingTransactions.test.tsx.snap │ │ │ │ │ └── index.tsx │ │ │ │ ├── SwapHeader/ │ │ │ │ │ ├── SwapHeader.test.tsx │ │ │ │ │ ├── SwapHeader.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── Tab/ │ │ │ │ │ └── TabNameContext.tsx │ │ │ │ ├── Tag/ │ │ │ │ │ ├── Tag.stories.tsx │ │ │ │ │ ├── Tag.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── ThresholdBadge/ │ │ │ │ │ ├── ThresholdBadge.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── Title/ │ │ │ │ │ ├── LargeHeaderTitle.tsx │ │ │ │ │ ├── NavBarTitle.tsx │ │ │ │ │ ├── SectionTitle.tsx │ │ │ │ │ ├── Title.test.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── TokenAmount/ │ │ │ │ │ ├── TokenAmount.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── TokenIcon/ │ │ │ │ │ ├── TokenIcon.test.tsx │ │ │ │ │ ├── TokenIcon.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── TransactionProcessingState/ │ │ │ │ │ ├── TransactionProcessingState.test.tsx │ │ │ │ │ ├── TransactionProcessingState.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── TransactionSkeleton/ │ │ │ │ │ ├── TransactionSkeleton.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── TxInfo/ │ │ │ │ │ ├── TxInfo.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── types.ts │ │ │ │ ├── ValidatorRow/ │ │ │ │ │ ├── ValidatorRow.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── ValidatorStatus/ │ │ │ │ │ ├── ValidatorStatus.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── navigation/ │ │ │ │ │ ├── TabBarIcon.test.tsx │ │ │ │ │ ├── TabBarIcon.tsx │ │ │ │ │ └── index.ts │ │ │ │ └── transactions-list/ │ │ │ │ └── Card/ │ │ │ │ ├── AccountCard/ │ │ │ │ │ ├── AccountCard.stories.tsx │ │ │ │ │ ├── AccountCard.test.tsx │ │ │ │ │ ├── AccountCard.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── AssetsCard/ │ │ │ │ │ ├── AssetsCard.test.tsx │ │ │ │ │ ├── AssetsCard.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── SignersCard/ │ │ │ │ │ ├── SignersCard.test.tsx │ │ │ │ │ ├── SignersCard.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── StakingTxDepositCard/ │ │ │ │ │ ├── StakingTxDepositCard.stories.tsx │ │ │ │ │ ├── StakingTxDepositCard.test.tsx │ │ │ │ │ ├── StakingTxDepositCard.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── StakingTxDepositCard.test.tsx.snap │ │ │ │ │ └── index.tsx │ │ │ │ ├── StakingTxExitCard/ │ │ │ │ │ ├── StakingTxExitCard.stories.tsx │ │ │ │ │ ├── StakingTxExitCard.test.tsx │ │ │ │ │ ├── StakingTxExitCard.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── StakingTxExitCard.test.tsx.snap │ │ │ │ │ └── index.tsx │ │ │ │ ├── StakingTxWithdrawCard/ │ │ │ │ │ ├── StakingTxWithdrawCard.stories.tsx │ │ │ │ │ ├── StakingTxWithdrawCard.test.tsx │ │ │ │ │ ├── StakingTxWithdrawCard.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── StakingTxWithdrawCard.test.tsx.snap │ │ │ │ │ └── index.tsx │ │ │ │ ├── TxBatchCard/ │ │ │ │ │ ├── TxBatchCard.stories.tsx │ │ │ │ │ ├── TxBatchCard.test.tsx │ │ │ │ │ ├── TxBatchCard.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── TxBatchCard.test.tsx.snap │ │ │ │ │ └── index.tsx │ │ │ │ ├── TxBridgeCard/ │ │ │ │ │ ├── TxBridgeCard.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── TxConflictingCard/ │ │ │ │ │ ├── TxConflictingCard.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── TxContractInteractionCard/ │ │ │ │ │ ├── TxContractInteractionCard.stories.tsx │ │ │ │ │ ├── TxContractInteractionCard.test.tsx │ │ │ │ │ ├── TxContractInteractionCard.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── TxCreationCard/ │ │ │ │ │ ├── TxCreationCard.stories.tsx │ │ │ │ │ ├── TxCreationCard.test.tsx │ │ │ │ │ ├── TxCreationCard.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── TxGroupedCard/ │ │ │ │ │ ├── TxGroupedCard.stories.tsx │ │ │ │ │ ├── TxGroupedCard.test.tsx │ │ │ │ │ ├── TxGroupedCard.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── TxLifiSwapCard/ │ │ │ │ │ ├── TxLifiSwapCard.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── TxOrderCard/ │ │ │ │ │ ├── SellOrder.tsx │ │ │ │ │ ├── TwapOrder.tsx │ │ │ │ │ ├── TxOrderCard.stories.tsx │ │ │ │ │ ├── TxOrderCard.test.tsx │ │ │ │ │ ├── TxOrderCard.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── TxRejectionCard/ │ │ │ │ │ ├── TxRejectionCard.stories.tsx │ │ │ │ │ ├── TxRejectionCard.test.tsx │ │ │ │ │ ├── TxRejectionCard.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── TxSafeAppCard/ │ │ │ │ │ ├── TxSafeAppCard.stories.tsx │ │ │ │ │ ├── TxSafeAppCard.test.tsx │ │ │ │ │ ├── TxSafeAppCard.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── TxSettingsCard/ │ │ │ │ │ ├── TxSettingCard.stories.tsx │ │ │ │ │ ├── TxSettingCard.test.tsx │ │ │ │ │ ├── TxSettingsCard.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── TxSettingCard.test.tsx.snap │ │ │ │ │ └── index.tsx │ │ │ │ ├── TxTokenCard/ │ │ │ │ │ ├── TxTokenCard.stories.tsx │ │ │ │ │ ├── TxTokenCard.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── VaultTxDepositCard/ │ │ │ │ │ ├── VaultTxDepositCard.test.tsx │ │ │ │ │ ├── VaultTxDepositCard.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── VaultTxDepositCard.test.tsx.snap │ │ │ │ │ └── index.tsx │ │ │ │ └── VaultTxRedeemCard/ │ │ │ │ ├── VaultTxRedeemCard.test.tsx │ │ │ │ ├── VaultTxRedeemCard.tsx │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── VaultTxRedeemCard.test.tsx.snap │ │ │ │ └── index.tsx │ │ │ ├── config/ │ │ │ │ └── constants.ts │ │ │ ├── context/ │ │ │ │ └── NotificationsContext.tsx │ │ │ ├── features/ │ │ │ │ ├── AccountsSheet/ │ │ │ │ │ ├── AccountItem/ │ │ │ │ │ │ ├── AccountItem.stories.tsx │ │ │ │ │ │ ├── AccountItem.test.tsx │ │ │ │ │ │ ├── AccountItem.tsx │ │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ │ └── useEditAccountItem.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── utils/ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ └── editAccountHelpers.test.ts │ │ │ │ │ │ ├── editAccountHelpers.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── AccountsSheet.container.tsx │ │ │ │ │ ├── MyAccounts/ │ │ │ │ │ │ ├── MyAccounts.container.test.tsx │ │ │ │ │ │ ├── MyAccounts.container.tsx │ │ │ │ │ │ ├── MyAccountsFooter.test.tsx │ │ │ │ │ │ ├── MyAccountsFooter.tsx │ │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ │ ├── useMyAccountsAnalytics.test.ts │ │ │ │ │ │ │ ├── useMyAccountsAnalytics.ts │ │ │ │ │ │ │ └── useMyAccountsSortable.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── AccountsSheet.container.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── ActionDetails/ │ │ │ │ │ ├── ActionDetails.container.tsx │ │ │ │ │ ├── ActionsDetails.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── utils.tsx │ │ │ │ ├── AddressBook/ │ │ │ │ │ ├── Contact/ │ │ │ │ │ │ ├── ContactDetail.container.tsx │ │ │ │ │ │ ├── ContactDisplayName.container.tsx │ │ │ │ │ │ ├── ContactForm.container.tsx │ │ │ │ │ │ ├── NetworkSelector/ │ │ │ │ │ │ │ ├── AllNetworksItem.tsx │ │ │ │ │ │ │ ├── ChainItem.tsx │ │ │ │ │ │ │ ├── NetworkSelector.tsx │ │ │ │ │ │ │ ├── NetworkSelectorContent.tsx │ │ │ │ │ │ │ ├── NetworkSelectorHeader.tsx │ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ │ └── NetworkSelectorHeader.test.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ ├── ContactActionButton.tsx │ │ │ │ │ │ │ ├── ContactAddressField.tsx │ │ │ │ │ │ │ ├── ContactHeader.tsx │ │ │ │ │ │ │ ├── ContactName.tsx │ │ │ │ │ │ │ ├── ContactNameField.tsx │ │ │ │ │ │ │ ├── ContactNetworkRow.tsx │ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ │ ├── ContactActionButton.test.tsx │ │ │ │ │ │ │ │ ├── ContactAddressField.test.tsx │ │ │ │ │ │ │ │ ├── ContactHeader.test.tsx │ │ │ │ │ │ │ │ ├── ContactName.test.tsx │ │ │ │ │ │ │ │ └── ContactNetworkRow.test.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ ├── useContactNetworkData.test.ts │ │ │ │ │ │ │ ├── useContactNetworkData.ts │ │ │ │ │ │ │ ├── useDeleteContact.test.ts │ │ │ │ │ │ │ ├── useDeleteContact.ts │ │ │ │ │ │ │ ├── useEditContact.test.ts │ │ │ │ │ │ │ └── useEditContact.ts │ │ │ │ │ │ └── schemas/ │ │ │ │ │ │ ├── contactSchema.test.ts │ │ │ │ │ │ ├── contactSchema.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── List/ │ │ │ │ │ │ ├── AddressBookList.container.test.tsx │ │ │ │ │ │ ├── AddressBookList.container.tsx │ │ │ │ │ │ ├── ContactItemActions.container.tsx │ │ │ │ │ │ ├── List.container.test.tsx │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ ├── AddressBookListView.test.tsx │ │ │ │ │ │ │ ├── AddressBookListView.tsx │ │ │ │ │ │ │ ├── List/ │ │ │ │ │ │ │ │ ├── ContactItem.tsx │ │ │ │ │ │ │ │ ├── ContactListItems.tsx │ │ │ │ │ │ │ │ ├── EmptyAddressBookDark.tsx │ │ │ │ │ │ │ │ ├── EmptyAddressBookLight.tsx │ │ │ │ │ │ │ │ ├── NoContacts.tsx │ │ │ │ │ │ │ │ ├── NoContactsFound.tsx │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ └── ListView.test.tsx │ │ │ │ │ │ └── hooks/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── useContactActions.test.ts │ │ │ │ │ │ └── useContactActions.ts │ │ │ │ │ └── index.tsx │ │ │ │ ├── AdvancedDetails/ │ │ │ │ │ ├── TxData.container.tsx │ │ │ │ │ ├── TxParameters.container.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ └── Receiver/ │ │ │ │ │ │ ├── Receiver.tsx │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ └── Receiver.test.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── formatters/ │ │ │ │ │ │ ├── arrayValue.test.tsx │ │ │ │ │ │ ├── arrayValue.tsx │ │ │ │ │ │ ├── singleValue.test.tsx │ │ │ │ │ │ └── singleValue.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── utils/ │ │ │ │ │ ├── formatParameters.test.tsx │ │ │ │ │ ├── formatParameters.tsx │ │ │ │ │ ├── formatTxDetails.test.tsx │ │ │ │ │ └── formatTxDetails.tsx │ │ │ │ ├── AppUpdate/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── ForceUpdateScreen.tsx │ │ │ │ │ │ └── SoftUpdatePrompt.tsx │ │ │ │ │ ├── constants.ts │ │ │ │ │ └── hooks/ │ │ │ │ │ ├── appUpdateE2eState.ts │ │ │ │ │ ├── useAppUpdateCheck.e2e.ts │ │ │ │ │ └── useAppUpdateCheck.ts │ │ │ │ ├── Assets/ │ │ │ │ │ ├── Assets.container.tsx │ │ │ │ │ ├── Assets.error.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── AssetsHeader/ │ │ │ │ │ │ │ ├── AssetsHeader.container.tsx │ │ │ │ │ │ │ ├── AssetsHeader.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── styles.ts │ │ │ │ │ │ ├── Balance/ │ │ │ │ │ │ │ ├── Balance.container.tsx │ │ │ │ │ │ │ ├── Balance.tsx │ │ │ │ │ │ │ ├── ChainItems.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── Fallback/ │ │ │ │ │ │ │ ├── Fallback.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── ManageTokensSheet/ │ │ │ │ │ │ │ ├── ManageTokensSheet.container.tsx │ │ │ │ │ │ │ ├── ManageTokensSheet.test.tsx │ │ │ │ │ │ │ ├── ManageTokensSheet.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── NFTs/ │ │ │ │ │ │ │ ├── NFTItem.tsx │ │ │ │ │ │ │ ├── NFTs.container.test.tsx │ │ │ │ │ │ │ ├── NFTs.container.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── Navbar/ │ │ │ │ │ │ │ ├── Navbar.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── theme.ts │ │ │ │ │ │ ├── NoFunds/ │ │ │ │ │ │ │ ├── EmptyNFT.tsx │ │ │ │ │ │ │ ├── EmptyToken.tsx │ │ │ │ │ │ │ ├── NoFunds.test.tsx │ │ │ │ │ │ │ ├── NoFunds.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── Positions/ │ │ │ │ │ │ │ ├── PositionItem/ │ │ │ │ │ │ │ │ ├── PositionFiatChange.test.tsx │ │ │ │ │ │ │ │ ├── PositionFiatChange.tsx │ │ │ │ │ │ │ │ ├── PositionItem.test.tsx │ │ │ │ │ │ │ │ ├── PositionItem.tsx │ │ │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ │ │ ├── PositionFiatChange.test.tsx.snap │ │ │ │ │ │ │ │ │ └── PositionItem.test.tsx.snap │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── Positions.container.test.tsx │ │ │ │ │ │ │ ├── Positions.container.tsx │ │ │ │ │ │ │ ├── PositionsEmpty/ │ │ │ │ │ │ │ │ ├── PositionsEmpty.test.tsx │ │ │ │ │ │ │ │ ├── PositionsEmpty.tsx │ │ │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ │ │ └── PositionsEmpty.test.tsx.snap │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── PositionsError/ │ │ │ │ │ │ │ │ ├── PositionsError.test.tsx │ │ │ │ │ │ │ │ ├── PositionsError.tsx │ │ │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ │ │ └── PositionsError.test.tsx.snap │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── ProtocolDetailSheet/ │ │ │ │ │ │ │ │ ├── ProtocolDetailSheet.container.tsx │ │ │ │ │ │ │ │ ├── ProtocolDetailSheet.tsx │ │ │ │ │ │ │ │ ├── ProtocolDetailSheetHeader.tsx │ │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ │ ├── utils.test.ts │ │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ │ ├── ProtocolSection/ │ │ │ │ │ │ │ │ ├── ProtocolSection.test.tsx │ │ │ │ │ │ │ │ ├── ProtocolSection.tsx │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── ReadOnly/ │ │ │ │ │ │ │ ├── ReadOnly.container.test.tsx │ │ │ │ │ │ │ ├── ReadOnly.container.tsx │ │ │ │ │ │ │ ├── ReadOnly.tsx │ │ │ │ │ │ │ └── ReadOnlyIconBlock.tsx │ │ │ │ │ │ └── Tokens/ │ │ │ │ │ │ ├── TokenItem.tsx │ │ │ │ │ │ ├── Tokens.container.test.tsx │ │ │ │ │ │ ├── Tokens.container.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── useTokenBalances.ts │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ └── usePositions.ts │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.ts │ │ │ │ ├── ChangeEstimatedFeeSheet/ │ │ │ │ │ ├── ChangeEstimatedFeeSheet.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ └── ChangeEstimatedFeeForm/ │ │ │ │ │ │ ├── ChangeEstimatedFeeForm.tsx │ │ │ │ │ │ ├── helpers.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── schema.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── ChangeSignerSheet/ │ │ │ │ │ ├── ChangeSignerSheet.container.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── useAvailableSigners.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── ConfirmTx/ │ │ │ │ │ ├── ConfirmTx.container.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── CanNotSign/ │ │ │ │ │ │ │ ├── CanNotSign.test.tsx │ │ │ │ │ │ │ ├── CanNotSign.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── ConfirmTxForm/ │ │ │ │ │ │ │ ├── ConfirmTxForm.test.tsx │ │ │ │ │ │ │ ├── ConfirmTxForm.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── ConfirmationView/ │ │ │ │ │ │ │ ├── ConfirmationView.tsx │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── types.ts │ │ │ │ │ │ ├── ConfirmationsInfo/ │ │ │ │ │ │ │ ├── ConfirmationsInfo.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── ExecuteForm/ │ │ │ │ │ │ │ ├── ExecuteForm.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── ListTable/ │ │ │ │ │ │ │ ├── ListTable.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── LoadingTx/ │ │ │ │ │ │ │ ├── LoadingTx.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── PendingTx/ │ │ │ │ │ │ │ ├── PendingTx.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── PendingTxInfo/ │ │ │ │ │ │ │ ├── PendingTxInfo.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── ReviewAndConfirm/ │ │ │ │ │ │ │ ├── ReviewAndConfirmContainer.tsx │ │ │ │ │ │ │ ├── ReviewAndConfirmView.tsx │ │ │ │ │ │ │ ├── ReviewFooter.test.tsx │ │ │ │ │ │ │ ├── ReviewFooter.tsx │ │ │ │ │ │ │ ├── ReviewHeader.tsx │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── tabs/ │ │ │ │ │ │ │ ├── DataTab.tsx │ │ │ │ │ │ │ ├── HashesTab.tsx │ │ │ │ │ │ │ └── JSONTab.tsx │ │ │ │ │ │ ├── SignForm/ │ │ │ │ │ │ │ ├── SignForm.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── SignTransaction/ │ │ │ │ │ │ │ ├── SignError.tsx │ │ │ │ │ │ │ ├── SignSuccess.tsx │ │ │ │ │ │ │ └── hooks/ │ │ │ │ │ │ │ ├── useTransactionSigning.test.ts │ │ │ │ │ │ │ └── useTransactionSigning.ts │ │ │ │ │ │ ├── TransactionChecks/ │ │ │ │ │ │ │ ├── TransactionChecks.tsx │ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ │ └── TransactionChecks.test.tsx │ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ │ ├── TransactionChecksBottomContent.tsx │ │ │ │ │ │ │ │ ├── TransactionChecksLeftNode.tsx │ │ │ │ │ │ │ │ └── __tests__/ │ │ │ │ │ │ │ │ ├── TransactionChecksBottomContent.test.tsx │ │ │ │ │ │ │ │ └── TransactionChecksLeftNode.test.tsx │ │ │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ │ │ └── useTransactionSecurity.test.ts │ │ │ │ │ │ │ │ └── useTransactionSecurity.ts │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── utils/ │ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ │ └── transactionChecksUtils.test.ts │ │ │ │ │ │ │ └── transactionChecksUtils.ts │ │ │ │ │ │ ├── TransactionHeader/ │ │ │ │ │ │ │ ├── TransactionHeader.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── TransactionInfo/ │ │ │ │ │ │ │ ├── TransactionInfo.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── confirmation-views/ │ │ │ │ │ │ ├── AddSigner/ │ │ │ │ │ │ │ ├── AddSigner.tsx │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── utils.tsx │ │ │ │ │ │ ├── AlreadySigned/ │ │ │ │ │ │ │ ├── AlreadySigned.test.tsx │ │ │ │ │ │ │ ├── AlreadySigned.tsx │ │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ │ └── AlreadySigned.test.tsx.snap │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── BridgeTransaction/ │ │ │ │ │ │ │ ├── BridgeTransaction.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── CancelTx/ │ │ │ │ │ │ │ ├── CancelTx.tsx │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── utils.tsx │ │ │ │ │ │ ├── Contract/ │ │ │ │ │ │ │ ├── Contract.tsx │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── utils.tsx │ │ │ │ │ │ ├── GenericView/ │ │ │ │ │ │ │ ├── GenericView.tsx │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── utils.tsx │ │ │ │ │ │ ├── LifiSwapTransaction/ │ │ │ │ │ │ │ ├── LifiSwapHeader.tsx │ │ │ │ │ │ │ ├── LifiSwapTransaction.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── RemoveSigner/ │ │ │ │ │ │ │ ├── RemoveSigner.tsx │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── utils.tsx │ │ │ │ │ │ ├── SendNFT/ │ │ │ │ │ │ │ ├── SendNFT.tsx │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── utils.tsx │ │ │ │ │ │ ├── Stake/ │ │ │ │ │ │ │ ├── Deposit/ │ │ │ │ │ │ │ │ ├── Deposit.stories.tsx │ │ │ │ │ │ │ │ ├── Deposit.test.tsx │ │ │ │ │ │ │ │ ├── Deposit.tsx │ │ │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ │ │ └── Deposit.test.tsx.snap │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ ├── Exit/ │ │ │ │ │ │ │ │ ├── Exit.stories.tsx │ │ │ │ │ │ │ │ ├── Exit.test.tsx │ │ │ │ │ │ │ │ ├── Exit.tsx │ │ │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ │ │ └── Exit.test.tsx.snap │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ ├── WithdrawRequest/ │ │ │ │ │ │ │ │ ├── WithdrawRequest.stories.tsx │ │ │ │ │ │ │ │ ├── WithdrawRequest.test.tsx │ │ │ │ │ │ │ │ ├── WithdrawRequest.tsx │ │ │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ │ │ └── WithdrawRequest.test.tsx.snap │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ ├── utils.test.tsx │ │ │ │ │ │ │ └── utils.tsx │ │ │ │ │ │ ├── SwapOrder/ │ │ │ │ │ │ │ ├── StatusLabel/ │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ ├── SwapOrder.tsx │ │ │ │ │ │ │ ├── SwapOrderHeader.test.tsx │ │ │ │ │ │ │ ├── SwapOrderHeader.tsx │ │ │ │ │ │ │ ├── TwapFallbackHandlerWarning.tsx │ │ │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ │ ├── useRecipientItem.test.tsx │ │ │ │ │ │ │ │ ├── useRecipientItem.tsx │ │ │ │ │ │ │ │ └── useRecipientItems.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── TokenTransfer/ │ │ │ │ │ │ │ ├── TokenTransfer.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── VaultDeposit/ │ │ │ │ │ │ │ ├── VaultDeposit.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── utils.tsx │ │ │ │ │ │ └── VaultRedeem/ │ │ │ │ │ │ ├── VaultRedeem.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── utils.tsx │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── useOpenExplorer/ │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── useOpenExplorer.ts │ │ │ │ │ │ ├── useTransactionData.test.ts │ │ │ │ │ │ ├── useTransactionData.ts │ │ │ │ │ │ ├── useTransactionSigner.test.ts │ │ │ │ │ │ ├── useTransactionSigner.ts │ │ │ │ │ │ ├── useTxSignerActions.test.ts │ │ │ │ │ │ ├── useTxSignerActions.ts │ │ │ │ │ │ ├── useTxSignerAutoSelection.test.ts │ │ │ │ │ │ ├── useTxSignerAutoSelection.ts │ │ │ │ │ │ ├── useTxSignerState.test.ts │ │ │ │ │ │ └── useTxSignerState.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── ConfirmationsSheet/ │ │ │ │ │ ├── ConfirmationsSheet.container.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── ConflictTxSheet/ │ │ │ │ │ ├── ConflictTxSheet.container.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── DataImport/ │ │ │ │ │ ├── DataTransfer.container.tsx │ │ │ │ │ ├── EnterPassword.container.tsx │ │ │ │ │ ├── FileSelection.container.tsx │ │ │ │ │ ├── HelpImport.container.tsx │ │ │ │ │ ├── ImportError.container.tsx │ │ │ │ │ ├── ImportProgressScreen.container.tsx │ │ │ │ │ ├── ImportSuccessScreen.container.tsx │ │ │ │ │ ├── ReviewData.container.tsx │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ ├── EnterPassword.test.tsx │ │ │ │ │ │ ├── FileSelection.test.tsx │ │ │ │ │ │ ├── ImportProgressScreen.test.tsx │ │ │ │ │ │ ├── ReviewData.test.tsx │ │ │ │ │ │ └── useLegacyImport.test.ts │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── DataTransferView.tsx │ │ │ │ │ │ ├── EnterPasswordView.tsx │ │ │ │ │ │ ├── FileSelectionView.tsx │ │ │ │ │ │ ├── HelpImportView.tsx │ │ │ │ │ │ ├── ImportErrorView.tsx │ │ │ │ │ │ ├── ImportProgressScreenView.tsx │ │ │ │ │ │ ├── ImportSuccessScreenView.tsx │ │ │ │ │ │ └── ReviewDataView.tsx │ │ │ │ │ ├── context/ │ │ │ │ │ │ └── DataImportProvider.tsx │ │ │ │ │ ├── helpers/ │ │ │ │ │ │ ├── transforms.test.ts │ │ │ │ │ │ └── transforms.ts │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ └── useLegacyImport.ts │ │ │ │ │ └── index.tsx │ │ │ │ ├── Developer/ │ │ │ │ │ ├── Developer.container.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ └── Developer.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── types.ts │ │ │ │ ├── ExecuteTx/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── CanNotEstimate/ │ │ │ │ │ │ │ ├── CanNotEstimate.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── CanNotExecute/ │ │ │ │ │ │ │ ├── CanNotExecute.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── EstimatedNetworkFee/ │ │ │ │ │ │ │ ├── EstimatedNetworkFee.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── ExecuteError.tsx │ │ │ │ │ │ ├── ExecuteSuccess.tsx │ │ │ │ │ │ ├── RelayFee/ │ │ │ │ │ │ │ ├── RelayFee.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── ReviewAndExecute/ │ │ │ │ │ │ │ ├── ReviewAndExecuteContainer.tsx │ │ │ │ │ │ │ ├── ReviewExecuteFooter.tsx │ │ │ │ │ │ │ ├── ReviewExecuteFooterSkeleton.tsx │ │ │ │ │ │ │ ├── helpers.test.ts │ │ │ │ │ │ │ └── helpers.ts │ │ │ │ │ │ └── SignerFee/ │ │ │ │ │ │ ├── SignerFee.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── hooks/ │ │ │ │ │ ├── useClearEstimatedFeeOnMount.ts │ │ │ │ │ ├── useExecutionFlow.test.ts │ │ │ │ │ ├── useExecutionFlow.ts │ │ │ │ │ ├── useExecutionFunds.test.tsx │ │ │ │ │ ├── useExecutionFunds.ts │ │ │ │ │ ├── useGasFee.test.ts │ │ │ │ │ ├── useGasFee.ts │ │ │ │ │ └── useTransactionExecution.ts │ │ │ │ ├── GetStarted/ │ │ │ │ │ ├── GetStarted.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── HistoryTransactionDetails/ │ │ │ │ │ ├── HistoryTransactionDetails.container.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── HistoryAdvancedDetailsButton/ │ │ │ │ │ │ │ ├── HistoryAdvancedDetailsButton.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── HistoryConfirmationsInfo/ │ │ │ │ │ │ │ ├── HistoryConfirmationsInfo.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── HistoryTransactionHeader/ │ │ │ │ │ │ │ ├── HistoryTransactionHeader.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── HistoryTransactionInfo/ │ │ │ │ │ │ │ ├── HistoryTransactionInfo.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── HistoryTransactionView/ │ │ │ │ │ │ │ ├── HistoryTransactionView.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── ViewOnExplorerButton/ │ │ │ │ │ │ │ ├── ViewOnExplorerButton.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── history-views/ │ │ │ │ │ │ │ ├── CancelTx.tsx │ │ │ │ │ │ │ ├── HistoryAddSigner.tsx │ │ │ │ │ │ │ ├── HistoryChangeThreshold.tsx │ │ │ │ │ │ │ ├── HistoryContract.tsx │ │ │ │ │ │ │ ├── HistoryGenericView.tsx │ │ │ │ │ │ │ ├── HistoryRemoveSigner.tsx │ │ │ │ │ │ │ ├── HistoryStakeDeposit.tsx │ │ │ │ │ │ │ ├── HistoryStakeWithdraw.tsx │ │ │ │ │ │ │ ├── HistoryStakeWithdrawRequest.tsx │ │ │ │ │ │ │ ├── HistorySwapOrder.tsx │ │ │ │ │ │ │ ├── HistorySwapSigner.tsx │ │ │ │ │ │ │ ├── HistoryTokenTransfer.tsx │ │ │ │ │ │ │ ├── HistoryTransactionBase.tsx │ │ │ │ │ │ │ ├── HistoryVaultDeposit.tsx │ │ │ │ │ │ │ ├── HistoryVaultRedeem.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── shared/ │ │ │ │ │ │ ├── NetworkDisplay.tsx │ │ │ │ │ │ ├── ThresholdChangeDisplay.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── utils/ │ │ │ │ │ ├── header.test.ts │ │ │ │ │ └── header.ts │ │ │ │ ├── HowToExecuteSheet/ │ │ │ │ │ ├── HowToExecuteSheet.container.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── RelayAvailable/ │ │ │ │ │ │ │ ├── RelayAvailable.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── RelayUnavailable/ │ │ │ │ │ │ ├── RelayUnavailable.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── ImportReadOnly/ │ │ │ │ │ ├── AddSignersForm.container.tsx │ │ │ │ │ ├── ImportAccountForm.container.tsx │ │ │ │ │ ├── NetworkBadge.container.tsx │ │ │ │ │ ├── ScanQrAccount.container.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── AddSignersFormView.tsx │ │ │ │ │ │ ├── AvailableNetworks.tsx │ │ │ │ │ │ ├── ImportAccountFormView.tsx │ │ │ │ │ │ ├── ScanQrAccountView.tsx │ │ │ │ │ │ └── VerificationStatus.tsx │ │ │ │ │ ├── helpers/ │ │ │ │ │ │ ├── safes.test.tsx │ │ │ │ │ │ └── safes.tsx │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ └── useScan/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── useScan.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── schema.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── ImportSigner/ │ │ │ │ │ ├── ImportSigner.container.tsx │ │ │ │ │ ├── ImportSigner.test.tsx │ │ │ │ │ ├── SeedPhraseAddresses.container.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── ConnectSignerError/ │ │ │ │ │ │ │ ├── ConnectSignerError.tsx │ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ │ └── ConnectSignerError.test.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── ImportError/ │ │ │ │ │ │ │ ├── ImportError.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── ImportSuccess/ │ │ │ │ │ │ │ ├── ImportSuccess.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── LoadingImport/ │ │ │ │ │ │ │ ├── LoadingImport.container.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── NameSigner/ │ │ │ │ │ │ │ ├── NameSigner.container.tsx │ │ │ │ │ │ │ ├── NameSignerView.tsx │ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ │ ├── NameSigner.test.tsx │ │ │ │ │ │ │ │ └── buildDefaultName.test.ts │ │ │ │ │ │ │ ├── buildDefaultName.ts │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── ReconnectError/ │ │ │ │ │ │ ├── ReconnectError.tsx │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ └── ReconnectError.test.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ ├── useImportPrivateKey.test.ts │ │ │ │ │ │ │ ├── useImportSeedPhraseAddress.test.ts │ │ │ │ │ │ │ ├── useSeedPhraseAddresses.test.ts │ │ │ │ │ │ │ └── useSignerCollisionGuard.test.ts │ │ │ │ │ │ ├── useImportPrivateKey.ts │ │ │ │ │ │ ├── useImportSeedPhraseAddress.ts │ │ │ │ │ │ ├── useSeedPhraseAddresses.ts │ │ │ │ │ │ └── useSignerCollisionGuard.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── utils/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── findCollidingSigner.test.ts │ │ │ │ │ ├── findCollidingSigner.ts │ │ │ │ │ └── showCollisionAlert.ts │ │ │ │ ├── ImportSigners/ │ │ │ │ │ ├── ImportSigners.container.tsx │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── ImportSigners.container.test.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── Ledger/ │ │ │ │ │ ├── LedgerAddresses.container.tsx │ │ │ │ │ ├── LedgerConnect.container.tsx │ │ │ │ │ ├── LedgerIntro.container.tsx │ │ │ │ │ ├── LedgerPairing.container.tsx │ │ │ │ │ ├── LedgerSuccess.container.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── AddressItem.tsx │ │ │ │ │ │ ├── AddressesEmptyState.tsx │ │ │ │ │ │ ├── BluetoothError.tsx │ │ │ │ │ │ ├── DeviceList.tsx │ │ │ │ │ │ ├── EmptyState.tsx │ │ │ │ │ │ ├── LedgerConnect.tsx │ │ │ │ │ │ ├── LedgerError.tsx │ │ │ │ │ │ ├── LedgerImportError.tsx │ │ │ │ │ │ ├── LedgerPairing.tsx │ │ │ │ │ │ ├── LedgerProgress.tsx │ │ │ │ │ │ ├── LedgerSignerBadge.tsx │ │ │ │ │ │ ├── LedgerSuccess.tsx │ │ │ │ │ │ ├── LoadMoreButton.tsx │ │ │ │ │ │ ├── PairingError.tsx │ │ │ │ │ │ ├── PairingProgress.tsx │ │ │ │ │ │ └── ScanningProgress.tsx │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── useBluetoothStatus.test.ts │ │ │ │ │ │ ├── useBluetoothStatus.ts │ │ │ │ │ │ ├── useImportLedgerAddress.test.ts │ │ │ │ │ │ ├── useImportLedgerAddress.ts │ │ │ │ │ │ ├── useLedgerAddresses.test.ts │ │ │ │ │ │ ├── useLedgerAddresses.ts │ │ │ │ │ │ ├── useLedgerConnection.test.ts │ │ │ │ │ │ ├── useLedgerConnection.ts │ │ │ │ │ │ ├── useLedgerDeviceScanning.test.ts │ │ │ │ │ │ └── useLedgerDeviceScanning.ts │ │ │ │ │ ├── icons/ │ │ │ │ │ │ ├── BluetoothIcon.tsx │ │ │ │ │ │ ├── DashIcon.tsx │ │ │ │ │ │ ├── LedgerIcon.tsx │ │ │ │ │ │ ├── PhoneIcon.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── LedgerExecute/ │ │ │ │ │ ├── LedgerConnect.container.tsx │ │ │ │ │ ├── LedgerPairing.container.tsx │ │ │ │ │ ├── LedgerReview.container.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── LedgerSign/ │ │ │ │ │ ├── LedgerConnect.container.tsx │ │ │ │ │ ├── LedgerPairing.container.tsx │ │ │ │ │ ├── LedgerReview.container.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── NetworksSheet/ │ │ │ │ │ ├── NetworksSheet.container.tsx │ │ │ │ │ ├── NetworksSheetFooter.tsx │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── NetworksSheetFooter.test.tsx │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ └── useScanForNewNetworks.test.ts │ │ │ │ │ │ └── useScanForNewNetworks.ts │ │ │ │ │ └── index.tsx │ │ │ │ ├── Notifications/ │ │ │ │ │ ├── NotificationsCenter.container.tsx │ │ │ │ │ ├── NotificationsSettings.container.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── EmptyBell.tsx │ │ │ │ │ │ ├── NotificationPermissions.tsx │ │ │ │ │ │ ├── NotificationsScreenEmpty.tsx │ │ │ │ │ │ └── NotificationsSettingsView.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── Onboarding/ │ │ │ │ │ ├── Onboarding.container.test.tsx │ │ │ │ │ ├── Onboarding.container.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── OnboardingCarousel/ │ │ │ │ │ │ │ ├── CarouselFeedback.test.tsx │ │ │ │ │ │ │ ├── CarouselFeedback.tsx │ │ │ │ │ │ │ ├── CarouselItem.test.tsx │ │ │ │ │ │ │ ├── CarouselItem.tsx │ │ │ │ │ │ │ ├── OnboardingCarousel.native.stories.tsx │ │ │ │ │ │ │ ├── OnboardingCarousel.test.tsx │ │ │ │ │ │ │ ├── OnboardingCarousel.tsx │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── items.tsx │ │ │ │ │ │ └── OnboardingHeader/ │ │ │ │ │ │ ├── OnboardingHeader.test.tsx │ │ │ │ │ │ ├── OnboardingHeader.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── PendingTx/ │ │ │ │ │ ├── PendingTx.container.test.tsx │ │ │ │ │ ├── PendingTx.container.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ └── PendingTxList/ │ │ │ │ │ │ ├── PendingTxList.container.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── utils.tsx │ │ │ │ ├── PrivateKey/ │ │ │ │ │ ├── PrivateKey.container.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── PrivateKeyView.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── SafeShield/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── AnalysisDetails/ │ │ │ │ │ │ │ ├── AnalysisDetails.stories.tsx │ │ │ │ │ │ │ ├── AnalysisDetails.test.tsx │ │ │ │ │ │ │ ├── AnalysisDetails.tsx │ │ │ │ │ │ │ ├── AnalysisDetailsContent.test.tsx │ │ │ │ │ │ │ ├── AnalysisDetailsContent.tsx │ │ │ │ │ │ │ ├── AnalysisDetailsHeader.test.tsx │ │ │ │ │ │ │ ├── AnalysisDetailsHeader.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── AnalysisGroup/ │ │ │ │ │ │ │ ├── AnalysisDisplay/ │ │ │ │ │ │ │ │ ├── AnalysisDisplay.test.tsx │ │ │ │ │ │ │ │ ├── AnalysisDisplay.tsx │ │ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ │ │ ├── AddressChanges.test.tsx │ │ │ │ │ │ │ │ │ ├── AddressChanges.tsx │ │ │ │ │ │ │ │ │ ├── AddressListItem.test.tsx │ │ │ │ │ │ │ │ │ ├── AddressListItem.tsx │ │ │ │ │ │ │ │ │ ├── AnalysisDetailsDropdown.test.tsx │ │ │ │ │ │ │ │ │ ├── AnalysisDetailsDropdown.tsx │ │ │ │ │ │ │ │ │ ├── AnalysisDisplay.stories.tsx │ │ │ │ │ │ │ │ │ ├── AnalysisIssuesDisplay.test.tsx │ │ │ │ │ │ │ │ │ ├── AnalysisIssuesDisplay.tsx │ │ │ │ │ │ │ │ │ ├── ShowAllAddress.test.tsx │ │ │ │ │ │ │ │ │ └── ShowAllAddress.tsx │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── AnalysisGroup.stories.tsx │ │ │ │ │ │ │ ├── AnalysisGroup.test.tsx │ │ │ │ │ │ │ ├── AnalysisGroup.tsx │ │ │ │ │ │ │ ├── DelegateCallItem.tsx │ │ │ │ │ │ │ ├── FallbackHandlerItem.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── AnalysisLabel/ │ │ │ │ │ │ │ ├── AnalysisLabel.stories.tsx │ │ │ │ │ │ │ ├── AnalysisLabel.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── AnalysisPaper/ │ │ │ │ │ │ │ ├── AnalysisPaper.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── BalanceChange/ │ │ │ │ │ │ │ ├── BalanceChange.stories.tsx │ │ │ │ │ │ │ ├── BalanceChangeBlock.test.tsx │ │ │ │ │ │ │ ├── BalanceChangeBlock.tsx │ │ │ │ │ │ │ ├── BalanceChangeItem.test.tsx │ │ │ │ │ │ │ ├── BalanceChangeItem.tsx │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── utils/ │ │ │ │ │ │ │ ├── utils.test.ts │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ ├── SafeShieldDetailsSheet/ │ │ │ │ │ │ │ ├── SafeShieldDetailsSheet.container.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── SafeShieldHeadline/ │ │ │ │ │ │ │ ├── SafeShieldHeadline.stories.tsx │ │ │ │ │ │ │ ├── SafeShieldHeadline.test.tsx │ │ │ │ │ │ │ ├── SafeShieldHeadline.tsx │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ ├── theme.ts │ │ │ │ │ │ │ └── variants.ts │ │ │ │ │ │ ├── SafeShieldIcons/ │ │ │ │ │ │ │ ├── SafeShieldInfo.tsx │ │ │ │ │ │ │ ├── SafeShieldIssues.tsx │ │ │ │ │ │ │ ├── SafeShieldNeutral.tsx │ │ │ │ │ │ │ ├── SafeShieldOk.tsx │ │ │ │ │ │ │ ├── SafeShieldWarning.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── SafeShieldWidget/ │ │ │ │ │ │ │ ├── SafeShieldWidget.stories.tsx │ │ │ │ │ │ │ ├── SafeShieldWidget.tsx │ │ │ │ │ │ │ ├── WidgetAction/ │ │ │ │ │ │ │ │ ├── WidgetAction.stories.tsx │ │ │ │ │ │ │ │ ├── WidgetAction.tsx │ │ │ │ │ │ │ │ ├── constants.tsx │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── WidgetDisplay/ │ │ │ │ │ │ │ │ ├── ErrorWidget/ │ │ │ │ │ │ │ │ │ ├── ErrorWidget.test.tsx │ │ │ │ │ │ │ │ │ ├── ErrorWidget.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ ├── LoadingWidget/ │ │ │ │ │ │ │ │ │ ├── LoadingWidget.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ ├── WidgetDisplay.stories.tsx │ │ │ │ │ │ │ │ ├── WidgetDisplay.tsx │ │ │ │ │ │ │ │ ├── WidgetDisplayWrapper.tsx │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── theme.ts │ │ │ │ │ │ └── TransactionSimulation/ │ │ │ │ │ │ ├── TransactionSimulation.tsx │ │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ │ └── useTransactionSimulation.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── useAnalysisAddress.ts │ │ │ │ │ │ ├── useCounterpartyAnalysis.ts │ │ │ │ │ │ ├── useSafeShieldSeverity.ts │ │ │ │ │ │ └── useThreatAnalysis.ts │ │ │ │ │ └── theme.ts │ │ │ │ ├── Send/ │ │ │ │ │ ├── EnterAmount.container.tsx │ │ │ │ │ ├── ScanQrSend.container.tsx │ │ │ │ │ ├── SelectRecipient.container.tsx │ │ │ │ │ ├── SelectToken.container.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── AddToAddressBookModal.tsx │ │ │ │ │ │ ├── AmountDisplay.tsx │ │ │ │ │ │ ├── CustomNonceModal.tsx │ │ │ │ │ │ ├── DialogModal.tsx │ │ │ │ │ │ ├── FooterAction.tsx │ │ │ │ │ │ ├── KnownOtherChainWarning.tsx │ │ │ │ │ │ ├── NonceBottomSheet.tsx │ │ │ │ │ │ ├── ProposerBottomSheet.tsx │ │ │ │ │ │ ├── RecipientDisplay.tsx │ │ │ │ │ │ ├── RecipientHeader.tsx │ │ │ │ │ │ ├── RecipientInput.tsx │ │ │ │ │ │ ├── RecipientSections.tsx │ │ │ │ │ │ ├── RecipientValidationBadge.tsx │ │ │ │ │ │ ├── SelectProposer.tsx │ │ │ │ │ │ ├── SuspiciousAddressComparison.tsx │ │ │ │ │ │ ├── TokenListItem.tsx │ │ │ │ │ │ └── TokenPill.tsx │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── useAmountInput.test.ts │ │ │ │ │ │ ├── useAmountInput.ts │ │ │ │ │ │ ├── useEnsureActiveSigner.test.ts │ │ │ │ │ │ ├── useEnsureActiveSigner.ts │ │ │ │ │ │ ├── useFiatConversion.test.tsx │ │ │ │ │ │ ├── useFiatConversion.ts │ │ │ │ │ │ ├── useKeyboardVisible.ts │ │ │ │ │ │ ├── useMaxAmount.test.ts │ │ │ │ │ │ ├── useMaxAmount.ts │ │ │ │ │ │ ├── useNonce.test.ts │ │ │ │ │ │ ├── useNonce.ts │ │ │ │ │ │ ├── useNonceSelection.ts │ │ │ │ │ │ ├── useProposerSheet.ts │ │ │ │ │ │ ├── useRecipientSearch.ts │ │ │ │ │ │ ├── useRecipientValidation.test.ts │ │ │ │ │ │ ├── useRecipientValidation.ts │ │ │ │ │ │ ├── useSendTransaction.ts │ │ │ │ │ │ ├── useSuspiciousAddressDetection.ts │ │ │ │ │ │ └── useTokenBalance.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── services/ │ │ │ │ │ │ ├── proposeSendTransaction.test.ts │ │ │ │ │ │ ├── proposeSendTransaction.ts │ │ │ │ │ │ ├── tokenTransferParams.test.ts │ │ │ │ │ │ └── tokenTransferParams.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── Settings/ │ │ │ │ │ ├── Settings.container.tsx │ │ │ │ │ ├── Settings.tsx │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── Settings.test.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── AppSettings/ │ │ │ │ │ │ │ ├── AppSettings.container.tsx │ │ │ │ │ │ │ ├── AppSettings.tsx │ │ │ │ │ │ │ ├── AppSettings.types.ts │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── Currency/ │ │ │ │ │ │ │ ├── Currency.container.tsx │ │ │ │ │ │ │ ├── Currency.types.ts │ │ │ │ │ │ │ ├── CurrencyItem/ │ │ │ │ │ │ │ │ ├── CurrencyItem.tsx │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── CurrencySection/ │ │ │ │ │ │ │ │ ├── CurrencySection.tsx │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── CurrencyView.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── FloatingMenu.tsx │ │ │ │ │ │ └── Navbar/ │ │ │ │ │ │ ├── Navbar.tsx │ │ │ │ │ │ ├── SettingsButton.tsx │ │ │ │ │ │ ├── SettingsMenu.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── index.tsx │ │ │ │ ├── Share/ │ │ │ │ │ ├── Share.container.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── ShareView.test.tsx │ │ │ │ │ │ ├── ShareView.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── Signer/ │ │ │ │ │ ├── Signer.container.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── SignerHeader.tsx │ │ │ │ │ │ ├── SignerView.test.tsx │ │ │ │ │ │ └── SignerView.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── schema.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── Signers/ │ │ │ │ │ ├── Signers.container.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ └── SignersList/ │ │ │ │ │ │ ├── ImportedBadge.tsx │ │ │ │ │ │ ├── SignersList.tsx │ │ │ │ │ │ ├── SignersListHeader.tsx │ │ │ │ │ │ ├── SignersListItem.tsx │ │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ │ └── useSignersActions.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── useSignersGroupService.test.ts │ │ │ │ │ │ └── useSignersGroupService.ts │ │ │ │ │ └── index.tsx │ │ │ │ ├── TransactionActions/ │ │ │ │ │ ├── TransactionActions.container.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ └── TxActionsList.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── TransactionChecks/ │ │ │ │ │ ├── TransactionChecks.container.tsx │ │ │ │ │ ├── blockaid/ │ │ │ │ │ │ └── useBlockaid.ts │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── TransactionChecksView.tsx │ │ │ │ │ │ └── blockaid/ │ │ │ │ │ │ ├── PoweredByBlockaid.tsx │ │ │ │ │ │ ├── ResultDescription.tsx │ │ │ │ │ │ ├── balance/ │ │ │ │ │ │ │ ├── BalanceChange.tsx │ │ │ │ │ │ │ ├── BlockaidBalanceChanges.tsx │ │ │ │ │ │ │ ├── FungibleBalanceChange.tsx │ │ │ │ │ │ │ └── NFTBalanceChange.tsx │ │ │ │ │ │ └── scans/ │ │ │ │ │ │ ├── BlockaidError.tsx │ │ │ │ │ │ ├── BlockaidHint.tsx │ │ │ │ │ │ ├── BlockaidMessage.tsx │ │ │ │ │ │ ├── BlockaidWarning.tsx │ │ │ │ │ │ └── ContractChangeWarning.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── tenderly/ │ │ │ │ │ ├── useSimulation.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── TxHistory/ │ │ │ │ │ ├── TxHistory.container.test.tsx │ │ │ │ │ ├── TxHistory.container.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── TransactionHeader/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── TxHistoryList/ │ │ │ │ │ │ ├── TxHistoryList.test.tsx │ │ │ │ │ │ ├── TxHistoryList.tsx │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ ├── DateHeaderItem.tsx │ │ │ │ │ │ │ ├── ErrorComponent.tsx │ │ │ │ │ │ │ ├── GroupedTransactionItem.tsx │ │ │ │ │ │ │ ├── LoadingComponents.tsx │ │ │ │ │ │ │ └── TransactionListItem.tsx │ │ │ │ │ │ ├── constants.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── utils.ts │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── utils.tsx │ │ │ │ └── WalletConnect/ │ │ │ │ ├── appKit.ts │ │ │ │ ├── components/ │ │ │ │ │ ├── AppKitInitializer/ │ │ │ │ │ │ ├── AppKitInitializer.tsx │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ └── AppKitInitializer.test.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── WalletConnectBadge/ │ │ │ │ │ │ ├── WalletConnectBadge.test.tsx │ │ │ │ │ │ ├── WalletConnectBadge.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── WalletConnectGate/ │ │ │ │ │ ├── WalletConnectGate.tsx │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── WalletConnectGate.test.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── context/ │ │ │ │ │ ├── WalletConnectContext.e2e.tsx │ │ │ │ │ ├── WalletConnectContext.tsx │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── WalletConnectContext.test.tsx │ │ │ │ │ ├── types.ts │ │ │ │ │ └── walletConnectE2eState.ts │ │ │ │ ├── hooks/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ ├── useChainSync.test.ts │ │ │ │ │ │ ├── useConnect.test.ts │ │ │ │ │ │ ├── useImportSignerFlow.test.ts │ │ │ │ │ │ ├── useReconnectFlow.test.ts │ │ │ │ │ │ ├── useStableAppKitEvent.test.ts │ │ │ │ │ │ ├── useSwitchNetwork.test.ts │ │ │ │ │ │ ├── useWalletConnectSigning.test.ts │ │ │ │ │ │ └── useWalletConnectStatus.test.ts │ │ │ │ │ ├── useChainSync.ts │ │ │ │ │ ├── useConnect.ts │ │ │ │ │ ├── useImportSignerFlow.ts │ │ │ │ │ ├── useReconnectFlow.ts │ │ │ │ │ ├── useStableAppKitEvent.ts │ │ │ │ │ ├── useSwitchNetwork.ts │ │ │ │ │ ├── useWalletConnectSigning.ts │ │ │ │ │ └── useWalletConnectStatus.ts │ │ │ │ └── utils/ │ │ │ │ ├── __tests__/ │ │ │ │ │ └── chains.test.ts │ │ │ │ └── chains.ts │ │ │ ├── hooks/ │ │ │ │ ├── __tests__/ │ │ │ │ │ ├── useAddressOwnershipValidation.test.ts │ │ │ │ │ ├── useDatadogConsent.test.ts │ │ │ │ │ ├── useDisplayName.test.ts │ │ │ │ │ ├── useNotificationHandler.test.ts │ │ │ │ │ ├── useScreenProtection.test.ts │ │ │ │ │ └── useShareTransaction.test.ts │ │ │ │ ├── coreSDK/ │ │ │ │ │ ├── safeCoreSDK.test.ts │ │ │ │ │ ├── safeCoreSDK.ts │ │ │ │ │ ├── useInitSafeCoreSDK.test.ts │ │ │ │ │ └── useInitSafeCoreSDK.ts │ │ │ │ ├── services/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ ├── useLazySafeOverviews.test.ts │ │ │ │ │ │ └── useSafeKnownChainsOverview.test.ts │ │ │ │ │ ├── overviewQueryArgs.ts │ │ │ │ │ ├── useLazySafeOverviews.ts │ │ │ │ │ ├── useSafeKnownChainsOverview.ts │ │ │ │ │ └── useSafeOverviewsQuery.ts │ │ │ │ ├── useAddressOwnershipValidation.ts │ │ │ │ ├── useAddresses.ts │ │ │ │ ├── useAnalytics.ts │ │ │ │ ├── useBalances.ts │ │ │ │ ├── useBiometrics.test.ts │ │ │ │ ├── useBiometrics.ts │ │ │ │ ├── useCopyAndDispatchToast/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── useCopyAndDisptachToast.test.tsx │ │ │ │ ├── useCurrencies.ts │ │ │ │ ├── useDatadogConsent.ts │ │ │ │ ├── useDelegate.test.ts │ │ │ │ ├── useDelegate.ts │ │ │ │ ├── useDelegateCleanup/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── utils.test.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── useDelegateCleanup.ts │ │ │ │ ├── useDisplayName.ts │ │ │ │ ├── useFeeParams/ │ │ │ │ │ ├── useFeeParams.test.ts │ │ │ │ │ └── useFeeParams.ts │ │ │ │ ├── useHasFeature.ts │ │ │ │ ├── useHasSigner.ts │ │ │ │ ├── useHeaderHeight.ts │ │ │ │ ├── useInitWeb3.ts │ │ │ │ ├── useIsMounted.ts │ │ │ │ ├── useIsNextTx.ts │ │ │ │ ├── useMakeSafesWithChainId/ │ │ │ │ │ ├── useMakeSafesWithChainId.test.ts │ │ │ │ │ └── useMakeSafesWithChainId.ts │ │ │ │ ├── useNotificationCleanup.ts │ │ │ │ ├── useNotificationGTWPermissions.test.ts │ │ │ │ ├── useNotificationGTWPermissions.ts │ │ │ │ ├── useNotificationHandler.ts │ │ │ │ ├── useNotificationManager.test.ts │ │ │ │ ├── useNotificationManager.ts │ │ │ │ ├── useNotificationPayload.test.ts │ │ │ │ ├── useNotificationPayload.ts │ │ │ │ ├── usePendingTxs/ │ │ │ │ │ └── index.ts │ │ │ │ ├── usePendingTxsMonitor.ts │ │ │ │ ├── usePreventLeaveScreen/ │ │ │ │ │ └── index.ts │ │ │ │ ├── useRegisterForNotifications.ts │ │ │ │ ├── useSafeCreationData.ts │ │ │ │ ├── useSafeInfo.ts │ │ │ │ ├── useSafeTx.test.ts │ │ │ │ ├── useSafeTx.ts │ │ │ │ ├── useScreenProtection.e2e.ts │ │ │ │ ├── useScreenProtection.ts │ │ │ │ ├── useScreenTracking.ts │ │ │ │ ├── useShareTransaction.ts │ │ │ │ ├── useSign/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── useSign.test.ts │ │ │ │ │ └── useSign.ts │ │ │ │ ├── useSiwe.ts │ │ │ │ ├── useTokenDetails/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── useTokenDetails.ts │ │ │ │ ├── useTotalBalances.ts │ │ │ │ ├── useTransactionProcessingState.test.tsx │ │ │ │ ├── useTransactionProcessingState.ts │ │ │ │ ├── useTransactionSigningState.ts │ │ │ │ ├── useTransactionType/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── useTransactionType.test.tsx │ │ │ │ └── wallets/ │ │ │ │ ├── web3.test.ts │ │ │ │ └── web3.ts │ │ │ ├── navigation/ │ │ │ │ ├── NavigationGuardHOC.tsx │ │ │ │ ├── dismissToConfirmTransaction.ts │ │ │ │ ├── hooks/ │ │ │ │ │ └── utils.tsx │ │ │ │ └── useScrollableHeader.tsx │ │ │ ├── platform/ │ │ │ │ ├── __tests__/ │ │ │ │ │ └── fetch.test.ts │ │ │ │ ├── crypto-shims.ts │ │ │ │ ├── fetch.ts │ │ │ │ ├── intl-polyfills.ts │ │ │ │ └── security.ts │ │ │ ├── providers/ │ │ │ │ └── DatadogWrapper.tsx │ │ │ ├── react-app-env.d.ts │ │ │ ├── services/ │ │ │ │ ├── analytics/ │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── datadogAnalytics.ts │ │ │ │ │ ├── events/ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ ├── copy.test.ts │ │ │ │ │ │ │ └── overview.test.ts │ │ │ │ │ │ ├── addressBook.ts │ │ │ │ │ │ ├── copy.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── nativeIntent.ts │ │ │ │ │ │ ├── overview.ts │ │ │ │ │ │ ├── safes.ts │ │ │ │ │ │ ├── settings.ts │ │ │ │ │ │ ├── signers.ts │ │ │ │ │ │ └── transactions.ts │ │ │ │ │ ├── firebaseAnalytics.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── bluetooth/ │ │ │ │ │ └── bluetooth.service.ts │ │ │ │ ├── contracts/ │ │ │ │ │ └── safeContracts.ts │ │ │ │ ├── delegate-cleanup/ │ │ │ │ │ ├── DelegateCleanupService.test.ts │ │ │ │ │ ├── DelegateCleanupService.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── key-storage/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── key-storage.service.test.ts │ │ │ │ │ ├── key-storage.service.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ └── wallet.service.ts │ │ │ │ ├── ledger/ │ │ │ │ │ ├── ledger-dmk.service.test.ts │ │ │ │ │ ├── ledger-dmk.service.ts │ │ │ │ │ ├── ledger-ethereum.service.test.ts │ │ │ │ │ ├── ledger-ethereum.service.ts │ │ │ │ │ ├── ledger-execution.service.test.ts │ │ │ │ │ ├── ledger-execution.service.ts │ │ │ │ │ ├── ledger-safe-signing.service.test.ts │ │ │ │ │ └── ledger-safe-signing.service.ts │ │ │ │ ├── notifications/ │ │ │ │ │ ├── BadgeManager.ts │ │ │ │ │ ├── FCMService.ts │ │ │ │ │ ├── NotificationService.test.ts │ │ │ │ │ ├── NotificationService.ts │ │ │ │ │ ├── SubscriptionManager.ts │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ ├── backend.test.ts │ │ │ │ │ │ └── notificationNavigationHandler.test.ts │ │ │ │ │ ├── backend.ts │ │ │ │ │ ├── backgroundHandlers.ts │ │ │ │ │ ├── notificationNavigationHandler.ts │ │ │ │ │ ├── notificationParser.test.ts │ │ │ │ │ ├── notificationParser.ts │ │ │ │ │ ├── operations.ts │ │ │ │ │ ├── registration.ts │ │ │ │ │ ├── store-sync/ │ │ │ │ │ │ ├── const.ts │ │ │ │ │ │ ├── read.ts │ │ │ │ │ │ └── sync.ts │ │ │ │ │ └── utils/ │ │ │ │ │ ├── messageDeduplication.test.ts │ │ │ │ │ └── messageDeduplication.ts │ │ │ │ ├── remoteConfig/ │ │ │ │ │ ├── remoteConfigService.e2e.ts │ │ │ │ │ └── remoteConfigService.ts │ │ │ │ ├── tx/ │ │ │ │ │ ├── extractTx.test.ts │ │ │ │ │ ├── extractTx.ts │ │ │ │ │ ├── fetchTransactionDetails.ts │ │ │ │ │ ├── proposeNewTransaction.ts │ │ │ │ │ └── tx-sender/ │ │ │ │ │ ├── create.test.ts │ │ │ │ │ ├── create.ts │ │ │ │ │ ├── execute.test.ts │ │ │ │ │ ├── execute.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── sign.test.ts │ │ │ │ │ └── sign.ts │ │ │ │ ├── tx-execution/ │ │ │ │ │ ├── ledgerExecutor.test.ts │ │ │ │ │ ├── ledgerExecutor.ts │ │ │ │ │ ├── privateKeyExecutor.test.ts │ │ │ │ │ ├── privateKeyExecutor.ts │ │ │ │ │ ├── relayExecutor.test.ts │ │ │ │ │ ├── relayExecutor.ts │ │ │ │ │ ├── walletConnectExecutor.test.ts │ │ │ │ │ └── walletConnectExecutor.ts │ │ │ │ ├── walletconnect/ │ │ │ │ │ ├── walletconnect-signing.service.test.ts │ │ │ │ │ └── walletconnect-signing.service.ts │ │ │ │ └── web3/ │ │ │ │ └── index.ts │ │ │ ├── store/ │ │ │ │ ├── __tests__/ │ │ │ │ │ ├── activeSafeSlice.test.ts │ │ │ │ │ ├── addressBookSlice.selector.test.ts │ │ │ │ │ ├── addressBookSlice.test.ts │ │ │ │ │ ├── migrations.test.ts │ │ │ │ │ ├── persistConfig.test.ts │ │ │ │ │ ├── persistMigrations.test.ts │ │ │ │ │ ├── safesSlice.test.ts │ │ │ │ │ ├── sanitizePendingQueriesTransform.test.ts │ │ │ │ │ ├── settingsSlice.test.ts │ │ │ │ │ └── signersSlice.test.ts │ │ │ │ ├── activeSafeSlice.ts │ │ │ │ ├── activeSignerSlice.ts │ │ │ │ ├── addressBookSlice.ts │ │ │ │ ├── biometricsSlice.ts │ │ │ │ ├── chains/ │ │ │ │ │ └── index.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── delegatesSlice.ts │ │ │ │ ├── estimatedFeeSlice.ts │ │ │ │ ├── executingStateSlice.test.ts │ │ │ │ ├── executingStateSlice.ts │ │ │ │ ├── executionMethodSlice.ts │ │ │ │ ├── hooks/ │ │ │ │ │ ├── activeSafe.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── storeHooks.test.ts │ │ │ │ ├── index.ts │ │ │ │ ├── middleware/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ ├── notificationSync.test.ts │ │ │ │ │ │ └── pendingTxs.test.ts │ │ │ │ │ ├── analytics/ │ │ │ │ │ │ ├── AnalyticsStrategyManager.ts │ │ │ │ │ │ └── strategies/ │ │ │ │ │ │ ├── AddressBookTrackingStrategy.ts │ │ │ │ │ │ ├── SafeManagementStrategy.ts │ │ │ │ │ │ ├── SafeViewedStrategy.ts │ │ │ │ │ │ ├── SettingsStrategy.ts │ │ │ │ │ │ ├── SignerTrackingStrategy.ts │ │ │ │ │ │ ├── TransactionConfirmationStrategy.ts │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ ├── AddressBookTrackingStrategy.test.ts │ │ │ │ │ │ │ ├── SafeManagementStrategy.test.ts │ │ │ │ │ │ │ ├── SafeViewedStrategy.test.ts │ │ │ │ │ │ │ ├── SettingsStrategy.test.ts │ │ │ │ │ │ │ ├── SignerTrackingStrategy.test.ts │ │ │ │ │ │ │ └── TransactionConfirmationStrategy.test.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── analytics.ts │ │ │ │ │ ├── notificationSync.ts │ │ │ │ │ ├── notifications/ │ │ │ │ │ │ ├── NotificationStrategyManager.ts │ │ │ │ │ │ └── strategies/ │ │ │ │ │ │ ├── AddDelegateStrategy.ts │ │ │ │ │ │ ├── AddSafeStrategy.ts │ │ │ │ │ │ ├── RemoveSafeStrategy.ts │ │ │ │ │ │ ├── ToggleAppNotificationsStrategy.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── notifications.ts │ │ │ │ │ └── pendingTxs.ts │ │ │ │ ├── migrations.ts │ │ │ │ ├── myAccountsSlice.ts │ │ │ │ ├── notificationsSlice.ts │ │ │ │ ├── pendingTxsSlice.ts │ │ │ │ ├── resetE2EState.test.ts │ │ │ │ ├── resetE2EState.ts │ │ │ │ ├── safeSubscriptionsSlice.ts │ │ │ │ ├── safesSettingsSlice.test.ts │ │ │ │ ├── safesSettingsSlice.ts │ │ │ │ ├── safesSlice.ts │ │ │ │ ├── settingsSlice.test.ts │ │ │ │ ├── settingsSlice.ts │ │ │ │ ├── signerImportFlowSlice.ts │ │ │ │ ├── signerThunks.ts │ │ │ │ ├── signersBalance.ts │ │ │ │ ├── signersSlice.ts │ │ │ │ ├── signingStateSlice.test.ts │ │ │ │ ├── signingStateSlice.ts │ │ │ │ ├── storage.ts │ │ │ │ ├── txHistorySlice.ts │ │ │ │ └── utils/ │ │ │ │ ├── cookieHandling.test.ts │ │ │ │ ├── cookieHandling.ts │ │ │ │ ├── singletonStore.ts │ │ │ │ └── strategy/ │ │ │ │ ├── Strategy.ts │ │ │ │ └── StrategyManager.ts │ │ │ ├── tests/ │ │ │ │ ├── e2e-maestro/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── TestCtrls.e2e.tsx │ │ │ │ │ │ └── TestCtrls.tsx │ │ │ │ │ └── setup/ │ │ │ │ │ ├── assetsSetup.ts │ │ │ │ │ ├── connectSignerSetup.ts │ │ │ │ │ ├── historySetup.ts │ │ │ │ │ ├── mockData.ts │ │ │ │ │ ├── onboardingSetup.ts │ │ │ │ │ ├── pendingTxSetup.ts │ │ │ │ │ ├── positionsSetup.ts │ │ │ │ │ └── setupHelpers.ts │ │ │ │ ├── factories/ │ │ │ │ │ └── transaction.ts │ │ │ │ ├── jest.setup.tsx │ │ │ │ ├── mocks.ts │ │ │ │ ├── server.ts │ │ │ │ └── test-utils.tsx │ │ │ ├── theme/ │ │ │ │ ├── SafeStatusBar.tsx │ │ │ │ ├── __tests__/ │ │ │ │ │ └── SafeStatusBar.test.tsx │ │ │ │ ├── hooks/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── useTheme.test.tsx │ │ │ │ │ ├── useSafeAreaPaddingBottom.tsx │ │ │ │ │ └── useTheme.tsx │ │ │ │ ├── navigation.ts │ │ │ │ ├── provider/ │ │ │ │ │ ├── DataFetchProvider.tsx │ │ │ │ │ ├── font.tsx │ │ │ │ │ ├── safeTheme.tsx │ │ │ │ │ ├── storybookTheme.tsx │ │ │ │ │ └── toastProvider.tsx │ │ │ │ ├── tamagui.config.ts │ │ │ │ └── tokens.ts │ │ │ ├── types/ │ │ │ │ ├── address.ts │ │ │ │ ├── iconTypes.ts │ │ │ │ ├── notifee.d.ts │ │ │ │ ├── react-native-device-info.d.ts │ │ │ │ ├── theme.ts │ │ │ │ └── txType.ts │ │ │ └── utils/ │ │ │ ├── balance.test.ts │ │ │ ├── balance.ts │ │ │ ├── chains.test.ts │ │ │ ├── chains.ts │ │ │ ├── currency.test.ts │ │ │ ├── currency.ts │ │ │ ├── date.test.ts │ │ │ ├── date.ts │ │ │ ├── delegate.ts │ │ │ ├── errors/ │ │ │ │ ├── index.ts │ │ │ │ └── standardErrors.ts │ │ │ ├── feeParams.test.ts │ │ │ ├── feeParams.ts │ │ │ ├── formatters.test.ts │ │ │ ├── formatters.ts │ │ │ ├── inputDetection.test.ts │ │ │ ├── inputDetection.ts │ │ │ ├── legacyData.test.ts │ │ │ ├── legacyData.ts │ │ │ ├── logger.ts │ │ │ ├── notifications/ │ │ │ │ ├── __tests__/ │ │ │ │ │ └── cleanup.test.ts │ │ │ │ ├── accountType.test.ts │ │ │ │ ├── accountType.ts │ │ │ │ ├── cleanup.ts │ │ │ │ └── index.ts │ │ │ ├── retry.ts │ │ │ ├── signer.test.ts │ │ │ ├── signer.ts │ │ │ ├── swapOrderUtils.test.tsx │ │ │ ├── swapOrderUtils.tsx │ │ │ ├── transaction-guards.test.ts │ │ │ ├── transaction-guards.ts │ │ │ ├── transactions.test.tsx │ │ │ ├── transactions.tsx │ │ │ ├── url.test.ts │ │ │ ├── url.ts │ │ │ ├── uuid.test.ts │ │ │ └── uuid.ts │ │ └── tsconfig.json │ ├── tx-builder/ │ │ ├── README.md │ │ ├── docs/ │ │ │ └── release-procedure.md │ │ ├── eslint.config.mjs │ │ ├── index.html │ │ ├── jest.config.cjs │ │ ├── package.json │ │ ├── public/ │ │ │ └── manifest.json │ │ ├── src/ │ │ │ ├── App.tsx │ │ │ ├── __mocks__/ │ │ │ │ └── fileMock.js │ │ │ ├── components/ │ │ │ │ ├── Accordion/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── Button.tsx │ │ │ │ ├── Card/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── ChecksumWarning.tsx │ │ │ │ ├── CreateNewBatchCard.tsx │ │ │ │ ├── Divider.tsx │ │ │ │ ├── Dot/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── ETHHashInfo.tsx │ │ │ │ ├── EditableLabel.tsx │ │ │ │ ├── EllipsisMenu/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── ErrorAlert.tsx │ │ │ │ ├── FixedIcon/ │ │ │ │ │ ├── images/ │ │ │ │ │ │ ├── arrowReceived.tsx │ │ │ │ │ │ ├── arrowReceivedWhite.tsx │ │ │ │ │ │ ├── arrowSent.tsx │ │ │ │ │ │ ├── arrowSentWhite.tsx │ │ │ │ │ │ ├── arrowSort.tsx │ │ │ │ │ │ ├── bullit.tsx │ │ │ │ │ │ ├── chevronDown.tsx │ │ │ │ │ │ ├── chevronLeft.tsx │ │ │ │ │ │ ├── chevronRight.tsx │ │ │ │ │ │ ├── chevronUp.tsx │ │ │ │ │ │ ├── connectedRinkeby.tsx │ │ │ │ │ │ ├── connectedWallet.tsx │ │ │ │ │ │ ├── creatingInProgress.tsx │ │ │ │ │ │ ├── dropdownArrowSmall.tsx │ │ │ │ │ │ ├── networkError.tsx │ │ │ │ │ │ ├── notConnected.tsx │ │ │ │ │ │ ├── notOwner.tsx │ │ │ │ │ │ ├── options.tsx │ │ │ │ │ │ ├── plus.tsx │ │ │ │ │ │ ├── settingsChange.tsx │ │ │ │ │ │ └── threeDots.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── GenericModal.tsx │ │ │ │ ├── Header.test.tsx │ │ │ │ ├── Header.tsx │ │ │ │ ├── Icon/ │ │ │ │ │ ├── images/ │ │ │ │ │ │ ├── alert.tsx │ │ │ │ │ │ ├── bookmark.tsx │ │ │ │ │ │ ├── bookmarkFilled.tsx │ │ │ │ │ │ ├── check.tsx │ │ │ │ │ │ ├── code.tsx │ │ │ │ │ │ ├── copy.tsx │ │ │ │ │ │ ├── cross.tsx │ │ │ │ │ │ ├── delete.tsx │ │ │ │ │ │ ├── edit.tsx │ │ │ │ │ │ ├── externalLink.tsx │ │ │ │ │ │ ├── import.tsx │ │ │ │ │ │ ├── info.tsx │ │ │ │ │ │ └── termsOfUse.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── IconText/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── Link/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── Loader/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── QuickTip.tsx │ │ │ │ ├── ShowMoreText.tsx │ │ │ │ ├── Switch.tsx │ │ │ │ ├── Text.tsx │ │ │ │ ├── Title.tsx │ │ │ │ ├── Tooltip.tsx │ │ │ │ ├── TransactionBatchListItem.tsx │ │ │ │ ├── TransactionDetails.tsx │ │ │ │ ├── TransactionsBatchList.tsx │ │ │ │ ├── VirtualizedList.tsx │ │ │ │ ├── Wrapper/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── buttons/ │ │ │ │ │ ├── ButtonLink/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── CopyToClipboardBtn/ │ │ │ │ │ │ ├── copyTextToClipboard.ts │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── ExplorerButton/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── Identicon/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── forms/ │ │ │ │ │ ├── AddNewTransactionForm.tsx │ │ │ │ │ ├── SolidityForm.test.tsx │ │ │ │ │ ├── SolidityForm.tsx │ │ │ │ │ ├── fields/ │ │ │ │ │ │ ├── AddressContractField.tsx │ │ │ │ │ │ ├── AddressInput.tsx │ │ │ │ │ │ ├── Field.tsx │ │ │ │ │ │ ├── JsonField.tsx │ │ │ │ │ │ ├── SelectContractField.tsx │ │ │ │ │ │ ├── TextContractField.tsx │ │ │ │ │ │ ├── TextFieldInput.tsx │ │ │ │ │ │ ├── TextareaContractField.tsx │ │ │ │ │ │ ├── fields.test.ts │ │ │ │ │ │ ├── fields.ts │ │ │ │ │ │ └── styles.ts │ │ │ │ │ └── validations/ │ │ │ │ │ ├── basicSolidityValidation.ts │ │ │ │ │ ├── validateAddressField.ts │ │ │ │ │ ├── validateAmountField.ts │ │ │ │ │ ├── validateBooleanField.ts │ │ │ │ │ ├── validateField.ts │ │ │ │ │ ├── validateHexEncodedDataField.ts │ │ │ │ │ └── validations.test.ts │ │ │ │ └── modals/ │ │ │ │ ├── DeleteBatchFromLibrary.tsx │ │ │ │ ├── DeleteBatchModal.tsx │ │ │ │ ├── DeleteTransactionModal.tsx │ │ │ │ ├── EditTransactionModal.tsx │ │ │ │ ├── ImplementationABIDialog.tsx │ │ │ │ ├── SaveBatchModal.tsx │ │ │ │ ├── SuccessBatchCreationModal.tsx │ │ │ │ └── WrongChainBatchModal.tsx │ │ │ ├── global.ts │ │ │ ├── hooks/ │ │ │ │ ├── useAbi.ts │ │ │ │ ├── useAsync.ts │ │ │ │ ├── useDebounce.ts │ │ │ │ ├── useDropZone/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── useElementHeight/ │ │ │ │ │ └── useElementHeight.tsx │ │ │ │ ├── useModal/ │ │ │ │ │ └── useModal.tsx │ │ │ │ ├── useSimulation.ts │ │ │ │ └── useThrottle.ts │ │ │ ├── lib/ │ │ │ │ ├── analytics.ts │ │ │ │ ├── batches/ │ │ │ │ │ └── index.ts │ │ │ │ ├── checksum.test.ts │ │ │ │ ├── checksum.ts │ │ │ │ ├── getAbi.test.ts │ │ │ │ ├── getAbi.ts │ │ │ │ ├── interfaceRepository.ts │ │ │ │ ├── local-storage/ │ │ │ │ │ ├── Storage.ts │ │ │ │ │ └── local.ts │ │ │ │ ├── simulation/ │ │ │ │ │ ├── multisend.ts │ │ │ │ │ ├── simulation.ts │ │ │ │ │ └── types.ts │ │ │ │ └── storage.ts │ │ │ ├── main.tsx │ │ │ ├── mocks/ │ │ │ │ └── handlers.ts │ │ │ ├── pages/ │ │ │ │ ├── CreateTransactions.tsx │ │ │ │ ├── Dashboard.tsx │ │ │ │ ├── EditTransactionLibrary.tsx │ │ │ │ ├── ReviewAndConfirm.tsx │ │ │ │ ├── SaveTransactionLibrary.tsx │ │ │ │ └── TransactionLibrary.tsx │ │ │ ├── routes/ │ │ │ │ └── routes.ts │ │ │ ├── setupTests.ts │ │ │ ├── store/ │ │ │ │ ├── index.tsx │ │ │ │ ├── networkContext.tsx │ │ │ │ ├── transactionLibraryContext.tsx │ │ │ │ └── transactionsContext.tsx │ │ │ ├── test-utils.tsx │ │ │ ├── theme/ │ │ │ │ ├── SafeThemeProvider.tsx │ │ │ │ ├── darkPalette.ts │ │ │ │ ├── lightPalette.ts │ │ │ │ ├── safeTheme.ts │ │ │ │ └── typography.ts │ │ │ ├── typings/ │ │ │ │ ├── custom.d.ts │ │ │ │ ├── errors.ts │ │ │ │ ├── fonts.d.ts │ │ │ │ └── models.ts │ │ │ ├── utils/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── env.ts │ │ │ │ ├── address.ts │ │ │ │ ├── env.ts │ │ │ │ └── strings.ts │ │ │ ├── utils.test.ts │ │ │ ├── utils.ts │ │ │ └── vite-env.d.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ └── web/ │ ├── .dockerignore │ ├── .gitignore │ ├── .storybook/ │ │ ├── AGENTS.md │ │ ├── COVERAGE.md │ │ ├── decorators/ │ │ │ ├── LayoutDecorator.tsx │ │ │ ├── MockProviderDecorator.tsx │ │ │ └── index.ts │ │ ├── main.ts │ │ ├── mocks/ │ │ │ ├── nextImage.js │ │ │ ├── querystring.ts │ │ │ ├── svgMock.tsx │ │ │ └── useIsOfficialHost.ts │ │ ├── preview-head.html │ │ ├── preview.tsx │ │ ├── shadcn-stories.css │ │ ├── shadcn.ts │ │ └── test-runner.mjs │ ├── .storybook-vite/ │ │ ├── main.ts │ │ ├── preview-head.html │ │ └── preview.tsx │ ├── AGENTS.md │ ├── Dockerfile │ ├── LICENSE │ ├── README.md │ ├── chromatic.config.json │ ├── components.json │ ├── cypress/ │ │ ├── AGENTS.md │ │ ├── CLAUDE.md │ │ ├── COVERAGE.md │ │ ├── ci.json │ │ ├── e2e/ │ │ │ ├── happypath/ │ │ │ │ ├── recovery_hp_1.cy.js │ │ │ │ ├── recovery_hp_2.cy.js │ │ │ │ ├── recovery_hp_3.cy.js │ │ │ │ ├── recovery_hp_4.cy.js │ │ │ │ ├── sendfunds_connected_wallet.cy.js │ │ │ │ ├── sendfunds_queue_1.cy.js │ │ │ │ ├── sendfunds_relay.cy.js │ │ │ │ ├── tx_history_filter_hp_1.cy.js │ │ │ │ └── tx_history_filter_hp_2.cy.js │ │ │ ├── happypath_2/ │ │ │ │ ├── add_owner.cy.js │ │ │ │ ├── create_safe_cf.cy.js │ │ │ │ ├── mass_payouts.cy.js │ │ │ │ ├── multichain_create_safe.cy.js │ │ │ │ ├── nested_safes.cy.js │ │ │ │ ├── proposers.cy.js │ │ │ │ ├── swaps.cy.js │ │ │ │ └── tx-builder.cy.js │ │ │ ├── pages/ │ │ │ │ ├── accounts_modal.pages.js │ │ │ │ ├── address_book.page.js │ │ │ │ ├── assets.pages.js │ │ │ │ ├── batches.pages.js │ │ │ │ ├── bridge.pages.js │ │ │ │ ├── copilot.js │ │ │ │ ├── create_tx.pages.js │ │ │ │ ├── create_wallet.pages.js │ │ │ │ ├── dashboard.pages.js │ │ │ │ ├── header.page.js │ │ │ │ ├── import_export.pages.js │ │ │ │ ├── load_safe.pages.js │ │ │ │ ├── main.page.js │ │ │ │ ├── messages.pages.js │ │ │ │ ├── modals/ │ │ │ │ │ └── message_confirmation.pages.js │ │ │ │ ├── modals.page.js │ │ │ │ ├── modules.page.js │ │ │ │ ├── navigation.page.js │ │ │ │ ├── nestedsafes.pages.js │ │ │ │ ├── network.pages.js │ │ │ │ ├── nfts.pages.js │ │ │ │ ├── notifications.page.js │ │ │ │ ├── owners.pages.js │ │ │ │ ├── portfolio.pages.js │ │ │ │ ├── proposers.pages.js │ │ │ │ ├── recovery.pages.js │ │ │ │ ├── safe_navigation.pages.js │ │ │ │ ├── safeapps.pages.js │ │ │ │ ├── sidebar.pages.js │ │ │ │ ├── spaces.page.js │ │ │ │ ├── spending_limits.pages.js │ │ │ │ ├── staking.page.js │ │ │ │ ├── swaps.pages.js │ │ │ │ ├── tables.page.js │ │ │ │ ├── transactions.page.js │ │ │ │ └── walletconnect.page.js │ │ │ ├── prodhealthcheck/ │ │ │ │ ├── add_owner.cy.js │ │ │ │ ├── create_tx.cy.js │ │ │ │ ├── load_safe.cy.js │ │ │ │ ├── messages_onchain.cy.js │ │ │ │ ├── multichain_network.cy.js │ │ │ │ ├── nfts.cy.js │ │ │ │ ├── recovery.cy.js │ │ │ │ ├── remove_owner.cy.js │ │ │ │ ├── sidebar.cy.js │ │ │ │ ├── sidebar_3.cy.js │ │ │ │ ├── spending_limits.cy.js │ │ │ │ ├── swaps_history_2.cy.js │ │ │ │ ├── swaps_tokens.cy.js │ │ │ │ ├── tokens.cy.js │ │ │ │ ├── tx_history.cy.js │ │ │ │ └── tx_history_2.cy.js │ │ │ ├── regression/ │ │ │ │ ├── add_owner.cy.js │ │ │ │ ├── address_book.cy.js │ │ │ │ ├── address_book_2.cy.js │ │ │ │ ├── address_book_3.cy.js │ │ │ │ ├── assets.cy.js │ │ │ │ ├── assets_2.cy.js │ │ │ │ ├── balances_pagination.cy.js │ │ │ │ ├── batch_tx.cy.js │ │ │ │ ├── bulk_execution.cy.js │ │ │ │ ├── copilot.cy.js │ │ │ │ ├── create_safe_cf.cy.js │ │ │ │ ├── create_safe_simple.cy.js │ │ │ │ ├── create_safe_simple_2.cy.js │ │ │ │ ├── create_safe_simple_3.cy.js │ │ │ │ ├── create_tx.cy.js │ │ │ │ ├── create_tx_2.cy.js │ │ │ │ ├── dashboard.cy.js │ │ │ │ ├── import_export_data_2.cy.js │ │ │ │ ├── limit_order.cy.js │ │ │ │ ├── limit_order_history.cy.js │ │ │ │ ├── limit_order_queue.cy.js │ │ │ │ ├── load_safe.cy.js │ │ │ │ ├── load_safe_2.cy.js │ │ │ │ ├── load_safe_3.cy.js │ │ │ │ ├── mass_payouts.cy.js │ │ │ │ ├── messages_offchain.cy.js │ │ │ │ ├── messages_onchain.cy.js │ │ │ │ ├── messages_popup.cy.js │ │ │ │ ├── multichain_create_safe.cy.js │ │ │ │ ├── multichain_create_safe_flow.cy.js │ │ │ │ ├── multichain_network.cy.js │ │ │ │ ├── multichain_networkswitch.cy.js │ │ │ │ ├── multichain_safe_selector.cy.js │ │ │ │ ├── multichain_setup.cy.js │ │ │ │ ├── multichain_setup_new.cy.js │ │ │ │ ├── multichain_sidebar.cy.js │ │ │ │ ├── nested_safes.cy.js │ │ │ │ ├── nested_safes_curation.cy.js │ │ │ │ ├── nested_safes_fund_asset.cy.js │ │ │ │ ├── nested_safes_review.cy.js │ │ │ │ ├── nfts.cy.js │ │ │ │ ├── nfts_2.cy.js │ │ │ │ ├── notifications.cy.js │ │ │ │ ├── portfolio.cy.js │ │ │ │ ├── proposers.cy.js │ │ │ │ ├── proposers_2.cy.js │ │ │ │ ├── recovery.cy.js │ │ │ │ ├── recovery_2.cy.js │ │ │ │ ├── remove_owner.cy.js │ │ │ │ ├── replace_owner.cy.js │ │ │ │ ├── safe_selector.cy.js │ │ │ │ ├── sidebar.cy.js │ │ │ │ ├── sidebar_2.cy.js │ │ │ │ ├── sidebar_3.cy.js │ │ │ │ ├── sidebar_4.cy.js │ │ │ │ ├── sidebar_5.cy.js │ │ │ │ ├── sidebar_6.cy.js │ │ │ │ ├── sidebar_7.cy.js │ │ │ │ ├── sidebar_8.cy.js │ │ │ │ ├── sidebar_9.cy.js │ │ │ │ ├── sidebar_new.cy.js │ │ │ │ ├── sidebar_nonowner.cy.js │ │ │ │ ├── spaces_basicflow.cy.js │ │ │ │ ├── spaces_dashboard.cy.js │ │ │ │ ├── spending_limits.cy.js │ │ │ │ ├── spending_limits_nonowner.cy.js │ │ │ │ ├── staking_history.cy.js │ │ │ │ ├── swaps.cy.js │ │ │ │ ├── swaps_2.cy.js │ │ │ │ ├── swaps_history.cy.js │ │ │ │ ├── swaps_history_2.cy.js │ │ │ │ ├── swaps_queue.cy.js │ │ │ │ ├── swaps_tokens.cy.js │ │ │ │ ├── tokens.cy.js │ │ │ │ ├── twaps_history.cy.js │ │ │ │ ├── twaps_integration.cy.js │ │ │ │ ├── twaps_queue.cy.js │ │ │ │ ├── tx_details_createtx.cy.js │ │ │ │ ├── tx_details_queue.cy.js │ │ │ │ ├── tx_history.cy.js │ │ │ │ ├── tx_history_2.cy.js │ │ │ │ ├── tx_history_3.cy.js │ │ │ │ ├── tx_history_4.cy.js │ │ │ │ ├── tx_history_5.cy.js │ │ │ │ ├── tx_history_6.cy.js │ │ │ │ ├── tx_history_filter.cy.js │ │ │ │ ├── tx_history_filter_2.cy.js │ │ │ │ ├── tx_notes.cy.js │ │ │ │ ├── tx_queue.cy.js │ │ │ │ ├── tx_queue_delete_btn.cy.js │ │ │ │ ├── tx_queue_reject_btn.cy.js │ │ │ │ ├── tx_queue_replace_btn.cy.js │ │ │ │ ├── tx_share_block.cy.js │ │ │ │ ├── walletconnect.cy.js │ │ │ │ └── walletconnect_2.cy.js │ │ │ ├── safe-apps/ │ │ │ │ ├── apps_list.cy.js │ │ │ │ ├── browser_permissions.cy.js │ │ │ │ ├── constants.js │ │ │ │ ├── drain_account.spec.cy.js │ │ │ │ ├── info_modal.cy.js │ │ │ │ ├── permissions_settings.cy.js │ │ │ │ ├── preview_drawer.cy.js │ │ │ │ ├── safe_permissions.cy.js │ │ │ │ ├── tx-builder.cy.js │ │ │ │ ├── tx-builder_2.cy.js │ │ │ │ └── tx-builder_3.cy.js │ │ │ ├── smoke/ │ │ │ │ ├── add_owner.cy.js │ │ │ │ ├── address_book.cy.js │ │ │ │ ├── assets.cy.js │ │ │ │ ├── balances_endpoints.cy.js │ │ │ │ ├── batch_tx.cy.js │ │ │ │ ├── create_tx.cy.js │ │ │ │ ├── dashboard.cy.js │ │ │ │ ├── import_export_data.cy.js │ │ │ │ ├── import_export_data_2.cy.js │ │ │ │ ├── landing.cy.js │ │ │ │ ├── load_safe.cy.js │ │ │ │ ├── messages_offchain.cy.js │ │ │ │ ├── nfts.cy.js │ │ │ │ ├── replace_owner.cy.js │ │ │ │ ├── safe_selector.cy.js │ │ │ │ ├── sidebar.cy.js │ │ │ │ ├── spending_limits.cy.js │ │ │ │ ├── tokens.cy.js │ │ │ │ └── tx_history.cy.js │ │ │ └── visual/ │ │ │ ├── address_book.cy.js │ │ │ ├── apps_custom.cy.js │ │ │ ├── balances.cy.js │ │ │ ├── batch_tx.cy.js │ │ │ ├── bridge.cy.js │ │ │ ├── create_tx_flow.cy.js │ │ │ ├── dashboard.cy.js │ │ │ ├── earn.cy.js │ │ │ ├── env_variables.cy.js │ │ │ ├── error_pages.cy.js │ │ │ ├── legal_pages.cy.js │ │ │ ├── messages.cy.js │ │ │ ├── msg_details.cy.js │ │ │ ├── new_safe.cy.js │ │ │ ├── new_safe_advanced.cy.js │ │ │ ├── nfts.cy.js │ │ │ ├── owner_management.cy.js │ │ │ ├── positions.cy.js │ │ │ ├── safe_apps.cy.js │ │ │ ├── settings_cookies.cy.js │ │ │ ├── settings_data_security.cy.js │ │ │ ├── settings_pages.cy.js │ │ │ ├── settings_safe_apps.cy.js │ │ │ ├── sidebar.cy.js │ │ │ ├── spaces.cy.js │ │ │ ├── spending_limits.cy.js │ │ │ ├── stake.cy.js │ │ │ ├── swap.cy.js │ │ │ ├── tx_details.cy.js │ │ │ ├── tx_history.cy.js │ │ │ ├── tx_queue.cy.js │ │ │ ├── user_settings.cy.js │ │ │ └── welcome.cy.js │ │ ├── fixtures/ │ │ │ ├── address_book_addedsafes.csv │ │ │ ├── address_book_duplicated.csv │ │ │ ├── address_book_empty_test.csv │ │ │ ├── address_book_networks.csv │ │ │ ├── address_book_test.csv │ │ │ ├── balances.json │ │ │ ├── data_import.json │ │ │ ├── history/ │ │ │ │ └── history_tx_1.json │ │ │ ├── messages/ │ │ │ │ └── messages.json │ │ │ ├── nfts/ │ │ │ │ └── nfts.json │ │ │ ├── pending_tx/ │ │ │ │ ├── pending_tx.json │ │ │ │ └── pending_tx_order.json │ │ │ ├── safe-app.html │ │ │ ├── safes/ │ │ │ │ ├── funds.json │ │ │ │ ├── nfts.json │ │ │ │ ├── recovery.json │ │ │ │ ├── safeapps.json │ │ │ │ └── static.js │ │ │ ├── spaces/ │ │ │ │ ├── address_book.json │ │ │ │ ├── members.json │ │ │ │ ├── staticSpaces.js │ │ │ │ ├── user.json │ │ │ │ └── visualSpacesApiMock.js │ │ │ ├── staking_data.json │ │ │ ├── swaps/ │ │ │ │ ├── quoteresponse1.json │ │ │ │ └── quoteresponse2.json │ │ │ ├── swaps_data.json │ │ │ ├── test-empty-batch.json │ │ │ ├── test-invalid-batch.json │ │ │ ├── test-mainnet-batch.json │ │ │ ├── test-modified-batch.json │ │ │ ├── test-working-batch.json │ │ │ ├── txhistory_data_data.json │ │ │ ├── txhistory_incoming_data.json │ │ │ └── txmessages_data.json │ │ ├── plugins/ │ │ │ └── index.js │ │ └── support/ │ │ ├── api/ │ │ │ ├── contracts.js │ │ │ ├── utils_ether.js │ │ │ └── utils_protocolkit.js │ │ ├── commands.js │ │ ├── constants.js │ │ ├── e2e.js │ │ ├── localstorage_data.js │ │ ├── safe-apps-commands.js │ │ ├── safes/ │ │ │ └── safesHandler.js │ │ ├── utils/ │ │ │ ├── checkers.js │ │ │ ├── ethers.js │ │ │ ├── gtag.js │ │ │ ├── txquery.js │ │ │ └── wallet.js │ │ └── visual-mocks.js │ ├── cypress.config.js │ ├── docs/ │ │ ├── TESTING.md │ │ ├── code-style.md │ │ ├── environments.md │ │ ├── feature-architecture.md │ │ ├── release-procedure-automated.md │ │ ├── release-procedure.md │ │ ├── spaces-accounts-architecture.md │ │ ├── storybook-snapshots.md │ │ ├── update-patch.md │ │ └── update-terms.md │ ├── eslint.config.mjs │ ├── jest.config.cjs │ ├── jest.setup.js │ ├── knip.json │ ├── mocks/ │ │ └── svg.js │ ├── next-env.d.ts │ ├── next.config.mjs │ ├── package.json │ ├── plugins/ │ │ └── sri-manifest-webpack-plugin.mjs │ ├── postcss.config.mjs │ ├── public/ │ │ ├── .well-known/ │ │ │ └── apple-app-site-association │ │ ├── beamer-embed.css │ │ ├── beamer-embed.js │ │ ├── fonts/ │ │ │ └── fonts.css │ │ ├── mockServiceWorker.js │ │ └── safe.webmanifest │ ├── scripts/ │ │ ├── cmp.sh │ │ ├── css-vars.ts │ │ ├── fetch-chains.ts │ │ ├── generate-routes.js │ │ ├── generate-storybook-tests.cjs │ │ ├── github/ │ │ │ ├── prepare_production_deployment.sh │ │ │ └── s3_upload.sh │ │ ├── integrity-hashes.cjs │ │ ├── release/ │ │ │ ├── README.md │ │ │ ├── generate-changelog.sh │ │ │ └── notify-slack.sh │ │ └── release-notes.sh │ ├── src/ │ │ ├── components/ │ │ │ ├── address-book/ │ │ │ │ ├── AddressBookHeader/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── AddressBookTable/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── EntryDialog/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── ExportDialog/ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── ImportDialog/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── validation.test.ts │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.module.css │ │ │ │ │ └── validation.ts │ │ │ │ ├── RemoveDialog/ │ │ │ │ │ └── index.tsx │ │ │ │ └── index.stories.tsx │ │ │ ├── balances/ │ │ │ │ ├── AssetsHeader/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── AssetsTable/ │ │ │ │ │ ├── ActionButtons.tsx │ │ │ │ │ ├── AssetRowContent.tsx │ │ │ │ │ ├── FiatBalance.tsx │ │ │ │ │ ├── FiatChange.test.tsx │ │ │ │ │ ├── FiatChange.tsx │ │ │ │ │ ├── HiddenTokensInfo.tsx │ │ │ │ │ ├── PromoButtons.tsx │ │ │ │ │ ├── SendButton.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── index.stories.test.tsx.snap │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── AssetsTable.test.tsx │ │ │ │ │ ├── index.stories.test.tsx │ │ │ │ │ ├── index.stories.tsx │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.module.css │ │ │ │ │ └── useHideAssets.ts │ │ │ │ ├── CurrencySelect/ │ │ │ │ │ ├── CurrencySelect.stories.tsx │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── useCurrencies.ts │ │ │ │ ├── HiddenTokenButton/ │ │ │ │ │ ├── HiddenTokenButton.stories.tsx │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── ManageTokensButton/ │ │ │ │ │ ├── ManageTokensMenu.module.css │ │ │ │ │ ├── ManageTokensMenu.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── index.stories.test.tsx.snap │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── ManageTokensButton.test.tsx │ │ │ │ │ ├── index.stories.test.tsx │ │ │ │ │ ├── index.stories.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── TokenMenu/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ └── TotalAssetValue/ │ │ │ │ ├── TotalAssetValue.stories.tsx │ │ │ │ └── index.tsx │ │ │ ├── common/ │ │ │ │ ├── ActionCard/ │ │ │ │ │ ├── ActionCard.stories.tsx │ │ │ │ │ ├── ActionCard.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── AddFunds/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── AddressBookInput/ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── AddressBookSourceProvider/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── AddressInput/ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.module.css │ │ │ │ │ └── useNameResolver.ts │ │ │ │ ├── AddressInputReadOnly/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── AssetActionButton/ │ │ │ │ │ └── styles.module.css │ │ │ │ ├── AuditLog/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── BackLink/ │ │ │ │ │ ├── BackLink.stories.tsx │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── BlockedAddress/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── Breadcrumbs/ │ │ │ │ │ ├── BreadcrumbItem.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── Captcha/ │ │ │ │ │ ├── CaptchaModal.tsx │ │ │ │ │ ├── CaptchaProvider.tsx │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ ├── CaptchaProvider.test.tsx │ │ │ │ │ │ ├── captchaHeadersInit.test.ts │ │ │ │ │ │ └── useCaptchaToken.test.ts │ │ │ │ │ ├── captchaHeadersInit.ts │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── useCaptchaToken.ts │ │ │ │ ├── ChainIndicator/ │ │ │ │ │ ├── ChainIndicator.stories.test.tsx │ │ │ │ │ ├── ChainIndicator.stories.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── ChainIndicator.stories.test.tsx.snap │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── ChainSwitcher/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── CheckWallet/ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── CheckWalletWithPermission/ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── Chip/ │ │ │ │ │ ├── Chip.stories.test.tsx │ │ │ │ │ ├── Chip.stories.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── Chip.stories.test.tsx.snap │ │ │ │ │ └── index.tsx │ │ │ │ ├── ChoiceButton/ │ │ │ │ │ ├── ChoiceButton.stories.test.tsx │ │ │ │ │ ├── ChoiceButton.stories.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── ChoiceButton.stories.test.tsx.snap │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── ConnectWallet/ │ │ │ │ │ ├── AccountCenter.tsx │ │ │ │ │ ├── ConnectWalletButton.tsx │ │ │ │ │ ├── ConnectionCenter.tsx │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ ├── AccountCenter.test.tsx │ │ │ │ │ │ └── ConnectionCenter.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.module.css │ │ │ │ │ └── useConnectWallet.ts │ │ │ │ ├── ContextMenu/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── CookieAndTermBanner/ │ │ │ │ │ ├── CookieBannerActions.tsx │ │ │ │ │ ├── CookieOptionsList.tsx │ │ │ │ │ ├── IntroText.tsx │ │ │ │ │ ├── WarningMessage.tsx │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── CooldownButton/ │ │ │ │ │ ├── CooldownButton.stories.test.tsx │ │ │ │ │ ├── CooldownButton.stories.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── CooldownButton.stories.test.tsx.snap │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── CopyAddressButton/ │ │ │ │ │ ├── CopyAddressButton.stories.test.tsx │ │ │ │ │ ├── CopyAddressButton.stories.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── CopyAddressButton.stories.test.tsx.snap │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── CopyButton/ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── index.stories.test.tsx.snap │ │ │ │ │ ├── index.stories.test.tsx │ │ │ │ │ ├── index.stories.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── CopyTooltip/ │ │ │ │ │ ├── ConfirmCopyModal.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── Countdown/ │ │ │ │ │ ├── Countdown.stories.test.tsx │ │ │ │ │ ├── Countdown.stories.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── Countdown.stories.test.tsx.snap │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── CustomLink/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── CustomTooltip/ │ │ │ │ │ ├── CustomTooltip.stories.test.tsx │ │ │ │ │ ├── CustomTooltip.stories.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── CustomTooltip.stories.test.tsx.snap │ │ │ │ │ └── index.tsx │ │ │ │ ├── DatePickerInput/ │ │ │ │ │ ├── DatePickerInput.stories.test.tsx │ │ │ │ │ ├── DatePickerInput.stories.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── DatePickerInput.stories.test.tsx.snap │ │ │ │ │ └── index.tsx │ │ │ │ ├── DateTime/ │ │ │ │ │ ├── DateTime.stories.test.tsx │ │ │ │ │ ├── DateTime.stories.tsx │ │ │ │ │ ├── DateTime.tsx │ │ │ │ │ ├── DateTimeContainer.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── DateTime.stories.test.tsx.snap │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── Disclaimer/ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── index.stories.test.tsx.snap │ │ │ │ │ ├── index.stories.test.tsx │ │ │ │ │ ├── index.stories.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── EnhancedTable/ │ │ │ │ │ ├── EnhancedTable.stories.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── ErrorBoundary/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── EthHashInfo/ │ │ │ │ │ ├── SrcEthHashInfo/ │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ └── index.stories.test.tsx.snap │ │ │ │ │ │ ├── index.stories.test.tsx │ │ │ │ │ │ ├── index.stories.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── index.stories.test.tsx.snap │ │ │ │ │ ├── index.stories.test.tsx │ │ │ │ │ ├── index.stories.tsx │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── ExplorerButton/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── ExternalLink/ │ │ │ │ │ ├── ExternalLink.stories.test.tsx │ │ │ │ │ ├── ExternalLink.stories.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── ExternalLink.stories.test.tsx.snap │ │ │ │ │ └── index.tsx │ │ │ │ ├── FiatValue/ │ │ │ │ │ ├── FiatValue.stories.test.tsx │ │ │ │ │ ├── FiatValue.stories.tsx │ │ │ │ │ ├── FiatValue.test.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── FiatValue.stories.test.tsx.snap │ │ │ │ │ └── index.tsx │ │ │ │ ├── FileUpload/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── Footer/ │ │ │ │ │ ├── footer.type.ts │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── GeoblockingProvider/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── GradientCircularProgress/ │ │ │ │ │ ├── GradientCircularProgress.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── Header/ │ │ │ │ │ ├── Topbar/ │ │ │ │ │ │ ├── NotificationsPopover.test.tsx │ │ │ │ │ │ ├── NotificationsPopover.tsx │ │ │ │ │ │ ├── SafenetStakingButton.tsx │ │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ │ ├── useNotificationsPopover.test.ts │ │ │ │ │ │ │ └── useNotificationsPopover.ts │ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── HelpMenu/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── Identicon/ │ │ │ │ │ ├── Identicon.stories.test.tsx │ │ │ │ │ ├── Identicon.stories.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── Identicon.stories.test.tsx.snap │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── IframeIcon/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── ImageFallback/ │ │ │ │ │ ├── ImageFallback.stories.test.tsx │ │ │ │ │ ├── ImageFallback.stories.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── ImageFallback.stories.test.tsx.snap │ │ │ │ │ └── index.tsx │ │ │ │ ├── InfiniteScroll/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── InfoTooltip/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── InlineRetryError/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── LazyWeb3Init/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── LegalDisclaimerContent/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── MarkdownContent/ │ │ │ │ │ ├── index.module.css │ │ │ │ │ └── index.tsx │ │ │ │ ├── MetaTags/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── ModalDialog/ │ │ │ │ │ ├── ModalDialog.stories.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── Mui/ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── NameInput/ │ │ │ │ │ ├── NameInput.stories.test.tsx │ │ │ │ │ ├── NameInput.stories.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── NameInput.stories.test.tsx.snap │ │ │ │ │ └── index.tsx │ │ │ │ ├── NamedAddressInfo/ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── NavTabs/ │ │ │ │ │ ├── NavTabs.stories.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── Navigate/ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── NestedSafeBreadcrumbs/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── NetworkInput/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── NetworkSelector/ │ │ │ │ │ ├── NetworkMultiSelectorInput.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── Notifications/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.module.css │ │ │ │ │ └── useCounter.ts │ │ │ │ ├── NumberField/ │ │ │ │ │ ├── index.test.ts │ │ │ │ │ └── index.tsx │ │ │ │ ├── ObservabilityErrorBoundary/ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── OnboardingTooltip/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── OnboardingTooltip.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── OnlyOwnerOrProposer/ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── PageHeader/ │ │ │ │ │ ├── PageHeader.stories.test.tsx │ │ │ │ │ ├── PageHeader.stories.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── PageHeader.stories.test.tsx.snap │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── PageLayout/ │ │ │ │ │ ├── SideDrawer.tsx │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── PagePlaceholder/ │ │ │ │ │ ├── PagePlaceholder.stories.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── PaginatedTxns/ │ │ │ │ │ ├── SkeletonTxList.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── PaperViewToggle/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── Popup/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── ProgressBar/ │ │ │ │ │ ├── ProgressBar.stories.test.tsx │ │ │ │ │ ├── ProgressBar.stories.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── ProgressBar.stories.test.tsx.snap │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── PromoBanner/ │ │ │ │ │ ├── PromoBanner.stories.test.tsx │ │ │ │ │ ├── PromoBanner.stories.tsx │ │ │ │ │ ├── PromoBanner.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── PromoBanner.stories.test.tsx.snap │ │ │ │ │ ├── index.ts │ │ │ │ │ └── styles.module.css │ │ │ │ ├── QRCode/ │ │ │ │ │ ├── QRCode.stories.test.tsx │ │ │ │ │ ├── QRCode.stories.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── QRCode.stories.test.tsx.snap │ │ │ │ │ └── index.tsx │ │ │ │ ├── SafeIcon/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── SafeLoadingError/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── SafeLogo/ │ │ │ │ │ ├── SafeLogo.module.css │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── SafeLogo.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── SafenetStakingWidget/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── SignerSelector/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── SpaceSafeBar/ │ │ │ │ │ ├── AccountsModal/ │ │ │ │ │ │ ├── MultiSafeItemCard.test.tsx │ │ │ │ │ │ ├── MultiSafeItemCard.tsx │ │ │ │ │ │ ├── PinnedMultiSafeItem.tsx │ │ │ │ │ │ ├── PinnedSafeContextMenu.tsx │ │ │ │ │ │ ├── PinnedSafeItem.tsx │ │ │ │ │ │ ├── SafeItemCard.test.tsx │ │ │ │ │ │ ├── SafeItemCard.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── shared.tsx │ │ │ │ │ ├── SpaceBackLink.test.tsx │ │ │ │ │ ├── SpaceBackLink.tsx │ │ │ │ │ ├── SpaceChainSelector.stories.tsx │ │ │ │ │ ├── SpaceChainSelector.test.tsx │ │ │ │ │ ├── SpaceChainSelector.tsx │ │ │ │ │ ├── SpaceNestedSafesButton.stories.tsx │ │ │ │ │ ├── SpaceNestedSafesButton.test.tsx │ │ │ │ │ ├── SpaceNestedSafesButton.tsx │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ ├── useSafeBarSafes.test.ts │ │ │ │ │ │ │ ├── useSpaceBackLink.test.ts │ │ │ │ │ │ │ ├── useSpaceChainSelector.test.ts │ │ │ │ │ │ │ └── useSpaceSafeSelectorItems.test.ts │ │ │ │ │ │ ├── useSafeBarSafes.ts │ │ │ │ │ │ ├── useSpaceBackLink.ts │ │ │ │ │ │ ├── useSpaceChainSelector.ts │ │ │ │ │ │ └── useSpaceSafeSelectorItems.ts │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── SpendingLimitLabel/ │ │ │ │ │ ├── SpendingLimitLabel.stories.test.tsx │ │ │ │ │ ├── SpendingLimitLabel.stories.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── SpendingLimitLabel.stories.test.tsx.snap │ │ │ │ │ └── index.tsx │ │ │ │ ├── SplitMenuButton/ │ │ │ │ │ ├── SplitMenuButton.stories.test.tsx │ │ │ │ │ ├── SplitMenuButton.stories.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── SplitMenuButton.stories.test.tsx.snap │ │ │ │ │ └── index.tsx │ │ │ │ ├── Sticky/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── Table/ │ │ │ │ │ ├── DataRow.stories.test.tsx │ │ │ │ │ ├── DataRow.stories.tsx │ │ │ │ │ ├── DataRow.tsx │ │ │ │ │ ├── DataTable.stories.test.tsx │ │ │ │ │ ├── DataTable.stories.tsx │ │ │ │ │ ├── DataTable.tsx │ │ │ │ │ ├── EmptyRow.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ ├── DataRow.stories.test.tsx.snap │ │ │ │ │ │ └── DataTable.stories.test.tsx.snap │ │ │ │ │ └── styles.module.css │ │ │ │ ├── ToggleButtonGroup/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── TokenAmount/ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── index.stories.test.tsx.snap │ │ │ │ │ ├── index.stories.test.tsx │ │ │ │ │ ├── index.stories.tsx │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── TokenAmountInput/ │ │ │ │ │ ├── TokenAmountInput.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── TokenIcon/ │ │ │ │ │ ├── TokenIcon.stories.test.tsx │ │ │ │ │ ├── TokenIcon.stories.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── TokenIcon.stories.test.tsx.snap │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── Track/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── TxModalDialog/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── UnreadBadge/ │ │ │ │ │ ├── UnreadBadge.stories.test.tsx │ │ │ │ │ ├── UnreadBadge.stories.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── UnreadBadge.stories.test.tsx.snap │ │ │ │ │ └── index.tsx │ │ │ │ ├── WalletBalance/ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── WalletIcon/ │ │ │ │ │ ├── WalletIcon.stories.test.tsx │ │ │ │ │ ├── WalletIcon.stories.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── WalletIcon.stories.test.tsx.snap │ │ │ │ │ └── index.tsx │ │ │ │ ├── WalletInfo/ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── WalletOverview/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── WalletProvider/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── WidgetDisclaimer/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ └── icons/ │ │ │ │ └── CircularIcon/ │ │ │ │ ├── index.tsx │ │ │ │ └── styles.module.css │ │ │ ├── dashboard/ │ │ │ │ ├── ActionRequiredPanel/ │ │ │ │ │ ├── ActionRequiredPanel.test.tsx │ │ │ │ │ ├── ActionRequiredPanel.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.module.css │ │ │ │ │ └── useWarningCount.ts │ │ │ │ ├── AddFundsBanner/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── Assets/ │ │ │ │ │ ├── Assets.stories.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── ExplorePossibleWidget/ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── index.stories.test.tsx.snap │ │ │ │ │ ├── index.stories.test.tsx │ │ │ │ │ ├── index.stories.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── FirstSteps/ │ │ │ │ │ ├── FirstSteps.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.module.css │ │ │ │ │ ├── utils.test.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── NewsCarousel/ │ │ │ │ │ ├── NewsDisclaimers.tsx │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── utils.test.ts │ │ │ │ │ ├── banners/ │ │ │ │ │ │ ├── EarnBanner.stories.test.tsx │ │ │ │ │ │ ├── EarnBanner.stories.tsx │ │ │ │ │ │ ├── EarnBanner.tsx │ │ │ │ │ │ ├── EurcvBoostBanner.stories.test.tsx │ │ │ │ │ │ ├── EurcvBoostBanner.stories.tsx │ │ │ │ │ │ ├── EurcvBoostBanner.tsx │ │ │ │ │ │ ├── SpacesBanner.stories.test.tsx │ │ │ │ │ │ ├── SpacesBanner.stories.tsx │ │ │ │ │ │ ├── SpacesBanner.tsx │ │ │ │ │ │ ├── StakeBanner.stories.test.tsx │ │ │ │ │ │ ├── StakeBanner.stories.tsx │ │ │ │ │ │ ├── StakeBanner.tsx │ │ │ │ │ │ └── __snapshots__/ │ │ │ │ │ │ ├── EarnBanner.stories.test.tsx.snap │ │ │ │ │ │ ├── EurcvBoostBanner.stories.test.tsx.snap │ │ │ │ │ │ ├── SpacesBanner.stories.test.tsx.snap │ │ │ │ │ │ └── StakeBanner.stories.test.tsx.snap │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.module.css │ │ │ │ │ └── utils.ts │ │ │ │ ├── Overview/ │ │ │ │ │ ├── Overview.stories.tsx │ │ │ │ │ ├── Overview.tsx │ │ │ │ │ └── OverviewSkeleton.tsx │ │ │ │ ├── PendingTxs/ │ │ │ │ │ ├── PendingRecoveryListItem.tsx │ │ │ │ │ ├── PendingTxList.test.ts │ │ │ │ │ ├── PendingTxListItem.tsx │ │ │ │ │ ├── PendingTxsList.stories.tsx │ │ │ │ │ ├── PendingTxsList.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── SafeAppsDashboardSection/ │ │ │ │ │ ├── SafeAppsDashboardSection.tsx │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── SafeAppsDashboardSection.test.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── StakingBanner/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.module.css │ │ │ │ │ ├── useIsStakingBannerVisible.test.ts │ │ │ │ │ └── useIsStakingBannerVisible.ts │ │ │ │ ├── index.tsx │ │ │ │ ├── styled.stories.tsx │ │ │ │ ├── styled.tsx │ │ │ │ └── styles.module.css │ │ │ ├── new-safe/ │ │ │ │ ├── CardStepper/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.module.css │ │ │ │ │ └── useCardStepper.ts │ │ │ │ ├── OwnerRow/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── ReviewRow/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── create/ │ │ │ │ │ ├── AdvancedCreateSafe.tsx │ │ │ │ │ ├── CreateSafeInfos/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── InfoWidget/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ ├── NetworkWarning/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── NoWalletConnectedWarning/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── OverviewWidget/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ ├── useEstimateSafeCreationGas.test.ts │ │ │ │ │ │ └── useSyncSafeCreationStep.test.ts │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── logic/ │ │ │ │ │ │ ├── address-book.ts │ │ │ │ │ │ ├── index.test.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── utils.test.ts │ │ │ │ │ │ └── utils.ts │ │ │ │ │ ├── steps/ │ │ │ │ │ │ ├── AdvancedOptionsStep/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── OwnerPolicyStep/ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── useSafeSetupHints.ts │ │ │ │ │ │ ├── ReviewStep/ │ │ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── styles.module.css │ │ │ │ │ │ │ ├── utils.test.ts │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ ├── SetNameStep/ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ │ └── StatusStep/ │ │ │ │ │ │ ├── LoadingSpinner/ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ │ ├── StatusMessage.tsx │ │ │ │ │ │ ├── StatusStep.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── styles.module.css │ │ │ │ │ │ └── useUndeployedSafe.ts │ │ │ │ │ ├── styles.module.css │ │ │ │ │ ├── types.d.ts │ │ │ │ │ ├── useEstimateSafeCreationGas.ts │ │ │ │ │ └── useSyncSafeCreationStep.ts │ │ │ │ ├── index.stories.tsx │ │ │ │ └── load/ │ │ │ │ ├── index.tsx │ │ │ │ └── steps/ │ │ │ │ ├── SafeOwnerStep/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── SafeReviewStep/ │ │ │ │ │ └── index.tsx │ │ │ │ └── SetAddressStep/ │ │ │ │ └── index.tsx │ │ │ ├── notification-center/ │ │ │ │ ├── NotificationCenter/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── NotificationCenterItem/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── NotificationCenterList/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── NotificationRenewal/ │ │ │ │ │ └── index.tsx │ │ │ │ └── index.stories.tsx │ │ │ ├── safe-apps/ │ │ │ │ ├── AddCustomAppModal/ │ │ │ │ │ ├── CustomApp.tsx │ │ │ │ │ ├── CustomAppPlaceholder.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── AddCustomSafeAppCard/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── AppFrame/ │ │ │ │ │ ├── SafeAppIframe.tsx │ │ │ │ │ ├── ThirdPartyCookiesWarning.tsx │ │ │ │ │ ├── TransactionQueueBar/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── AppFrame.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.module.css │ │ │ │ │ ├── useAppCommunicator.ts │ │ │ │ │ ├── useAppIsLoading.ts │ │ │ │ │ ├── useFromAppAnalytics.ts │ │ │ │ │ ├── useGetSafeInfo.ts │ │ │ │ │ ├── useThirdPartyCookies.test.ts │ │ │ │ │ ├── useThirdPartyCookies.ts │ │ │ │ │ └── useTransactionQueueBarState.ts │ │ │ │ ├── NativeSwapsCard/ │ │ │ │ │ ├── index.stories.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── PermissionCheckbox.tsx │ │ │ │ ├── PermissionsPrompt.tsx │ │ │ │ ├── RemoveCustomAppModal.tsx │ │ │ │ ├── SafeAppActionButtons/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── SafeAppCard/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── SafeAppIconCard/ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── SafeAppLandingPage/ │ │ │ │ │ ├── AppActions.tsx │ │ │ │ │ ├── SafeAppDetails.tsx │ │ │ │ │ ├── TryDemo.tsx │ │ │ │ │ ├── constants.ts │ │ │ │ │ └── index.tsx │ │ │ │ ├── SafeAppList/ │ │ │ │ │ ├── SafeAppList.stories.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── SafeAppPreviewDrawer/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── SafeAppSocialLinksCard/ │ │ │ │ │ ├── SafeAppSocialLinksCard.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── SafeAppTags/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── SafeAppsErrorBoundary/ │ │ │ │ │ ├── SafeAppsLoadError.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── SafeAppsFilters/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── SafeAppsHeader/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── SafeAppsInfoModal/ │ │ │ │ │ ├── AllowedFeaturesList.tsx │ │ │ │ │ ├── Domain.tsx │ │ │ │ │ ├── Slider.tsx │ │ │ │ │ ├── UnknownAppWarning.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.module.css │ │ │ │ │ └── useSafeAppsInfoModal.ts │ │ │ │ ├── SafeAppsListHeader/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── SafeAppsSDKLink/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── SafeAppsZeroResultsPlaceholder/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── hooks/ │ │ │ │ │ └── useShareSafeAppUrl.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils.ts │ │ │ ├── safe-messages/ │ │ │ │ ├── DecodedMsg/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── InfoBox/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── Msg/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── MsgAuditLog/ │ │ │ │ │ ├── MsgAuditLog.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── MsgDetails/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── MsgList/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── MsgListItem/ │ │ │ │ │ ├── ExpandableMsgItem.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── MsgShareLink/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── MsgSigners/ │ │ │ │ │ ├── MsgSigners.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── MsgSummary/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── MsgType/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── PaginatedMsgs/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── SignMsgButton/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── SingleMsg/ │ │ │ │ │ ├── SingleMsg.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ └── index.stories.tsx │ │ │ ├── settings/ │ │ │ │ ├── ClearPendingTxs/ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── ContractVersion/ │ │ │ │ │ ├── ContractVersion.stories.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── DataManagement/ │ │ │ │ │ ├── FileListCard.tsx │ │ │ │ │ ├── ImportDialog.tsx │ │ │ │ │ ├── ImportFileUpload.tsx │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── useGlobalImportFileParser.test.ts │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.module.css │ │ │ │ │ └── useGlobalImportFileParser.ts │ │ │ │ ├── EnvironmentVariables/ │ │ │ │ │ ├── EnvHintButton/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ ├── RpcProviderSection.tsx │ │ │ │ │ ├── TenderlySection.tsx │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── FallbackHandler/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── FeeTokenPreference/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── NestedSafesList/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── ProposersList/ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── PushNotifications/ │ │ │ │ │ ├── GlobalPushNotifications.tsx │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ ├── GlobalPushNotifications.test.ts │ │ │ │ │ │ └── logic.test.ts │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ ├── useNotificationPreferences.test.ts │ │ │ │ │ │ │ ├── useNotificationRegistrations.test.ts │ │ │ │ │ │ │ ├── useNotificationTracking.test.ts │ │ │ │ │ │ │ ├── useNotificationsRenewal.test.ts │ │ │ │ │ │ │ ├── useNotificationsTokenVersion.test.ts │ │ │ │ │ │ │ └── useShowNotificationsRenewalMessage.test.ts │ │ │ │ │ │ ├── useNotificationPreferences.ts │ │ │ │ │ │ ├── useNotificationRegistrations.ts │ │ │ │ │ │ ├── useNotificationTracking.ts │ │ │ │ │ │ ├── useNotificationsRenewal.ts │ │ │ │ │ │ ├── useNotificationsTokenVersion.ts │ │ │ │ │ │ └── useShowNotificationsRenewalMessage.ts │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── logic.ts │ │ │ │ │ └── styles.module.css │ │ │ │ ├── RequiredConfirmations/ │ │ │ │ │ ├── RequiredConfirmations.stories.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── SafeAppsPermissions/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── SafeAppsSigningMethod/ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── SafeModules/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── SafeModules.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── SecurityLogin/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── SecuritySettings/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── SettingsHeader/ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── TransactionGuards/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── TransactionGuards.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── __tests__/ │ │ │ │ │ └── SecurityLogin.test.tsx │ │ │ │ └── owner/ │ │ │ │ ├── EditOwnerDialog/ │ │ │ │ │ └── index.tsx │ │ │ │ └── OwnerList/ │ │ │ │ ├── OwnerList.stories.tsx │ │ │ │ └── index.tsx │ │ │ ├── sidebar/ │ │ │ │ ├── DebugToggle/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── IndexingStatus/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── NestedSafeInfo/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── NestedSafeIntro/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── NestedSafesButton/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── NestedSafesList/ │ │ │ │ │ ├── SimilarityConfirmDialog.tsx │ │ │ │ │ ├── SimilarityGroupContainer.tsx │ │ │ │ │ ├── SimilarityWarning.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── useManageNestedSafes.ts │ │ │ │ ├── NestedSafesPopover/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.module.css │ │ │ │ │ ├── utils.test.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── NewTxButton/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── QrCodeButton/ │ │ │ │ │ ├── QrModal.stories.tsx │ │ │ │ │ ├── QrModal.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── SafeListContextMenu/ │ │ │ │ │ ├── MultiAccountContextMenu.stories.tsx │ │ │ │ │ ├── MultiAccountContextMenu.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── SafeListRemoveDialog/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── Sidebar/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── SidebarFooter/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── SidebarHeader/ │ │ │ │ │ ├── SafeHeaderInfo.stories.tsx │ │ │ │ │ ├── SafeHeaderInfo.test.tsx │ │ │ │ │ ├── SafeHeaderInfo.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── SidebarList/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ └── SidebarNavigation/ │ │ │ │ ├── config.tsx │ │ │ │ └── index.tsx │ │ │ ├── terms/ │ │ │ │ ├── __tests__/ │ │ │ │ │ └── safe-labs-terms.test.tsx │ │ │ │ ├── safe-labs-terms.tsx │ │ │ │ └── styles.module.css │ │ │ ├── theme/ │ │ │ │ ├── SafeThemeProvider.tsx │ │ │ │ ├── mui.d.ts │ │ │ │ └── safeTheme.ts │ │ │ ├── transactions/ │ │ │ │ ├── BatchExecuteButton/ │ │ │ │ │ ├── BatchExecuteHoverProvider.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── BulkTxListGroup/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── CsvTxExportButton/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── CsvTxExportModal/ │ │ │ │ │ ├── CsvTxExportModal.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── ExecuteTxButton/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── GroupLabel/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── GroupedTxListItems/ │ │ │ │ │ ├── ReplaceTxHoverProvider.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── HexEncodedData/ │ │ │ │ │ ├── HexEncodedData.test.tsx │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── HexEncodedData.test.tsx.snap │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── ImitationTransactionWarning/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── InfoDetails/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── MaliciousTxWarning/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── QueuedTxSimulation/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── RejectTxButton/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── SafeCreationTx/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── SignTxButton/ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── SignedMessagesHelpLink/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── SingleTx/ │ │ │ │ │ ├── SingleTx.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── TrustedToggle/ │ │ │ │ │ ├── TrustedToggleButton.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── TxConfirmations/ │ │ │ │ │ ├── TxConfirmations.stories.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── TxDateLabel/ │ │ │ │ │ ├── TxDateLabel.stories.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── TxDetails/ │ │ │ │ │ ├── Summary/ │ │ │ │ │ │ ├── DecoderLinks.tsx │ │ │ │ │ │ ├── SafeTxHashDataRow/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── TxDataRow/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── TxData/ │ │ │ │ │ │ ├── DecodedData/ │ │ │ │ │ │ │ ├── MethodCall.tsx │ │ │ │ │ │ │ ├── MethodDetails/ │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ ├── Multisend/ │ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ │ │ ├── SingleTxDecoded/ │ │ │ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ │ ├── styles.module.css │ │ │ │ │ │ │ │ ├── useTransferTokenInfo.test.ts │ │ │ │ │ │ │ │ └── useTransferTokenInfo.ts │ │ │ │ │ │ │ ├── ValueArray/ │ │ │ │ │ │ │ │ ├── ValueArray.test.tsx │ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── MigrationToL2TxData/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── NestedTransaction/ │ │ │ │ │ │ │ ├── ExecTransaction/ │ │ │ │ │ │ │ │ ├── ExecTransaction.stories.tsx │ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ │ └── mockData.ts │ │ │ │ │ │ │ ├── NestedTransaction.tsx │ │ │ │ │ │ │ ├── OnChainConfirmation/ │ │ │ │ │ │ │ │ ├── OnChainConfirmation.stories.tsx │ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ │ └── mockData.ts │ │ │ │ │ │ │ └── useSignedHash.tsx │ │ │ │ │ │ ├── Rejection/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── SafeUpdate/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── SettingsChange/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── SpendingLimits/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── Staking/ │ │ │ │ │ │ │ ├── StakingConfirmationTxDeposit.tsx │ │ │ │ │ │ │ ├── StakingConfirmationTxWithdraw.tsx │ │ │ │ │ │ │ ├── StakingStatus.tsx │ │ │ │ │ │ │ ├── StakingTxDepositDetails.tsx │ │ │ │ │ │ │ ├── StakingTxExitDetails.tsx │ │ │ │ │ │ │ ├── StakingTxWithdrawDetails.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── Transfer/ │ │ │ │ │ │ │ ├── TransferActions.tsx │ │ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── useTransferFiatValue.test.ts │ │ │ │ │ │ │ └── useTransferFiatValue.ts │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── TxFilterForm/ │ │ │ │ │ ├── TxFilterForm.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── TxHeader/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── TxInfo/ │ │ │ │ │ ├── Staking/ │ │ │ │ │ │ ├── StakingTxDepositInfo.tsx │ │ │ │ │ │ ├── StakingTxExitInfo.tsx │ │ │ │ │ │ ├── StakingTxWithdrawInfo.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── SwapTx.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── TxList/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── TxListItem/ │ │ │ │ │ ├── ExpandableTransactionItem.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── TxNavigation/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── TxShareLink/ │ │ │ │ │ ├── TxShareLink.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── TxSigners/ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── TxStatusChip/ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ └── index.stories.test.tsx.snap │ │ │ │ │ ├── index.stories.test.tsx │ │ │ │ │ ├── index.stories.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── TxStatusLabel/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── TxSummary/ │ │ │ │ │ ├── QueueActions.tsx │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── TxType/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ └── Warning/ │ │ │ │ ├── Warning.stories.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── styles.module.css │ │ │ ├── tx/ │ │ │ │ ├── AdvancedParams/ │ │ │ │ │ ├── AdvancedParamsForm.tsx │ │ │ │ │ ├── GasLimitInput.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── types.ts │ │ │ │ │ ├── useAdvancedParams.ts │ │ │ │ │ └── useUserNonce.ts │ │ │ │ ├── ApprovalEditor/ │ │ │ │ │ ├── ApprovalEditor.test.tsx │ │ │ │ │ ├── ApprovalEditorForm.test.tsx │ │ │ │ │ ├── ApprovalEditorForm.tsx │ │ │ │ │ ├── ApprovalItem.tsx │ │ │ │ │ ├── ApprovalValueField.tsx │ │ │ │ │ ├── Approvals.tsx │ │ │ │ │ ├── EditableApprovalItem.tsx │ │ │ │ │ ├── SpenderField.test.tsx │ │ │ │ │ ├── SpenderField.tsx │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── useApprovalInfos.test.ts │ │ │ │ │ │ └── useApprovalInfos.ts │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── styles.module.css │ │ │ │ │ └── utils/ │ │ │ │ │ └── approvals.ts │ │ │ │ ├── BalanceInfo/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── ColorCodedTxAccordion/ │ │ │ │ │ ├── HelpTooltip.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── ConfirmTxDetails/ │ │ │ │ │ ├── JsonView.tsx │ │ │ │ │ ├── NameChip.test.tsx │ │ │ │ │ ├── NameChip.tsx │ │ │ │ │ ├── Receipt.tsx │ │ │ │ │ └── TxDetailsRow.tsx │ │ │ │ ├── ConfirmTxReceipt/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── ConfirmationOrder/ │ │ │ │ │ └── ConfirmationOrderHeader.tsx │ │ │ │ ├── ErrorMessage/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── ExecuteCheckbox/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── ExecutionMethodSelector/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── FieldsGrid/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── GasParams/ │ │ │ │ │ ├── GasParams.test.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── RemainingRelays/ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── ReviewTransactionV2/ │ │ │ │ │ ├── ErrorTransactionPreview.tsx │ │ │ │ │ ├── ReviewTransactionContent.tsx │ │ │ │ │ ├── ReviewTransactionSkeleton.tsx │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── SendFromBlock/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── SendToBlock/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── SponsoredBy/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── SuccessMessage/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── confirmation-views/ │ │ │ │ │ ├── BatchTransactions/ │ │ │ │ │ │ ├── BatchTransactions.stories.test.tsx │ │ │ │ │ │ ├── BatchTransactions.stories.tsx │ │ │ │ │ │ ├── BatchTransactions.test.tsx │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ ├── BatchTransactions.stories.test.tsx.snap │ │ │ │ │ │ │ └── BatchTransactions.test.tsx.snap │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── mockData.ts │ │ │ │ │ ├── BridgeTransaction/ │ │ │ │ │ │ ├── BridgeTransaction.stories.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── mockData.ts │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ ├── ChangeThreshold/ │ │ │ │ │ │ ├── ChangeThreshold.stories.test.tsx │ │ │ │ │ │ ├── ChangeThreshold.stories.tsx │ │ │ │ │ │ ├── ChangeThreshold.test.tsx │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ ├── ChangeThreshold.stories.test.tsx.snap │ │ │ │ │ │ │ └── ChangeThreshold.test.tsx.snap │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── LifiSwapTransaction/ │ │ │ │ │ │ ├── LifiSwapTransaction.stories.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── mockData.ts │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ ├── ManageSigners/ │ │ │ │ │ │ ├── ManageSigners.stories.tsx │ │ │ │ │ │ ├── get-new-safe-setup.test.ts │ │ │ │ │ │ ├── get-new-safe-setup.ts │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── mockData.ts │ │ │ │ │ ├── MigrateToL2Information/ │ │ │ │ │ │ ├── MigrateToL2Information.stories.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── NestedSafeCreation/ │ │ │ │ │ │ ├── NestedSafeCreation.stories.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── mockData.ts │ │ │ │ │ ├── SettingsChange/ │ │ │ │ │ │ ├── SettingsChange.stories.test.tsx │ │ │ │ │ │ ├── SettingsChange.stories.tsx │ │ │ │ │ │ ├── SettingsChange.test.tsx │ │ │ │ │ │ ├── UntrustedFallbackHandlerTxAlert.tsx │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ ├── SettingsChange.stories.test.tsx.snap │ │ │ │ │ │ │ └── SettingsChange.test.tsx.snap │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── mockData.ts │ │ │ │ │ ├── StakingTx/ │ │ │ │ │ │ ├── StakingTx.stories.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── mockData.ts │ │ │ │ │ ├── SwapOrder/ │ │ │ │ │ │ ├── SwapOrder.stories.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── mockData.ts │ │ │ │ │ ├── UpdateSafe/ │ │ │ │ │ │ ├── UpdateSafe.stories.tsx │ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── mockData.ts │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── types.d.ts │ │ │ │ │ ├── useTxPreview.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── security/ │ │ │ │ │ ├── BalanceChanges/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ └── tenderly/ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ ├── useSimulation.test.ts │ │ │ │ │ │ └── utils.test.ts │ │ │ │ │ ├── useSimulation.ts │ │ │ │ │ └── utils.ts │ │ │ │ └── shared/ │ │ │ │ ├── ConfirmationTitle.tsx │ │ │ │ ├── __tests__/ │ │ │ │ │ └── hooks.test.ts │ │ │ │ ├── errors/ │ │ │ │ │ ├── NonOwnerError.tsx │ │ │ │ │ ├── RiskConfirmationError.tsx │ │ │ │ │ ├── UnknownContractError.tsx │ │ │ │ │ └── WalletRejectionError.tsx │ │ │ │ ├── hooks.ts │ │ │ │ ├── styles.module.css │ │ │ │ ├── tracking.test.ts │ │ │ │ ├── tracking.ts │ │ │ │ └── types.ts │ │ │ ├── tx-flow/ │ │ │ │ ├── SafeTxProvider.tsx │ │ │ │ ├── TxFlow.tsx │ │ │ │ ├── TxFlowProvider.tsx │ │ │ │ ├── TxFlowStep.tsx │ │ │ │ ├── TxInfoProvider.tsx │ │ │ │ ├── __tests__/ │ │ │ │ │ └── SafeTxProvider.test.tsx │ │ │ │ ├── actions/ │ │ │ │ │ ├── Batching/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── ComboSubmit.tsx │ │ │ │ │ ├── Counterfactual.tsx │ │ │ │ │ ├── Execute/ │ │ │ │ │ │ ├── ExecuteForm.tsx │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ └── ExecuteForm.test.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ ├── ExecuteThroughRole/ │ │ │ │ │ │ ├── ExecuteThroughRoleForm/ │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ ├── ExecuteThroughRoleForm.test.tsx │ │ │ │ │ │ │ │ └── hooks.test.ts │ │ │ │ │ │ │ ├── hooks.ts │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── Propose/ │ │ │ │ │ │ ├── ProposerForm.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── Sign/ │ │ │ │ │ │ ├── SignForm.tsx │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ └── SignForm.test.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ ├── ComboSubmit.test.tsx │ │ │ │ │ │ └── ExecuteThroughRoleSlot.test.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── common/ │ │ │ │ │ ├── OwnerList/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ ├── SafeInfo/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── TxButton.tsx │ │ │ │ │ ├── TxCard/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── TxFlowContent/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ ├── TxLayout/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ ├── TxNonce/ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ └── TxNonce.test.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ ├── TxStatusWidget/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ ├── constants.ts │ │ │ │ │ └── styles.module.css │ │ │ │ ├── features/ │ │ │ │ │ ├── BalanceChanges.tsx │ │ │ │ │ ├── ExecuteCheckbox.tsx │ │ │ │ │ ├── FeeInfoBanner.tsx │ │ │ │ │ ├── FeesPreview.tsx │ │ │ │ │ ├── RiskConfirmation.tsx │ │ │ │ │ ├── SignerSelect/ │ │ │ │ │ │ ├── SignerForm/ │ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── TxNote.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── flows/ │ │ │ │ │ ├── AddOwner/ │ │ │ │ │ │ ├── ChooseOwner.tsx │ │ │ │ │ │ ├── ReviewOwner.tsx │ │ │ │ │ │ ├── context.ts │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── CancelRecovery/ │ │ │ │ │ │ ├── CancelRecoveryFlowReview.tsx │ │ │ │ │ │ ├── CancelRecoveryOverview.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ ├── ChangeThreshold/ │ │ │ │ │ │ ├── ChooseThreshold.tsx │ │ │ │ │ │ ├── ReviewChangeThreshold.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── ConfirmBatch/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── ConfirmTx/ │ │ │ │ │ │ ├── ConfirmProposedTx.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── CreateNestedSafe/ │ │ │ │ │ │ ├── ReviewNestedSafe.tsx │ │ │ │ │ │ ├── SetupNestedSafe.tsx │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ ├── ExecuteBatch/ │ │ │ │ │ │ ├── DecodedTxs.tsx │ │ │ │ │ │ ├── ReviewBatch.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── useMultiSendContract.ts │ │ │ │ │ ├── ManagerSigners/ │ │ │ │ │ │ ├── ReviewSigners.tsx │ │ │ │ │ │ ├── SignersStructure.tsx │ │ │ │ │ │ ├── SignersStructureView.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── MigrateSafeL2/ │ │ │ │ │ │ ├── MigrateSafeL2Review.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── NestedTxSuccessScreen/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ ├── NewSpendingLimit/ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ └── SpendingLimitForm.test.ts │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── NewTx/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ ├── NftTransfer/ │ │ │ │ │ │ ├── ReviewNftBatch.tsx │ │ │ │ │ │ ├── SendNftBatch.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── RecoverAccount/ │ │ │ │ │ │ ├── RecoverAccountFlowReview.tsx │ │ │ │ │ │ ├── RecoverAccountFlowSetup.tsx │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ └── RecoverAccountFlowSetup.test.ts │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── RecoveryAttempt/ │ │ │ │ │ │ ├── RecoveryAttemptReview.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── RejectTx/ │ │ │ │ │ │ ├── RejectTx.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── RemoveGuard/ │ │ │ │ │ │ ├── ReviewRemoveGuard.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── RemoveModule/ │ │ │ │ │ │ ├── ReviewRemoveModule.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── RemoveOwner/ │ │ │ │ │ │ ├── ReviewRemoveOwner.tsx │ │ │ │ │ │ ├── SetThreshold.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ ├── RemoveRecovery/ │ │ │ │ │ │ ├── RemoveRecoveryFlowOverview.tsx │ │ │ │ │ │ ├── RemoveRecoveryFlowReview.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── RemoveSpendingLimit/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── ReplaceOwner/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── ReplaceTx/ │ │ │ │ │ │ ├── DeleteTxModal.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ ├── SafeAppsTx/ │ │ │ │ │ │ ├── ReviewSafeAppsTx.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── SignMessage/ │ │ │ │ │ │ ├── SignMessage.test.tsx │ │ │ │ │ │ ├── SignMessage.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── SignMessageOnChain/ │ │ │ │ │ │ ├── ReviewSignMessageOnChain.test.tsx │ │ │ │ │ │ ├── ReviewSignMessageOnChain.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── SuccessScreen/ │ │ │ │ │ │ ├── StatusStepper.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── statuses/ │ │ │ │ │ │ │ ├── DefaultStatus.tsx │ │ │ │ │ │ │ ├── IndexingStatus.tsx │ │ │ │ │ │ │ └── ProcessingStatus.tsx │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ ├── TokenTransfer/ │ │ │ │ │ │ ├── CSVAirdropAppModal/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── CreateTokenTransfer.tsx │ │ │ │ │ │ ├── RecipientRow/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── ReviewRecipientRow.tsx │ │ │ │ │ │ ├── ReviewTokenTransfer.tsx │ │ │ │ │ │ ├── ReviewTokenTx.tsx │ │ │ │ │ │ ├── SendAmountBlock.stories.tsx │ │ │ │ │ │ ├── SendAmountBlock.tsx │ │ │ │ │ │ ├── SpendingLimitRow/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ ├── CreateTokenTransfer.test.tsx │ │ │ │ │ │ │ ├── ReviewTokenTransfer.test.tsx │ │ │ │ │ │ │ ├── SendAmountBlock.test.tsx │ │ │ │ │ │ │ └── utils.test.ts │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ └── utils.ts │ │ │ │ │ ├── UpdateSafe/ │ │ │ │ │ │ ├── UpdateSafeReview.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── UpsertRecovery/ │ │ │ │ │ │ ├── RecovererSmartContractWarning.tsx │ │ │ │ │ │ ├── UpsertRecoveryFlowIntro.tsx │ │ │ │ │ │ ├── UpsertRecoveryFlowReview.tsx │ │ │ │ │ │ ├── UpsertRecoveryFlowSettings.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── styles.module.css │ │ │ │ │ │ ├── useRecoveryPeriods.ts │ │ │ │ │ │ └── utils.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── index.stories.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── slots/ │ │ │ │ │ ├── Slot.tsx │ │ │ │ │ ├── SlotProvider.tsx │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── useRegisterSlot.ts │ │ │ │ │ │ ├── useSlot.ts │ │ │ │ │ │ ├── useSlotContext.ts │ │ │ │ │ │ └── useSlotIds.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── withSlot.tsx │ │ │ │ └── useTxStepper.tsx │ │ │ ├── ui/ │ │ │ │ ├── README.md │ │ │ │ ├── ShadcnProvider.tsx │ │ │ │ ├── accordion.tsx │ │ │ │ ├── alert-dialog.tsx │ │ │ │ ├── alert.tsx │ │ │ │ ├── aspect-ratio.tsx │ │ │ │ ├── avatar.tsx │ │ │ │ ├── badge.tsx │ │ │ │ ├── breadcrumb.tsx │ │ │ │ ├── button.tsx │ │ │ │ ├── card.tsx │ │ │ │ ├── checkbox.tsx │ │ │ │ ├── collapsible.tsx │ │ │ │ ├── combobox.tsx │ │ │ │ ├── context-menu.tsx │ │ │ │ ├── dialog.tsx │ │ │ │ ├── docs/ │ │ │ │ │ └── figma-code-connect.md │ │ │ │ ├── drawer.tsx │ │ │ │ ├── dropdown-menu.tsx │ │ │ │ ├── empty.tsx │ │ │ │ ├── field.tsx │ │ │ │ ├── hover-card.tsx │ │ │ │ ├── input-group.tsx │ │ │ │ ├── input-otp.tsx │ │ │ │ ├── input.test.ts │ │ │ │ ├── input.tsx │ │ │ │ ├── kbd.tsx │ │ │ │ ├── label.tsx │ │ │ │ ├── native-select.tsx │ │ │ │ ├── navigation-menu.tsx │ │ │ │ ├── pagination.tsx │ │ │ │ ├── popover.tsx │ │ │ │ ├── progress.tsx │ │ │ │ ├── radio-group.tsx │ │ │ │ ├── resizable.tsx │ │ │ │ ├── scroll-area.tsx │ │ │ │ ├── select.tsx │ │ │ │ ├── separator.tsx │ │ │ │ ├── sheet.tsx │ │ │ │ ├── sidebar.tsx │ │ │ │ ├── skeleton.tsx │ │ │ │ ├── slider.tsx │ │ │ │ ├── sonner.tsx │ │ │ │ ├── spinner.tsx │ │ │ │ ├── stories/ │ │ │ │ │ ├── accordion.stories.tsx │ │ │ │ │ ├── alert-dialog.stories.tsx │ │ │ │ │ ├── alert.stories.tsx │ │ │ │ │ ├── aspect-ratio.stories.tsx │ │ │ │ │ ├── avatar.stories.tsx │ │ │ │ │ ├── badge.stories.tsx │ │ │ │ │ ├── breadcrumb.stories.tsx │ │ │ │ │ ├── button.stories.tsx │ │ │ │ │ ├── card.stories.tsx │ │ │ │ │ ├── checkbox.stories.tsx │ │ │ │ │ ├── collapsible.stories.tsx │ │ │ │ │ ├── combobox.stories.tsx │ │ │ │ │ ├── context-menu.stories.tsx │ │ │ │ │ ├── drawer.stories.tsx │ │ │ │ │ ├── dropdown-menu.stories.tsx │ │ │ │ │ ├── empty.stories.tsx │ │ │ │ │ ├── field.stories.tsx │ │ │ │ │ ├── hover-card.stories.tsx │ │ │ │ │ ├── input-group.stories.tsx │ │ │ │ │ ├── input-otp.stories.tsx │ │ │ │ │ ├── input.stories.tsx │ │ │ │ │ ├── kbd.stories.tsx │ │ │ │ │ ├── label.stories.tsx │ │ │ │ │ ├── native-select.stories.tsx │ │ │ │ │ ├── navigation-menu.stories.tsx │ │ │ │ │ ├── pagination.stories.tsx │ │ │ │ │ ├── popover.stories.tsx │ │ │ │ │ ├── progress.stories.tsx │ │ │ │ │ ├── radio-group.stories.tsx │ │ │ │ │ ├── resizable.stories.tsx │ │ │ │ │ ├── scroll-area.stories.tsx │ │ │ │ │ ├── select.stories.tsx │ │ │ │ │ ├── separator.stories.tsx │ │ │ │ │ ├── sheet.stories.tsx │ │ │ │ │ ├── sidebar.stories.tsx │ │ │ │ │ ├── skeleton.stories.tsx │ │ │ │ │ ├── slider.stories.tsx │ │ │ │ │ ├── sonner.stories.tsx │ │ │ │ │ ├── spinner.stories.tsx │ │ │ │ │ ├── switch.stories.tsx │ │ │ │ │ ├── table.stories.tsx │ │ │ │ │ ├── tabs.stories.tsx │ │ │ │ │ ├── textarea.stories.tsx │ │ │ │ │ ├── toggle.stories.tsx │ │ │ │ │ ├── tooltip.stories.tsx │ │ │ │ │ └── typography.stories.tsx │ │ │ │ ├── switch.tsx │ │ │ │ ├── table.tsx │ │ │ │ ├── tabs.tsx │ │ │ │ ├── textarea.tsx │ │ │ │ ├── toggle.tsx │ │ │ │ ├── tooltip.tsx │ │ │ │ └── typography.tsx │ │ │ ├── welcome/ │ │ │ │ ├── NewSafe.tsx │ │ │ │ ├── WelcomeLogin/ │ │ │ │ │ ├── WalletLogin.tsx │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ └── WalletLogin.test.tsx │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ ├── useHomeAuth.test.ts │ │ │ │ │ │ │ └── useSignInRedirect.test.ts │ │ │ │ │ │ ├── useHomeAuth.ts │ │ │ │ │ │ └── useSignInRedirect.ts │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.module.css │ │ │ │ ├── index.stories.tsx │ │ │ │ ├── styles.module.css │ │ │ │ └── welcomeFooter.module.css │ │ │ └── wrappers/ │ │ │ ├── DisclaimerWrapper/ │ │ │ │ ├── index.test.tsx │ │ │ │ └── index.tsx │ │ │ ├── FeatureWrapper/ │ │ │ │ ├── index.test.tsx │ │ │ │ └── index.tsx │ │ │ └── SanctionWrapper/ │ │ │ ├── index.test.tsx │ │ │ └── index.tsx │ │ ├── config/ │ │ │ ├── constants.ts │ │ │ ├── eurcv.ts │ │ │ ├── gateway.ts │ │ │ ├── routes.ts │ │ │ ├── securityHeaders.ts │ │ │ └── version.ts │ │ ├── definitions.d.ts │ │ ├── features/ │ │ │ ├── __core__/ │ │ │ │ ├── __tests__/ │ │ │ │ │ └── useLoadFeature.test.ts │ │ │ │ ├── createFeatureHandle.ts │ │ │ │ ├── index.ts │ │ │ │ ├── types.ts │ │ │ │ ├── useLoadFeature.ts │ │ │ │ └── withSuspense.tsx │ │ │ ├── __tests__/ │ │ │ │ └── feature-flags-integration.test.tsx │ │ │ ├─
Showing preview only (786K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (7344 symbols across 2490 files)
FILE: .github/scripts/capture-mobile-screenshots.js
function createServer (line 13) | function createServer(staticDir, port) {
function captureScreenshots (line 89) | async function captureScreenshots() {
FILE: .github/scripts/capture-page-screenshots.js
constant COOKIE_CONSENT (line 21) | const COOKIE_CONSENT = JSON.stringify({
function capturePageScreenshots (line 29) | async function capturePageScreenshots() {
FILE: .github/scripts/capture-web-storybook-screenshots.js
function captureScreenshots (line 11) | async function captureScreenshots() {
FILE: .github/scripts/generate-mobile-story-urls.js
function extractTitleFromFile (line 27) | function extractTitleFromFile(filePath) {
function titleToStoryId (line 50) | function titleToStoryId(title) {
function filePathToStoryId (line 57) | function filePathToStoryId(filePath) {
function extractStoryNames (line 70) | function extractStoryNames(filePath) {
FILE: .github/scripts/generate-web-story-urls.js
function extractTitleFromFile (line 26) | function extractTitleFromFile(filePath) {
function titleToStoryId (line 50) | function titleToStoryId(title) {
function filePathToStoryId (line 60) | function filePathToStoryId(filePath) {
function extractStoryNames (line 79) | function extractStoryNames(filePath) {
FILE: .github/scripts/map-files-to-routes.js
constant TEST_SAFE (line 12) | const TEST_SAFE = 'eth:0xA77DE01e157f9f57C7c4A326eeE9C4874D0598b6'
constant EXCLUDED_ROUTES (line 15) | const EXCLUDED_ROUTES = [
function parseRoutesFromFile (line 49) | function parseRoutesFromFile() {
function routeToName (line 73) | function routeToName(route) {
function parseImports (line 87) | function parseImports(filePath) {
function resolveToFile (line 127) | function resolveToFile(basePath) {
function resolveImportPath (line 157) | function resolveImportPath(importPath, fromFile) {
function getAllSourceFiles (line 205) | function getAllSourceFiles(dir, files = []) {
function buildReverseDependencyMap (line 235) | function buildReverseDependencyMap(sourceFiles) {
function findAllDependents (line 276) | function findAllDependents(file, reverseDeps, visited = new Set()) {
function isPageFile (line 300) | function isPageFile(filePath) {
function pageFileToRoute (line 313) | function pageFileToRoute(filePath) {
constant MAX_ROUTES (line 416) | const MAX_ROUTES = 10
FILE: .github/scripts/publish/download-artifact.js
constant ARTIFACT_CONFIG (line 22) | const ARTIFACT_CONFIG = {
constant SIZE_CAP_BYTES (line 38) | const SIZE_CAP_BYTES = 50 * 1024 * 1024
constant FILENAME_REGEX (line 40) | const FILENAME_REGEX = ARTIFACT_CONFIG.page.filenameRegex
FILE: .github/scripts/publish/post-comment.js
constant BOT_LOGIN (line 15) | const BOT_LOGIN = 'github-actions[bot]'
constant COLLAPSIBLE_THRESHOLD (line 16) | const COLLAPSIBLE_THRESHOLD = 8
constant ARTIFACT_PROFILES (line 25) | const ARTIFACT_PROFILES = {
constant MARKER (line 50) | const MARKER = ARTIFACT_PROFILES.page.marker
constant COMMENT_HEADER (line 51) | const COMMENT_HEADER = `## ${MARKER}`
constant FILENAME_REGEX (line 52) | const FILENAME_REGEX = ARTIFACT_PROFILES.page.filenameRegex
FILE: apps/mobile/.storybook/mocks/react-native-reanimated.js
method get (line 17) | get(target, prop) {
method set (line 30) | set(target, prop, newValue) {
FILE: apps/mobile/app.config.ts
constant IS_DEV (line 3) | const IS_DEV = process.env.APP_VARIANT === 'development'
FILE: apps/mobile/expo-plugins/ssl-pinning/withSSLPinning.js
function withIOSSSLPinning (line 7) | function withIOSSSLPinning(config, { domains }) {
function withAndroidSSLPinning (line 93) | function withAndroidSSLPinning(config, { domains }) {
FILE: apps/mobile/expo-plugins/withDrawableAssets.js
function copyFolderRecursiveSync (line 37) | function copyFolderRecursiveSync(source, target) {
FILE: apps/mobile/expo-plugins/withNotificationIcons.js
function addNotificationIconMetadata (line 3) | function addNotificationIconMetadata(androidManifest) {
FILE: apps/mobile/index.js
function App (line 14) | function App() {
FILE: apps/mobile/scripts/getCertificates.js
function getFullCertificateChain (line 17) | function getFullCertificateChain(hostname, port = 443) {
function extractCertificateHash (line 99) | function extractCertificateHash(cert) {
function displayCertificateInfo (line 104) | function displayCertificateInfo(domain, chain) {
function main (line 184) | async function main() {
FILE: apps/mobile/src/app/(import-accounts)/_layout.tsx
function ImportAccountsLayout (line 7) | function ImportAccountsLayout() {
FILE: apps/mobile/src/app/(import-accounts)/form.tsx
function ImportAccountFormScreen (line 5) | function ImportAccountFormScreen() {
FILE: apps/mobile/src/app/(import-accounts)/index.tsx
function IndexScreen (line 4) | function IndexScreen() {
FILE: apps/mobile/src/app/(import-accounts)/signers.tsx
function ImportSignersFormScreen (line 6) | function ImportSignersFormScreen() {
FILE: apps/mobile/src/app/(send)/_layout.tsx
function SendLayout (line 8) | function SendLayout() {
FILE: apps/mobile/src/app/(send)/amount.tsx
function AmountScreen (line 5) | function AmountScreen() {
FILE: apps/mobile/src/app/(send)/recipient.tsx
function RecipientScreen (line 4) | function RecipientScreen() {
FILE: apps/mobile/src/app/(send)/scan-qr.tsx
function ScanQrScreen (line 3) | function ScanQrScreen() {
FILE: apps/mobile/src/app/(send)/token.tsx
function TokenScreen (line 4) | function TokenScreen() {
FILE: apps/mobile/src/app/(tabs)/_layout.tsx
function TabBarBackground (line 12) | function TabBarBackground() {
function TabLayout (line 25) | function TabLayout() {
FILE: apps/mobile/src/app/(tabs)/settings.tsx
function SettingsScreen (line 3) | function SettingsScreen() {
FILE: apps/mobile/src/app/(tabs)/transactions.tsx
function TransactionScreen (line 3) | function TransactionScreen() {
FILE: apps/mobile/src/app/+html.tsx
function Root (line 8) | function Root({ children }: PropsWithChildren) {
FILE: apps/mobile/src/app/+native-intent.tsx
function redirectSystemPath (line 18) | function redirectSystemPath({ path, initial: _initial }: { path: string;...
FILE: apps/mobile/src/app/+not-found.tsx
function NotFoundScreen (line 7) | function NotFoundScreen() {
FILE: apps/mobile/src/app/_layout.tsx
function NavigationStack (line 86) | function NavigationStack() {
function RootLayout (line 139) | function RootLayout() {
FILE: apps/mobile/src/app/action-details.tsx
function ActionDetails (line 8) | function ActionDetails() {
FILE: apps/mobile/src/app/address-book.tsx
function AddressBookScreen (line 4) | function AddressBookScreen() {
FILE: apps/mobile/src/app/app-settings.tsx
function SignersScreen (line 4) | function SignersScreen() {
FILE: apps/mobile/src/app/biometrics-opt-in.tsx
function BiometricsOptIn (line 12) | function BiometricsOptIn() {
FILE: apps/mobile/src/app/confirm-transaction.tsx
function ConfirmTransactionPage (line 5) | function ConfirmTransactionPage() {
FILE: apps/mobile/src/app/contact.tsx
function ContactScreen (line 5) | function ContactScreen() {
FILE: apps/mobile/src/app/currency.tsx
function Currency (line 4) | function Currency() {
FILE: apps/mobile/src/app/developer.tsx
function DeveloperScreen (line 6) | function DeveloperScreen() {
FILE: apps/mobile/src/app/execute-transaction/_layout.tsx
function ExecuteTransactionLayout (line 4) | function ExecuteTransactionLayout() {
FILE: apps/mobile/src/app/execute-transaction/ledger-connect.tsx
function Page (line 4) | function Page() {
FILE: apps/mobile/src/app/execute-transaction/ledger-pairing.tsx
function Page (line 4) | function Page() {
FILE: apps/mobile/src/app/execute-transaction/ledger-review.tsx
function Page (line 4) | function Page() {
FILE: apps/mobile/src/app/execution-error.tsx
function ExecutionErrorScreen (line 4) | function ExecutionErrorScreen() {
FILE: apps/mobile/src/app/execution-success.tsx
function ExecutionSuccessScreen (line 3) | function ExecutionSuccessScreen() {
FILE: apps/mobile/src/app/get-started.tsx
function getStartedScreen (line 4) | function getStartedScreen() {
FILE: apps/mobile/src/app/history-transaction-details.tsx
function HistoryTransactionDetailsPage (line 5) | function HistoryTransactionDetailsPage() {
FILE: apps/mobile/src/app/import-data/_layout.tsx
function ImportDataLayout (line 14) | function ImportDataLayout() {
FILE: apps/mobile/src/app/import-data/import-progress.tsx
function ImportProgress (line 4) | function ImportProgress() {
FILE: apps/mobile/src/app/import-data/import-success.tsx
function ImportSuccess (line 4) | function ImportSuccess() {
FILE: apps/mobile/src/app/import-signers/_layout.tsx
function ImportSignersLayout (line 8) | function ImportSignersLayout() {
FILE: apps/mobile/src/app/import-signers/connect-signer-error.tsx
function ConnectSignerErrorScreen (line 9) | function ConnectSignerErrorScreen() {
FILE: apps/mobile/src/app/import-signers/connect-signer-success.tsx
function ConnectSignerSuccess (line 6) | function ConnectSignerSuccess() {
FILE: apps/mobile/src/app/import-signers/hardware-devices.tsx
function HardwareDevicesPage (line 6) | function HardwareDevicesPage() {
FILE: apps/mobile/src/app/import-signers/index.tsx
function ImportSignersPage (line 5) | function ImportSignersPage() {
FILE: apps/mobile/src/app/import-signers/ledger-addresses.tsx
function LedgerAddressesPage (line 3) | function LedgerAddressesPage() {
FILE: apps/mobile/src/app/import-signers/ledger-connect.tsx
function LedgerConnectPage (line 6) | function LedgerConnectPage() {
FILE: apps/mobile/src/app/import-signers/ledger-error.tsx
function LedgerErrorPage (line 8) | function LedgerErrorPage() {
FILE: apps/mobile/src/app/import-signers/ledger-pairing.tsx
function LedgerPairingPage (line 6) | function LedgerPairingPage() {
FILE: apps/mobile/src/app/import-signers/ledger-success.tsx
function LedgerSuccessPage (line 4) | function LedgerSuccessPage() {
FILE: apps/mobile/src/app/import-signers/loading.tsx
function LoadingImportPage (line 4) | function LoadingImportPage() {
FILE: apps/mobile/src/app/import-signers/name-signer.tsx
function NameSigner (line 12) | function NameSigner() {
FILE: apps/mobile/src/app/import-signers/private-key-error.tsx
function App (line 8) | function App() {
FILE: apps/mobile/src/app/import-signers/private-key-success.tsx
function ImportPrivateKeySuccess (line 7) | function ImportPrivateKeySuccess() {
FILE: apps/mobile/src/app/import-signers/private-key.tsx
function PrivateKeyImport (line 6) | function PrivateKeyImport() {
FILE: apps/mobile/src/app/import-signers/reconnect-error.tsx
function ReconnectErrorScreen (line 9) | function ReconnectErrorScreen() {
FILE: apps/mobile/src/app/import-signers/seed-phrase-addresses.tsx
function SeedPhraseAddresses (line 6) | function SeedPhraseAddresses() {
FILE: apps/mobile/src/app/import-signers/signer.tsx
function SignerImport (line 6) | function SignerImport() {
FILE: apps/mobile/src/app/index.tsx
function IndexScreen (line 13) | function IndexScreen() {
FILE: apps/mobile/src/app/notifications-center.tsx
function NotificationsCenterScreen (line 4) | function NotificationsCenterScreen() {
FILE: apps/mobile/src/app/notifications-opt-in.tsx
function NotificationsOptIn (line 11) | function NotificationsOptIn() {
FILE: apps/mobile/src/app/notifications-settings.tsx
function NotificationsSettingsScreen (line 4) | function NotificationsSettingsScreen() {
FILE: apps/mobile/src/app/onboarding.tsx
function OnboardingPage (line 4) | function OnboardingPage() {
FILE: apps/mobile/src/app/pending-transactions.tsx
function PendingScreen (line 5) | function PendingScreen() {
FILE: apps/mobile/src/app/review-and-confirm.tsx
function ReviewAndConfirmScreen (line 4) | function ReviewAndConfirmScreen() {
FILE: apps/mobile/src/app/review-and-execute.tsx
function ReviewAndExecuteScreen (line 4) | function ReviewAndExecuteScreen() {
FILE: apps/mobile/src/app/share.tsx
function ShareScreen (line 5) | function ShareScreen() {
FILE: apps/mobile/src/app/sign-transaction/_layout.tsx
function SignTransactionLayout (line 4) | function SignTransactionLayout() {
FILE: apps/mobile/src/app/sign-transaction/ledger-connect.tsx
function Page (line 4) | function Page() {
FILE: apps/mobile/src/app/sign-transaction/ledger-pairing.tsx
function Page (line 4) | function Page() {
FILE: apps/mobile/src/app/sign-transaction/ledger-review.tsx
function Page (line 4) | function Page() {
FILE: apps/mobile/src/app/signers/[address].tsx
function SignerDetailsPage (line 5) | function SignerDetailsPage() {
FILE: apps/mobile/src/app/signers/[address]/private-key.tsx
function PrivateKeyScreen (line 7) | function PrivateKeyScreen() {
FILE: apps/mobile/src/app/signers/_layout.tsx
function SignersLayout (line 5) | function SignersLayout() {
FILE: apps/mobile/src/app/signers/index.tsx
function SignersScreen (line 6) | function SignersScreen() {
FILE: apps/mobile/src/app/signing-error.tsx
function SigningErrorScreen (line 4) | function SigningErrorScreen() {
FILE: apps/mobile/src/app/signing-success.tsx
function SigningSuccessScreen (line 3) | function SigningSuccessScreen() {
FILE: apps/mobile/src/app/transaction-actions.tsx
function TransactionActions (line 8) | function TransactionActions() {
FILE: apps/mobile/src/app/transaction-parameters/(tabs)/_layout.tsx
function TransactionsLayout (line 17) | function TransactionsLayout() {
FILE: apps/mobile/src/app/transaction-parameters/(tabs)/index.tsx
function TransactionData (line 8) | function TransactionData() {
FILE: apps/mobile/src/app/transaction-parameters/(tabs)/parameters.tsx
function TransactionParameters (line 7) | function TransactionParameters() {
FILE: apps/mobile/src/app/transaction-parameters/_layout.tsx
function TransactionsParametersLayout (line 4) | function TransactionsParametersLayout() {
FILE: apps/mobile/src/components/ActionsRow/ActionsRow.tsx
type ActionsRowProps (line 10) | interface ActionsRowProps {
function ActionsRow (line 16) | function ActionsRow({ txId, decodedData, actionCount }: ActionsRowProps) {
FILE: apps/mobile/src/components/Alert/Alert.stories.tsx
type Story (line 17) | type Story = StoryObj<typeof Alert>
FILE: apps/mobile/src/components/Alert/Alert.tsx
type AlertType (line 7) | type AlertType = 'error' | 'warning' | 'info' | 'success'
type AlertOrientation (line 8) | type AlertOrientation = 'left' | 'center' | 'right'
type AlertProps (line 10) | interface AlertProps {
FILE: apps/mobile/src/components/Badge/Badge.tsx
type BadgeThemeKeys (line 5) | type BadgeThemeKeys = keyof typeof badgeTheme
type ExtractAfterUnderscore (line 7) | type ExtractAfterUnderscore<T extends string> = T extends `${string}_${i...
type BadgeThemeTypes (line 8) | type BadgeThemeTypes = ExtractAfterUnderscore<BadgeThemeKeys>
type BadgeProps (line 10) | interface BadgeProps {
FILE: apps/mobile/src/components/Badge/badge.stories.tsx
type Story (line 17) | type Story = StoryObj<typeof Badge>
FILE: apps/mobile/src/components/BadgeWrapper/BadgeWrapper.tsx
type BadgePosition (line 4) | type BadgePosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-...
type BadgeWrapperProps (line 6) | interface BadgeWrapperProps {
FILE: apps/mobile/src/components/BlurredIdenticonBackground/BlurredIdenticonBackground.stories.tsx
type Story (line 13) | type Story = StoryObj<typeof BlurredIdenticonBackground>
FILE: apps/mobile/src/components/BlurredIdenticonBackground/BlurredIdenticonBackground.tsx
type Props (line 10) | type Props = {
FILE: apps/mobile/src/components/Camera/QrCamera.tsx
type QrCameraProps (line 14) | type QrCameraProps = {
type LensButtonConfig (line 25) | type LensButtonConfig = {
function getLensButtonConfig (line 35) | function getLensButtonConfig({
function CameraHeader (line 63) | function CameraHeader({ heading }: { heading: React.ReactNode }) {
function CameraFooter (line 86) | function CameraFooter(props: { footer: React.ReactNode }) {
function CameraLens (line 94) | function CameraLens({
constant BOX_RADIUS (line 226) | const BOX_RADIUS = 5
constant CORNER_SIZE (line 227) | const CORNER_SIZE = 30
FILE: apps/mobile/src/components/ChainIndicator/ChainIndicator.stories.tsx
type Story (line 37) | type Story = StoryObj<typeof ChainIndicator>
FILE: apps/mobile/src/components/ChainIndicator/ChainIndicator.tsx
type ChainIndicatorProps (line 12) | interface ChainIndicatorProps {
FILE: apps/mobile/src/components/ChainsDisplay/ChainsDisplay.stories.tsx
type Story (line 14) | type Story = StoryObj<typeof ChainsDisplay>
FILE: apps/mobile/src/components/ChainsDisplay/ChainsDisplay.tsx
type ChainsDisplayProps (line 7) | interface ChainsDisplayProps {
function ChainsDisplay (line 13) | function ChainsDisplay({ chains, activeChainId, max }: ChainsDisplayProp...
FILE: apps/mobile/src/components/CloseButton/CloseButton.tsx
type CloseButtonProps (line 5) | interface CloseButtonProps {
function CloseButton (line 10) | function CloseButton({ onPress, testID }: CloseButtonProps) {
FILE: apps/mobile/src/components/Container/Container.stories.tsx
type Story (line 15) | type Story = StoryObj<typeof Container>
FILE: apps/mobile/src/components/CopyButton/CopyButton.stories.tsx
type Story (line 12) | type Story = StoryObj<typeof CopyButton>
FILE: apps/mobile/src/components/CopyButton/CopyButton.tsx
type CopyButtonProps (line 6) | interface CopyButtonProps {
FILE: apps/mobile/src/components/DataRow/DataRow.tsx
type Props (line 4) | type Props = {
type ValueProps (line 8) | type ValueProps = {
FILE: apps/mobile/src/components/Dropdown/DropdownLabel.tsx
type DropdownLabelProps (line 6) | type DropdownLabelProps = {
FILE: apps/mobile/src/components/EncodedData/EncodedData.tsx
type EncodedDataProps (line 5) | interface EncodedDataProps {
function EncodedData (line 9) | function EncodedData({ data }: EncodedDataProps) {
FILE: apps/mobile/src/components/ErrorBoundary/SilentErrorBoundary.tsx
class SilentErrorBoundary (line 9) | class SilentErrorBoundary extends Component<{ children: ReactNode }, { h...
method getDerivedStateFromError (line 12) | static getDerivedStateFromError() {
method componentDidCatch (line 16) | componentDidCatch(_error: Error, _info: ErrorInfo) {
method render (line 20) | render() {
FILE: apps/mobile/src/components/EthAddress/ETHAddress.stories.tsx
type Story (line 12) | type Story = StoryObj<typeof EthAddress>
FILE: apps/mobile/src/components/EthAddress/ETHAddress.tsx
type Props (line 7) | type Props = {
FILE: apps/mobile/src/components/ExecutingMonitor/ExecutingMonitor.tsx
function ExecutingMonitor (line 9) | function ExecutingMonitor() {
FILE: apps/mobile/src/components/Fiat/Fiat.tsx
type FiatProps (line 6) | interface FiatProps {
FILE: apps/mobile/src/components/FiatChange/FiatChange.tsx
type FiatChangeProps (line 6) | interface FiatChangeProps {
FILE: apps/mobile/src/components/FloatingContainer/FloatingContainer.tsx
type FloatingContainerProps (line 7) | interface FloatingContainerProps {
FILE: apps/mobile/src/components/GradientText/GradientText.tsx
type GradientTextProps (line 7) | interface GradientTextProps extends TextProps {
FILE: apps/mobile/src/components/HashDisplay/HashDisplay.tsx
type HashDisplaySize (line 16) | type HashDisplaySize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
type SizeConfig (line 18) | interface SizeConfig {
constant SIZE_CONFIGS (line 25) | const SIZE_CONFIGS: Record<HashDisplaySize, SizeConfig> = {
type HashDisplayProps (line 33) | interface HashDisplayProps {
function HashDisplay (line 59) | function HashDisplay({
FILE: apps/mobile/src/components/HexDataDisplay/HexDataDisplay.tsx
type HexDataDisplayProps (line 7) | interface HexDataDisplayProps {
FILE: apps/mobile/src/components/Identicon/Identicon.stories.tsx
type Story (line 17) | type Story = StoryObj<typeof Identicon>
FILE: apps/mobile/src/components/Identicon/Identicon.tsx
type Props (line 6) | type Props = {
constant DEFAULT_SIZE (line 12) | const DEFAULT_SIZE = 56
FILE: apps/mobile/src/components/LoadableSwitch/LoadableSwitch.tsx
type LoadableSwitchProps (line 6) | interface LoadableSwitchProps {
FILE: apps/mobile/src/components/Loader/Loader.tsx
type LoaderProps (line 5) | type LoaderProps = CircleSnailPropTypes & {
function Loader (line 10) | function Loader({ size = 64, color = '#12FF80', ...rest }: LoaderProps) {
FILE: apps/mobile/src/components/LoadingScreen/LoadingScreen.tsx
type LoadingScreenProps (line 6) | interface LoadingScreenProps {
function LoadingScreen (line 11) | function LoadingScreen({ title, description }: LoadingScreenProps) {
FILE: apps/mobile/src/components/Logo/Logo.tsx
type BadgeThemeKeys (line 8) | type BadgeThemeKeys = keyof typeof badgeTheme
type ExtractAfterUnderscore (line 9) | type ExtractAfterUnderscore<T extends string> = T extends `${string}_${i...
type BadgeThemeTypes (line 10) | type BadgeThemeTypes = ExtractAfterUnderscore<BadgeThemeKeys>
type LogoProps (line 12) | interface LogoProps {
function Logo (line 23) | function Logo({
FILE: apps/mobile/src/components/NetworkBadge/NetworkBadge.stories.tsx
type Story (line 19) | type Story = StoryObj<typeof NetworkBadge>
FILE: apps/mobile/src/components/NetworkBadge/NetworkBadge.tsx
type Props (line 5) | type Props = {
FILE: apps/mobile/src/components/NetworkRow/NetworkRow.tsx
type NetworkRowProps (line 7) | interface NetworkRowProps {
function NetworkRow (line 15) | function NetworkRow({ showLabel = false }: NetworkRowProps) {
FILE: apps/mobile/src/components/OptIn/OptIn.tsx
type OptInProps (line 11) | interface OptInProps {
FILE: apps/mobile/src/components/ParametersButton/ParametersButton.tsx
type ParametersButtonProps (line 6) | interface ParametersButtonProps {
function ParametersButton (line 11) | function ParametersButton({ txId, title = 'Transaction details' }: Param...
FILE: apps/mobile/src/components/ProposalBadge/ProposalBadge.stories.tsx
type Story (line 11) | type Story = StoryObj<typeof ProposalBadge>
FILE: apps/mobile/src/components/ReadOnlyWarningModal/ReadOnlyWarningModal.tsx
type ReadOnlyWarningModalProps (line 11) | interface ReadOnlyWarningModalProps {
FILE: apps/mobile/src/components/RiskAcknowledgmentCheckbox/RiskAcknowledgmentCheckbox.tsx
type RiskAcknowledgmentCheckboxProps (line 6) | interface RiskAcknowledgmentCheckboxProps {
FILE: apps/mobile/src/components/SafeAccountInput/hooks/useImportSafe.test.tsx
constant VALID_ADDRESS (line 22) | const VALID_ADDRESS = '0x1234567890123456789012345678901234567890'
FILE: apps/mobile/src/components/SafeAccountInput/hooks/useImportSafe.ts
constant NO_SAFE_DEPLOYMENT_ERROR (line 14) | const NO_SAFE_DEPLOYMENT_ERROR = 'No Safe deployment found for this addr...
FILE: apps/mobile/src/components/SafeAccountInput/index.tsx
function SafeAccountInput (line 11) | function SafeAccountInput() {
FILE: apps/mobile/src/components/SafeAvatar/SafeAvatar.stories.tsx
type Story (line 25) | type Story = StoryObj<typeof SafeAvatar>
FILE: apps/mobile/src/components/SafeAvatar/SafeAvatar.tsx
type LoadingStatus (line 7) | type LoadingStatus = 'idle' | 'loading' | 'loaded' | 'error'
type SafeAvatarProps (line 9) | interface SafeAvatarProps extends Omit<AvatarProps, 'children'> {
function SafeAvatar (line 26) | function SafeAvatar({
FILE: apps/mobile/src/components/SafeBottomSheet/SafeBottomSheet.tsx
type SafeBottomSheetProps (line 17) | interface SafeBottomSheetProps<T> {
function SafeBottomSheet (line 31) | function SafeBottomSheet<T>({
FILE: apps/mobile/src/components/SafeButton/SafeButton.stories.tsx
type Story (line 19) | type Story = StoryObj<typeof SafeButton>
type RenderScreenProps (line 27) | type RenderScreenProps = {
FILE: apps/mobile/src/components/SafeButton/SafeButton.tsx
type SafeButtonProps (line 100) | interface SafeButtonProps extends GetProps<typeof BaseButton> {
function useTextColor (line 108) | function useTextColor(props: Record<string, unknown>): string {
constant TYPE_VARIANTS (line 134) | const TYPE_VARIANTS = ['primary', 'secondary', 'danger', 'success', 'out...
FILE: apps/mobile/src/components/SafeCard/SafeCard.stories.tsx
type Story (line 18) | type Story = StoryObj<typeof SafeCard>
FILE: apps/mobile/src/components/SafeCard/SafeCard.tsx
type SafeCardProps (line 7) | interface SafeCardProps {
function SafeCard (line 26) | function SafeCard({
FILE: apps/mobile/src/components/SafeFontIcon/SafeFontIcon.stories.tsx
type Story (line 15) | type Story = StoryObj<typeof SafeFontIcon>
FILE: apps/mobile/src/components/SafeFontIcon/SafeFontIcon.tsx
type IconProps (line 13) | interface IconProps extends Omit<React.ComponentProps<typeof SafeIcon>, ...
FILE: apps/mobile/src/components/SafeInput/SafeInput.stories.tsx
type SafeInputStory (line 48) | type SafeInputStory = StoryObj<typeof SafeInput>
FILE: apps/mobile/src/components/SafeInput/SafeInput.tsx
type StyledInputProps (line 8) | type StyledInputProps = GetProps<typeof StyledInput>
type SafeInputProps (line 10) | interface SafeInputProps {
function SafeInput (line 34) | function SafeInput({
FILE: apps/mobile/src/components/SafeInput/SafeInputWithLabel.tsx
type Props (line 6) | interface Props {
FILE: apps/mobile/src/components/SafeListItem/SafeListItem.tsx
type SafeListItemProps (line 10) | interface SafeListItemProps {
function SafeListItem (line 32) | function SafeListItem({
FILE: apps/mobile/src/components/SafeSearchBar/SafeSearchBar.tsx
type SafeSearchBarProps (line 6) | interface SafeSearchBarProps {
FILE: apps/mobile/src/components/SafeSkeleton/SafeSkeleton.tsx
constant SHIMMER_COLORS (line 15) | const SHIMMER_COLORS = {
constant BG_COLORS (line 20) | const BG_COLORS = { light: '#ececec', dark: '#1a1a1a' } as const
constant DEFAULT_SIZE (line 22) | const DEFAULT_SIZE = 32
constant ANIMATION_DURATION (line 23) | const ANIMATION_DURATION = 1500
function SafeSkeletonGroup (line 29) | function SafeSkeletonGroup({ show, children }: { show: boolean; children...
function ShimmerOverlay (line 37) | function ShimmerOverlay({ measuredWidth, colorMode }: { measuredWidth: n...
type SafeSkeletonProps (line 74) | interface SafeSkeletonProps {
function SafeSkeleton (line 82) | function SafeSkeleton({ height, width, radius = 8, show: showProp, child...
FILE: apps/mobile/src/components/SafeTab/SafeTab.tsx
type SafeTabProps (line 9) | interface SafeTabProps<T> {
function SafeTabInner (line 19) | function SafeTabInner<T extends object>({
function SafeTab (line 55) | function SafeTab<T extends object>(props: SafeTabProps<T>) {
FILE: apps/mobile/src/components/SafeTab/SafeTabBar.tsx
type SafeTabBarProps (line 8) | interface SafeTabBarProps {
FILE: apps/mobile/src/components/SafeTab/types.ts
type safeTabItem (line 1) | interface safeTabItem<T> {
FILE: apps/mobile/src/components/SelectExecutor/SelectExecutor.tsx
type Props (line 12) | type Props = {
function SelectExecutor (line 18) | function SelectExecutor({ address, txId, executionMethod }: Props) {
FILE: apps/mobile/src/components/SelectSigner/SelectSigner.tsx
type Props (line 11) | type Props = {
function SelectSigner (line 17) | function SelectSigner({ address, txId, disabled = false }: Props) {
FILE: apps/mobile/src/components/ShareButton/ShareButton.tsx
type ShareButtonProps (line 6) | interface ShareButtonProps {
function ShareButton (line 11) | function ShareButton({ onPress, testID }: ShareButtonProps) {
FILE: apps/mobile/src/components/SignerTypeBadge/SignerTypeBadge.tsx
type SignerBadgeProps (line 7) | interface SignerBadgeProps {
FILE: apps/mobile/src/components/SigningMonitor/SigningMonitor.tsx
function SigningMonitor (line 11) | function SigningMonitor() {
FILE: apps/mobile/src/components/StatusBanners/PendingTransactions/PendingTransactions.stories.tsx
type Story (line 21) | type Story = StoryObj<typeof PendingTransactions>
FILE: apps/mobile/src/components/StatusBanners/PendingTransactions/PendingTransactions.tsx
type Props (line 9) | interface Props {
FILE: apps/mobile/src/components/SwapHeader/SwapHeader.tsx
type TokenInfo (line 9) | interface TokenInfo {
type SwapHeaderProps (line 14) | interface SwapHeaderProps {
function SwapHeader (line 25) | function SwapHeader({
FILE: apps/mobile/src/components/Tag/Tag.stories.tsx
type Story (line 11) | type Story = StoryObj<typeof Tag>
FILE: apps/mobile/src/components/ThresholdBadge/ThresholdBadge.tsx
type ThresholdBadgeProps (line 5) | interface ThresholdBadgeProps {
FILE: apps/mobile/src/components/Title/SectionTitle.tsx
type SectionTitleProps (line 5) | interface SectionTitleProps {
function SectionTitle (line 11) | function SectionTitle({ title, description, paddingHorizontal = '$3' }: ...
FILE: apps/mobile/src/components/TokenAmount/TokenAmount.tsx
constant PRECISION (line 8) | const PRECISION = 20
type TokenAmountProps (line 10) | interface TokenAmountProps {
FILE: apps/mobile/src/components/TokenIcon/TokenIcon.tsx
type TokenIconProps (line 7) | interface TokenIconProps {
function TokenIcon (line 17) | function TokenIcon({
FILE: apps/mobile/src/components/TransactionProcessingState/TransactionProcessingState.tsx
type TransactionProcessingStateProps (line 10) | interface TransactionProcessingStateProps {
function TransactionProcessingState (line 23) | function TransactionProcessingState({ txId, executionInfo, isProposedTx ...
FILE: apps/mobile/src/components/TransactionSkeleton/TransactionSkeleton.tsx
type TransactionSkeletonProps (line 7) | interface TransactionSkeletonProps {
FILE: apps/mobile/src/components/TxInfo/TxInfo.tsx
type TxInfoProps (line 38) | type TxInfoProps = {
function TxInfoComponent (line 43) | function TxInfoComponent({ tx, onPress, ...rest }: TxInfoProps) {
FILE: apps/mobile/src/components/TxInfo/types.ts
type TxCardPress (line 4) | type TxCardPress = { tx: Transaction; type?: TxType }
FILE: apps/mobile/src/components/ValidatorStatus/ValidatorStatus.tsx
type NativeStakingStatus (line 7) | type NativeStakingStatus = NativeStakingDepositTransactionInfo['status']
type ValidatorStatusConfig (line 9) | interface ValidatorStatusConfig {
type ValidatorStatusProps (line 58) | interface ValidatorStatusProps {
function ValidatorStatus (line 62) | function ValidatorStatus({ status }: ValidatorStatusProps) {
FILE: apps/mobile/src/components/navigation/TabBarIcon.tsx
function TabBarIcon (line 3) | function TabBarIcon({ name, ...rest }: IconProps) {
FILE: apps/mobile/src/components/transactions-list/Card/AccountCard/AccountCard.stories.tsx
type Story (line 16) | type Story = StoryObj<typeof AccountCard>
FILE: apps/mobile/src/components/transactions-list/Card/AccountCard/AccountCard.tsx
type AccountCardProps (line 16) | interface AccountCardProps {
function AccountCard (line 28) | function AccountCard({
FILE: apps/mobile/src/components/transactions-list/Card/AssetsCard/AssetsCard.tsx
type AssetsCardProps (line 7) | interface AssetsCardProps {
function AssetsCard (line 18) | function AssetsCard({
FILE: apps/mobile/src/components/transactions-list/Card/SignersCard/SignersCard.tsx
type SignersCardProps (line 8) | type SignersCardProps = {
function SignersCard (line 29) | function SignersCard({
FILE: apps/mobile/src/components/transactions-list/Card/StakingTxDepositCard/StakingTxDepositCard.stories.tsx
type Story (line 44) | type Story = StoryObj<typeof StakingTxDepositCard>
FILE: apps/mobile/src/components/transactions-list/Card/StakingTxExitCard/StakingTxExitCard.stories.tsx
type Story (line 36) | type Story = StoryObj<typeof StakingTxExitCard>
FILE: apps/mobile/src/components/transactions-list/Card/StakingTxExitCard/StakingTxExitCard.tsx
type StakingTxExitCardProps (line 7) | interface StakingTxExitCardProps {
FILE: apps/mobile/src/components/transactions-list/Card/StakingTxWithdrawCard/StakingTxWithdrawCard.stories.tsx
type Story (line 32) | type Story = StoryObj<typeof StakingTxWithdrawCard>
FILE: apps/mobile/src/components/transactions-list/Card/StakingTxWithdrawCard/StakingTxWithdrawCard.tsx
type StakingTxWithdrawCardProps (line 6) | interface StakingTxWithdrawCardProps {
FILE: apps/mobile/src/components/transactions-list/Card/TxBatchCard/TxBatchCard.stories.tsx
type Story (line 33) | type Story = StoryObj<typeof TxBatchCard>
FILE: apps/mobile/src/components/transactions-list/Card/TxBatchCard/TxBatchCard.tsx
type TxBatchCardProps (line 8) | type TxBatchCardProps = {
function TxBatchCard (line 12) | function TxBatchCard({ txInfo, ...rest }: TxBatchCardProps) {
FILE: apps/mobile/src/components/transactions-list/Card/TxBridgeCard/TxBridgeCard.tsx
type TxBridgeCardProps (line 10) | interface TxBridgeCardProps {
function TxBridgeCard (line 18) | function TxBridgeCard({ txInfo, bordered, executionInfo, inQueue, onPres...
FILE: apps/mobile/src/components/transactions-list/Card/TxConflictingCard/TxConflictingCard.tsx
type TxConflictingCard (line 10) | interface TxConflictingCard {
function TxConflictingComponent (line 16) | function TxConflictingComponent({ transactions, inQueue, onPress }: TxCo...
FILE: apps/mobile/src/components/transactions-list/Card/TxContractInteractionCard/TxContractInteractionCard.stories.tsx
type Story (line 33) | type Story = StoryObj<typeof TxContractInteractionCard>
FILE: apps/mobile/src/components/transactions-list/Card/TxContractInteractionCard/TxContractInteractionCard.tsx
type TxContractInteractionCardProps (line 9) | type TxContractInteractionCardProps = {
function TxContractInteractionCard (line 14) | function TxContractInteractionCard({ txInfo, safeAppInfo, ...rest }: TxC...
FILE: apps/mobile/src/components/transactions-list/Card/TxCreationCard/TxCreationCard.stories.tsx
type Story (line 33) | type Story = StoryObj<typeof TxCreationCard>
FILE: apps/mobile/src/components/transactions-list/Card/TxCreationCard/TxCreationCard.tsx
type TxCreationCardProps (line 9) | type TxCreationCardProps = {
function TxCreationCard (line 13) | function TxCreationCard({ txInfo, ...rest }: TxCreationCardProps) {
FILE: apps/mobile/src/components/transactions-list/Card/TxGroupedCard/TxGroupedCard.stories.tsx
type Story (line 39) | type Story = StoryObj<typeof TxGroupedCard>
FILE: apps/mobile/src/components/transactions-list/Card/TxGroupedCard/TxGroupedCard.tsx
type TxGroupedCard (line 11) | interface TxGroupedCard {
function TxGroupedCardComponent (line 29) | function TxGroupedCardComponent({ transactions, inQueue, onPress }: TxGr...
FILE: apps/mobile/src/components/transactions-list/Card/TxLifiSwapCard/TxLifiSwapCard.tsx
type TxLifiSwapCardProps (line 8) | interface TxLifiSwapCardProps {
function TxLifiSwapCard (line 16) | function TxLifiSwapCard({ txInfo, bordered, executionInfo, inQueue, onPr...
FILE: apps/mobile/src/components/transactions-list/Card/TxOrderCard/SellOrder.tsx
type TxSellOrderCardProps (line 12) | type TxSellOrderCardProps = {
function SellOrder (line 17) | function SellOrder({ order, type, ...rest }: TxSellOrderCardProps) {
FILE: apps/mobile/src/components/transactions-list/Card/TxOrderCard/TwapOrder.tsx
type TxTwappOrderCardProps (line 9) | type TxTwappOrderCardProps = {
FILE: apps/mobile/src/components/transactions-list/Card/TxOrderCard/TxOrderCard.stories.tsx
type Story (line 16) | type Story = StoryObj<typeof TxOrderCard>
FILE: apps/mobile/src/components/transactions-list/Card/TxOrderCard/TxOrderCard.tsx
type TxSwapCardProps (line 9) | type TxSwapCardProps = {
function TxOrderCard (line 13) | function TxOrderCard({ txInfo, ...rest }: TxSwapCardProps) {
FILE: apps/mobile/src/components/transactions-list/Card/TxRejectionCard/TxRejectionCard.stories.tsx
type Story (line 25) | type Story = StoryObj<typeof TxRejectionCard>
FILE: apps/mobile/src/components/transactions-list/Card/TxRejectionCard/TxRejectionCard.tsx
type TxRejectionCardProps (line 9) | type TxRejectionCardProps = {
function TxRejectionCard (line 14) | function TxRejectionCard({ txInfo, ...rest }: TxRejectionCardProps) {
FILE: apps/mobile/src/components/transactions-list/Card/TxSafeAppCard/TxSafeAppCard.stories.tsx
type Story (line 30) | type Story = StoryObj<typeof TxSafeAppCard>
FILE: apps/mobile/src/components/transactions-list/Card/TxSafeAppCard/TxSafeAppCard.tsx
type TxSafeAppCardProps (line 8) | type TxSafeAppCardProps = {
function TxSafeAppCard (line 13) | function TxSafeAppCard({ safeAppInfo, txInfo, ...rest }: TxSafeAppCardPr...
FILE: apps/mobile/src/components/transactions-list/Card/TxSettingsCard/TxSettingCard.stories.tsx
type Story (line 20) | type Story = StoryObj<typeof TxSettingsCard>
FILE: apps/mobile/src/components/transactions-list/Card/TxSettingsCard/TxSettingsCard.tsx
type TxSettingsCardProps (line 9) | type TxSettingsCardProps = {
function TxSettingsCard (line 14) | function TxSettingsCard({ txInfo, onPress, ...rest }: TxSettingsCardProp...
FILE: apps/mobile/src/components/transactions-list/Card/TxTokenCard/TxTokenCard.stories.tsx
type Story (line 24) | type Story = StoryObj<typeof TxTokenCard>
constant NFT (line 32) | const NFT: Story = {
FILE: apps/mobile/src/components/transactions-list/Card/TxTokenCard/TxTokenCard.tsx
type TxTokenCardProps (line 11) | type TxTokenCardProps = {
function TxTokenCard (line 16) | function TxTokenCard({ inQueue, txStatus, txInfo, ...rest }: TxTokenCard...
FILE: apps/mobile/src/components/transactions-list/Card/VaultTxDepositCard/VaultTxDepositCard.tsx
type VaultTxDepositCardProps (line 7) | type VaultTxDepositCardProps = {
FILE: apps/mobile/src/components/transactions-list/Card/VaultTxRedeemCard/VaultTxRedeemCard.tsx
type VaultTxRedeemCardProps (line 7) | type VaultTxRedeemCardProps = {
FILE: apps/mobile/src/config/constants.ts
constant POLLING_INTERVAL (line 10) | const POLLING_INTERVAL = 15_000
constant DUST_THRESHOLD (line 11) | const DUST_THRESHOLD = 0.01
constant POSITIONS_POLLING_INTERVAL (line 12) | const POSITIONS_POLLING_INTERVAL = 300_000 // 5 minutes
constant COMING_SOON_MESSAGE (line 14) | const COMING_SOON_MESSAGE = 'This feature is coming soon.'
constant COMING_SOON_TITLE (line 15) | const COMING_SOON_TITLE = 'Coming soon'
constant GATEWAY_URL_PRODUCTION (line 17) | const GATEWAY_URL_PRODUCTION =
constant GATEWAY_URL_STAGING (line 19) | const GATEWAY_URL_STAGING = process.env.EXPO_PUBLIC_GATEWAY_URL_STAGING ...
constant GATEWAY_URL (line 20) | const GATEWAY_URL = isProduction ? GATEWAY_URL_PRODUCTION : GATEWAY_URL_...
constant CONFIG_SERVICE_KEY (line 21) | const CONFIG_SERVICE_KEY = process.env.EXPO_PUBLIC_CONFIG_SERVICE_KEY ||...
constant SECURITY_CERTIFICATE_HASH_BASE64 (line 23) | const SECURITY_CERTIFICATE_HASH_BASE64 = process.env.EXPO_PUBLIC_SECURIT...
constant SECURITY_WATCHER_MAIL (line 24) | const SECURITY_WATCHER_MAIL = process.env.EXPO_PUBLIC_SECURITY_WATCHER_MAIL
constant SECURITY_RASP_ENABLED (line 25) | const SECURITY_RASP_ENABLED = process.env.EXPO_PUBLIC_SECURITY_RASP_ENAB...
constant ONBOARDING_VERSION (line 31) | const ONBOARDING_VERSION = 'v1'
constant SAFE_WEB_URL (line 33) | const SAFE_WEB_URL = 'https://app.safe.global'
constant SAFE_WEB_TRANSACTIONS_URL (line 34) | const SAFE_WEB_TRANSACTIONS_URL = `${SAFE_WEB_URL}/transactions/tx?safe=...
constant SAFE_WEB_FEEDBACK_URL (line 35) | const SAFE_WEB_FEEDBACK_URL =
constant PRIVACY_POLICY_URL (line 38) | const PRIVACY_POLICY_URL =
constant TERMS_OF_USE_URL (line 40) | const TERMS_OF_USE_URL =
constant APP_STORE_URL (line 43) | const APP_STORE_URL = 'https://apps.apple.com/app/id6748754793'
constant GOOGLE_PLAY_URL (line 44) | const GOOGLE_PLAY_URL = 'https://play.google.com/store/apps/details?id=g...
FILE: apps/mobile/src/context/NotificationsContext.tsx
type NotificationContextType (line 5) | interface NotificationContextType {
type NotificationProviderProps (line 19) | interface NotificationProviderProps {
FILE: apps/mobile/src/features/AccountsSheet/AccountItem/AccountItem.stories.tsx
type Story (line 16) | type Story = StoryObj<typeof AccountItem>
FILE: apps/mobile/src/features/AccountsSheet/AccountItem/AccountItem.tsx
type AccountItemProps (line 15) | interface AccountItemProps {
function AccountItem (line 32) | function AccountItem({ account, drag, chains, isDragging, activeAccount,...
FILE: apps/mobile/src/features/AccountsSheet/AccountItem/utils/editAccountHelpers.ts
type SafesCollection (line 14) | interface SafesCollection extends Record<string, SafesSliceItem> {}
type SignersCollection (line 16) | interface SignersCollection extends Record<string, Signer> {}
type SafeDeletionContext (line 18) | interface SafeDeletionContext {
type CategorizedOwners (line 74) | interface CategorizedOwners {
type HandleConfirmedDeletionParams (line 265) | interface HandleConfirmedDeletionParams {
type HandleSafeDeletionParams (line 331) | interface HandleSafeDeletionParams {
FILE: apps/mobile/src/features/AccountsSheet/MyAccounts/MyAccounts.container.tsx
type MyAccountsContainerProps (line 14) | interface MyAccountsContainerProps {
function MyAccountsContainer (line 21) | function MyAccountsContainer({ item, isDragging, drag, onClose }: MyAcco...
FILE: apps/mobile/src/features/AccountsSheet/MyAccounts/MyAccountsFooter.tsx
function MyAccountsFooter (line 21) | function MyAccountsFooter() {
FILE: apps/mobile/src/features/AccountsSheet/MyAccounts/hooks/useMyAccountsSortable.ts
type SafeListItem (line 8) | type SafeListItem = { address: Address; info: SafesSliceItem }
type useMyAccountsSortableReturn (line 10) | type useMyAccountsSortableReturn = {
FILE: apps/mobile/src/features/ActionDetails/ActionDetails.container.tsx
function ActionDetailsContainer (line 14) | function ActionDetailsContainer() {
FILE: apps/mobile/src/features/ActionDetails/ActionsDetails.tsx
function ActionsDetails (line 8) | function ActionsDetails({ txDetails, action }: { txDetails: TransactionD...
FILE: apps/mobile/src/features/ActionDetails/utils.tsx
type formatActionDetailsReturn (line 14) | type formatActionDetailsReturn = {
FILE: apps/mobile/src/features/AddressBook/Contact/ContactDisplayName.container.tsx
type Props (line 6) | type Props = {
FILE: apps/mobile/src/features/AddressBook/Contact/ContactForm.container.tsx
type ContactFormProps (line 18) | interface ContactFormProps {
FILE: apps/mobile/src/features/AddressBook/Contact/NetworkSelector/AllNetworksItem.tsx
type AllNetworksItemProps (line 7) | interface AllNetworksItemProps {
FILE: apps/mobile/src/features/AddressBook/Contact/NetworkSelector/ChainItem.tsx
type ChainItemProps (line 8) | interface ChainItemProps {
FILE: apps/mobile/src/features/AddressBook/Contact/NetworkSelector/NetworkSelector.tsx
type NetworkSelectorProps (line 12) | interface NetworkSelectorProps {
FILE: apps/mobile/src/features/AddressBook/Contact/NetworkSelector/NetworkSelectorContent.tsx
type NetworkSelectorContentProps (line 7) | interface NetworkSelectorContentProps {
FILE: apps/mobile/src/features/AddressBook/Contact/NetworkSelector/NetworkSelectorHeader.tsx
type NetworkSelectorHeaderProps (line 4) | interface NetworkSelectorHeaderProps {
type TitleProps (line 10) | interface TitleProps {
type SubtitleProps (line 14) | interface SubtitleProps {
FILE: apps/mobile/src/features/AddressBook/Contact/components/ContactActionButton.tsx
type ContactActionButtonProps (line 4) | interface ContactActionButtonProps {
FILE: apps/mobile/src/features/AddressBook/Contact/components/ContactAddressField.tsx
type ContactAddressFieldProps (line 8) | interface ContactAddressFieldProps {
FILE: apps/mobile/src/features/AddressBook/Contact/components/ContactHeader.tsx
type ContactHeaderProps (line 7) | interface ContactHeaderProps {
FILE: apps/mobile/src/features/AddressBook/Contact/components/ContactName.tsx
type Props (line 4) | type Props = {
FILE: apps/mobile/src/features/AddressBook/Contact/components/ContactNameField.tsx
type ContactNameFieldProps (line 8) | interface ContactNameFieldProps {
FILE: apps/mobile/src/features/AddressBook/Contact/components/ContactNetworkRow.tsx
type ContactNetworkRowProps (line 7) | interface ContactNetworkRowProps {
FILE: apps/mobile/src/features/AddressBook/Contact/hooks/useDeleteContact.ts
type UseDeleteContactParams (line 7) | interface UseDeleteContactParams {
FILE: apps/mobile/src/features/AddressBook/Contact/hooks/useEditContact.ts
type UseEditContactParams (line 7) | interface UseEditContactParams {
FILE: apps/mobile/src/features/AddressBook/Contact/schemas/contactSchema.ts
type ContactFormData (line 31) | type ContactFormData = z.infer<typeof contactSchema>
FILE: apps/mobile/src/features/AddressBook/List/ContactItemActions.container.tsx
type ContactItemActionsContainerProps (line 10) | interface ContactItemActionsContainerProps {
FILE: apps/mobile/src/features/AddressBook/List/components/AddressBookListView.tsx
type Props (line 13) | type Props = {
FILE: apps/mobile/src/features/AddressBook/List/components/List/ContactItem.tsx
type ContactItemProps (line 12) | interface ContactItemProps {
FILE: apps/mobile/src/features/AddressBook/List/components/List/ContactListItems.tsx
type ContactListItemsProps (line 7) | interface ContactListItemsProps {
FILE: apps/mobile/src/features/AddressBook/List/components/List/EmptyAddressBookDark.tsx
function EmptyAddressBookDark (line 4) | function EmptyAddressBookDark() {
FILE: apps/mobile/src/features/AddressBook/List/components/List/EmptyAddressBookLight.tsx
function EmptyAddressBookLight (line 4) | function EmptyAddressBookLight() {
FILE: apps/mobile/src/features/AdvancedDetails/TxData.container.tsx
function TxDataContainer (line 12) | function TxDataContainer() {
FILE: apps/mobile/src/features/AdvancedDetails/TxParameters.container.tsx
function TxParametersContainer (line 11) | function TxParametersContainer() {
FILE: apps/mobile/src/features/AdvancedDetails/components/Receiver/Receiver.tsx
type ReceiverProps (line 10) | interface ReceiverProps {
function Receiver (line 14) | function Receiver({ txData }: ReceiverProps) {
FILE: apps/mobile/src/features/AdvancedDetails/formatters/arrayValue.test.tsx
type LabelValueItem (line 5) | type LabelValueItem = {
FILE: apps/mobile/src/features/AdvancedDetails/formatters/singleValue.test.tsx
type LabelValueItem (line 6) | type LabelValueItem = {
FILE: apps/mobile/src/features/AdvancedDetails/utils/formatParameters.tsx
type formatParametersProps (line 10) | interface formatParametersProps {
FILE: apps/mobile/src/features/AdvancedDetails/utils/formatTxDetails.tsx
type formatTxDetailsProps (line 19) | interface formatTxDetailsProps {
FILE: apps/mobile/src/features/AppUpdate/components/ForceUpdateScreen.tsx
type ForceUpdateScreenProps (line 13) | interface ForceUpdateScreenProps {
constant STORE_LABEL (line 17) | const STORE_LABEL = Platform.OS === 'ios' ? 'App Store' : 'Google Play'
function ForceUpdateScreen (line 19) | function ForceUpdateScreen({ minVersion }: ForceUpdateScreenProps) {
FILE: apps/mobile/src/features/AppUpdate/components/SoftUpdatePrompt.tsx
type SoftUpdatePromptProps (line 17) | interface SoftUpdatePromptProps {
constant STORE_LABEL (line 21) | const STORE_LABEL = Platform.OS === 'ios' ? 'App Store' : 'Google Play'
function SoftUpdatePrompt (line 23) | function SoftUpdatePrompt({ onDismiss }: SoftUpdatePromptProps) {
FILE: apps/mobile/src/features/AppUpdate/constants.ts
constant APP_UPDATE_EVENTS (line 1) | const APP_UPDATE_EVENTS = {
FILE: apps/mobile/src/features/AppUpdate/hooks/appUpdateE2eState.ts
type AppUpdateState (line 8) | interface AppUpdateState {
function get (line 21) | function get(): AppUpdateState {
function set (line 25) | function set(next: AppUpdateState) {
function subscribe (line 30) | function subscribe(listener: () => void): () => void {
FILE: apps/mobile/src/features/AppUpdate/hooks/useAppUpdateCheck.e2e.ts
function useAppUpdateCheck (line 11) | function useAppUpdateCheck() {
FILE: apps/mobile/src/features/AppUpdate/hooks/useAppUpdateCheck.ts
function isValidVersion (line 7) | function isValidVersion(version: string | null): version is string {
type UpdateCheckResult (line 11) | interface UpdateCheckResult {
function useAppUpdateCheck (line 17) | function useAppUpdateCheck(): UpdateCheckResult {
FILE: apps/mobile/src/features/Assets/Assets.container.tsx
function AssetsContainer (line 15) | function AssetsContainer() {
FILE: apps/mobile/src/features/Assets/components/AssetsHeader/AssetsHeader.tsx
type AssetsHeaderProps (line 10) | interface AssetsHeaderProps {
function AssetsHeader (line 20) | function AssetsHeader({
FILE: apps/mobile/src/features/Assets/components/Balance/Balance.container.tsx
function BalanceContainer (line 10) | function BalanceContainer() {
FILE: apps/mobile/src/features/Assets/components/Balance/Balance.tsx
type BalanceProps (line 9) | interface BalanceProps {
function Balance (line 14) | function Balance({ isLoading, balanceAmount }: BalanceProps) {
FILE: apps/mobile/src/features/Assets/components/Balance/ChainItems.tsx
type ChainItemsProps (line 8) | interface ChainItemsProps {
function ChainItems (line 18) | function ChainItems({
FILE: apps/mobile/src/features/Assets/components/ManageTokensSheet/ManageTokensSheet.tsx
type ManageTokensSheetProps (line 6) | interface ManageTokensSheetProps {
constant DUST_THRESHOLD (line 13) | const DUST_THRESHOLD = 0.01
FILE: apps/mobile/src/features/Assets/components/NFTs/NFTItem.tsx
function NFTItem (line 5) | function NFTItem({ item }: { item: Collectible }) {
FILE: apps/mobile/src/features/Assets/components/NFTs/NFTs.container.tsx
function NFTsContainer (line 16) | function NFTsContainer() {
FILE: apps/mobile/src/features/Assets/components/Navbar/Navbar.tsx
function PendingTxBadge (line 27) | function PendingTxBadge({ amount, onPress }: { amount: number; onPress: ...
function NetworkSelector (line 53) | function NetworkSelector({
FILE: apps/mobile/src/features/Assets/components/NoFunds/EmptyNFT.tsx
function EmptyNft (line 5) | function EmptyNft() {
FILE: apps/mobile/src/features/Assets/components/NoFunds/EmptyToken.tsx
function EmptyToken (line 4) | function EmptyToken() {
FILE: apps/mobile/src/features/Assets/components/NoFunds/NoFunds.tsx
type Props (line 19) | type Props = {
FILE: apps/mobile/src/features/Assets/components/Positions/PositionItem/PositionFiatChange.tsx
type PositionFiatChangeProps (line 7) | interface PositionFiatChangeProps {
constant INFO_SHEET_TITLE (line 13) | const INFO_SHEET_TITLE = '24h change'
constant INFO_SHEET_DESCRIPTION (line 14) | const INFO_SHEET_DESCRIPTION =
FILE: apps/mobile/src/features/Assets/components/Positions/PositionItem/PositionItem.tsx
type PositionItemProps (line 12) | interface PositionItemProps {
FILE: apps/mobile/src/features/Assets/components/Positions/PositionsError/PositionsError.tsx
type PositionsErrorProps (line 6) | interface PositionsErrorProps {
FILE: apps/mobile/src/features/Assets/components/Positions/ProtocolDetailSheet/ProtocolDetailSheet.tsx
type ProtocolDetailSheetPositionsProps (line 6) | interface ProtocolDetailSheetPositionsProps {
FILE: apps/mobile/src/features/Assets/components/Positions/ProtocolDetailSheet/ProtocolDetailSheetHeader.tsx
type ProtocolDetailSheetHeaderProps (line 10) | interface ProtocolDetailSheetHeaderProps {
FILE: apps/mobile/src/features/Assets/components/Positions/ProtocolSection/ProtocolSection.tsx
type ProtocolSectionProps (line 13) | interface ProtocolSectionProps {
FILE: apps/mobile/src/features/Assets/components/ReadOnly/ReadOnly.tsx
type ReadOnlyProps (line 6) | interface ReadOnlyProps {
FILE: apps/mobile/src/features/Assets/components/Tokens/TokenItem.tsx
type TokenItemProps (line 11) | interface TokenItemProps {
function TokenItem (line 16) | function TokenItem({ item, currency }: TokenItemProps) {
FILE: apps/mobile/src/features/Assets/components/Tokens/Tokens.container.tsx
function TokensContainer (line 12) | function TokensContainer() {
FILE: apps/mobile/src/features/Assets/components/Tokens/useTokenBalances.ts
function filterDustTokens (line 11) | function filterDustTokens(items: Balance[] | undefined, shouldFilter: bo...
function useTokenBalances (line 21) | function useTokenBalances() {
FILE: apps/mobile/src/features/Assets/hooks/usePositions.ts
type UsePositionsResult (line 15) | interface UsePositionsResult {
FILE: apps/mobile/src/features/ChangeEstimatedFeeSheet/components/ChangeEstimatedFeeForm/ChangeEstimatedFeeForm.tsx
type ChangeEstimatedFeeFormProps (line 23) | interface ChangeEstimatedFeeFormProps {
FILE: apps/mobile/src/features/ChangeEstimatedFeeSheet/components/ChangeEstimatedFeeForm/schema.ts
type EstimatedFeeFormData (line 67) | type EstimatedFeeFormData = z.infer<typeof estimatedFeeFormSchema>
FILE: apps/mobile/src/features/ChangeSignerSheet/utils.ts
type ActionType (line 1) | enum ActionType {
FILE: apps/mobile/src/features/ConfirmTx/ConfirmTx.container.tsx
function ConfirmTxContainer (line 30) | function ConfirmTxContainer() {
FILE: apps/mobile/src/features/ConfirmTx/components/CanNotSign/CanNotSign.tsx
function CanNotSign (line 4) | function CanNotSign() {
FILE: apps/mobile/src/features/ConfirmTx/components/ConfirmTxForm/ConfirmTxForm.tsx
type ConfirmTxFormProps (line 11) | interface ConfirmTxFormProps {
function ConfirmTxForm (line 21) | function ConfirmTxForm({
FILE: apps/mobile/src/features/ConfirmTx/components/ConfirmationView/ConfirmationView.tsx
type ConfirmationViewProps (line 34) | interface ConfirmationViewProps {
function ConfirmationView (line 38) | function ConfirmationView({ txDetails }: ConfirmationViewProps) {
FILE: apps/mobile/src/features/ConfirmTx/components/ConfirmationView/types.ts
type NormalizedSettingsChangeTransaction (line 5) | type NormalizedSettingsChangeTransaction = SettingsChangeTransaction & {
FILE: apps/mobile/src/features/ConfirmTx/components/ConfirmationsInfo/ConfirmationsInfo.tsx
type ConfirmationsInfoProps (line 9) | interface ConfirmationsInfoProps {
function ConfirmationsInfo (line 14) | function ConfirmationsInfo({ detailedExecutionInfo, txId }: Confirmation...
FILE: apps/mobile/src/features/ConfirmTx/components/ExecuteForm/ExecuteForm.tsx
type ExecuteFormProps (line 10) | interface ExecuteFormProps {
function ExecuteForm (line 18) | function ExecuteForm({ txId, riskAcknowledged, onRiskAcknowledgedChange,...
FILE: apps/mobile/src/features/ConfirmTx/components/ListTable/ListTable.tsx
type BaseItem (line 5) | type BaseItem = {
type RenderRowItem (line 10) | type RenderRowItem = BaseItem & {
type LabelValueItem (line 14) | type LabelValueItem = BaseItem & {
type ListTableItem (line 20) | type ListTableItem = RenderRowItem | LabelValueItem
type ListTableProps (line 22) | interface ListTableProps {
FILE: apps/mobile/src/features/ConfirmTx/components/LoadingTx/LoadingTx.tsx
function LoadingTx (line 5) | function LoadingTx() {
FILE: apps/mobile/src/features/ConfirmTx/components/ReviewAndConfirm/ReviewAndConfirmContainer.tsx
function ReviewAndConfirmContainer (line 14) | function ReviewAndConfirmContainer() {
FILE: apps/mobile/src/features/ConfirmTx/components/ReviewAndConfirm/ReviewAndConfirmView.tsx
type ReviewAndConfirmViewProps (line 11) | interface ReviewAndConfirmViewProps {
function ReviewAndConfirmView (line 17) | function ReviewAndConfirmView({ txDetails, children, header }: ReviewAnd...
FILE: apps/mobile/src/features/ConfirmTx/components/ReviewAndConfirm/ReviewFooter.tsx
type ReviewFooterProps (line 10) | interface ReviewFooterProps {
function ReviewFooter (line 17) | function ReviewFooter({ txId, activeSigner, isSigningLoading, onConfirmP...
FILE: apps/mobile/src/features/ConfirmTx/components/ReviewAndConfirm/ReviewHeader.tsx
function ReviewHeader (line 4) | function ReviewHeader() {
FILE: apps/mobile/src/features/ConfirmTx/components/ReviewAndConfirm/tabs/DataTab.tsx
function DataTab (line 5) | function DataTab() {
FILE: apps/mobile/src/features/ConfirmTx/components/ReviewAndConfirm/tabs/HashesTab.tsx
type HashesTabProps (line 12) | interface HashesTabProps {
FILE: apps/mobile/src/features/ConfirmTx/components/ReviewAndConfirm/tabs/JSONTab.tsx
type JSONTabProps (line 8) | interface JSONTabProps {
function JSONTab (line 12) | function JSONTab({ txDetails }: JSONTabProps) {
FILE: apps/mobile/src/features/ConfirmTx/components/SignForm/SignForm.tsx
type SignFormProps (line 8) | interface SignFormProps {
function SignForm (line 15) | function SignForm({ txId, riskAcknowledged, onRiskAcknowledgedChange, sh...
FILE: apps/mobile/src/features/ConfirmTx/components/SignTransaction/SignError.tsx
function SignError (line 11) | function SignError({ description }: { description?: string }) {
FILE: apps/mobile/src/features/ConfirmTx/components/SignTransaction/hooks/useTransactionSigning.ts
type SigningStatus (line 20) | enum SigningStatus {
type UseTransactionSigningProps (line 27) | interface UseTransactionSigningProps {
function useTransactionSigning (line 32) | function useTransactionSigning({ txId, signerAddress }: UseTransactionSi...
FILE: apps/mobile/src/features/ConfirmTx/components/TransactionChecks/TransactionChecks.tsx
type TransactionChecksProps (line 16) | interface TransactionChecksProps {
function TransactionChecks (line 21) | function TransactionChecks({ txId, txDetails }: TransactionChecksProps) {
FILE: apps/mobile/src/features/ConfirmTx/components/TransactionChecks/__tests__/TransactionChecks.test.tsx
type SecurityHookReturn (line 10) | type SecurityHookReturn = ReturnType<typeof useTransactionSecurity>
type MockSafeListItemProps (line 12) | interface MockSafeListItemProps {
type MockTransactionChecksLeftNodeProps (line 20) | interface MockTransactionChecksLeftNodeProps {
type MockTransactionChecksBottomContentProps (line 24) | interface MockTransactionChecksBottomContentProps {
FILE: apps/mobile/src/features/ConfirmTx/components/TransactionChecks/components/TransactionChecksBottomContent.tsx
type TransactionChecksBottomContentProps (line 5) | interface TransactionChecksBottomContentProps {
FILE: apps/mobile/src/features/ConfirmTx/components/TransactionChecks/components/TransactionChecksLeftNode.tsx
type TransactionChecksLeftNodeProps (line 6) | interface TransactionChecksLeftNodeProps {
FILE: apps/mobile/src/features/ConfirmTx/components/TransactionChecks/components/__tests__/TransactionChecksBottomContent.test.tsx
type MockAlertProps (line 7) | interface MockAlertProps {
FILE: apps/mobile/src/features/ConfirmTx/components/TransactionChecks/components/__tests__/TransactionChecksLeftNode.test.tsx
type MockSafeFontIconProps (line 6) | interface MockSafeFontIconProps {
type MockCircleSnailProps (line 11) | interface MockCircleSnailProps {
FILE: apps/mobile/src/features/ConfirmTx/components/TransactionChecks/utils/transactionChecksUtils.ts
type SecurityState (line 4) | interface SecurityState {
FILE: apps/mobile/src/features/ConfirmTx/components/TransactionHeader/TransactionHeader.tsx
type TransactionHeaderProps (line 12) | interface TransactionHeaderProps {
function TransactionHeader (line 23) | function TransactionHeader({
FILE: apps/mobile/src/features/ConfirmTx/components/TransactionInfo/TransactionInfo.tsx
function TransactionInfo (line 16) | function TransactionInfo({
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/AddSigner/AddSigner.tsx
type AddSignerProps (line 15) | interface AddSignerProps {
function AddSigner (line 21) | function AddSigner({ txInfo, executionInfo, txId }: AddSignerProps) {
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/AlreadySigned/AlreadySigned.tsx
function AlreadySigned (line 5) | function AlreadySigned() {
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/BridgeTransaction/BridgeTransaction.tsx
type BridgeTransactionProps (line 17) | interface BridgeTransactionProps {
function BridgeTransaction (line 23) | function BridgeTransaction({ txId, txInfo, decodedData }: BridgeTransact...
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/CancelTx/CancelTx.tsx
type CancelTxProps (line 20) | interface CancelTxProps {
function CancelTx (line 26) | function CancelTx({ txInfo, executionInfo, txId }: CancelTxProps) {
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/Contract/Contract.tsx
type ContractProps (line 20) | interface ContractProps {
function Contract (line 26) | function Contract({ txInfo, executionInfo, txId }: ContractProps) {
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/GenericView/GenericView.tsx
type GenericViewProps (line 19) | interface GenericViewProps {
function GenericView (line 26) | function GenericView({ txInfo, txData, executionInfo, txId }: GenericVie...
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/LifiSwapTransaction/LifiSwapHeader.tsx
type LifiSwapHeaderProps (line 7) | interface LifiSwapHeaderProps {
function LifiSwapHeader (line 12) | function LifiSwapHeader({ txInfo, executionInfo }: LifiSwapHeaderProps) {
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/LifiSwapTransaction/LifiSwapTransaction.tsx
type LifiSwapTransactionProps (line 12) | interface LifiSwapTransactionProps {
function LifiSwapTransaction (line 18) | function LifiSwapTransaction({ txId, executionInfo, txInfo }: LifiSwapTr...
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/RemoveSigner/RemoveSigner.tsx
type RemoveSignerProps (line 18) | interface RemoveSignerProps {
function RemoveSigner (line 24) | function RemoveSigner({ txInfo, executionInfo, txId }: RemoveSignerProps) {
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/SendNFT/SendNFT.tsx
type SendNFTProps (line 16) | interface SendNFTProps {
function SendNFT (line 22) | function SendNFT({ txId, txInfo, executionInfo }: SendNFTProps) {
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/Stake/Deposit/Deposit.stories.tsx
type Story (line 95) | type Story = StoryObj<typeof StakingDeposit>
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/Stake/Deposit/Deposit.tsx
type StakingDepositProps (line 14) | interface StakingDepositProps {
function StakingDeposit (line 21) | function StakingDeposit({ txInfo, executionInfo, txId, txData }: Staking...
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/Stake/Exit/Exit.stories.tsx
type Story (line 62) | type Story = StoryObj<typeof StakingExit>
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/Stake/Exit/Exit.tsx
type StakingExitProps (line 12) | interface StakingExitProps {
function StakingExit (line 18) | function StakingExit({ txInfo, executionInfo, txId }: StakingExitProps) {
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/Stake/WithdrawRequest/WithdrawRequest.stories.tsx
type Story (line 66) | type Story = StoryObj<typeof StakingWithdrawRequest>
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/Stake/WithdrawRequest/WithdrawRequest.tsx
type StakingWithdrawRequestProps (line 15) | interface StakingWithdrawRequestProps {
function StakingWithdrawRequest (line 22) | function StakingWithdrawRequest({ txInfo, executionInfo, txId, txData }:...
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/Stake/utils.tsx
constant CURRENCY (line 17) | const CURRENCY = 'USD'
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/SwapOrder/StatusLabel/index.tsx
type CustomOrderStatuses (line 8) | type CustomOrderStatuses = Order['status'] | 'partiallyFilled'
type Props (line 9) | type Props = {
type StatusProps (line 13) | type StatusProps = {
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/SwapOrder/SwapOrder.tsx
type SwapOrderProps (line 19) | interface SwapOrderProps {
function SwapOrder (line 26) | function SwapOrder({ executionInfo, txInfo, decodedData, txId }: SwapOrd...
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/SwapOrder/SwapOrderHeader.tsx
type SwapOrderHeaderProps (line 8) | interface SwapOrderHeaderProps {
function SwapOrderHeader (line 13) | function SwapOrderHeader({ txInfo, executionInfo }: SwapOrderHeaderProps) {
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/TokenTransfer/TokenTransfer.tsx
type TokenTransferProps (line 20) | interface TokenTransferProps {
function TokenTransfer (line 27) | function TokenTransfer({ txId, txInfo, executionInfo, executedAt }: Toke...
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/VaultDeposit/VaultDeposit.tsx
type VaultDepositProps (line 60) | interface VaultDepositProps {
function VaultDeposit (line 67) | function VaultDeposit({ txInfo, executionInfo, txId, decodedData }: Vaul...
FILE: apps/mobile/src/features/ConfirmTx/components/confirmation-views/VaultRedeem/VaultRedeem.tsx
type VaultRedeemProps (line 60) | interface VaultRedeemProps {
function VaultRedeem (line 66) | function VaultRedeem({ txInfo, executionInfo, txId }: VaultRedeemProps) {
FILE: apps/mobile/src/features/ConfirmTx/hooks/useOpenExplorer/useOpenExplorer.ts
function useOpenExplorer (line 8) | function useOpenExplorer(address: string) {
FILE: apps/mobile/src/features/ConfirmTx/hooks/useTxSignerState.test.ts
type MockActiveSafe (line 20) | interface MockActiveSafe {
FILE: apps/mobile/src/features/DataImport/ImportError.container.tsx
function ImportError (line 7) | function ImportError() {
FILE: apps/mobile/src/features/DataImport/__tests__/useLegacyImport.test.ts
method constructor (line 19) | constructor() {
method constructor (line 25) | constructor() {
method constructor (line 31) | constructor() {
FILE: apps/mobile/src/features/DataImport/components/DataTransferView.tsx
type DataTransferViewProps (line 14) | interface DataTransferViewProps {
FILE: apps/mobile/src/features/DataImport/components/EnterPasswordView.tsx
type EnterPasswordViewProps (line 8) | interface EnterPasswordViewProps {
FILE: apps/mobile/src/features/DataImport/components/FileSelectionView.tsx
type FileSelectionViewProps (line 15) | interface FileSelectionViewProps {
FILE: apps/mobile/src/features/DataImport/components/HelpImportView.tsx
type HelpImportViewProps (line 23) | interface HelpImportViewProps {
FILE: apps/mobile/src/features/DataImport/components/ImportErrorView.tsx
type ImportErrorViewProps (line 10) | interface ImportErrorViewProps {
FILE: apps/mobile/src/features/DataImport/components/ImportProgressScreenView.tsx
type ImportProgressScreenViewProps (line 5) | interface ImportProgressScreenViewProps {
FILE: apps/mobile/src/features/DataImport/components/ImportSuccessScreenView.tsx
type ImportSuccessScreenViewProps (line 13) | interface ImportSuccessScreenViewProps {
FILE: apps/mobile/src/features/DataImport/components/ReviewDataView.tsx
type ImportSummary (line 8) | interface ImportSummary {
type ReviewDataViewProps (line 14) | interface ReviewDataViewProps {
FILE: apps/mobile/src/features/DataImport/context/DataImportProvider.tsx
type DataImportContextType (line 4) | type DataImportContextType = ReturnType<typeof useLegacyImport>
type DataImportProviderProps (line 16) | interface DataImportProviderProps {
FILE: apps/mobile/src/features/DataImport/helpers/transforms.ts
constant LEGACY_KEY_TYPE_LEDGER (line 2) | const LEGACY_KEY_TYPE_LEDGER = 3
type LegacyDataStructure (line 4) | interface LegacyDataStructure {
type NotImportedKey (line 36) | interface NotImportedKey {
type SafeInfo (line 126) | interface SafeInfo {
type ImportProgressCallback (line 143) | type ImportProgressCallback = (progress: number, message: string) => void
constant KEY_IMPORT_DELAY (line 146) | const KEY_IMPORT_DELAY = 1000 // 1 second delay between key imports to t...
FILE: apps/mobile/src/features/DataImport/hooks/useLegacyImport.ts
function useLegacyImport (line 15) | function useLegacyImport() {
FILE: apps/mobile/src/features/Developer/components/Developer.tsx
type DeveloperProps (line 8) | type DeveloperProps = {
type InfoProps (line 14) | type InfoProps = {
FILE: apps/mobile/src/features/Developer/types.ts
type Info (line 1) | type Info = {
FILE: apps/mobile/src/features/ExecuteTx/components/CanNotEstimate/CanNotEstimate.tsx
type CanNotEstimateProps (line 5) | interface CanNotEstimateProps {
FILE: apps/mobile/src/features/ExecuteTx/components/CanNotExecute/CanNotExecute.tsx
function CanNotExecute (line 4) | function CanNotExecute() {
FILE: apps/mobile/src/features/ExecuteTx/components/EstimatedNetworkFee/EstimatedNetworkFee.tsx
type EstimatedNetworkFeeProps (line 13) | interface EstimatedNetworkFeeProps {
FILE: apps/mobile/src/features/ExecuteTx/components/ExecuteError.tsx
function ExecuteError (line 11) | function ExecuteError({ description }: { description?: string }) {
FILE: apps/mobile/src/features/ExecuteTx/components/RelayFee/RelayFee.tsx
type RelayFeeProps (line 9) | interface RelayFeeProps {
FILE: apps/mobile/src/features/ExecuteTx/components/ReviewAndExecute/ReviewAndExecuteContainer.tsx
function ReviewAndExecuteContainer (line 27) | function ReviewAndExecuteContainer() {
FILE: apps/mobile/src/features/ExecuteTx/components/ReviewAndExecute/ReviewExecuteFooter.tsx
type ReviewExecuteFooterProps (line 17) | interface ReviewExecuteFooterProps {
function ReviewExecuteFooter (line 34) | function ReviewExecuteFooter({
FILE: apps/mobile/src/features/ExecuteTx/components/ReviewAndExecute/ReviewExecuteFooterSkeleton.tsx
function ReviewExecuteFooterSkeleton (line 7) | function ReviewExecuteFooterSkeleton() {
FILE: apps/mobile/src/features/ExecuteTx/components/ReviewAndExecute/helpers.ts
type ExecutionPath (line 10) | type ExecutionPath = 'ledger' | 'walletconnect' | 'biometrics' | 'standard'
FILE: apps/mobile/src/features/ExecuteTx/components/SignerFee/SignerFee.tsx
type SignerFeeProps (line 5) | interface SignerFeeProps {
FILE: apps/mobile/src/features/ExecuteTx/hooks/useExecutionFlow.ts
type UseExecutionFlowParams (line 13) | interface UseExecutionFlowParams {
type UseExecutionFlowReturn (line 22) | interface UseExecutionFlowReturn {
FILE: apps/mobile/src/features/ExecuteTx/hooks/useExecutionFunds.ts
type UseExecutionFundsParams (line 7) | interface UseExecutionFundsParams {
type UseExecutionFundsResult (line 14) | interface UseExecutionFundsResult {
FILE: apps/mobile/src/features/ExecuteTx/hooks/useTransactionExecution.ts
type ExecutionStatus (line 20) | enum ExecutionStatus {
type UseTransactionExecutionProps (line 28) | interface UseTransactionExecutionProps {
function useTransactionExecution (line 36) | function useTransactionExecution({
FILE: apps/mobile/src/features/HistoryTransactionDetails/HistoryTransactionDetails.container.tsx
function HistoryTransactionDetailsContainer (line 16) | function HistoryTransactionDetailsContainer() {
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/HistoryAdvancedDetailsButton/HistoryAdvancedDetailsButton.tsx
type HistoryAdvancedDetailsButtonProps (line 4) | interface HistoryAdvancedDetailsButtonProps {
function HistoryAdvancedDetailsButton (line 8) | function HistoryAdvancedDetailsButton({ txId }: HistoryAdvancedDetailsBu...
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/HistoryConfirmationsInfo/HistoryConfirmationsInfo.tsx
type HistoryConfirmationsInfoProps (line 12) | interface HistoryConfirmationsInfoProps {
function HistoryConfirmationsInfo (line 17) | function HistoryConfirmationsInfo({ detailedExecutionInfo, txId }: Histo...
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/HistoryTransactionHeader/HistoryTransactionHeader.tsx
type HistoryTransactionHeaderProps (line 11) | interface HistoryTransactionHeaderProps {
function HistoryTransactionHeader (line 24) | function HistoryTransactionHeader({
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/HistoryTransactionInfo/HistoryTransactionInfo.tsx
type HistoryTransactionInfoProps (line 14) | interface HistoryTransactionInfoProps {
function HistoryTransactionInfo (line 19) | function HistoryTransactionInfo({ txId, txDetails }: HistoryTransactionI...
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/HistoryTransactionView/HistoryTransactionView.tsx
type HistoryTransactionViewProps (line 35) | interface HistoryTransactionViewProps {
function HistoryTransactionView (line 39) | function HistoryTransactionView({ txDetails }: HistoryTransactionViewPro...
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/ViewOnExplorerButton/ViewOnExplorerButton.tsx
type ViewOnExplorerButtonProps (line 7) | interface ViewOnExplorerButtonProps {
function ViewOnExplorerButton (line 11) | function ViewOnExplorerButton({ txHash }: ViewOnExplorerButtonProps) {
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/history-views/CancelTx.tsx
type CancelTxProps (line 8) | interface CancelTxProps {
function CancelTx (line 14) | function CancelTx({ txId, txInfo, executionInfo }: CancelTxProps) {
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/history-views/HistoryAddSigner.tsx
type HistoryAddSignerProps (line 11) | interface HistoryAddSignerProps {
function HistoryAddSigner (line 17) | function HistoryAddSigner({ txId, txInfo, executionInfo }: HistoryAddSig...
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/history-views/HistoryChangeThreshold.tsx
type HistoryChangeThresholdProps (line 11) | interface HistoryChangeThresholdProps {
function HistoryChangeThreshold (line 17) | function HistoryChangeThreshold({ txId, txInfo, executionInfo }: History...
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/history-views/HistoryContract.tsx
type HistoryContractProps (line 17) | interface HistoryContractProps {
function HistoryContract (line 24) | function HistoryContract({ txId, txInfo }: HistoryContractProps) {
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/history-views/HistoryGenericView.tsx
type HistoryGenericViewProps (line 11) | interface HistoryGenericViewProps {
function HistoryGenericView (line 18) | function HistoryGenericView({ txId, txInfo, txData, executedAt }: Histor...
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/history-views/HistoryRemoveSigner.tsx
type HistoryRemoveSignerProps (line 11) | interface HistoryRemoveSignerProps {
function HistoryRemoveSigner (line 17) | function HistoryRemoveSigner({ txId, txInfo, executionInfo }: HistoryRem...
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/history-views/HistoryStakeDeposit.tsx
type HistoryStakeDepositProps (line 17) | interface HistoryStakeDepositProps {
function HistoryStakeDeposit (line 23) | function HistoryStakeDeposit({ txId, txInfo, txData }: HistoryStakeDepos...
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/history-views/HistoryStakeWithdraw.tsx
type HistoryStakeWithdrawProps (line 15) | interface HistoryStakeWithdrawProps {
function HistoryStakeWithdraw (line 21) | function HistoryStakeWithdraw({ txId, txInfo, txData }: HistoryStakeWith...
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/history-views/HistoryStakeWithdrawRequest.tsx
type HistoryStakeWithdrawRequestProps (line 16) | interface HistoryStakeWithdrawRequestProps {
function HistoryStakeWithdrawRequest (line 22) | function HistoryStakeWithdrawRequest({ txId, txInfo, txData }: HistorySt...
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/history-views/HistorySwapOrder.tsx
type HistorySwapOrderProps (line 15) | interface HistorySwapOrderProps {
function HistorySwapOrder (line 20) | function HistorySwapOrder({ txId, txInfo }: HistorySwapOrderProps) {
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/history-views/HistorySwapSigner.tsx
type HistorySwapSignerProps (line 12) | interface HistorySwapSignerProps {
function HistorySwapSigner (line 17) | function HistorySwapSigner({ txId, txInfo }: HistorySwapSignerProps) {
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/history-views/HistoryTokenTransfer.tsx
type HistoryTokenTransferProps (line 13) | interface HistoryTokenTransferProps {
function HistoryTokenTransfer (line 19) | function HistoryTokenTransfer({ txId, txInfo, txData }: HistoryTokenTran...
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/history-views/HistoryTransactionBase.tsx
type HistoryTransactionBaseProps (line 12) | interface HistoryTransactionBaseProps {
function HistoryTransactionBase (line 30) | function HistoryTransactionBase({
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/history-views/HistoryVaultDeposit.tsx
type HistoryVaultDepositProps (line 15) | interface HistoryVaultDepositProps {
function HistoryVaultDeposit (line 60) | function HistoryVaultDeposit({ txId, txInfo }: HistoryVaultDepositProps) {
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/history-views/HistoryVaultRedeem.tsx
type HistoryVaultRedeemProps (line 13) | interface HistoryVaultRedeemProps {
function HistoryVaultRedeem (line 59) | function HistoryVaultRedeem({ txId, txInfo }: HistoryVaultRedeemProps) {
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/shared/NetworkDisplay.tsx
function NetworkDisplay (line 4) | function NetworkDisplay() {
FILE: apps/mobile/src/features/HistoryTransactionDetails/components/shared/ThresholdChangeDisplay.tsx
type ThresholdChangeDisplayProps (line 8) | interface ThresholdChangeDisplayProps {
function ThresholdChangeDisplay (line 13) | function ThresholdChangeDisplay({ txInfo, executionInfo }: ThresholdChan...
FILE: apps/mobile/src/features/HowToExecuteSheet/components/RelayAvailable/RelayAvailable.tsx
type RelayAvailableProps (line 8) | interface RelayAvailableProps {
FILE: apps/mobile/src/features/HowToExecuteSheet/types.ts
type ExecutionMethod (line 1) | enum ExecutionMethod {
FILE: apps/mobile/src/features/ImportReadOnly/NetworkBadge.container.tsx
type Props (line 5) | type Props = {
FILE: apps/mobile/src/features/ImportReadOnly/components/AddSignersFormView.tsx
type AddSignersFormViewProps (line 10) | type AddSignersFormViewProps = {
FILE: apps/mobile/src/features/ImportReadOnly/components/ImportAccountFormView.tsx
type ImportAccountFormViewProps (line 15) | type ImportAccountFormViewProps = {
FILE: apps/mobile/src/features/ImportReadOnly/components/ScanQrAccountView.tsx
type QrCameraViewProps (line 9) | type QrCameraViewProps = {
FILE: apps/mobile/src/features/ImportReadOnly/components/VerificationStatus.tsx
type VerificationStatusProps (line 7) | type VerificationStatusProps = {
FILE: apps/mobile/src/features/ImportReadOnly/types.ts
type LazyQueryResult (line 5) | type LazyQueryResult = ReturnType<typeof useLazySafesGetOverviewForManyQ...
type FormValues (line 7) | type FormValues = z.infer<typeof formSchema> & {
FILE: apps/mobile/src/features/ImportSigner/ImportSigner.container.tsx
constant CUSTOM_VERTICAL_OFFSET (line 14) | const CUSTOM_VERTICAL_OFFSET = 70
function ImportSigner (line 16) | function ImportSigner() {
FILE: apps/mobile/src/features/ImportSigner/SeedPhraseAddresses.container.tsx
constant TITLE (line 17) | const TITLE = 'Select address to import'
FILE: apps/mobile/src/features/ImportSigner/components/ConnectSignerError/ConnectSignerError.tsx
function ConnectSignerError (line 10) | function ConnectSignerError() {
FILE: apps/mobile/src/features/ImportSigner/components/ImportError/ImportError.tsx
function ImportError (line 11) | function ImportError() {
FILE: apps/mobile/src/features/ImportSigner/components/ImportSuccess/ImportSuccess.tsx
function ImportSuccess (line 15) | function ImportSuccess() {
FILE: apps/mobile/src/features/ImportSigner/components/LoadingImport/LoadingImport.container.tsx
function LoadingImport (line 8) | function LoadingImport() {
FILE: apps/mobile/src/features/ImportSigner/components/NameSigner/NameSigner.container.tsx
function NameSignerContainer (line 14) | function NameSignerContainer() {
FILE: apps/mobile/src/features/ImportSigner/components/NameSigner/NameSignerView.tsx
constant CUSTOM_VERTICAL_OFFSET (line 14) | const CUSTOM_VERTICAL_OFFSET = 70
type Props (line 16) | type Props = {
function NameSignerView (line 27) | function NameSignerView({
FILE: apps/mobile/src/features/ImportSigner/components/NameSigner/buildDefaultName.ts
function buildDefaultName (line 1) | function buildDefaultName(walletName: string | undefined, address: strin...
FILE: apps/mobile/src/features/ImportSigner/components/ReconnectError/ReconnectError.tsx
function ReconnectError (line 11) | function ReconnectError() {
FILE: apps/mobile/src/features/ImportSigner/hooks/__tests__/useSignerCollisionGuard.test.ts
constant ADDRESS_A (line 9) | const ADDRESS_A = faker.finance.ethereumAddress()
constant ADDRESS_B (line 10) | const ADDRESS_B = faker.finance.ethereumAddress()
FILE: apps/mobile/src/features/ImportSigner/hooks/useImportPrivateKey.ts
constant ERROR_MESSAGE (line 11) | const ERROR_MESSAGE = 'Invalid private key or seed phrase.'
FILE: apps/mobile/src/features/ImportSigner/hooks/useImportSeedPhraseAddress.ts
type ImportError (line 10) | interface ImportError {
type ImportSuccess (line 15) | interface ImportSuccess {
type ImportFailure (line 20) | interface ImportFailure {
type ImportResult (line 24) | type ImportResult = ImportSuccess | ImportFailure
FILE: apps/mobile/src/features/ImportSigner/hooks/useSeedPhraseAddresses.ts
type UseSeedPhraseAddressesParams (line 6) | interface UseSeedPhraseAddressesParams {
FILE: apps/mobile/src/features/ImportSigner/hooks/useSignerCollisionGuard.ts
type SignerKind (line 7) | type SignerKind = Signer['type']
FILE: apps/mobile/src/features/ImportSigner/utils/__tests__/findCollidingSigner.test.ts
constant ADDRESS_A (line 5) | const ADDRESS_A = faker.finance.ethereumAddress()
constant ADDRESS_B (line 6) | const ADDRESS_B = faker.finance.ethereumAddress()
FILE: apps/mobile/src/features/Ledger/LedgerAddresses.container.tsx
constant TITLE (line 20) | const TITLE = 'Select address to import'
constant DERIVATION_PATH_OPTIONS (line 22) | const DERIVATION_PATH_OPTIONS = [
FILE: apps/mobile/src/features/Ledger/components/AddressItem.tsx
type AddressItemData (line 9) | interface AddressItemData {
type AddressItemProps (line 16) | interface AddressItemProps {
FILE: apps/mobile/src/features/Ledger/components/BluetoothError.tsx
type BluetoothErrorProps (line 6) | interface BluetoothErrorProps {
FILE: apps/mobile/src/features/Ledger/components/DeviceList.tsx
type LedgerDevice (line 8) | interface LedgerDevice {
type DeviceListProps (line 14) | interface DeviceListProps {
FILE: apps/mobile/src/features/Ledger/components/EmptyState.tsx
type EmptyStateProps (line 6) | interface EmptyStateProps {
FILE: apps/mobile/src/features/Ledger/components/LedgerConnect.tsx
type LedgerDevice (line 13) | interface LedgerDevice {
type NavigationConfig (line 19) | interface NavigationConfig {
type LedgerConnectProps (line 24) | interface LedgerConnectProps {
FILE: apps/mobile/src/features/Ledger/components/LedgerError.tsx
type LedgerErrorProps (line 5) | interface LedgerErrorProps {
FILE: apps/mobile/src/features/Ledger/components/LedgerImportError.tsx
function LedgerImportError (line 11) | function LedgerImportError() {
FILE: apps/mobile/src/features/Ledger/components/LedgerPairing.tsx
type NavigationConfig (line 9) | interface NavigationConfig {
type LedgerPairingProps (line 18) | interface LedgerPairingProps {
FILE: apps/mobile/src/features/Ledger/components/LedgerProgress.tsx
type LedgerProgressProps (line 5) | interface LedgerProgressProps {
FILE: apps/mobile/src/features/Ledger/components/LedgerSignerBadge.tsx
type LedgerSignerBadgeProps (line 5) | interface LedgerSignerBadgeProps {
FILE: apps/mobile/src/features/Ledger/components/LedgerSuccess.tsx
type LedgerSuccessProps (line 14) | interface LedgerSuccessProps {
FILE: apps/mobile/src/features/Ledger/components/LoadMoreButton.tsx
type LoadMoreButtonProps (line 8) | interface LoadMoreButtonProps {
FILE: apps/mobile/src/features/Ledger/components/PairingError.tsx
type PairingErrorProps (line 5) | interface PairingErrorProps {
FILE: apps/mobile/src/features/Ledger/components/PairingProgress.tsx
type PairingProgressProps (line 3) | interface PairingProgressProps {
FILE: apps/mobile/src/features/Ledger/hooks/useBluetoothStatus.ts
type BluetoothStatus (line 6) | interface BluetoothStatus {
FILE: apps/mobile/src/features/Ledger/hooks/useImportLedgerAddress.ts
type ImportError (line 9) | type ImportError = {
type ImportResult (line 14) | interface ImportResult {
type ImportFailure (line 23) | interface ImportFailure {
FILE: apps/mobile/src/features/Ledger/hooks/useLedgerAddresses.ts
type DerivationPathType (line 8) | type DerivationPathType = 'ledger-live' | 'legacy-ledger' | 'bip44'
type UseLedgerAddressesParams (line 10) | interface UseLedgerAddressesParams {
FILE: apps/mobile/src/features/Ledger/hooks/useLedgerConnection.test.ts
type LedgerDevice (line 17) | interface LedgerDevice {
FILE: apps/mobile/src/features/Ledger/hooks/useLedgerConnection.ts
type LedgerDevice (line 5) | interface LedgerDevice {
type ConnectionError (line 11) | interface ConnectionError {
FILE: apps/mobile/src/features/Ledger/hooks/useLedgerDeviceScanning.ts
type LedgerDevice (line 6) | interface LedgerDevice {
constant CONTINUE_SCAN_AFTER_FIRST_DEVICE_MS (line 12) | const CONTINUE_SCAN_AFTER_FIRST_DEVICE_MS = 10000
FILE: apps/mobile/src/features/NetworksSheet/NetworksSheetFooter.tsx
type NetworksSheetFooterProps (line 25) | interface NetworksSheetFooterProps {
function NetworksSheetFooter (line 49) | function NetworksSheetFooter({
FILE: apps/mobile/src/features/NetworksSheet/hooks/useScanForNewNetworks.ts
type ScanPhase (line 15) | type ScanPhase = 'idle' | 'scanning' | 'error'
type LastScanResult (line 17) | type LastScanResult = {
type UseScanForNewNetworksResult (line 22) | type UseScanForNewNetworksResult = {
FILE: apps/mobile/src/features/Notifications/components/EmptyBell.tsx
function EmptyBell (line 4) | function EmptyBell() {
FILE: apps/mobile/src/features/Notifications/components/NotificationPermissions.tsx
type Props (line 7) | type Props = {
FILE: apps/mobile/src/features/Notifications/components/NotificationsSettingsView.tsx
type Props (line 10) | type Props = {
FILE: apps/mobile/src/features/Onboarding/Onboarding.container.tsx
function Onboarding (line 5) | function Onboarding() {
FILE: apps/mobile/src/features/Onboarding/components/OnboardingCarousel/CarouselFeedback.tsx
type CarouselFeedbackProps (line 5) | interface CarouselFeedbackProps {
constant UNACTIVE_WIDTH (line 9) | const UNACTIVE_WIDTH = 4
constant ACTIVE_WIDTH (line 10) | const ACTIVE_WIDTH = 24
function CarouselFeedback (line 12) | function CarouselFeedback({ isActive }: CarouselFeedbackProps) {
FILE: apps/mobile/src/features/Onboarding/components/OnboardingCarousel/CarouselItem.tsx
type CarouselItem (line 5) | type CarouselItem = {
type CarouselItemProps (line 15) | interface CarouselItemProps {
FILE: apps/mobile/src/features/Onboarding/components/OnboardingCarousel/OnboardingCarousel.native.stories.tsx
type Story (line 13) | type Story = StoryObj<typeof OnboardingCarousel>
FILE: apps/mobile/src/features/Onboarding/components/OnboardingCarousel/OnboardingCarousel.tsx
type OnboardingCarouselProps (line 14) | interface OnboardingCarouselProps {
function OnboardingCarousel (line 18) | function OnboardingCarousel({ items }: OnboardingCarouselProps) {
FILE: apps/mobile/src/features/Onboarding/components/OnboardingHeader/OnboardingHeader.tsx
function OnboardingHeader (line 6) | function OnboardingHeader() {
FILE: apps/mobile/src/features/PendingTx/PendingTx.container.tsx
function PendingTxContainer (line 7) | function PendingTxContainer() {
FILE: apps/mobile/src/features/PendingTx/components/PendingTxList/PendingTxList.container.tsx
type GroupedPendingTxsWithTitle (line 17) | interface GroupedPendingTxsWithTitle {
type PendingTxListContainerProps (line 22) | interface PendingTxListContainerProps {
function PendingTxListContainer (line 32) | function PendingTxListContainer({
FILE: apps/mobile/src/features/PendingTx/utils.tsx
type GroupedTxs (line 22) | type GroupedTxs = (PendingTransactionItems | TransactionQueuedItem[])[]
FILE: apps/mobile/src/features/PrivateKey/PrivateKey.container.tsx
type Props (line 11) | type Props = {
FILE: apps/mobile/src/features/PrivateKey/components/PrivateKeyView.tsx
type Props (line 10) | type Props = {
constant MASKED_PRIVATE_KEY (line 20) | const MASKED_PRIVATE_KEY = '•'.repeat(64)
FILE: apps/mobile/src/features/SafeShield/components/AnalysisDetails/AnalysisDetails.stories.tsx
type Story (line 25) | type Story = StoryObj<typeof AnalysisDetails>
FILE: apps/mobile/src/features/SafeShield/components/AnalysisDetails/AnalysisDetails.tsx
type SafeShieldWidgetProps (line 15) | interface SafeShieldWidgetProps {
FILE: apps/mobile/src/features/SafeShield/components/AnalysisDetails/AnalysisDetailsContent.tsx
type AnalysisDetailsContentProps (line 22) | interface AnalysisDetailsContentProps {
FILE: apps/mobile/src/features/SafeShield/components/AnalysisDetails/AnalysisDetailsHeader.tsx
type AnalysisDetailsHeaderProps (line 5) | interface AnalysisDetailsHeaderProps {
FILE: apps/mobile/src/features/SafeShield/components/AnalysisGroup/AnalysisDisplay/AnalysisDisplay.tsx
type AnalysisDisplayProps (line 16) | interface AnalysisDisplayProps {
function AnalysisDisplay (line 22) | function AnalysisDisplay({ result, description, severity }: AnalysisDisp...
FILE: apps/mobile/src/features/SafeShield/components/AnalysisGroup/AnalysisDisplay/components/AddressChanges.tsx
type AddressChangesProps (line 5) | interface AddressChangesProps {
function AddressChanges (line 9) | function AddressChanges({ result }: AddressChangesProps) {
FILE: apps/mobile/src/features/SafeShield/components/AnalysisGroup/AnalysisDisplay/components/AddressListItem.tsx
type AddressListItemProps (line 8) | interface AddressListItemProps {
function AddressListItem (line 17) | function AddressListItem({
FILE: apps/mobile/src/features/SafeShield/components/AnalysisGroup/AnalysisDisplay/components/AnalysisDetailsDropdown.tsx
type AnalysisDetailsDropdownProps (line 7) | interface AnalysisDetailsDropdownProps {
function AnalysisDetailsDropdown (line 16) | function AnalysisDetailsDropdown({
FILE: apps/mobile/src/features/SafeShield/components/AnalysisGroup/AnalysisDisplay/components/AnalysisDisplay.stories.tsx
type Story (line 24) | type Story = StoryObj<typeof AnalysisDisplay>
FILE: apps/mobile/src/features/SafeShield/components/AnalysisGroup/AnalysisDisplay/components/AnalysisIssuesDisplay.tsx
type AnalysisIssuesDisplayProps (line 19) | interface AnalysisIssuesDisplayProps {
function AnalysisIssuesDisplay (line 24) | function AnalysisIssuesDisplay({ result, severity }: AnalysisIssuesDispl...
FILE: apps/mobile/src/features/SafeShield/components/AnalysisGroup/AnalysisDisplay/components/ShowAllAddress.tsx
type ShowAllAddressProps (line 14) | interface ShowAllAddressProps {
function ShowAllAddress (line 18) | function ShowAllAddress({ addresses }: ShowAllAddressProps) {
FILE: apps/mobile/src/features/SafeShield/components/AnalysisGroup/AnalysisGroup.stories.tsx
type Story (line 25) | type Story = StoryObj<typeof AnalysisGroup>
FILE: apps/mobile/src/features/SafeShield/components/AnalysisGroup/AnalysisGroup.tsx
type AnalysisGroup (line 12) | interface AnalysisGroup {
FILE: apps/mobile/src/features/SafeShield/components/AnalysisGroup/DelegateCallItem.tsx
type DelegateCallItemProps (line 8) | interface DelegateCallItemProps {
FILE: apps/mobile/src/features/SafeShield/components/AnalysisGroup/FallbackHandlerItem.tsx
type FallbackHandlerItemProps (line 8) | interface FallbackHandlerItemProps {
FILE: apps/mobile/src/features/SafeShield/components/AnalysisLabel/AnalysisLabel.stories.tsx
type Story (line 24) | type Story = StoryObj<typeof AnalysisLabel>
FILE: apps/mobile/src/features/SafeShield/components/AnalysisLabel/AnalysisLabel.tsx
type AnalysisLabelProps (line 7) | interface AnalysisLabelProps {
function AnalysisLabel (line 13) | function AnalysisLabel({ label, severity, highlighted }: AnalysisLabelPr...
FILE: apps/mobile/src/features/SafeShield/components/AnalysisPaper/AnalysisPaper.tsx
type AnalysisPaperProps (line 4) | interface AnalysisPaperProps {
function AnalysisPaper (line 10) | function AnalysisPaper({ children, spaced, fitBottom }: AnalysisPaperPro...
FILE: apps/mobile/src/features/SafeShield/components/BalanceChange/BalanceChange.stories.tsx
type Story (line 14) | type Story = StoryObj<typeof BalanceChangeBlock>
FILE: apps/mobile/src/features/SafeShield/components/BalanceChange/BalanceChangeBlock.tsx
type BalanceChangeBlockProps (line 11) | interface BalanceChangeBlockProps {
constant BALANCE_CHANGE_INFO (line 15) | const BALANCE_CHANGE_INFO =
function BalanceChangeBlock (line 18) | function BalanceChangeBlock({ threat }: BalanceChangeBlockProps) {
FILE: apps/mobile/src/features/SafeShield/components/BalanceChange/BalanceChangeItem.tsx
type BalanceChangeItemProps (line 20) | interface BalanceChangeItemProps {
function BalanceChangeItem (line 26) | function BalanceChangeItem({ asset, diff, positive = false }: BalanceCha...
FILE: apps/mobile/src/features/SafeShield/components/BalanceChange/utils/utils.ts
type AssetType (line 8) | type AssetType = BalanceChangeDto['asset']
type DiffType (line 9) | type DiffType = FungibleDiffDto | NftDiffDto
FILE: apps/mobile/src/features/SafeShield/components/SafeShieldHeadline/SafeShieldHeadline.stories.tsx
type Story (line 18) | type Story = StoryObj<typeof SafeShieldHeadline>
FILE: apps/mobile/src/features/SafeShield/components/SafeShieldHeadline/SafeShieldHeadline.tsx
type SafeShieldHeadlineProps (line 6) | interface SafeShieldHeadlineProps {
function SafeShieldHeadline (line 10) | function SafeShieldHeadline({ type = Severity.OK }: SafeShieldHeadlinePr...
FILE: apps/mobile/src/features/SafeShield/components/SafeShieldIcons/SafeShieldInfo.tsx
function SafeShieldInfo (line 4) | function SafeShieldInfo() {
FILE: apps/mobile/src/features/SafeShield/components/SafeShieldIcons/SafeShieldIssues.tsx
function SafeShieldIssues (line 4) | function SafeShieldIssues() {
FILE: apps/mobile/src/features/SafeShield/components/SafeShieldIcons/SafeShieldNeutral.tsx
function SafeShieldNeutral (line 4) | function SafeShieldNeutral() {
FILE: apps/mobile/src/features/SafeShield/components/SafeShieldIcons/SafeShieldOk.tsx
function SafeShieldOk (line 4) | function SafeShieldOk() {
FILE: apps/mobile/src/features/SafeShield/components/SafeShieldIcons/SafeShieldWarning.tsx
function SafeShieldWarning (line 4) | function SafeShieldWarning() {
FILE: apps/mobile/src/features/SafeShield/components/SafeShieldWidget/SafeShieldWidget.stories.tsx
type Story (line 17) | type Story = StoryObj<typeof SafeShieldWidget>
FILE: apps/mobile/src/features/SafeShield/components/SafeShieldWidget/SafeShieldWidget.tsx
type SafeShieldWidgetProps (line 15) | interface SafeShieldWidgetProps {
function SafeShieldWidget (line 23) | function SafeShieldWidget({ recipient, contract, threat, safeTx, txId }:...
FILE: apps/mobile/src/features/SafeShield/components/SafeShieldWidget/WidgetAction/WidgetAction.stories.tsx
type Story (line 22) | type Story = StoryObj<typeof WidgetAction>
FILE: apps/mobile/src/features/SafeShield/components/SafeShieldWidget/WidgetAction/WidgetAction.tsx
type WidgetActionProps (line 7) | interface WidgetActionProps {
function WidgetAction (line 25) | function WidgetAction({ loading, error, status, onPress }: WidgetActionP...
FILE: apps/mobile/src/features/SafeShield/components/SafeShieldWidget/WidgetDisplay/ErrorWidget/ErrorWidget.tsx
type ErrorWidgetProps (line 6) | interface ErrorWidgetProps {
function ErrorWidget (line 11) | function ErrorWidget({ message = 'Unable to load content', onRefresh }: ...
FILE: apps/mobile/src/features/SafeShield/components/SafeShieldWidget/WidgetDisplay/LoadingWidget/LoadingWidget.tsx
function LoadingWidget (line 5) | function LoadingWidget() {
FILE: apps/mobile/src/features/SafeShield/components/SafeShieldWidget/WidgetDisplay/WidgetDisplay.stories.tsx
type Story (line 18) | type Story = StoryObj<typeof WidgetDisplay>
FILE: apps/mobile/src/features/SafeShield/components/SafeShieldWidget/WidgetDisplay/WidgetDisplay.tsx
type WidgetDisplayProps (line 24) | interface WidgetDisplayProps {
function WidgetDisplay (line 32) | function WidgetDisplay({ recipient, contract, threat, loading, safeTx }:...
FILE: apps/mobile/src/features/SafeShield/components/TransactionSimulation/TransactionSimulation.tsx
type TransactionSimulationProps (line 10) | interface TransactionSimulationProps {
function TransactionSimulation (line 20) | function TransactionSimulation({
FILE: apps/mobile/src/features/SafeShield/hooks/useCounterpartyAnalysis.ts
function useCounterpartyAnalysis (line 13) | function useCounterpartyAnalysis(overrideSafeTx?: SafeTransaction): {
FILE: apps/mobile/src/features/SafeShield/hooks/useSafeShieldSeverity.ts
type UseSafeShieldSeverityProps (line 9) | interface UseSafeShieldSeverityProps {
FILE: apps/mobile/src/features/SafeShield/hooks/useThreatAnalysis.ts
function useThreatAnalysis (line 8) | function useThreatAnalysis(overrideSafeTx?: SafeTransaction) {
FILE: apps/mobile/src/features/SafeShield/theme.ts
type SafeShieldSeverityType (line 4) | type SafeShieldSeverityType = `safeShield_${Severity}`
type SafeShieldAnalysisStatusType (line 5) | type SafeShieldAnalysisStatusType = `safeShieldAnalysisStatus_${Severity}`
FILE: apps/mobile/src/features/Send/EnterAmount.container.tsx
function FiatToggleButton (line 31) | function FiatToggleButton({ onToggle }: { onToggle: () => void }) {
function EnterAmountContainer (line 48) | function EnterAmountContainer() {
FILE: apps/mobile/src/features/Send/ScanQrSend.container.tsx
function isChainMismatch (line 15) | function isChainMismatch(prefix: string | undefined, activeShortName: st...
function ScanQrSendContainer (line 45) | function ScanQrSendContainer() {
FILE: apps/mobile/src/features/Send/SelectRecipient.container.tsx
function IconRow (line 20) | function IconRow({
function SelectRecipientContainer (line 52) | function SelectRecipientContainer() {
FILE: apps/mobile/src/features/Send/SelectToken.container.tsx
function ItemSeparator (line 14) | function ItemSeparator() {
function filterTokensByQuery (line 18) | function filterTokensByQuery(items: Balance[] | undefined, query: string...
type TokenListHeaderProps (line 36) | interface TokenListHeaderProps {
function TokenListHeader (line 45) | function TokenListHeader({
function EmptySearchResult (line 118) | function EmptySearchResult({ searchQuery }: { searchQuery: string }) {
function SelectTokenContainer (line 129) | function SelectTokenContainer() {
FILE: apps/mobile/src/features/Send/components/AddToAddressBookModal.tsx
type AddToAddressBookModalProps (line 12) | interface AddToAddressBookModalProps {
function AddToAddressBookModal (line 19) | function AddToAddressBookModal({ visible, address, onClose, onSaved }: A...
FILE: apps/mobile/src/features/Send/components/AmountDisplay.tsx
constant MAX_FONT_SIZE (line 4) | const MAX_FONT_SIZE = 44
constant MIN_FONT_SIZE (line 5) | const MIN_FONT_SIZE = 24
constant SHRINK_START (line 6) | const SHRINK_START = 8
type AmountDisplayProps (line 8) | interface AmountDisplayProps {
function AmountDisplay (line 14) | function AmountDisplay({ primaryDisplay, secondaryDisplay, hasValue }: A...
FILE: apps/mobile/src/features/Send/components/CustomNonceModal.tsx
type CustomNonceModalProps (line 6) | interface CustomNonceModalProps {
function isNonceInRange (line 14) | function isNonceInRange(parsed: number, currentNonce: number): boolean {
function validateNonce (line 18) | function validateNonce(value: string, currentNonce: number): string | un...
function CustomNonceModal (line 40) | function CustomNonceModal({ visible, defaultNonce, currentNonce, onSave,...
FILE: apps/mobile/src/features/Send/components/DialogModal.tsx
type DialogModalProps (line 5) | interface DialogModalProps {
function DialogModal (line 16) | function DialogModal({
FILE: apps/mobile/src/features/Send/components/FooterAction.tsx
type FooterActionProps (line 9) | interface FooterActionProps {
function FooterAction (line 19) | function FooterAction({
FILE: apps/mobile/src/features/Send/components/KnownOtherChainWarning.tsx
type KnownOtherChainWarningProps (line 8) | interface KnownOtherChainWarningProps {
function KnownOtherChainWarning (line 14) | function KnownOtherChainWarning({ contactAddress, chainId, chainName }: ...
FILE: apps/mobile/src/features/Send/components/NonceBottomSheet.tsx
type QueuedNonceItem (line 12) | interface QueuedNonceItem {
type NonceBottomSheetProps (line 17) | interface NonceBottomSheetProps {
function RecommendedNonceRow (line 28) | function RecommendedNonceRow({
function ReplaceExistingDivider (line 59) | function ReplaceExistingDivider() {
function QueuedNonceRow (line 71) | function QueuedNonceRow({
function useRenderFooter (line 102) | function useRenderFooter(insets: { bottom: number }, onAddCustomNonce: (...
FILE: apps/mobile/src/features/Send/components/ProposerBottomSheet.tsx
type ProposerBottomSheetProps (line 13) | interface ProposerBottomSheetProps {
function SignerRow (line 20) | function SignerRow({ signer, isSelected, onPress }: { signer: Signer; is...
FILE: apps/mobile/src/features/Send/components/RecipientDisplay.tsx
type RecipientDisplayProps (line 15) | interface RecipientDisplayProps {
function RecipientDisplay (line 20) | function RecipientDisplay({ name, address }: RecipientDisplayProps) {
FILE: apps/mobile/src/features/Send/components/RecipientHeader.tsx
type RecipientHeaderProps (line 7) | interface RecipientHeaderProps {
function RecipientHeader (line 15) | function RecipientHeader({
FILE: apps/mobile/src/features/Send/components/RecipientInput.tsx
type RecipientInputProps (line 12) | interface RecipientInputProps {
function RecipientLabel (line 59) | function RecipientLabel({
function SelectedRecipient (line 91) | function SelectedRecipient({
function AddressInputField (line 120) | function AddressInputField({
function RecipientInput (line 183) | function RecipientInput({
FILE: apps/mobile/src/features/Send/components/RecipientSections.tsx
type RecipientSectionsProps (line 9) | interface RecipientSectionsProps {
function SectionHeader (line 16) | function SectionHeader({ title }: { title: string }) {
function RecipientSections (line 56) | function RecipientSections({ safes, signers, addressBook, onSelect }: Re...
FILE: apps/mobile/src/features/Send/components/RecipientValidationBadge.tsx
type RecipientValidationBadgeProps (line 6) | interface RecipientValidationBadgeProps {
function RecipientValidationBadge (line 38) | function RecipientValidationBadge({ state, contactName }: RecipientValid...
FILE: apps/mobile/src/features/Send/components/SelectProposer.tsx
type SelectProposerProps (line 8) | interface SelectProposerProps {
function SelectProposer (line 14) | function SelectProposer({ address, showChevron, onPress }: SelectPropose...
FILE: apps/mobile/src/features/Send/components/SuspiciousAddressComparison.tsx
type SuspiciousAddressComparisonProps (line 7) | interface SuspiciousAddressComparisonProps {
function HighlightedAddress (line 14) | function HighlightedAddress({ address }: { address: string }) {
function AddressCard (line 34) | function AddressCard({
function SuspiciousAddressComparison (line 80) | function SuspiciousAddressComparison({
FILE: apps/mobile/src/features/Send/components/TokenListItem.tsx
type TokenListItemProps (line 11) | interface TokenListItemProps {
FILE: apps/mobile/src/features/Send/components/TokenPill.tsx
type TokenPillProps (line 6) | interface TokenPillProps {
function TokenPill (line 13) | function TokenPill({ symbol, logoUri, balance, onMaxPress }: TokenPillPr...
FILE: apps/mobile/src/features/Send/hooks/useAmountInput.ts
type UseAmountInputResult (line 5) | interface UseAmountInputResult {
function useAmountInput (line 24) | function useAmountInput(): UseAmountInputResult {
function useTokenAmountValidation (line 77) | function useTokenAmountValidation({
FILE: apps/mobile/src/features/Send/hooks/useEnsureActiveSigner.test.ts
function setupSelectors (line 47) | function setupSelectors(
FILE: apps/mobile/src/features/Send/hooks/useEnsureActiveSigner.ts
function resolveActiveSigner (line 9) | function resolveActiveSigner(current: Signer | undefined, available: Sig...
function useEnsureActiveSigner (line 16) | function useEnsureActiveSigner() {
FILE: apps/mobile/src/features/Send/hooks/useFiatConversion.ts
type UseFiatConversionArgs (line 6) | interface UseFiatConversionArgs {
type UseFiatConversionResult (line 15) | interface UseFiatConversionResult {
type DisplayResult (line 72) | interface DisplayResult {
type BuildFiatDisplayArgs (line 78) | interface BuildFiatDisplayArgs {
type BuildTokenDisplayArgs (line 105) | interface BuildTokenDisplayArgs {
function useFiatConversion (line 132) | function useFiatConversion({
FILE: apps/mobile/src/features/Send/hooks/useKeyboardVisible.ts
function useKeyboardVisible (line 4) | function useKeyboardVisible(): boolean {
FILE: apps/mobile/src/features/Send/hooks/useMaxAmount.ts
constant FIAT_DECIMALS (line 5) | const FIAT_DECIMALS = 2
function computeFiatMax (line 7) | function computeFiatMax(formatted: string, fiatRate: string | undefined)...
function getDecimalError (line 16) | function getDecimalError(exceedsDecimals: boolean, decimals: number): st...
type UseMaxAmountArgs (line 23) | interface UseMaxAmountArgs {
type UseMaxAmountResult (line 34) | interface UseMaxAmountResult {
function useMaxAmount (line 40) | function useMaxAmount({
FILE: apps/mobile/src/features/Send/hooks/useNonce.test.ts
function makeTxItem (line 24) | function makeTxItem(nonce: number, humanDescription?: string): Transacti...
function makeConflictHeader (line 41) | function makeConflictHeader(nonce: number): ConflictHeaderQueuedItem {
FILE: apps/mobile/src/features/Send/hooks/useNonce.ts
type QueuedNonceItem (line 11) | interface QueuedNonceItem {
type QueuedItem (line 16) | type QueuedItem = QueuedItemPage['results'][number]
type UseNonceResult (line 18) | interface UseNonceResult {
function flattenPages (line 28) | function flattenPages(pages: QueuedItemPage[] | undefined): QueuedItem[] {
function resolveTransactionNonce (line 35) | function resolveTransactionNonce(txItem: TransactionQueuedItem, fallback...
function buildQueuedNonceItem (line 43) | function buildQueuedNonceItem(txItem: TransactionQueuedItem, nonce: numb...
function collectQueuedNonces (line 47) | function collectQueuedNonces(items: QueuedItem[]): QueuedNonceItem[] {
function deriveLoadingState (line 76) | function deriveLoadingState(
function useNonce (line 89) | function useNonce(chainId: string, safeAddress: string): UseNonceResult {
function extractTxLabel (line 128) | function extractTxLabel(txItem: TransactionQueuedItem): string {
FILE: apps/mobile/src/features/Send/hooks/useNonceSelection.ts
type UseNonceSelectionArgs (line 7) | interface UseNonceSelectionArgs {
type UseNonceSelectionResult (line 13) | interface UseNonceSelectionResult {
function useNonceSelection (line 31) | function useNonceSelection({ chainId, safeAddress, inputRef }: UseNonceS...
FILE: apps/mobile/src/features/Send/hooks/useProposerSheet.ts
type UseProposerSheetArgs (line 9) | interface UseProposerSheetArgs {
type UseProposerSheetResult (line 14) | interface UseProposerSheetResult {
function useProposerSheet (line 21) | function useProposerSheet({ safeAddress, inputRef }: UseProposerSheetArg...
FILE: apps/mobile/src/features/Send/hooks/useRecipientSearch.ts
type RecipientOption (line 8) | interface RecipientOption {
function buildAllContactNames (line 14) | function buildAllContactNames(contacts: { value: string; name: string }[...
function buildChainFilteredContactNames (line 22) | function buildChainFilteredContactNames(
function buildSafeOptions (line 35) | function buildSafeOptions(
function buildSignerOptions (line 49) | function buildSignerOptions(
function buildContactOptions (line 63) | function buildContactOptions(
function useRecipientSearch (line 82) | function useRecipientSearch(query: string): {
FILE: apps/mobile/src/features/Send/hooks/useRecipientValidation.ts
type RecipientValidationState (line 13) | type RecipientValidationState =
type RecipientValidationResult (line 23) | interface RecipientValidationResult {
function findContact (line 32) | function findContact(contacts: Record<string, Contact>, addr: string): C...
function resolveContactName (line 38) | function resolveContactName(contacts: Record<string, Contact>, addr: str...
function resolveSignerName (line 43) | function resolveSignerName(
type AddressContext (line 51) | interface AddressContext {
function resolveIncompleteAddress (line 58) | function resolveIncompleteAddress(trimmed: string): RecipientValidationR...
function resolveKnownAddress (line 71) | function resolveKnownAddress(trimmed: string, ctx: AddressContext): Reci...
constant UNKNOWN_RESULT (line 90) | const UNKNOWN_RESULT: RecipientValidationResult = {
function resolveCrossChainContact (line 96) | function resolveCrossChainContact(
function resolveAddressState (line 114) | function resolveAddressState(trimmed: string, ctx: AddressContext): Reci...
function useRecipientValidation (line 118) | function useRecipientValidation(address: string): RecipientValidationRes...
FILE: apps/mobile/src/features/Send/hooks/useSendTransaction.ts
type UseSendTransactionArgs (line 8) | interface UseSendTransactionArgs {
type UseSendTransactionResult (line 18) | interface UseSendTransactionResult {
function useSendTransaction (line 24) | function useSendTransaction({
FILE: apps/mobile/src/features/Send/hooks/useSuspiciousAddressDetection.ts
type SuspiciousAddressMatch (line 10) | interface SuspiciousAddressMatch {
type SuspiciousDetectionResult (line 15) | interface SuspiciousDetectionResult {
constant EMPTY_RESULT (line 20) | const EMPTY_RESULT: SuspiciousDetectionResult = {
function resolveAddressName (line 25) | function resolveAddressName(
function useSuspiciousAddressDetection (line 35) | function useSuspiciousAddressDetection(address: string): SuspiciousDetec...
FILE: apps/mobile/src/features/Send/hooks/useTokenBalance.ts
type UseTokenBalanceArgs (line 7) | interface UseTokenBalanceArgs {
type UseTokenBalanceResult (line 11) | interface UseTokenBalanceResult {
function findToken (line 20) | function findToken(items: Balance[], tokenAddress: string): Balance | un...
function getDecimals (line 26) | function getDecimals(token: Balance | undefined): number {
function hasFiatConversion (line 31) | function hasFiatConversion(token: Balance | undefined): boolean {
function useTokenBalance (line 35) | function useTokenBalance({ tokenAddress }: UseTokenBalanceArgs): UseToke...
FILE: apps/mobile/src/features/Send/services/proposeSendTransaction.test.ts
constant ZERO_ADDRESS (line 11) | const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
FILE: apps/mobile/src/features/Send/services/proposeSendTransaction.ts
type ProposeSendTransactionArgs (line 9) | interface ProposeSendTransactionArgs extends SendTransactionParams {
function validateAddresses (line 20) | function validateAddresses(recipient: string, tokenAddress: string, send...
function getVerifiedSafeSDK (line 32) | async function getVerifiedSafeSDK(chainId: string) {
FILE: apps/mobile/src/features/Send/services/tokenTransferParams.test.ts
constant ZERO_ADDRESS (line 5) | const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
constant POLYGON_MRC20 (line 6) | const POLYGON_MRC20 = '0x0000000000000000000000000000000000001010'
FILE: apps/mobile/src/features/Send/services/tokenTransferParams.ts
constant ZERO_ADDRESS (line 6) | const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
constant POLYGON_MRC20 (line 9) | const POLYGON_MRC20 = '0x0000000000000000000000000000000000001010'
FILE: apps/mobile/src/features/Send/types.ts
type SendTransactionParams (line 1) | interface SendTransactionParams {
FILE: apps/mobile/src/features/Settings/Settings.tsx
type SettingsProps (line 22) | interface SettingsProps {
FILE: apps/mobile/src/features/Settings/components/AppSettings/AppSettings.tsx
type AppSettingsProps (line 12) | interface AppSettingsProps {
FILE: apps/mobile/src/features/Settings/components/AppSettings/AppSettings.types.ts
type BaseSettingsItem (line 3) | interface BaseSettingsItem {
type StaticSettingsItem (line 11) | interface StaticSettingsItem extends BaseSettingsItem {
type PressableSettingsItem (line 16) | interface PressableSettingsItem extends BaseSettingsItem {
type SettingsItem (line 21) | type SettingsItem = StaticSettingsItem | PressableSettingsItem
type SettingsSection (line 23) | interface SettingsSection {
FILE: apps/mobile/src/features/Settings/components/Currency/Currency.container.tsx
constant CRYPTO_CURRENCIES (line 9) | const CRYPTO_CURRENCIES = ['BTC', 'ETH']
FILE: apps/mobile/src/features/Settings/components/Currency/Currency.types.ts
type CurrencyItemProps (line 3) | interface CurrencyItemProps {
type CurrencySectionProps (line 11) | interface CurrencySectionProps {
type CurrencyViewProps (line 18) | interface CurrencyViewProps {
type CurrencyScreenProps (line 26) | interface CurrencyScreenProps {
FILE: apps/mobile/src/features/Settings/components/FloatingMenu.tsx
type FloatingMenuProps (line 6) | type FloatingMenuProps = {
FILE: apps/mobile/src/features/Settings/components/Navbar/SettingsMenu.tsx
type Props (line 19) | type Props = {
FILE: apps/mobile/src/features/Share/components/ShareView.tsx
type ShareViewProps (line 19) | type ShareViewProps = {
FILE: apps/mobile/src/features/Signer/components/SignerView.test.tsx
function SignerViewWithForm (line 26) | function SignerViewWithForm(
FILE: apps/mobile/src/features/Signer/components/SignerView.tsx
type Props (line 19) | type Props = {
FILE: apps/mobile/src/features/Signer/types.ts
type FormValues (line 4) | type FormValues = z.infer<typeof formSchema>
FILE: apps/mobile/src/features/Signers/components/SignersList/ImportedBadge.tsx
function ImportedBadge (line 5) | function ImportedBadge() {
FILE: apps/mobile/src/features/Signers/components/SignersList/SignersList.tsx
type SignerSection (line 12) | type SignerSection = {
type SignersListProps (line 20) | interface SignersListProps {
function SignersList (line 27) | function SignersList({ signersGroup, isFetching, hasLocalSigners, navbar...
FILE: apps/mobile/src/features/Signers/components/SignersList/SignersListHeader.tsx
type SignersListHeaderProps (line 6) | interface SignersListHeaderProps {
function SignersListHeader (line 11) | function SignersListHeader({ withAlert, sectionTitle }: SignersListHeade...
FILE: apps/mobile/src/features/Signers/components/SignersList/SignersListItem.tsx
type SignersListItemProps (line 22) | interface SignersListItemProps {
function SignersListItem (line 27) | function SignersListItem({ item, signersGroup }: SignersListItemProps) {
FILE: apps/mobile/src/features/TransactionActions/TransactionActions.container.tsx
function TransactionActionsContainer (line 14) | function TransactionActionsContainer() {
FILE: apps/mobile/src/features/TransactionActions/components/TxActionsList.tsx
type TxActionsListProps (line 15) | interface TxActionsListProps {
type TxActionItemProps (line 30) | interface TxActionItemProps {
function TxActionsList (line 82) | function TxActionsList({ txDetails }: TxActionsListProps) {
FILE: apps/mobile/src/features/TransactionChecks/blockaid/useBlockaid.ts
constant DEFAULT_ERROR_MESSAGE (line 18) | const DEFAULT_ERROR_MESSAGE = 'Unavailable'
type BlockaidScanParams (line 20) | type BlockaidScanParams = {
type UseBlockaidReturn (line 26) | type UseBlockaidReturn = {
FILE: apps/mobile/src/features/TransactionChecks/components/TransactionChecksView.tsx
type Props (line 18) | type Props = {
FILE: apps/mobile/src/features/TransactionChecks/components/blockaid/balance/BlockaidBalanceChanges.tsx
type BlockaidBalanceChangesProps (line 10) | type BlockaidBalanceChangesProps = {
FILE: apps/mobile/src/features/TransactionChecks/components/blockaid/scans/BlockaidMessage.tsx
type BlockaidMessageProps (line 7) | type BlockaidMessageProps = {
FILE: apps/mobile/src/features/TransactionChecks/components/blockaid/scans/BlockaidWarning.tsx
type BlockaidWarningProps (line 13) | type BlockaidWarningProps = {
FILE: apps/mobile/src/features/TxHistory/TxHistory.container.tsx
function TxHistoryContainer (line 14) | function TxHistoryContainer() {
FILE: apps/mobile/src/features/TxHistory/components/TxHistoryList/TxHistoryList.tsx
type TxHistoryList (line 19) | interface TxHistoryList {
function TxHistoryList (line 29) | function TxHistoryList({
FILE: apps/mobile/src/features/TxHistory/components/TxHistoryList/components/DateHeaderItem.tsx
type DateHeaderItemProps (line 5) | interface DateHeaderItemProps {
FILE: apps/mobile/src/features/TxHistory/components/TxHistoryList/components/GroupedTransactionItem.tsx
type GroupedTransactionItemProps (line 7) | interface GroupedTransactionItemProps {
FILE: apps/mobile/src/features/TxHistory/components/TxHistoryList/components/TransactionListItem.tsx
type TransactionListItemProps (line 7) | interface TransactionListItemProps {
FILE: apps/mobile/src/features/TxHistory/components/TxHistoryList/constants.ts
constant EMPTY_ARRAY (line 4) | const EMPTY_ARRAY: HistoryTransactionItems[] = []
FILE: apps/mobile/src/features/WalletConnect/appKit.ts
function parseEntry (line 19) | function parseEntry(key: string): [string, T] {
type AppKitInstance (line 43) | type AppKitInstance = ReturnType<typeof createAppKit>
function createAppKitInstance (line 52) | function createAppKitInstance(networks: [Network, ...Network[]], default...
FILE: apps/mobile/src/features/WalletConnect/components/AppKitInitializer/AppKitInitializer.tsx
function AppKitInitializer (line 17) | function AppKitInitializer({ children }: { children: React.ReactNode }) {
FILE: apps/mobile/src/features/WalletConnect/components/AppKitInitializer/__tests__/AppKitInitializer.test.tsx
function renderAppKitInitializer (line 47) | function renderAppKitInitializer() {
FILE: apps/mobile/src/features/WalletConnect/components/WalletConnectBadge/WalletConnectBadge.test.tsx
function renderBadge (line 24) | function renderBadge(props: Partial<React.ComponentProps<typeof WalletCo...
function getBadgeBg (line 28) | function getBadgeBg(props: Partial<React.ComponentProps<typeof WalletCon...
FILE: apps/mobile/src/features/WalletConnect/components/WalletConnectBadge/WalletConnectBadge.tsx
type BadgeStatus (line 11) | type BadgeStatus = 'connected' | 'disconnected' | 'error'
type WalletConnectBadgeProps (line 13) | interface WalletConnectBadgeProps {
function WalletConnectBadge (line 24) | function WalletConnectBadge(props: WalletConnectBadgeProps) {
function resolveStatus (line 32) | function resolveStatus(isWcSigner: boolean, isConnected: boolean): Badge...
function WalletConnectBadgeInner (line 46) | function WalletConnectBadgeInner({
FILE: apps/mobile/src/features/WalletConnect/components/WalletConnectGate/WalletConnectGate.tsx
type WalletConnectGateProps (line 7) | interface WalletConnectGateProps {
function WalletConnectGate (line 12) | function WalletConnectGate({ signerAddress, children }: WalletConnectGat...
FILE: apps/mobile/src/features/WalletConnect/context/WalletConnectContext.e2e.tsx
function useWalletConnectContext (line 31) | function useWalletConnectContext(): WalletConnectContextValue {
function useOptionalWalletConnectContext (line 41) | function useOptionalWalletConnectContext(): WalletConnectContextValue | ...
type WalletConnectProviderProps (line 45) | interface WalletConnectProviderProps {
function WalletConnectProvider (line 50) | function WalletConnectProvider({ children }: WalletConnectProviderProps) {
FILE: apps/mobile/src/features/WalletConnect/context/WalletConnectContext.tsx
function useWalletConnectContext (line 24) | function useWalletConnectContext(): WalletConnectContextValue {
function useOptionalWalletConnectContext (line 38) | function useOptionalWalletConnectContext(): WalletConnectContextValue | ...
function WalletConnectContextBridge (line 46) | function WalletConnectContextBridge({
type WalletConnectProviderProps (line 134) | interface WalletConnectProviderProps {
function WalletConnectProvider (line 154) | function WalletConnectProvider({ children, instance }: WalletConnectProv...
FILE: apps/mobile/src/features/WalletConnect/context/__tests__/WalletConnectContext.test.tsx
function renderWithProvider (line 72) | async function renderWithProvider(storeOverrides?: Parameters<typeof cre...
FILE: apps/mobile/src/features/WalletConnect/context/types.ts
type WalletConnectContextValue (line 19) | interface WalletConnectContextValue
FILE: apps/mobile/src/features/WalletConnect/context/walletConnectE2eState.ts
type WalletConnectE2eState (line 8) | interface WalletConnectE2eState {
function notifyListeners (line 61) | function notifyListeners() {
function get (line 71) | function get(): WalletConnectE2eState {
function set (line 75) | function set(next: Partial<WalletConnectE2eState>) {
function reset (line 80) | function reset() {
function subscribe (line 85) | function subscribe(listener: () => void): () => void {
FILE: apps/mobile/src/features/WalletConnect/hooks/__tests__/useConnect.test.ts
type EventCallback (line 25) | type EventCallback = (state?: { data: { address?: string; properties: { ...
FILE: apps/mobile/src/features/WalletConnect/hooks/__tests__/useStableAppKitEvent.test.ts
function makeState (line 12) | function makeState(event: string) {
FILE: apps/mobile/src/features/WalletConnect/hooks/useChainSync.ts
function useChainSync (line 13) | function useChainSync() {
FILE: apps/mobile/src/features/WalletConnect/hooks/useConnect.ts
type ConnectResult (line 9) | interface ConnectResult {
class ConnectError (line 15) | class ConnectError extends Error {
method constructor (line 16) | constructor(message: string) {
class UserRejectedError (line 22) | class UserRejectedError extends Error {
method constructor (line 23) | constructor() {
class UnsupportedChainError (line 29) | class UnsupportedChainError extends Error {
method constructor (line 30) | constructor() {
type PendingConnect (line 49) | interface PendingConnect {
constant SWITCH_SETTLE_TIMEOUT_MS (line 58) | const SWITCH_SETTLE_TIMEOUT_MS = 8000
function useConnect (line 66) | function useConnect() {
FILE: apps/mobile/src/features/WalletConnect/hooks/useImportSignerFlow.ts
function useImportSignerFlow (line 15) | function useImportSignerFlow() {
type ImportSignerFlowResult (line 66) | type ImportSignerFlowResult = ReturnType<typeof useImportSignerFlow>
FILE: apps/mobile/src/features/WalletConnect/hooks/useReconnectFlow.ts
function useReconnectFlow (line 13) | function useReconnectFlow() {
type ReconnectFlowResult (line 50) | type ReconnectFlowResult = ReturnType<typeof useReconnectFlow>
FILE: apps/mobile/src/features/WalletConnect/hooks/useStableAppKitEvent.ts
type AppKitEvent (line 6) | type AppKitEvent<N extends EventName> = Extract<Event, { event: N }>
type EventsControllerState (line 7) | type EventsControllerState<N extends EventName> = Omit<CoreEventsControl...
function useStableAppKitEvent (line 23) | function useStableAppKitEvent<E extends EventName>(
FILE: apps/mobile/src/features/WalletConnect/hooks/useSwitchNetwork.ts
function useSwitchNetwork (line 15) | function useSwitchNetwork() {
type SwitchNetworkResult (line 46) | type SwitchNetworkResult = ReturnType<typeof useSwitchNetwork>
FILE: apps/mobile/src/features/WalletConnect/hooks/useWalletConnectSigning.ts
type SignParams (line 10) | type SignParams = Omit<WalletConnectSigningParams, 'provider' | 'safeVer...
function useWalletConnectSigning (line 19) | function useWalletConnectSigning() {
type WalletConnectSigningResult (line 44) | type WalletConnectSigningResult = ReturnType<typeof useWalletConnectSign...
FILE: apps/mobile/src/features/WalletConnect/hooks/useWalletConnectStatus.ts
function useWalletConnectStatus (line 10) | function useWalletConnectStatus(signerAddress: string): boolean {
FILE: apps/mobile/src/features/WalletConnect/utils/chains.ts
function extractBlockExplorerUrl (line 10) | function extractBlockExplorerUrl(template: string): string | undefined {
function cgwChainToReownNetwork (line 24) | function cgwChainToReownNetwork(chain: Chain): Network | undefined {
function cgwChainsToReownNetworks (line 59) | function cgwChainsToReownNetworks(chains: Chain[]): Network[] {
FILE: apps/mobile/src/hooks/__tests__/useNotificationHandler.test.ts
type TestNotificationEvent (line 12) | interface TestNotificationEvent {
FILE: apps/mobile/src/hooks/services/overviewQueryArgs.ts
type OverviewQueryArgs (line 8) | type OverviewQueryArgs = {
FILE: apps/mobile/src/hooks/services/useLazySafeOverviews.ts
type LazyTrigger (line 5) | type LazyTrigger = ReturnType<typeof useLazySafesGetOverviewForManyQuery...
type LazyResult (line 6) | type LazyResult = ReturnType<typeof useLazySafesGetOverviewForManyQuery>[1]
type LazyTriggerExtraArgs (line 7) | type LazyTriggerExtraArgs = Parameters<LazyTrigger> extends [unknown, .....
FILE: apps/mobile/src/hooks/services/useSafeKnownChainsOverview.ts
type Options (line 10) | type Options = {
FILE: apps/mobile/src/hooks/services/useSafeOverviewsQuery.ts
type OverviewQueryOptions (line 4) | type OverviewQueryOptions = {
function useSafeOverviewsQuery (line 9) | function useSafeOverviewsQuery(args: OverviewQueryArgs, options?: Overvi...
FILE: apps/mobile/src/hooks/useAddressOwnershipValidation.ts
type AddressValidationResult (line 15) | interface AddressValidationResult {
FILE: apps/mobile/src/hooks/useAddresses.ts
type BaseAddress (line 3) | interface BaseAddress {
type State (line 9) | interface State<T extends BaseAddress> {
type Action (line 15) | type Action<T extends BaseAddress> =
function reducer (line 28) | function reducer<T extends BaseAddress>(state: State<T>, action: Action<...
type UseAddressesConfig (line 59) | interface UseAddressesConfig<T extends BaseAddress, TExtra extends unkno...
FILE: apps/mobile/src/hooks/useBiometrics.ts
constant BIOMETRICS_KEY (line 14) | const BIOMETRICS_KEY = 'SAFE_WALLET_BIOMETRICS'
type EnableBiometricsResult (line 16) | type EnableBiometricsResult =
type DisableBiometricsResult (line 22) | type DisableBiometricsResult = { status: 'disabled' } | { status: 'error...
type ToggleBiometricsResult (line 24) | type ToggleBiometricsResult = EnableBiometricsResult | DisableBiometrics...
function useBiometrics (line 26) | function useBiometrics() {
FILE: apps/mobile/src/hooks/useDelegate.test.ts
constant TEST_PRIVATE_KEY (line 5) | const TEST_PRIVATE_KEY = '0xdd503e13625fa99fdea1e1dfb180dd3de94ee4d16c85...
constant OWNER_ADDRESS (line 7) | const OWNER_ADDRESS = '0x82E92d643B9B4e767Bd95a85C5e83D248Cb40548'
constant TEST_SAFE_ADDRESS (line 9) | const TEST_SAFE_ADDRESS = '0x1234567890123456789012345678901234567890'
method createRandom (line 23) | static createRandom() {
method signTypedData (line 30) | signTypedData() {
method constructor (line 41) | constructor(props: {
method prepareMessage (line 54) | prepareMessage() {
FILE: apps/mobile/src/hooks/useDelegate.ts
type UseDelegateProps (line 13) | interface UseDelegateProps {
FILE: apps/mobile/src/hooks/useDelegateCleanup.ts
type UseDelegateCleanupProps (line 36) | interface UseDelegateCleanupProps {
FILE: apps/mobile/src/hooks/useDelegateCleanup/utils.ts
type CleanupResult (line 13) | interface CleanupResult {
type NotificationCleanupResult (line 21) | interface NotificationCleanupResult {
type DelegateRemovalResult (line 27) | interface DelegateRemovalResult {
type KeychainCleanupResult (line 33) | interface KeychainCleanupResult {
FILE: apps/mobile/src/hooks/useDisplayName.ts
type UseDisplayNameOptions (line 6) | interface UseDisplayNameOptions {
type UseDisplayNameResult (line 13) | interface UseDisplayNameResult {
FILE: apps/mobile/src/hooks/useFeeParams/useFeeParams.test.ts
constant SAFE_ADDRESS (line 44) | const SAFE_ADDRESS = '0x1234567890123456789012345678901234567890' as Add...
constant SIGNER_ADDRESS (line 45) | const SIGNER_ADDRESS = '0x0987654321098765432109876543210987654321'
FILE: apps/mobile/src/hooks/useFeeParams/useFeeParams.ts
type FeeParams (line 17) | type FeeParams = {
type UseFeeParamsSettings (line 27) | interface UseFeeParamsSettings {
FILE: apps/mobile/src/hooks/useHasSigner.ts
function useHasSigner (line 8) | function useHasSigner() {
FILE: apps/mobile/src/hooks/useHeaderHeight.ts
function useHeaderHeight (line 15) | function useHeaderHeight(): number {
FILE: apps/mobile/src/hooks/useMakeSafesWithChainId/useMakeSafesWithChainId.ts
function useMakeSafesWithChainId (line 6) | function useMakeSafesWithChainId(safeAddress: string) {
FILE: apps/mobile/src/hooks/useNotificationCleanup.ts
type NotificationCleanupResult (line 16) | interface NotificationCleanupResult {
type UseNotificationCleanupProps (line 21) | interface UseNotificationCleanupProps {
FILE: apps/mobile/src/hooks/useNotificationGTWPermissions.ts
function useNotificationGTWPermissions (line 8) | function useNotificationGTWPermissions(safeAddress: string, chainId?: st...
FILE: apps/mobile/src/hooks/useNotificationPayload.ts
function useNotificationPayload (line 9) | function useNotificationPayload() {
FILE: apps/mobile/src/hooks/useRegisterForNotifications.ts
type RegisterForNotificationsProps (line 20) | type RegisterForNotificationsProps = {
type NotificationsProps (line 25) | interface NotificationsProps {
FILE: apps/mobile/src/hooks/useScreenProtection.e2e.ts
type ScreenProtectionOptions (line 1) | interface ScreenProtectionOptions {
FILE: apps/mobile/src/hooks/useScreenProtection.ts
type ScreenProtectionOptions (line 7) | interface ScreenProtectionOptions {
FILE: apps/mobile/src/hooks/useShareTransaction.ts
function useShareTransaction (line 8) | function useShareTransaction(txId: string) {
FILE: apps/mobile/src/hooks/useSiwe.ts
type SiweMessageProps (line 5) | interface SiweMessageProps {
function useSiwe (line 12) | function useSiwe() {
FILE: apps/mobile/src/hooks/useTokenDetails/useTokenDetails.ts
type tokenDetails (line 7) | interface tokenDetails {
FILE: apps/mobile/src/hooks/useTransactionProcessingState.ts
function useTransactionProcessingState (line 17) | function useTransactionProcessingState(txId: string) {
FILE: apps/mobile/src/hooks/useTransactionSigningState.ts
function useTransactionSigningState (line 13) | function useTransactionSigningState(txId: string) {
FILE: apps/mobile/src/hooks/useTransactionType/index.tsx
type TxType (line 32) | interface TxType {
FILE: apps/mobile/src/hooks/wallets/web3.ts
constant BATCH_MAX_COUNT (line 13) | const BATCH_MAX_COUNT = 3
FILE: apps/mobile/src/navigation/NavigationGuardHOC.tsx
function useInitialNavigationScreen (line 15) | function useInitialNavigationScreen() {
function NavigationGuardHOC (line 71) | function NavigationGuardHOC({ children }: { children: React.ReactNode }) {
FILE: apps/mobile/src/navigation/dismissToConfirmTransaction.ts
type NavigationWithState (line 4) | interface NavigationWithState {
function dismissToConfirmTransaction (line 15) | function dismissToConfirmTransaction(navigation: NavigationWithState, tx...
FILE: apps/mobile/src/navigation/useScrollableHeader.tsx
type UseScrollableHeaderProps (line 7) | interface UseScrollableHeaderProps {
FILE: apps/mobile/src/platform/security.ts
constant SECURITY_MESSAGES (line 25) | const SECURITY_MESSAGES = {
FILE: apps/mobile/src/providers/DatadogWrapper.tsx
type DatadogWrapperProps (line 45) | interface DatadogWrapperProps {
function DatadogWrapper (line 49) | function DatadogWrapper({ children }: DatadogWrapperProps) {
FILE: apps/mobile/src/services/analytics/constants.ts
constant ANALYTICS_LABELS (line 3) | const ANALYTICS_LABELS = {
FILE: apps/mobile/src/services/analytics/events/copy.ts
constant COPY_CATEGORY (line 3) | const COPY_CATEGORY = 'copy'
FILE: apps/mobile/src/services/analytics/events/nativeIntent.ts
constant NATIVE_INTENT_CATEGORY (line 3) | const NATIVE_INTENT_CATEGORY = 'native-intent'
constant NATIVE_INTENT_EVENTS (line 5) | const NATIVE_INTENT_EVENTS = {
FILE: apps/mobile/src/services/analytics/events/overview.ts
constant OVERVIEW_CATEGORY (line 3) | const OVERVIEW_CATEGORY = 'overview'
constant OVERVIEW_EVENTS (line 5) | const OVERVIEW_EVENTS = {
type ScanForNewNetworksResult (line 44) | type ScanForNewNetworksResult = 'success' | 'empty' | 'error'
FILE: apps/mobile/src/services/analytics/events/safes.ts
constant SAFES_CATEGORY (line 3) | const SAFES_CATEGORY = 'safes'
FILE: apps/mobile/src/services/analytics/events/settings.ts
constant SETTINGS_CATEGORY (line 3) | const SETTINGS_CATEGORY = 'settings'
constant SETTINGS_EVENTS (line 5) | const SETTINGS_EVENTS = {
FILE: apps/mobile/src/services/analytics/events/signers.ts
constant SIGNERS_CATEGORY (line 3) | const SIGNERS_CATEGORY = 'signers'
FILE: apps/mobile/src/services/analytics/events/transactions.ts
constant TRANSACTIONS_CATEGORY (line 3) | const TRANSACTIONS_CATEGORY = 'transactions'
constant TRANSACTIONS_EVENTS (line 5) | const TRANSACTIONS_EVENTS = {
FILE: apps/mobile/src/services/analytics/firebaseAnalytics.ts
function truncateParam (line 105) | function truncateParam(value: string | undefined): string | undefined {
FILE: apps/mobile/src/services/analytics/types.ts
type EventType (line 19) | enum EventType {
type EventLabel (line 33) | type EventLabel = string | number | boolean | null
type AnalyticsEvent (line 35) | type AnalyticsEvent = {
type AnalyticsUserProperties (line 43) | enum AnalyticsUserProperties {
type TransactionInfoType (line 49) | type TransactionInfoType = Transaction['txInfo']['type']
type TransferInfoType (line 50) | type TransferInfoType = TransferTransactionInfo['transferInfo']['type']
type SettingsInfoType (line 51) | type SettingsInfoType = SettingsChangeTransaction['settingsInfo']['type']
type AnalyticsLabel (line 54) | type AnalyticsLabel =
FILE: apps/mobile/src/services/bluetooth/bluetooth.service.ts
type BluetoothPermissionResult (line 5) | interface BluetoothPermissionResult {
class BluetoothService (line 10) | class BluetoothService {
method getInstance (line 13) | public static getInstance(): BluetoothService {
method constructor (line 20) | private constructor() {
method getBluetoothPermission (line 27) | private getBluetoothPermission() {
method checkBluetoothPermission (line 40) | public async checkBluetoothPermission(): Promise<PermissionStatus> {
method requestBluetoothPermissions (line 55) | public async requestBluetoothPermissions(): Promise<BluetoothPermissio...
method openDeviceSettings (line 105) | public async openDeviceSettings(): Promise<void> {
FILE: apps/mobile/src/services/delegate-cleanup/DelegateCleanupService.ts
type DelegateCleanupErrorType (line 17) | enum DelegateCleanupErrorType {
type DelegateCleanupError (line 26) | interface DelegateCleanupError {
type DelegateCleanupPhase (line 36) | enum DelegateCleanupPhase {
type DelegateCleanupProgress (line 46) | interface DelegateCleanupProgress {
type DelegateCleanupConfig (line 54) | interface DelegateCleanupConfig {
class DelegateCleanupService (line 63) | class DelegateCleanupService {
method constructor (line 66) | constructor(config: DelegateCleanupConfig) {
method removeAllDelegatesForOwner (line 70) | async removeAllDelegatesForOwner(
method reportProgress (line 216) | private reportProgress(
FILE: apps/mobile/src/services/key-storage/key-storage.service.ts
class KeyStorageService (line 9) | class KeyStorageService implements IKeyStorageService {
method storePrivateKey (line 29) | async storePrivateKey(
method getPrivateKey (line 47) | async getPrivateKey(
method removePrivateKey (line 59) | async removePrivateKey(
method getKeyNameDeviceCrypto (line 72) | private getKeyNameDeviceCrypto(userId: string): string {
method getKeyService (line 76) | private getKeyService(userId: string): string {
method getOrCreateKeyIOS (line 80) | private async getOrCreateKeyIOS(keyName: string, requireAuth: boolean,...
method getOrCreateKeyAndroid (line 98) | private async getOrCreateKeyAndroid(keyName: string, requireAuth: bool...
method storeKey (line 110) | private async storeKey(userId: string, privateKey: string, requireAuth...
method getKey (line 147) | private async getKey(userId: string, requireAuth: boolean): Promise<st...
method isKeyPermanentlyInvalidatedError (line 171) | private isKeyPermanentlyInvalidatedError(error: unknown): boolean {
method handleKeyInvalidation (line 176) | private async handleKeyInvalidation(userId: string, requireAuth: boole...
method removeKey (line 181) | private async removeKey(userId: string, requireAuth: boolean): Promise...
FILE: apps/mobile/src/services/key-storage/types.ts
type PrivateKeyStorageOptions (line 1) | type PrivateKeyStorageOptions = {
type IKeyStorageService (line 5) | interface IKeyStorageService {
FILE: apps/mobile/src/services/key-storage/wallet.service.ts
type IWalletService (line 4) | interface IWalletService {
class WalletService (line 8) | class WalletService implements IWalletService {
method createMnemonicAccount (line 9) | async createMnemonicAccount(mnemonic: string): Promise<HDNodeWallet | ...
FILE: apps/mobile/src/services/ledger/ledger-dmk.service.ts
class LedgerDMKService (line 13) | class LedgerDMKService {
method constructor (line 22) | private constructor() {
method getInstance (line 29) | public static getInstance(): LedgerDMKService {
method startScanning (line 39) | public startScanning(onDeviceFound: (device: DiscoveredDevice) => void...
method stopScanning (line 87) | public stopScanning(): void {
method connectToDevice (line 106) | public async connectToDevice(device: DiscoveredDevice): Promise<Device...
method performConnection (line 134) | private async performConnection(device: DiscoveredDevice): Promise<Dev...
method isSessionValid (line 189) | private async isSessionValid(sessionId: DeviceSessionId): Promise<bool...
method startMonitoringSession (line 218) | private startMonitoringSession(sessionId: DeviceSessionId): void {
method stopMonitoringSession (line 247) | private stopMonitoringSession(): void {
method clearSession (line 258) | private clearSession(): void {
method disconnect (line 266) | public async disconnect(): Promise<void> {
method getCurrentSession (line 285) | public getCurrentSession(): DeviceSessionId | null {
method dispose (line 292) | public dispose(): void {
FILE: apps/mobile/src/services/ledger/ledger-ethereum.service.ts
type EthereumAddress (line 8) | interface EthereumAddress {
type DerivationPathType (line 14) | type DerivationPathType = 'ledger-live' | 'legacy-ledger' | 'bip44'
class LedgerEthereumService (line 16) | class LedgerEthereumService {
method constructor (line 19) | private constructor() {
method createSigner (line 28) | private createSigner(session: DeviceSessionId) {
method executeDeviceAction (line 41) | private executeDeviceAction<T, E, I>(deviceAction: ExecuteDeviceAction...
method formatSignature (line 64) | private formatSignature(signature: Signature): string {
method getInstance (line 71) | public static getInstance(): LedgerEthereumService {
method getEthereumAddresses (line 86) | public async getEthereumAddresses(
method getEthereumAddress (line 132) | public async getEthereumAddress(session: DeviceSessionId, index: numbe...
method signTransaction (line 147) | public async signTransaction(session: DeviceSessionId, path: string, t...
method signTypedData (line 166) | public async signTypedData(session: DeviceSessionId, path: string, typ...
FILE: apps/mobile/src/services/ledger/ledger-execution.service.ts
type LedgerExecutionParams (line 15) | interface LedgerExecutionParams {
type LedgerExecutionResult (line 24) | interface LedgerExecutionResult {
class LedgerExecutionService (line 31) | class LedgerExecutionService {
method getInstance (line 34) | public static getInstance(): LedgerExecutionService {
method ensureLedgerConnection (line 44) | public async ensureLedgerConnection(): Promise<void> {
method executeTransaction (line 58) | public async executeTransaction(params: LedgerExecutionParams): Promis...
method parseSignature (line 197) | private parseSignature(signatureHex: string): { r: string; s: string; ...
FILE: apps/mobile/src/services/ledger/ledger-safe-signing.service.ts
type LedgerSafeSigningParams (line 14) | interface LedgerSafeSigningParams {
type SigningResponse (line 23) | interface SigningResponse {
class LedgerSafeSigningService (line 28) | class LedgerSafeSigningService {
method constructor (line 31) | private constructor() {
method getInstance (line 35) | public static getInstance(): LedgerSafeSigningService {
method signSafeTransaction (line 47) | public async signSafeTransaction(params: LedgerSafeSigningParams): Pro...
method createSafeTransactionForLedger (line 105) | private async createSafeTransactionForLedger(activeSafe: SafeInfo, txI...
method convertToLedgerFormat (line 121) | private convertToLedgerFormat(typedData: ReturnType<typeof generateTyp...
method calculateTransactionHash (line 140) | private calculateTransactionHash(typedData: TypedData): string {
method isLedgerReady (line 147) | public isLedgerReady(): boolean {
method ensureLedgerConnection (line 155) | public async ensureLedgerConnection(): Promise<void> {
FILE: apps/mobile/src/services/notifications/BadgeManager.ts
class BadgeManager (line 4) | class BadgeManager {
method incrementBadgeCount (line 5) | async incrementBadgeCount(incrementBy?: number): Promise<void> {
method decrementBadgeCount (line 11) | async decrementBadgeCount(decrementBy?: number): Promise<void> {
method setBadgeCount (line 17) | async setBadgeCount(count: number): Promise<void> {
method getBadgeCount (line 22) | async getBadgeCount(): Promise<number> {
method clearAllBadges (line 28) | async clearAllBadges(): Promise<void> {
FILE: apps/mobile/src/services/notifications/FCMService.ts
class FCMService (line 6) | class FCMService {
method getFCMToken (line 7) | async getFCMToken(): Promise<string | undefined> {
method saveFCMToken (line 16) | async saveFCMToken(): Promise<void> {
method initNotification (line 29) | async initNotification(): Promise<string | undefined> {
FILE: apps/mobile/src/services/notifications/NotificationService.ts
type AlertButton (line 29) | interface AlertButton {
type UnsubscribeFunc (line 34) | type UnsubscribeFunc = () => void
class NotificationsService (line 36) | class NotificationsService {
method getBlockedNotifications (line 37) | async getBlockedNotifications(): Promise<Map<ChannelId, boolean>> {
method enableNotifications (line 63) | enableNotifications() {
method getAllPermissions (line 74) | async getAllPermissions() {
method isDeviceNotificationEnabled (line 101) | async isDeviceNotificationEnabled() {
method getAuthorizationStatus (line 111) | async getAuthorizationStatus() {
method isAuthorizationDenied (line 116) | async isAuthorizationDenied() {
method openDeviceSettings (line 124) | async openDeviceSettings() {
method requestPushNotificationsPermission (line 169) | async requestPushNotificationsPermission(): Promise<void> {
method checkCurrentPermissions (line 180) | async checkCurrentPermissions() {
method onForegroundEvent (line 192) | onForegroundEvent(observer: (event: NotifeeEvent) => Promise<void>): (...
method onBackgroundEvent (line 196) | onBackgroundEvent(observer: (event: NotifeeEvent) => Promise<void>) {
method handleNotificationPress (line 200) | async handleNotificationPress({
method handleNotificationEvent (line 220) | async handleNotificationEvent({
method cancelTriggerNotification (line 240) | async cancelTriggerNotification(id?: string) {
method getInitialNotification (line 247) | async getInitialNotification(callback: HandleNotificationCallback): Pr...
method cancelAllNotifications (line 254) | async cancelAllNotifications() {
method createChannel (line 258) | async createChannel(channel: AndroidChannel): Promise<string> {
method displayNotification (line 262) | async displayNotification({
method initializeNotificationHandlers (line 309) | initializeNotificationHandlers(): void {
method registerFirebaseNotificationOpenedHandler (line 334) | private registerFirebaseNotificationOpenedHandler(): void {
FILE: apps/mobile/src/services/notifications/__tests__/notificationNavigationHandler.test.ts
type MockActiveSafeAction (line 9) | interface MockActiveSafeAction {
type TestNotificationData (line 17) | interface TestNotificationData {
FILE: apps/mobile/src/services/notifications/backend.ts
type CustomRTKQueryOptions (line 15) | interface CustomRTKQueryOptions {
FILE: apps/mobile/src/services/notifications/notificationNavigationHandler.ts
type NotificationNavigationData (line 31) | interface NotificationNavigationData {
method handleNotificationPress (line 42) | async handleNotificationPress(data: FirebaseMessagingTypes.RemoteMessage...
method switchToSafe (line 103) | async switchToSafe(address: Address, chainId: string): Promise<void> {
method safeNavigate (line 136) | async safeNavigate(path: string | { pathname: string; params?: Record<st...
method safeDismissAll (line 154) | async safeDismissAll(): Promise<void> {
method navigateToTransactionHistory (line 161) | async navigateToTransactionHistory(): Promise<void> {
method navigateToConfirmTransaction (line 168) | async navigateToConfirmTransaction(safeTxHash?: string): Promise<void> {
FILE: apps/mobile/src/services/notifications/notificationParser.ts
type ParsedNotification (line 10) | interface ParsedNotification {
type NotificationMetadata (line 15) | interface NotificationMetadata {
FILE: apps/mobile/src/services/notifications/registration.ts
type StoreLike (line 6) | type StoreLike = Pick<Store<RootState>, 'dispatch' | 'getState'>
type DelegateInfo (line 21) | type DelegateInfo = { owner: string; delegateAddress: string } | null
function registerSafe (line 41) | async function registerSafe(store: StoreLike, address: string, chainIds:...
function unregisterSafe (line 91) | async function unregisterSafe(store: StoreLike, address: string, chainId...
FILE: apps/mobile/src/services/notifications/store-sync/read.ts
type ExtensionStore (line 4) | interface ExtensionStore {
function getExtensionData (line 14) | function getExtensionData(): ExtensionStore | null {
FILE: apps/mobile/src/services/notifications/store-sync/sync.ts
function syncNotificationExtensionData (line 16) | function syncNotificationExtensionData(store: AppStore) {
FILE: apps/mobile/src/services/remoteConfig/remoteConfigService.e2e.ts
constant VALUES (line 9) | const VALUES: Record<string, string> = {
function initialize (line 16) | async function initialize(): Promise<void> {
function getString (line 20) | function getString(key: string): string {
function getPlatformString (line 24) | function getPlatformString(key: string): string {
FILE: apps/mobile/src/services/remoteConfig/remoteConfigService.ts
constant PLATFORM_SUFFIX (line 10) | const PLATFORM_SUFFIX = Platform.OS === 'ios' ? 'ios' : 'android'
constant DEFAULTS (line 12) | const DEFAULTS: Record<string, string> = {
function initialize (line 21) | async function initialize(): Promise<void> {
function getString (line 37) | function getString(key: string): string {
function getPlatformString (line 51) | function getPlatformString(key: string): string {
FILE: apps/mobile/src/services/tx-execution/ledgerExecutor.ts
type ExecuteLedgerTxParams (line 11) | interface ExecuteLedgerTxParams {
type ExecuteLedgerTxResult (line 19) | interface ExecuteLedgerTxResult {
FILE: apps/mobile/src/services/tx-execution/privateKeyExecutor.ts
type ExecutePrivateKeyTxParams (line 10) | interface ExecutePrivateKeyTxParams {
type ExecutePrivateKeyTxResult (line 18) | interface ExecutePrivateKeyTxResult {
FILE: apps/mobile/src/services/tx-execution/relayExecutor.ts
type ExecuteRelayTxParams (line 11) | interface ExecuteRelayTxParams {
type ExecuteRelayTxResult (line 26) | interface ExecuteRelayTxResult {
FILE: apps/mobile/src/services/tx-execution/walletConnectExecutor.test.ts
constant VALID_TX_HASH (line 51) | const VALID_TX_HASH = faker.string.hexadecimal({ length: 64, prefix: '0x...
FILE: apps/mobile/src/services/tx-execution/walletConnectExecutor.ts
constant TX_HASH_REGEX (line 15) | const TX_HASH_REGEX = /^0x[0-9a-fA-F]{64}$/
type ExecuteWalletConnectTxParams (line 17) | interface ExecuteWalletConnectTxParams {
type ExecuteWalletConnectTxResult (line 25) | interface ExecuteWalletConnectTxResult {
FILE: apps/mobile/src/services/tx/extractTx.ts
constant ZERO_ADDRESS (line 6) | const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
constant EMPTY_DATA (line 7) | const EMPTY_DATA = '0x'
FILE: apps/mobile/src/services/tx/proposeNewTransaction.ts
type ProposeNewTransactionParams (line 11) | interface ProposeNewTransactionParams {
function buildProposeDto (line 21) | function buildProposeDto(
FILE: apps/mobile/src/services/tx/tx-sender/create.ts
type CreateTxParams (line 10) | interface CreateTxParams {
FILE: apps/mobile/src/services/tx/tx-sender/execute.ts
type ExecuteTxParams (line 7) | interface ExecuteTxParams {
FILE: apps/mobile/src/services/tx/tx-sender/sign.ts
type signTxParams (line 7) | type signTxParams = {
FILE: apps/mobile/src/services/walletconnect/walletconnect-signing.service.ts
type WalletConnectSigningParams (line 13) | interface WalletConnectSigningParams {
type SigningResponse (line 22) | interface SigningResponse {
FILE: apps/mobile/src/store/__tests__/migrations.test.ts
type PersistedContact (line 3) | interface PersistedContact {
type TestState (line 9) | interface TestState {
FILE: apps/mobile/src/store/__tests__/persistMigrations.test.ts
type TestState (line 3) | interface TestState {
FILE: apps/mobile/src/store/__tests__/sanitizePendingQueriesTransform.test.ts
type TransformResult (line 5) | interface TransformResult {
FILE: apps/mobile/src/store/activeSignerSlice.ts
type ActiveSignerState (line 6) | type ActiveSignerState = Record<Address, SignerInfo>
FILE: apps/mobile/src/store/addressBookSlice.ts
type Contact (line 6) | type Contact = Omit<AddressInfo, 'name'> & {
type AddressBookState (line 11) | interface AddressBookState {
FILE: apps/mobile/src/store/biometricsSlice.ts
type BiometricsState (line 4) | interface BiometricsState {
FILE: apps/mobile/src/store/constants.ts
constant WINDOW_HEIGHT (line 6) | const WINDOW_HEIGHT = Dimensions.get('window').height
constant WINDOW_WIDTH (line 7) | const WINDOW_WIDTH = Dimensions.get('window').width
type STORAGE_IDS (line 323) | enum STORAGE_IDS {
type STORAGE_TYPES (line 342) | enum STORAGE_TYPES {
type HandleNotificationCallback (line 369) | type HandleNotificationCallback = (data: FirebaseMessagingTypes.RemoteMe...
type PressActionId (line 371) | enum PressActionId {
constant IS_DEV (line 376) | const IS_DEV = process.env.EXPO_PUBLIC_APP_VARIANT === 'development'
constant LAUNCH_ACTIVITY (line 378) | const LAUNCH_ACTIVITY = IS_DEV ? 'global.safe.mobileapp.dev.MainActivity...
constant ERROR_MSG (line 380) | const ERROR_MSG = 'useDelegateKey: Something went wrong'
type NOTIFICATION_ACCOUNT_TYPE (line 382) | enum NOTIFICATION_ACCOUNT_TYPE {
FILE: apps/mobile/src/store/delegatesSlice.ts
type DelegateInfo (line 6) | interface DelegateInfo {
type DelegatesSliceState (line 13) | type DelegatesSliceState = Record<string, Record<string, DelegateInfo>>
FILE: apps/mobile/src/store/estimatedFeeSlice.ts
type EstimatedFeeValues (line 4) | interface EstimatedFeeValues {
type EstimatedFeeState (line 11) | type EstimatedFeeState = EstimatedFeeValues | null
FILE: apps/mobile/src/store/executingStateSlice.test.ts
type ExecutingStateSlice (line 12) | type ExecutingStateSlice = ReturnType<typeof executingStateReducer>
FILE: apps/mobile/src/store/executingStateSlice.ts
type ExecutingState (line 5) | interface ExecutingState {
type ExecutingStateSlice (line 13) | interface ExecutingStateSlice {
FILE: apps/mobile/src/store/executionMethodSlice.ts
type ExecutionMethodState (line 5) | type ExecutionMethodState = ExecutionMethod
FILE: apps/mobile/src/store/index.ts
type QueryEntry (line 65) | type QueryEntry = { status?: string } | undefined
type RtkQueryState (line 66) | type RtkQueryState = {
type RootReducerState (line 142) | type RootReducerState = ReturnType<typeof rootReducer>
type AppStartListening (line 147) | type AppStartListening = TypedStartListening<RootState, AppDispatch>
type AppListenerEffectAPI (line 148) | type AppListenerEffectAPI = ListenerEffectAPI<RootState, AppDispatch>
type RootState (line 200) | type RootState = ReturnType<typeof rootReducer>
type AppDispatch (line 201) | type AppDispatch = typeof store.dispatch
type AppStore (line 202) | type AppStore = typeof store
FILE: apps/mobile/src/store/middleware/__tests__/notificationSync.test.ts
constant TEST_GATEWAY_URL (line 21) | const TEST_GATEWAY_URL = 'https://safe-client.staging.5afe.dev'
FILE: apps/mobile/src/store/middleware/analytics/AnalyticsStrategyManager.ts
class AnalyticsStrategyManager (line 11) | class AnalyticsStrategyManager extends StrategyManager<RootState, Middle...
method constructor (line 12) | constructor() {
method registerDefaultStrategies (line 17) | private registerDefaultStrategies(): void {
FILE: apps/mobile/src/store/middleware/analytics/strategies/AddressBookTrackingStrategy.ts
class AddressBookTrackingStrategy (line 16) | class AddressBookTrackingStrategy implements Strategy<RootState, Middlew...
method execute (line 17) | execute(store: MiddlewareAPI<Dispatch, RootState>, action: ActionWithP...
method trackContactAdded (line 29) | private trackContactAdded(state: RootState): void {
method trackContactEdited (line 40) | private trackContactEdited(state: RootState): void {
method trackContactRemoved (line 51) | private trackContactRemoved(state: RootState): void {
FILE: apps/mobile/src/store/middleware/analytics/strategies/SafeManagementStrategy.ts
class SafeManagementStrategy (line 9) | class SafeManagementStrategy implements Strategy<RootState, MiddlewareAP...
method execute (line 10) | execute(store: MiddlewareAPI<Dispatch, RootState>, action: AnyAction, ...
FILE: apps/mobile/src/store/middleware/analytics/strategies/SafeViewedStrategy.ts
class SafeViewedStrategy (line 8) | class SafeViewedStrategy implements Strategy<RootState> {
method execute (line 9) | execute(store: MiddlewareAPI<Dispatch, RootState>, action: ActionWithP...
FILE: apps/mobile/src/store/middleware/analytics/strategies/SettingsStrategy.ts
class SettingsStrategy (line 12) | class SettingsStrategy implements Strategy<RootState, MiddlewareAPI<Disp...
method execute (line 13) | execute(_store: MiddlewareAPI<Dispatch, RootState>, action: ActionWith...
method trackSettingsChanges (line 20) | private trackSettingsChanges(payload: Record<string, unknown>): void {
FILE: apps/mobile/src/store/middleware/analytics/strategies/SignerTrackingStrategy.ts
class SignerTrackingStrategy (line 12) | class SignerTrackingStrategy implements Strategy<RootState, MiddlewareAP...
method execute (line 13) | execute(store: MiddlewareAPI<Dispatch, RootState>, action: ActionWithP...
method trackSignerAddition (line 20) | private trackSignerAddition(state: RootState): void {
FILE: apps/mobile/src/store/middleware/analytics/strategies/TransactionConfirmationStrategy.ts
class TransactionConfirmationStrategy (line 9) | class TransactionConfirmationStrategy implements Strategy<RootState, Mid...
method execute (line 10) | execute(_store: MiddlewareAPI<Dispatch, RootState>, action: ActionWith...
FILE: apps/mobile/src/store/middleware/notificationSync.ts
function shouldSyncNotificationData (line 17) | function shouldSyncNotificationData(action: unknown): boolean {
FILE: apps/mobile/src/store/middleware/notifications/NotificationStrategyManager.ts
class NotificationStrategyManager (line 14) | class NotificationStrategyManager extends StrategyManager<RootState, Mid...
method constructor (line 15) | constructor() {
method registerDefaultStrategies (line 20) | private registerDefaultStrategies(): void {
FILE: apps/mobile/src/store/middleware/notifications/strategies/AddDelegateStrategy.ts
class AddDelegateStrategy (line 10) | class AddDelegateStrategy implements Strategy<RootState, MiddlewareAPI<D...
method execute (line 11) | execute(store: MiddlewareAPI<Dispatch, RootState>, action: AnyAction):...
FILE: apps/mobile/src/store/middleware/notifications/strategies/AddSafeStrategy.ts
class AddSafeStrategy (line 8) | class AddSafeStrategy implements Strategy<RootState, MiddlewareAPI<Dispa...
method execute (line 9) | execute(store: MiddlewareAPI<Dispatch, RootState>, action: AnyAction):...
FILE: apps/mobile/src/store/middleware/notifications/strategies/RemoveSafeStrategy.ts
class RemoveSafeStrategy (line 8) | class RemoveSafeStrategy implements Strategy<RootState, MiddlewareAPI<Di...
method execute (line 9) | execute(store: MiddlewareAPI<Dispatch, RootState>, action: AnyAction, ...
FILE: apps/mobile/src/store/middleware/notifications/strategies/ToggleAppNotificationsStrategy.ts
class ToggleAppNotificationsStrategy (line 9) | class ToggleAppNotificationsStrategy implements Strategy<RootState, Midd...
method execute (line 10) | execute(store: MiddlewareAPI<Dispatch, RootState>, _action: AnyAction,...
FILE: apps/mobile/src/store/middleware/pendingTxs.ts
function isHydrateAction (line 129) | function isHydrateAction(action: Action): action is Action<typeof REHYDR...
FILE: apps/mobile/src/store/migrations.ts
type PersistedContact (line 5) | interface PersistedContact {
type PersistedSafeOverview (line 11) | interface PersistedSafeOverview {
type PersistedRootState (line 15) | type PersistedRootState = {
type SafesMap (line 20) | type SafesMap = Record<string, Record<string, PersistedSafeOverview>>
function buildSafeChainMap (line 23) | function buildSafeChainMap(safes: SafesMap): Map<string, string[]> {
function buildSignerChainMap (line 32) | function buildSignerChainMap(safes: SafesMap): Map<string, Set<string>> {
function backfillContactChainIds (line 51) | function backfillContactChainIds(
FILE: apps/mobile/src/store/notificationsSlice.ts
type NotificationsSliceItem (line 4) | interface NotificationsSliceItem {
FILE: apps/mobile/src/store/pendingTxsSlice.ts
type PendingStatus (line 5) | enum PendingStatus {
type PendingSingleTxBase (line 12) | type PendingSingleTxBase = {
type PendingSingleTx (line 21) | type PendingSingleTx =
type PendingRelayTxBase (line 30) | type PendingRelayTxBase = {
type PendingRelayTx (line 38) | type PendingRelayTx =
type PendingTx (line 47) | type PendingTx = PendingSingleTx | PendingRelayTx
type PendingTxsState (line 49) | type PendingTxsState = Record<string, PendingTx>
FILE: apps/mobile/src/store/resetE2EState.test.ts
constant SAFE_ADDRESS (line 16) | const SAFE_ADDRESS = faker.finance.ethereumAddress() as Address
constant SIGNER_ADDRESS (line 17) | const SIGNER_ADDRESS = faker.finance.ethereumAddress() as Address
FILE: apps/mobile/src/store/safeSubscriptionsSlice.ts
type SafeAddress (line 4) | type SafeAddress = string
type ChainId (line 5) | type ChainId = string
type SafeSubscriptionsState (line 7) | type SafeSubscriptionsState = Record<SafeAddress, Record<ChainId, boolean>>
FILE: apps/mobile/src/store/safesSettingsSlice.ts
type GlobalSafeSettings (line 7) | interface GlobalSafeSettings {
type PerChainSafeSettings (line 15) | interface PerChainSafeSettings {
type SafeSettingsData (line 20) | interface SafeSettingsData {
type SafesSettingsState (line 25) | type SafesSettingsState = Record<string, SafeSettingsData>
FILE: apps/mobile/src/store/safesSlice.ts
type SafesSliceItem (line 7) | type SafesSliceItem = Record<string, SafeOverview>
type SafesSlice (line 8) | type SafesSlice = Record<Address, SafesSliceItem>
FILE: apps/mobile/src/store/settingsSlice.ts
type TOKEN_LISTS (line 9) | enum TOKEN_LISTS {
type SettingsState (line 14) | interface SettingsState {
method updateSettings (line 48) | updateSettings(state, action: PayloadAction<Partial<SettingsState>>) {
method resetSettings (line 51) | resetSettings() {
FILE: apps/mobile/src/store/signerImportFlowSlice.ts
type PendingSafe (line 4) | interface PendingSafe {
type SignerImportFlowState (line 9) | interface SignerImportFlowState {
FILE: apps/mobile/src/store/signersBalance.ts
method queryFn (line 16) | async queryFn({ addresses, chain }) {
FILE: apps/mobile/src/store/signersSlice.ts
type Signer (line 7) | type Signer = AddressInfo &
FILE: apps/mobile/src/store/signingStateSlice.test.ts
type SigningStateSlice (line 10) | type SigningStateSlice = ReturnType<typeof signingStateReducer>
FILE: apps/mobile/src/store/signingStateSlice.ts
type SigningState (line 4) | interface SigningState {
type SigningStateSlice (line 11) | interface SigningStateSlice {
FILE: apps/mobile/src/store/storage.ts
class safeMMKVStorage (line 25) | class safeMMKVStorage {
method getLocal (line 26) | static getLocal(key: STORAGE_IDS) {
method saveLocal (line 47) | static saveLocal(key: string, value: string | number | boolean | Array...
method clearAllStorages (line 60) | static clearAllStorages() {
FILE: apps/mobile/src/store/utils/cookieHandling.ts
function isAuthVerifyEndpoint (line 9) | function isAuthVerifyEndpoint(url: string): boolean {
FILE: apps/mobile/src/store/utils/singletonStore.ts
type StoreLike (line 3) | type StoreLike = { dispatch: AppDispatch; getState: () => RootState }
FILE: apps/mobile/src/store/utils/strategy/Strategy.ts
type ActionWithPayload (line 4) | interface ActionWithPayload extends Action<string> {
type Strategy (line 8) | interface Strategy<TState, TStore extends MiddlewareAPI<Dispatch, TState...
FILE: apps/mobile/src/store/utils/strategy/StrategyManager.ts
class StrategyManager (line 5) | class StrategyManager<TState, TStore extends MiddlewareAPI<Dispatch, TSt...
method constructor (line 8) | constructor() {
method registerStrategy (line 12) | protected registerStrategy(actionType: string, strategy: Strategy<TSta...
method executeStrategy (line 16) | public executeStrategy(store: TStore, action: AnyAction, prevState: TS...
FILE: apps/mobile/src/tests/e2e-maestro/components/TestCtrls.e2e.tsx
constant BTN (line 39) | const BTN = { height: 1, width: 1, backgroundColor: 'red' }
function ClipboardVerificationTrigger (line 41) | function ClipboardVerificationTrigger({ onPress }: { onPress: () => void...
function ClipboardVerificationContainer (line 52) | function ClipboardVerificationContainer({
function TestCtrls (line 92) | function TestCtrls() {
FILE: apps/mobile/src/tests/e2e-maestro/components/TestCtrls.tsx
function TestCtrls (line 1) | function TestCtrls() {
FILE: apps/mobile/src/tests/e2e-maestro/setup/connectSignerSetup.ts
constant OWNER_ADDRESS (line 24) | const OWNER_ADDRESS = mockedActiveSafeInfo.owners[0].value
constant NON_OWNER_ADDRESS (line 27) | const NON_OWNER_ADDRESS = '0x000000000000000000000000000000000000dEaD'
constant WALLET_NAME (line 29) | const WALLET_NAME = 'E2E Wallet'
constant WALLET_ICON (line 31) | const WALLET_ICON =
FILE: apps/mobile/src/tests/factories/transaction.ts
function generateTransactionSignature (line 7) | function generateTransactionSignature(): string {
function generateSafeTxHash (line 15) | function generateSafeTxHash(): string {
function generateAddress (line 23) | function generateAddress(): string {
function generateTxId (line 30) | function generateTxId(): string {
function generateMockTransaction (line 37) | function generateMockTransaction() {
function generateMockSigner (line 58) | function generateMockSigner(type: 'seed' | 'private_key' | 'ledger' = 's...
FILE: apps/mobile/src/tests/mocks.ts
type mockTransferWithInfoArgs (line 169) | interface mockTransferWithInfoArgs {
FILE: apps/mobile/src/tests/test-utils.tsx
type TestStore (line 14) | type TestStore = EnhancedStore<RootState> & {
type TestStoreState (line 17) | type TestStoreState = Partial<Omit<RootState, 'settings'>> & {
type getProvidersArgs (line 20) | type getProvidersArgs = (initialStoreState?: TestStoreState) => React.FC...
function WrapperWithCustom (line 86) | function WrapperWithCustom({ children }: { children: React.ReactNode }) {
function customRenderHook (line 93) | function customRenderHook<Result, Props>(render: (initialProps: Props) =...
function renderHookWithStore (line 120) | function renderHookWithStore<Result, Props>(
function renderWithStore (line 143) | function renderWithStore(
FILE: apps/mobile/src/theme/SafeStatusBar.tsx
constant DARK_SCREENS (line 5) | const DARK_SCREENS = [
FILE: apps/mobile/src/theme/provider/font.tsx
type SafeThemeProviderProps (line 12) | interface SafeThemeProviderProps {
FILE: apps/mobile/src/theme/provider/safeTheme.tsx
type SafeThemeProviderProps (line 13) | interface SafeThemeProviderProps {
FILE: apps/mobile/src/theme/provider/storybookTheme.tsx
type StorybookThemeProviderProps (line 9) | interface StorybookThemeProviderProps {
FILE: apps/mobile/src/theme/provider/toastProvider.tsx
type SafeThemeProviderProps (line 6) | interface SafeThemeProviderProps {
FILE: apps/mobile/src/theme/tamagui.config.ts
type Conf (line 194) | type Conf = typeof config
type TamaguiCustomConfig (line 197) | interface TamaguiCustomConfig extends Conf {
FILE: apps/mobile/src/types/address.ts
type SafeInfo (line 3) | interface SafeInfo {
type SignerInfo (line 8) | type SignerInfo = Signer
type Address (line 10) | type Address = `0x${string}`
FILE: apps/mobile/src/types/iconTypes.ts
type IconName (line 1) | type IconName =
FILE: apps/mobile/src/types/theme.ts
type ThemePreference (line 1) | type ThemePreference = 'light' | 'dark' | 'auto'
type ColorScheme (line 3) | type ColorScheme = 'light' | 'dark'
FILE: apps/mobile/src/types/txType.ts
type ETxType (line 1) | enum ETxType {
FILE: apps/mobile/src/utils/date.test.ts
constant MOCKED_TIMESTAMP (line 4) | const MOCKED_TIMESTAMP = 1729506116962
FILE: apps/mobile/src/utils/date.ts
function getCountdown (line 13) | function getCountdown(seconds: number): { days: number; hours: number; m...
function getPeriod (line 27) | function getPeriod(seconds: number): string | undefined {
FILE: apps/mobile/src/utils/errors/standardErrors.ts
type ErrorType (line 1) | enum ErrorType {
type StandardErrorResult (line 11) | interface StandardErrorResult<T = unknown> {
function createStandardError (line 23) | function createStandardError(
function standardizeError (line 38) | function standardizeError(
function createSuccessResult (line 52) | function createSuccessResult<T>(data?: T): StandardErrorResult<T> {
function createErrorResult (line 56) | function createErrorResult<T>(
FILE: apps/mobile/src/utils/formatters.ts
type Quantity (line 4) | type Quantity = {
function asDecimal (line 9) | function asDecimal(amount: number | bigint, decimals: number): number {
type CurrencyParts (line 82) | interface CurrencyParts {
FILE: apps/mobile/src/utils/inputDetection.ts
type InputType (line 3) | type InputType = 'private-key' | 'seed-phrase' | 'unknown'
FILE: apps/mobile/src/utils/legacyData.ts
type SecuredDataFile (line 3) | type SecuredDataFile = {
type SerializedDataFile (line 11) | type SerializedDataFile = {
class LegacyDataPasswordError (line 17) | class LegacyDataPasswordError extends Error {
method constructor (line 18) | constructor() {
class LegacyDataFormatError (line 24) | class LegacyDataFormatError extends Error {
method constructor (line 25) | constructor() {
class LegacyDataCorruptedError (line 31) | class LegacyDataCorruptedError extends Error {
method constructor (line 32) | constructor() {
function decodeLegacyData (line 38) | function decodeLegacyData(file: SecuredDataFile, password: string): Seri...
FILE: apps/mobile/src/utils/logger.ts
type LogLevel (line 3) | enum LogLevel {
class Logger (line 27) | class Logger {
FILE: apps/mobile/src/utils/notifications/cleanup.ts
type NotificationCleanupError (line 6) | interface NotificationCleanupError {
type SafeNotificationInfo (line 12) | interface SafeNotificationInfo {
FILE: apps/mobile/src/utils/notifications/index.ts
type ChannelId (line 5) | enum ChannelId {
type SafeAndroidChannel (line 10) | interface SafeAndroidChannel extends AndroidChannel {
function withTimeout (line 39) | function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {
function getSigner (line 44) | function getSigner(signerPK: string): Wallet | HDNodeWallet {
constant REGULAR_NOTIFICATIONS (line 50) | const REGULAR_NOTIFICATIONS: NotificationTypeEnum[] = [
constant OWNER_NOTIFICATIONS (line 57) | const OWNER_NOTIFICATIONS: NotificationTypeEnum[] = [
FILE: apps/mobile/src/utils/retry.ts
type RetryOptions (line 3) | interface RetryOptions {
function isRateLimitError (line 51) | function isRateLimitError(error: unknown): boolean {
function isRetryableError (line 66) | function isRetryableError(error: unknown): boolean {
function calculateDelay (line 70) | function calculateDelay(attempt: number, baseDelay: number, enableJitter...
FILE: apps/mobile/src/utils/swapOrderUtils.test.tsx
type LabelValueItem (line 23) | type LabelValueItem = {
FILE: apps/mobile/src/utils/transaction-guards.ts
type TransactionInfo (line 46) | type TransactionInfo = Transaction['txInfo']
type SettingsChangeSwapOwner (line 47) | type SettingsChangeSwapOwner = SettingsChangeTransaction & { settingsInf...
FILE: apps/mobile/src/utils/transactions.tsx
type GroupedTxs (line 91) | type GroupedTxs<T> = (T | T[])[]
FILE: apps/mobile/src/utils/url.ts
function isIpOrLocalhostUrl (line 6) | function isIpOrLocalhostUrl(urlString: string): boolean {
function isHttpsUrl (line 31) | function isHttpsUrl(urlString: string): boolean {
FILE: apps/tx-builder/src/components/Accordion/index.tsx
type AccordionProps (line 7) | type AccordionProps = AccordionMUIProps & {
type StyledAccordionProps (line 11) | type StyledAccordionProps = AccordionMUIProps & {
FILE: apps/tx-builder/src/components/Button.tsx
type Colors (line 8) | type Colors = 'primary' | 'secondary' | 'error'
type Variations (line 9) | type Variations = 'bordered' | 'contained' | 'outlined'
type CustomButtonMuiProps (line 11) | type CustomButtonMuiProps = Omit<ButtonMUIProps, 'size' | 'color' | 'var...
type LocalProps (line 15) | type LocalProps = {
type Props (line 23) | type Props = LocalProps & CustomButtonMuiProps & HTMLAttributes<HTMLButt...
FILE: apps/tx-builder/src/components/Card/index.tsx
type Props (line 24) | type Props = {
FILE: apps/tx-builder/src/components/CreateNewBatchCard.tsx
type CreateNewBatchCardProps (line 17) | type CreateNewBatchCardProps = {
FILE: apps/tx-builder/src/components/Divider.tsx
type Props (line 4) | type Props = {
FILE: apps/tx-builder/src/components/Dot/index.tsx
type Props (line 5) | type Props = {
FILE: apps/tx-builder/src/components/ETHHashInfo.tsx
type ExplorerInfo (line 12) | type ExplorerInfo = () => { url: string; alt: string }
type SizeType (line 14) | type SizeType = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
type EllipsisMenuItem (line 16) | interface EllipsisMenuItem {
type Props (line 50) | type Props = {
type ShortNameProps (line 68) | type ShortNameProps =
type EthHashInfoProps (line 85) | type EthHashInfoProps = Props & ShortNameProps
FILE: apps/tx-builder/src/components/EditableLabel.tsx
type EditableLabelProps (line 3) | type EditableLabelProps = {
FILE: apps/tx-builder/src/components/EllipsisMenu/index.tsx
type EllipsisMenuItem (line 52) | type EllipsisMenuItem = {
type Props (line 58) | type Props = {
FILE: apps/tx-builder/src/components/FixedIcon/index.tsx
type IconType (line 59) | type IconType = typeof icons
type IconTypes (line 60) | type IconTypes = keyof IconType
type Props (line 62) | type Props = {
function FixedIcon (line 70) | function FixedIcon({ type, className }: Props): React.ReactElement {
FILE: apps/tx-builder/src/components/GenericModal.tsx
type GenericModalProps (line 56) | type GenericModalProps = {
FILE: apps/tx-builder/src/components/Header.tsx
constant HELP_ARTICLE_LINK (line 20) | const HELP_ARTICLE_LINK = 'https://help.safe.global/articles/4180673514-...
type LocationType (line 29) | type LocationType = {
FILE: apps/tx-builder/src/components/Icon/index.tsx
type IconType (line 49) | type IconType = typeof icons
type IconTypes (line 50) | type IconTypes = keyof IconType
type IconProps (line 52) | type IconProps = {
FILE: apps/tx-builder/src/components/IconText/index.tsx
type IconMargins (line 18) | type IconMargins = keyof typeof iconTextMargins
type Props (line 20) | type Props = {
FILE: apps/tx-builder/src/components/Link/index.tsx
type Props (line 5) | interface Props extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
FILE: apps/tx-builder/src/components/Loader/index.tsx
type Props (line 14) | type Props = {
FILE: apps/tx-builder/src/components/QuickTip.tsx
type QuickTipProps (line 6) | type QuickTipProps = {
FILE: apps/tx-builder/src/components/ShowMoreText.tsx
type ShowMoreTextProps (line 4) | type ShowMoreTextProps = {
constant SHOW_MORE (line 11) | const SHOW_MORE = 'Show more'
constant SHOW_LESS (line 12) | const SHOW_LESS = 'Show less'
FILE: apps/tx-builder/src/components/Switch.tsx
type Props (line 34) | type Props = {
FILE: apps/tx-builder/src/components/Text.tsx
type Props (line 6) | type Props = {
FILE: apps/tx-builder/src/components/Title.tsx
type SizeType (line 4) | type SizeType = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
type Props (line 6) | type Props = {
FILE: apps/tx-builder/src/components/Tooltip.tsx
type SizeType (line 6) | type SizeType = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
type TooltipProps (line 8) | type TooltipProps = {
type StyledTooltipProps (line 54) | interface StyledTooltipProps {
type Props (line 89) | type Props = {
FILE: apps/tx-builder/src/components/TransactionBatchListItem.tsx
constant UNKNOWN_POSITION_LABEL (line 17) | const UNKNOWN_POSITION_LABEL = '?'
type TransactionProps (line 20) | type TransactionProps = {
FILE: apps/tx-builder/src/components/TransactionDetails.tsx
type TransactionDetailsProp (line 12) | type TransactionDetailsProp = {
constant LINE_HEIGHT (line 117) | const LINE_HEIGHT = 22
constant MAX_HEIGHT (line 118) | const MAX_HEIGHT = 2 * LINE_HEIGHT // 2 lines as max height
FILE: apps/tx-builder/src/components/TransactionsBatchList.tsx
type TransactionsBatchListProps (line 33) | type TransactionsBatchListProps = {
constant TRANSACTION_LIST_DROPPABLE_ID (line 50) | const TRANSACTION_LIST_DROPPABLE_ID = 'Transaction_List'
constant DROP_EVENT (line 51) | const DROP_EVENT = 'DROP'
FILE: apps/tx-builder/src/components/VirtualizedList.tsx
type VirtualizedListProps (line 5) | type VirtualizedListProps<T> = {
type HeightPreservingItemProps (line 33) | interface HeightPreservingItemProps {
FILE: apps/tx-builder/src/components/Wrapper/index.tsx
function Wrapper (line 4) | function Wrapper({ children, centered }: { children: React.ReactNode; ce...
FILE: apps/tx-builder/src/components/buttons/ButtonLink/index.tsx
type Props (line 8) | interface Props extends React.ComponentPropsWithoutRef<'button'> {
FILE: apps/tx-builder/src/components/buttons/CopyToClipboardBtn/index.tsx
type Props (line 27) | type Props = {
FILE: apps/tx-builder/src/components/buttons/ExplorerButton/index.tsx
type Props (line 26) | type Props = {
FILE: apps/tx-builder/src/components/buttons/Identicon/index.tsx
type Props (line 15) | type Props = {
FILE: apps/tx-builder/src/components/forms/AddNewTransactionForm.tsx
type AddNewTransactionFormProps (line 16) | type AddNewTransactionFormProps = {
FILE: apps/tx-builder/src/components/forms/SolidityForm.tsx
constant TO_ADDRESS_FIELD_NAME (line 18) | const TO_ADDRESS_FIELD_NAME = 'toAddress'
constant NATIVE_VALUE_FIELD_NAME (line 19) | const NATIVE_VALUE_FIELD_NAME = 'nativeAmount'
constant CONTRACT_METHOD_INDEX_FIELD_NAME (line 20) | const CONTRACT_METHOD_INDEX_FIELD_NAME = 'contractMethodIndex'
constant CONTRACT_VALUES_FIELD_NAME (line 21) | const CONTRACT_VALUES_FIELD_NAME = 'contractFieldsValues'
constant CUSTOM_TRANSACTION_DATA_FIELD_NAME (line 22) | const CUSTOM_TRANSACTION_DATA_FIELD_NAME = 'customTransactionData'
type SolidityFormPropsTypes (line 24) | type SolidityFormPropsTypes = {
type SolidityInitialFormValuesTypes (line 37) | type SolidityInitialFormValuesTypes = {
type SolidityFormValuesTypes (line 42) | type SolidityFormValuesTypes = {
FILE: apps/tx-builder/src/components/forms/fields/AddressContractField.tsx
type AddressContractFieldProps (line 4) | interface AddressContractFieldProps {
FILE: apps/tx-builder/src/components/forms/fields/AddressInput.tsx
type AddressInputProps (line 17) | type AddressInputProps = {
function AddressInput (line 30) | function AddressInput({
function LoaderSpinnerAdornment (line 171) | function LoaderSpinnerAdornment() {
function checksumValidAddress (line 180) | function checksumValidAddress(address: string) {
function addPrefix (line 189) | function addPrefix(address: string, networkPrefix: string | undefined, s...
FILE: apps/tx-builder/src/components/forms/fields/Field.tsx
type SelectItem (line 3) | interface SelectItem {
constant CUSTOM_DEFAULT_VALUES (line 23) | const CUSTOM_DEFAULT_VALUES: CustomDefaultValueTypes = {
constant BOOLEAN_DEFAULT_OPTIONS (line 28) | const BOOLEAN_DEFAULT_OPTIONS: SelectItem[] = [
constant DEFAULT_OPTIONS (line 33) | const DEFAULT_OPTIONS: DefaultOptionTypes = {
type CustomDefaultValueTypes (line 37) | interface CustomDefaultValueTypes {
type DefaultOptionTypes (line 41) | interface DefaultOptionTypes {
type FieldProps (line 45) | type FieldProps<T extends FieldValues = FieldValues> = {
type FieldComponentBaseProps (line 104) | interface FieldComponentBaseProps {
FILE: apps/tx-builder/src/components/forms/fields/JsonField.tsx
constant DEFAULT_ROWS (line 11) | const DEFAULT_ROWS = 4
type Props (line 13) | type Props = {
FILE: apps/tx-builder/src/components/forms/fields/SelectContractField.tsx
type SelectItem (line 5) | interface SelectItem {
type SelectContractFieldTypes (line 12) | type SelectContractFieldTypes = {
FILE: apps/tx-builder/src/components/forms/fields/TextContractField.tsx
type TextContractFieldTypes (line 4) | type TextContractFieldTypes = TextFieldInputProps & {
FILE: apps/tx-builder/src/components/forms/fields/TextFieldInput.tsx
type TextFieldInputProps (line 6) | type TextFieldInputProps = {
function TextFieldInput (line 16) | function TextFieldInput({
FILE: apps/tx-builder/src/components/forms/fields/TextareaContractField.tsx
constant DEFAULT_ROWS (line 4) | const DEFAULT_ROWS = 4
FILE: apps/tx-builder/src/components/forms/fields/fields.ts
constant BASIC_INT_FIELD_TYPE (line 9) | const BASIC_INT_FIELD_TYPE = 'int' // equivalent to int256
constant BASIC_UINT_FIELD_TYPE (line 10) | const BASIC_UINT_FIELD_TYPE = 'uint' // equivalent to uint256
constant ADDRESS_FIELD_TYPE (line 12) | const ADDRESS_FIELD_TYPE = 'address' // equivalent to uint160
constant BOOLEAN_FIELD_TYPE (line 14) | const BOOLEAN_FIELD_TYPE = 'bool' // equivalent to uint8 restricted to t...
constant STRING_FIELD_TYPE (line 21) | const STRING_FIELD_TYPE = 'string' // dynamic sized unicode string assum...
constant FUNCTION_FIELD_TYPE (line 23) | const FUNCTION_FIELD_TYPE = 'function'
constant NATIVE_AMOUNT_FIELD_TYPE (line 104) | const NATIVE_AMOUNT_FIELD_TYPE = 'nativeAmount'
constant CONTRACT_METHOD_FIELD_TYPE (line 107) | const CONTRACT_METHOD_FIELD_TYPE = 'contractMethod'
constant CUSTOM_TRANSACTION_DATA_FIELD_TYPE (line 110) | const CUSTOM_TRANSACTION_DATA_FIELD_TYPE = 'customTransactionData'
constant TEXT_FIELD_TYPE (line 113) | const TEXT_FIELD_TYPE = 'text'
constant NON_SOLIDITY_TYPES (line 115) | const NON_SOLIDITY_TYPES = [
FILE: apps/tx-builder/src/components/forms/validations/validateAmountField.ts
constant INVALID_AMOUNT_ERROR (line 6) | const INVALID_AMOUNT_ERROR = 'Invalid amount value'
FILE: apps/tx-builder/src/components/forms/validations/validateField.ts
type ValidationFunction (line 16) | type ValidationFunction = (value: string, fieldType: string) => Validate...
FILE: apps/tx-builder/src/components/forms/validations/validations.test.ts
constant NO_ERROR_IS_PRESENT (line 7) | const NO_ERROR_IS_PRESENT = undefined
FILE: apps/tx-builder/src/components/modals/DeleteBatchFromLibrary.tsx
type DeleteBatchFromLibraryProps (line 10) | type DeleteBatchFromLibraryProps = {
FILE: apps/tx-builder/src/components/modals/DeleteBatchModal.tsx
type DeleteBatchModalProps (line 8) | type DeleteBatchModalProps = {
FILE: apps/tx-builder/src/components/modals/DeleteTransactionModal.tsx
type DeleteTransactionModalProps (line 8) | type DeleteTransactionModalProps = {
FILE: apps/tx-builder/src/components/modals/EditTransactionModal.tsx
type EditTransactionModalProps (line 16) | type EditTransactionModalProps = {
FILE: apps/tx-builder/src/components/modals/ImplementationABIDialog.tsx
type Props (line 9) | type Props = {
FILE: apps/tx-builder/src/components/modals/SaveBatchModal.tsx
type SaveBatchModalProps (line 14) | type SaveBatchModalProps = {
constant BATCH_NAME_FIELD (line 18) | const BATCH_NAME_FIELD = 'batchName'
type CreateBatchFormValuesTypes (line 20) | type CreateBatchFormValuesTypes = {
FILE: apps/tx-builder/src/components/modals/SuccessBatchCreationModal.tsx
type SuccessBatchCreationModalProps (line 11) | type SuccessBatchCreationModalProps = {
FILE: apps/tx-builder/src/components/modals/WrongChainBatchModal.tsx
type WrongChainBatchModalProps (line 8) | type WrongChainBatchModalProps = {
FILE: apps/tx-builder/src/hooks/useAsync.ts
type AsyncResult (line 3) | type AsyncResult<T> = [result: T | undefined, error: Error | undefined, ...
FILE: apps/tx-builder/src/hooks/useDropZone/index.tsx
type DropHandlers (line 3) | interface DropHandlers {
method onDragOver (line 24) | onDragOver(event) {
method onDragEnter (line 27) | onDragEnter(event) {
method onDragLeave (line 32) | onDragLeave(event) {
method onDrop (line 39) | onDrop(event) {
FILE: apps/tx-builder/src/hooks/useElementHeight/useElementHeight.tsx
type useElementHeightTypes (line 3) | type useElementHeightTypes<T extends HTMLElement> = {
FILE: apps/tx-builder/src/hooks/useSimulation.ts
type UseSimulationReturn (line 14) | type UseSimulationReturn =
FILE: apps/tx-builder/src/hooks/useThrottle.ts
constant DEFAULT_DELAY (line 3) | const DEFAULT_DELAY = 650
type ThrottleType (line 5) | type ThrottleType = (callback: () => void, delay?: number) => void
FILE: apps/tx-builder/src/lib/analytics.ts
constant SAFE_APPS_ANALYTICS_CATEGORY (line 1) | const SAFE_APPS_ANALYTICS_CATEGORY = 'safe-apps-analytics'
FILE: apps/tx-builder/src/lib/checksum.ts
type JSONValue (line 4) | type JSONValue = string | number | boolean | null | JSONValue[] | { [key...
FILE: apps/tx-builder/src/lib/getAbi.ts
type PROVIDER (line 5) | enum PROVIDER {
type SourcifyV2Response (line 10) | type SourcifyV2Response = {
type GatewayContractResponse (line 21) | interface GatewayContractResponse {
constant DEFAULT_TIMEOUT (line 27) | const DEFAULT_TIMEOUT = 10000
FILE: apps/tx-builder/src/lib/interfaceRepository.ts
type AbiItem (line 5) | interface AbiItem {
class InterfaceRepository (line 15) | class InterfaceRepository {
method constructor (line 18) | constructor(chainInfo: ChainInfo) {
method loadAbi (line 24) | async loadAbi(address: string): Promise<string | null> {
method abiExists (line 30) | async abiExists(address: string): Promise<boolean> {
method getMethods (line 36) | getMethods(abi: string): ContractInterface {
type InterfaceRepo (line 86) | type InterfaceRepo = InstanceType<typeof InterfaceRepository>
FILE: apps/tx-builder/src/lib/local-storage/Storage.ts
constant LS_NAMESPACE (line 1) | const LS_NAMESPACE = 'TX_BUILDER__'
type BrowserStorage (line 3) | type BrowserStorage = typeof localStorage | typeof sessionStorage
type ItemWithExpiry (line 5) | type ItemWithExpiry<T> = {
class Storage (line 10) | class Storage {
method constructor (line 14) | constructor(storage?: BrowserStorage, prefix = LS_NAMESPACE) {
FILE: apps/tx-builder/src/lib/simulation/multisend.ts
constant MULTI_SEND_ABI (line 7) | const MULTI_SEND_ABI = [
FILE: apps/tx-builder/src/lib/simulation/simulation.ts
type OptionalExceptFor (line 9) | type OptionalExceptFor<T, TRequired extends keyof T = keyof T> = Partial...
constant TENDERLY_SIMULATE_ENDPOINT_URL (line 13) | const TENDERLY_SIMULATE_ENDPOINT_URL = import.meta.env.VITE_TENDERLY_SIM...
constant TENDERLY_PROJECT_NAME (line 14) | const TENDERLY_PROJECT_NAME = import.meta.env.VITE_TENDERLY_PROJECT_NAME...
constant TENDERLY_ORG_NAME (line 15) | const TENDERLY_ORG_NAME = import.meta.env.VITE_TENDERLY_ORG_NAME || ''
constant THRESHOLD_ONE_STORAGE_OVERRIDE (line 37) | const THRESHOLD_ONE_STORAGE_OVERRIDE = {
type SafeTransaction (line 54) | interface SafeTransaction {
type SignedSafeTransaction (line 67) | interface SignedSafeTransaction extends SafeTransaction {
constant ZERO_ADDRESS (line 71) | const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
constant EXEC_TRANSACTION_ABI (line 73) | const EXEC_TRANSACTION_ABI = [
type SimulationTxParams (line 133) | type SimulationTxParams = {
FILE: apps/tx-builder/src/lib/simulation/types.ts
type StateObject (line 4) | type StateObject = {
type ContractObject (line 10) | type ContractObject = {
type TenderlySimulatePayload (line 29) | type TenderlySimulatePayload = {
type TenderlySimulation (line 55) | interface TenderlySimulation {
type TenderlyContract (line 62) | interface TenderlyContract {
FILE: apps/tx-builder/src/routes/routes.ts
constant HOME_PATH (line 1) | const HOME_PATH = '/'
constant CREATE_BATCH_PATH (line 3) | const CREATE_BATCH_PATH = HOME_PATH
constant BATCH_PATH (line 4) | const BATCH_PATH = '/batch'
constant SAVE_BATCH_PATH (line 5) | const SAVE_BATCH_PATH = BATCH_PATH
constant EDIT_BATCH_PATH (line 6) | const EDIT_BATCH_PATH = `${BATCH_PATH}/:batchId`
constant REVIEW_AND_CONFIRM_PATH (line 8) | const REVIEW_AND_CONFIRM_PATH = '/review-and-confirm'
constant TRANSACTION_LIBRARY_PATH (line 10) | const TRANSACTION_LIBRARY_PATH = '/transaction-library'
FILE: apps/tx-builder/src/store/networkContext.tsx
type NetworkContextProps (line 8) | type NetworkContextProps = {
FILE: apps/tx-builder/src/store/transactionLibraryContext.tsx
type TransactionLibraryContextProps (line 12) | type TransactionLibraryContextProps = {
FILE: apps/tx-builder/src/store/transactionsContext.tsx
type TransactionContextProps (line 6) | type TransactionContextProps = {
FILE: apps/tx-builder/src/theme/SafeThemeProvider.tsx
type EModes (line 7) | enum EModes {
type SafeThemeProviderProps (line 12) | type SafeThemeProviderProps = {
FILE: apps/tx-builder/src/theme/safeTheme.ts
type Palette (line 14) | interface Palette {
type PaletteOptions (line 21) | interface PaletteOptions {
type TypeBackground (line 28) | interface TypeBackground {
type PaletteColor (line 34) | interface PaletteColor {
type SimplePaletteColorOptions (line 38) | interface SimplePaletteColorOptions {
type SvgIconPropsColorOverrides (line 44) | interface SvgIconPropsColorOverrides {
type ButtonPropsSizeOverrides (line 50) | interface ButtonPropsSizeOverrides {
type ButtonPropsColorOverrides (line 54) | interface ButtonPropsColorOverrides {
type ButtonPropsVariantOverrides (line 58) | interface ButtonPropsVariantOverrides {
type IconButtonPropsColorOverrides (line 64) | interface IconButtonPropsColorOverrides {
FILE: apps/tx-builder/src/typings/custom.d.ts
type MediaProps (line 21) | interface MediaProps {
type EllipsisMenuItem (line 31) | interface EllipsisMenuItem {
type SelectItem (line 39) | interface SelectItem {
type BreakpointDefaults (line 49) | interface BreakpointDefaults {
FILE: apps/tx-builder/src/typings/errors.ts
type EthersError (line 4) | interface EthersError extends Error {
FILE: apps/tx-builder/src/typings/models.ts
type ProposedTransaction (line 1) | interface ProposedTransaction {
type ContractInterface (line 17) | interface ContractInterface {
type Batch (line 21) | interface Batch {
type BatchFile (line 27) | interface BatchFile {
type BatchFileMeta (line 35) | interface BatchFileMeta {
type BatchTransaction (line 44) | interface BatchTransaction {
type ContractMethod (line 52) | interface ContractMethod {
type ContractInput (line 58) | interface ContractInput {
FILE: apps/tx-builder/src/utils.ts
type FETCH_STATUS (line 15) | const enum FETCH_STATUS {
class SoliditySyntaxError (line 21) | class SoliditySyntaxError extends Error {}
constant NON_VALID_CONTRACT_METHODS (line 212) | const NON_VALID_CONTRACT_METHODS = ['receive', 'fallback']
FILE: apps/tx-builder/src/vite-env.d.ts
type ImportMetaEnv (line 3) | interface ImportMetaEnv {
type ImportMeta (line 11) | interface ImportMeta {
FILE: apps/tx-builder/vite.config.ts
method manualChunks (line 24) | manualChunks(id) {
FILE: apps/web/.storybook-vite/main.ts
constant STATIC_IMAGE_EXTENSIONS (line 19) | const STATIC_IMAGE_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.gif', '.webp...
function publicAssetsPlugin (line 25) | function publicAssetsPlugin(): Plugin {
FILE: apps/web/.storybook-vite/preview.tsx
constant BACKGROUND_COLORS (line 26) | const BACKGROUND_COLORS: Record<string, string> = { light: '#ffffff', da...
constant SAFE_VIEWPORTS (line 52) | const SAFE_VIEWPORTS = {
FILE: apps/web/.storybook/decorators/LayoutDecorator.tsx
constant SIDEBAR_WIDTH (line 10) | const SIDEBAR_WIDTH = 230
type LayoutDecoratorProps (line 12) | type LayoutDecoratorProps = {
FILE: apps/web/.storybook/decorators/MockProviderDecorator.tsx
type MockProviderDecoratorProps (line 7) | type MockProviderDecoratorProps = {
FILE: apps/web/.storybook/mocks/querystring.ts
type ParsedUrlQuery (line 4) | type ParsedUrlQuery = Record<string, string | string[] | undefined>
function parse (line 6) | function parse(str: string): ParsedUrlQuery {
function stringify (line 27) | function stringify(obj: Record<string, unknown>): string {
FILE: apps/web/.storybook/preview.tsx
constant BACKGROUND_COLORS (line 26) | const BACKGROUND_COLORS: Record<string, string> = { light: '#ffffff', da...
constant SAFE_VIEWPORTS (line 52) | const SAFE_VIEWPORTS = {
FILE: apps/web/.storybook/test-runner.mjs
constant FAILURE_THRESHOLD (line 11) | const FAILURE_THRESHOLD = parseFloat(process.env.VISUAL_REGRESSION_THRES...
method setup (line 15) | setup() {
method postVisit (line 20) | async postVisit(page, context) {
FILE: apps/web/cypress.config.js
function setupArgosPlugin (line 7) | function setupArgosPlugin(on, config) {
constant HEADLESS_WIDTH (line 16) | const HEADLESS_WIDTH = 1920 + 16 // +16px to account for the scrollbar g...
constant HEADLESS_HEIGHT (line 17) | const HEADLESS_HEIGHT = 1080
function setupHeadlessViewport (line 19) | function setupHeadlessViewport(on) {
method setupNodeEvents (line 48) | setupNodeEvents(on, config) {
FILE: apps/web/cypress/e2e/happypath/sendfunds_connected_wallet.cy.js
function visit (line 44) | function visit(url) {
function executeTransactionFlow (line 80) | function executeTransactionFlow(fromSafe, toSafe) {
function executeTransactionFlow (line 114) | function executeTransactionFlow(fromSafe, toSafe, tokenAmount) {
function executeTransactionFlow (line 170) | function executeTransactionFlow(fromSafe, toSafe) {
FILE: apps/web/cypress/e2e/happypath/sendfunds_queue_1.cy.js
function visit (line 44) | function visit(url) {
function executeTransactionFlow (line 48) | function executeTransactionFlow(fromSafe) {
function executeTransactionFlow (line 126) | function executeTransactionFlow(fromSafe) {
function executeTransaction (line 165) | function executeTransaction(fromSafe) {
FILE: apps/web/cypress/e2e/happypath/sendfunds_relay.cy.js
function visit (line 44) | function visit(url) {
function executeTransactionFlow (line 80) | function executeTransactionFlow(fromSafe, toSafe) {
function executeTransactionFlow (line 118) | function executeTransactionFlow(fromSafe, toSafe, tokenAmount) {
function executeTransactionFlow (line 179) | function executeTransactionFlow(fromSafe, toSafe) {
FILE: apps/web/cypress/e2e/pages/accounts_modal.pages.js
function openAccountsModal (line 22) | function openAccountsModal() {
function verifyAccountsListVisible (line 30) | function verifyAccountsListVisible() {
function verifyPinnedAccountsSectionVisible (line 34) | function verifyPinnedAccountsSectionVisible() {
function verifyPinnedSafeExists (line 38) | function verifyPinnedSafeExists(address) {
function verifyEmptyPinnedList (line 42) | function verifyEmptyPinnedList() {
function clickAddSafeButton (line 46) | function clickAddSafeButton() {
function clickBookmarkIconByIndex (line 50) | function clickBookmarkIconByIndex(index) {
function unpinSafeByName (line 54) | function unpinSafeByName(name) {
function pinSafeByName (line 58) | function pinSafeByName(name) {
function verifyMissingSignatureInfo (line 62) | function verifyMissingSignatureInfo(threshold, owners) {
function verifyThresholdBadgeOnSafeCard (line 66) | function verifyThresholdBadgeOnSafeCard(name) {
function verifyMissingSignatureInfoExists (line 70) | function verifyMissingSignatureInfoExists() {
function verifyReadOnlyChipVisible (line 74) | function verifyReadOnlyChipVisible() {
function verifyPendingActivationIconVisible (line 78) | function verifyPendingActivationIconVisible() {
function clickSafeOptionsBtn (line 82) | function clickSafeOptionsBtn(index = 0) {
function clickRenameBtn (line 87) | function clickRenameBtn() {
function verifyAccountsListContains (line 91) | function verifyAccountsListContains(name) {
function typeSafeName (line 95) | function typeSafeName(name) {
function clickSaveBtn (line 99) | function clickSaveBtn() {
function renameSafe (line 103) | function renameSafe(oldName, newName) {
function clickOnImportBtn (line 110) | function clickOnImportBtn() {
function verifyImportBtnVisible (line 114) | function verifyImportBtnVisible() {
function verifyFiatBalanceExists (line 118) | function verifyFiatBalanceExists() {
function verifyAddSafeButtonVisible (line 122) | function verifyAddSafeButtonVisible() {
function clickAddSafeButtonAndVerifyLoadFlow (line 126) | function clickAddSafeButtonAndVerifyLoadFlow() {
function searchSafe (line 131) | function searchSafe(query) {
function clearSearchInput (line 135) | function clearSearchInput() {
function verifySearchInputAbovePinnedSection (line 139) | function verifySearchInputAbovePinnedSection() {
function verifyAccountsListDoesNotContain (line 148) | function verifyAccountsListDoesNotContain(text) {
function verifyAccountsListItemCount (line 152) | function verifyAccountsListItemCount(count) {
function verifyPinnedSectionDoesNotExist (line 156) | function verifyPinnedSectionDoesNotExist() {
function verifyPinnedSafeDoesNotExist (line 160) | function verifyPinnedSafeDoesNotExist(address) {
FILE: apps/web/cypress/e2e/pages/address_book.page.js
function clickOnNextPageBtn (line 63) | function clickOnNextPageBtn() {
function clickOnPrevPageBtn (line 67) | function clickOnPrevPageBtn() {
function verifyCountOfSafes (line 71) | function verifyCountOfSafes(count) {
function verifyRecipientData (line 74) | function verifyRecipientData(data) {
function clickOnSendBtn (line 78) | function clickOnSendBtn() {
function clickOnMoreActionsBtn (line 82) | function clickOnMoreActionsBtn() {
function clickOnAddToAddressBookBtn (line 86) | function clickOnAddToAddressBookBtn() {
function verifyExportMessage (line 90) | function verifyExportMessage(count) {
function clickOnNameSortBtn (line 95) | function clickOnNameSortBtn() {
function clickOnAddrressSortBtn (line 100) | function clickOnAddrressSortBtn() {
function verifyEntriesOrder (line 105) | function verifyEntriesOrder(option = 'ascending') {
function addEntryByENS (line 117) | function addEntryByENS(name, ens) {
function verifyModalSummaryMessage (line 124) | function verifyModalSummaryMessage(entryCount, chainCount) {
function verifyUploadExportMessage (line 135) | function verifyUploadExportMessage(msg) {
function verifyImportBtnStatus (line 139) | function verifyImportBtnStatus(status) {
function verifyNumberOfRows (line 143) | function verifyNumberOfRows(number) {
function clickOnImportFileBtn (line 147) | function clickOnImportFileBtn() {
function importCSVFile (line 151) | fu
Copy disabled (too large)
Download .json
Condensed preview — 5930 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (24,761K chars).
[
{
"path": ".claude/commands/speckit.analyze.md",
"chars": 7280,
"preview": "---\ndescription: Perform a non-destructive cross-artifact consistency and quality analysis across spec.md, plan.md, and "
},
{
"path": ".claude/commands/speckit.checklist.md",
"chars": 16721,
"preview": "---\ndescription: Generate a custom checklist for the current feature based on user requirements.\n---\n\n## Checklist Purpo"
},
{
"path": ".claude/commands/speckit.clarify.md",
"chars": 11608,
"preview": "---\ndescription: Identify underspecified areas in the current feature spec by asking up to 5 highly targeted clarificati"
},
{
"path": ".claude/commands/speckit.constitution.md",
"chars": 5232,
"preview": "---\ndescription: Create or update the project constitution from interactive or provided principle inputs, ensuring all d"
},
{
"path": ".claude/commands/speckit.implement.md",
"chars": 7486,
"preview": "---\ndescription: Execute the implementation plan by processing and executing all tasks defined in tasks.md\n---\n\n## User "
},
{
"path": ".claude/commands/speckit.plan.md",
"chars": 3110,
"preview": "---\ndescription: Execute the implementation planning workflow using the plan template to generate design artifacts.\nhand"
},
{
"path": ".claude/commands/speckit.specify.md",
"chars": 12577,
"preview": "---\ndescription: Create or update the feature specification from a natural language feature description.\nhandoffs:\n - l"
},
{
"path": ".claude/commands/speckit.tasks.md",
"chars": 6292,
"preview": "---\ndescription: Generate an actionable, dependency-ordered tasks.md for the feature based on available design artifacts"
},
{
"path": ".claude/commands/speckit.taskstoissues.md",
"chars": 1089,
"preview": "---\ndescription: Convert existing tasks into actionable, dependency-ordered GitHub issues for the feature based on avail"
},
{
"path": ".claude/skills/cypress-e2e/SKILL.md",
"chars": 12338,
"preview": "---\nname: cypress-e2e\ndescription: Write or refactor Cypress E2E tests following Page Object Model, action/assertion sep"
},
{
"path": ".claude/skills/design.figma-to-code/SKILL.md",
"chars": 5565,
"preview": "---\nname: design.figma-to-code\ndescription: Implement a Figma design using shadcn/ui components. Use when converting Fig"
},
{
"path": ".claude/skills/design.figma-to-code/reference.md",
"chars": 5998,
"preview": "# Figma to Code Reference\n\n## Typography (CRITICAL)\n\n**Never hardcode Tailwind classes for text.** Always use the `Typog"
},
{
"path": ".claude/skills/design.prototype/SKILL.md",
"chars": 4548,
"preview": "---\nname: design.prototype\ndescription: Creates a Storybook UI prototype from a PRD-style input using existing shadcn/ui"
},
{
"path": ".claude/skills/design.sync-component/SKILL.md",
"chars": 3615,
"preview": "---\nname: design.sync-component\ndescription: Sync a UI component from Figma to code using the component sync workflow. U"
},
{
"path": ".claude/skills/design.sync-variables/SKILL.md",
"chars": 3402,
"preview": "---\nname: design.sync-variables\ndescription: Sync CSS variables from Figma plugin export to globals.css. Use when updati"
},
{
"path": ".claude/skills/design.verify/SKILL.md",
"chars": 4307,
"preview": "---\nname: design.verify\ndescription: Verify Figma implementation is pixel-perfect. Use after implementing Figma designs "
},
{
"path": ".codescene.yml",
"chars": 410,
"preview": "# CodeScene Configuration\n# https://docs.enterprise.codescene.io/latest/configuration/code-health-configuration.html\n\nve"
},
{
"path": ".cursor/rules/cypress-e2e.mdc",
"chars": 24163,
"preview": "---\ndescription: Cypress E2E test automation rules and best practices for Safe Wallet\nglobs:\n - \"**/cypress/**/*.cy.js\""
},
{
"path": ".cursor/rules/safe-monorepo.mdc",
"chars": 4556,
"preview": "---\ndescription: \nglobs: \nalwaysApply: true\n---\nYou are an expert developer proficient in TypeScript, Web3/Blockchain(et"
},
{
"path": ".editorconfig",
"chars": 659,
"preview": "# EditorConfig is awesome: https://EditorConfig.org\n\n# top-most EditorConfig file\nroot = true\n\n# Unix-style newlines wit"
},
{
"path": ".gitattributes",
"chars": 18,
"preview": "* text=auto eol=lf"
},
{
"path": ".github/ISSUE_TEMPLATE/bug-report.md",
"chars": 359,
"preview": "---\nname: Bug report\nabout: Create an issue to fix a bug\ntype: 'bug'\n---\n\n<!--\nBEFORE SUBMITTING: Please search to make "
},
{
"path": ".github/ISSUE_TEMPLATE/feature-request.md",
"chars": 476,
"preview": "---\nname: Feature request\nabout: Create a feature request for the Safe UI\n---\n\n<!--\n\nNB: this repository is ONLY for the"
},
{
"path": ".github/ISSUE_TEMPLATE/task.md",
"chars": 183,
"preview": "---\nname: Task\nabout: Internal implementation task – only for the Safe team!\ntype: 'task'\n---\n\n## Links\n\nEpic on Notion:"
},
{
"path": ".github/ISSUE_TEMPLATE/tech-debt.md",
"chars": 178,
"preview": "---\nname: Tech debt task\nabout: Internal tech debt task – only for the Safe team!\ntype: 'task'\nlabels: 'tech debt'\n---\n\n"
},
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 1599,
"preview": "## What it solves\n\nResolves:\n\n## How this PR fixes it\n\n## How to test it\n\n## Affected flows\n\n<!-- The primary user journ"
},
{
"path": ".github/actions/branch-slug/action.yml",
"chars": 758,
"preview": "name: 'Branch Slug'\n\ndescription: 'Sanitize branch name into a DNS-safe slug for preview subdomains'\n\ninputs:\n max-leng"
},
{
"path": ".github/actions/build/action.yml",
"chars": 4551,
"preview": "name: 'Build'\n\ndescription: 'Build the app'\n\ninputs:\n secrets:\n required: true\n description: 'GitHub secrets as J"
},
{
"path": ".github/actions/build-storybook/action.yml",
"chars": 260,
"preview": "name: 'Build Storybook'\n\ndescription: 'Build the storybook'\n\ninputs:\n secrets:\n required: true\n\nruns:\n using: 'comp"
},
{
"path": ".github/actions/cache-deps/action.yml",
"chars": 3201,
"preview": "name: 'Cache Yarn Dependencies'\ndescription: 'Restore or save yarn dependencies'\ninputs:\n mode:\n description: 'resto"
},
{
"path": ".github/actions/corepack/action.yml",
"chars": 136,
"preview": "name: 'Enable corepack'\n\nruns:\n using: 'composite'\n steps:\n - name: 'Enable Corepack'\n shell: bash\n run: "
},
{
"path": ".github/actions/cypress/action.yml",
"chars": 2356,
"preview": "name: 'Cypress'\n\ndescription: 'Run Cypress'\n\ninputs:\n secrets:\n description: 'GitHub secrets as JSON'\n required: "
},
{
"path": ".github/actions/upload-coverage/action.yml",
"chars": 979,
"preview": "name: 'Upload Coverage to Datadog'\ndescription: 'Upload LCOV coverage report to Datadog Code Coverage'\n\ninputs:\n api-ke"
},
{
"path": ".github/actions/upload-to-storage-branch/action.yml",
"chars": 5441,
"preview": "name: 'Upload to Storage Branch'\ndescription: 'Uploads files to a separate storage branch (creates orphan branch if need"
},
{
"path": ".github/actions/yarn/action.yml",
"chars": 1887,
"preview": "name: 'Yarn'\n\ndescription: 'Set up Node.js and install dependencies'\n\ninputs:\n after-install:\n description: 'Run web"
},
{
"path": ".github/dependabot.yml",
"chars": 622,
"preview": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where "
},
{
"path": ".github/scripts/capture-mobile-screenshots.js",
"chars": 7693,
"preview": "/**\n * Capture screenshots of Mobile Storybook stories using Playwright\n *\n * This script serves the built Storybook loc"
},
{
"path": ".github/scripts/capture-page-screenshots.js",
"chars": 4928,
"preview": "/**\n * Capture screenshots of web app pages using Playwright\n *\n * This script reads route URLs and captures screenshots"
},
{
"path": ".github/scripts/capture-web-storybook-screenshots.js",
"chars": 3277,
"preview": "/**\n * Capture screenshots of Web Storybook stories using Playwright\n *\n * This script captures screenshots from the dep"
},
{
"path": ".github/scripts/generate-mobile-story-urls.js",
"chars": 3983,
"preview": "/**\n * Generate Storybook URLs from changed mobile story files\n *\n * This script takes changed story files and converts "
},
{
"path": ".github/scripts/generate-web-story-urls.js",
"chars": 4377,
"preview": "/**\n * Generate Storybook URLs from changed web story files\n *\n * This script takes changed story files and converts the"
},
{
"path": ".github/scripts/map-files-to-routes.js",
"chars": 13153,
"preview": "/**\n * Map changed files to affected routes by analyzing import dependencies\n *\n * This script builds a dependency graph"
},
{
"path": ".github/scripts/publish/download-artifact.js",
"chars": 4026,
"preview": "/**\n * Resolve, download, and validate the page-screenshots artifact for the\n * originating workflow_run.\n *\n * Loaded b"
},
{
"path": ".github/scripts/publish/post-comment.js",
"chars": 5224,
"preview": "/**\n * Post, update, or delete the sticky page-screenshots PR comment.\n *\n * Loaded by .github/workflows/page-screenshot"
},
{
"path": ".github/scripts/publish/resolve-pr.js",
"chars": 1835,
"preview": "/**\n * Resolve the open PR for a given head SHA, with same-repo + state filtering,\n * and report whether the PR's curren"
},
{
"path": ".github/workflows/claude-code-review.yml",
"chars": 3642,
"preview": "name: Claude Code Review\n\non:\n # Disabled automatic PR review - now only runs on manual trigger or when @claude is ment"
},
{
"path": ".github/workflows/mobile-checks.yml",
"chars": 1507,
"preview": "name: Mobile Checks\n\non:\n pull_request:\n paths:\n - apps/mobile/**\n - packages/**\n push:\n branches:\n "
},
{
"path": ".github/workflows/mobile-dev-release.yml",
"chars": 1455,
"preview": "name: EAS Dev Build\n\non:\n push:\n branches:\n - dev\n paths:\n - apps/mobile/**\n - packages/**\n -"
},
{
"path": ".github/workflows/mobile-e2e.yml",
"chars": 1094,
"preview": "name: EAS Mobile E2E tests\n\non:\n workflow_dispatch:\n schedule:\n - cron: '0 6 * * *'\n pull_request:\n paths:\n "
},
{
"path": ".github/workflows/mobile-storybook-screenshots.yml",
"chars": 11364,
"preview": "name: Mobile Storybook Screenshots\n\non:\n pull_request:\n paths:\n - 'apps/mobile/src/**/*.tsx'\n - 'apps/mobi"
},
{
"path": ".github/workflows/mobile-unit-tests.yml",
"chars": 1562,
"preview": "name: Mobile Tests and Coverage\n\non:\n push:\n branches:\n - main\n paths:\n - apps/mobile/**\n - packag"
},
{
"path": ".github/workflows/package-utils-unit-tests.yml",
"chars": 1571,
"preview": "name: Package @safe-global/utils unit tests\non:\n pull_request:\n paths:\n - packages/utils/**\n - packages/st"
},
{
"path": ".github/workflows/page-screenshots-build.yml",
"chars": 4739,
"preview": "# Build half of a two-workflow pair. Keep the following invariants:\n# workflow-level `permissions: {}`, no `secrets.*` r"
},
{
"path": ".github/workflows/page-screenshots-publish.yml",
"chars": 3597,
"preview": "# Publish half of a two-workflow pair. This workflow has write tokens and\n# secrets available, so it must only check out"
},
{
"path": ".github/workflows/store-codegen-check.yml",
"chars": 2245,
"preview": "name: Store Codegen Check\n\non:\n pull_request:\n paths:\n - packages/store/src/gateway/AUTO_GENERATED/**\n - p"
},
{
"path": ".github/workflows/store-codegen-drift.yml",
"chars": 4156,
"preview": "name: Store Codegen Drift\n\non:\n schedule:\n - cron: '0 6 * * *'\n workflow_dispatch:\n\nconcurrency:\n group: ${{ githu"
},
{
"path": ".github/workflows/tx-builder-checks.yml",
"chars": 2308,
"preview": "name: tx-builder Checks\n\non:\n pull_request:\n paths:\n - apps/tx-builder/**\n - packages/**\n push:\n branc"
},
{
"path": ".github/workflows/tx-builder-deploy.yml",
"chars": 8105,
"preview": "name: tx-builder Deploy\n\non:\n pull_request:\n paths:\n - apps/tx-builder/**\n - packages/**\n - .github/w"
},
{
"path": ".github/workflows/web-argos-e2e.yml",
"chars": 2890,
"preview": "name: Web Argos E2E\n\non:\n workflow_dispatch:\n inputs:\n reference_branch:\n description: 'Argos baseline b"
},
{
"path": ".github/workflows/web-checks.yml",
"chars": 3682,
"preview": "name: Web Checks\n\non:\n pull_request:\n paths:\n - apps/web/**\n - packages/**\n push:\n branches:\n - m"
},
{
"path": ".github/workflows/web-chromatic.yml",
"chars": 2833,
"preview": "name: Web Chromatic\n\non:\n workflow_dispatch:\n\nconcurrency:\n group: ${{ github.workflow }}-${{ github.ref }}\n cancel-i"
},
{
"path": ".github/workflows/web-deploy-dev.yml",
"chars": 3262,
"preview": "name: Web Deploy to dev/staging\n\non:\n pull_request:\n\n push:\n branches:\n - dev\n - main\n paths:\n - "
},
{
"path": ".github/workflows/web-deploy-dockerhub.yml",
"chars": 2942,
"preview": "name: Web Deploy to Dockerhub\n\non:\n pull_request:\n branches:\n - docker\n paths:\n - apps/web/**\n - p"
},
{
"path": ".github/workflows/web-e2e-full-ondemand.yml",
"chars": 2087,
"preview": "name: Web Full Regression on demand tests\n\non:\n workflow_dispatch:\n schedule:\n - cron: '0 3 * * 1-5'\n\nconcurrency:\n"
},
{
"path": ".github/workflows/web-e2e-hp-ondemand.yml",
"chars": 1778,
"preview": "name: Web Happy path on demand tests\n\non:\n workflow_dispatch:\n schedule:\n - cron: '0 4 * * 3'\n\nconcurrency:\n group"
},
{
"path": ".github/workflows/web-e2e-prod-ondemand.yml",
"chars": 1883,
"preview": "name: Web Production health check tests\n\non:\n workflow_dispatch:\n\nconcurrency:\n group: ${{ github.workflow }}-${{ gith"
},
{
"path": ".github/workflows/web-e2e-smoke.yml",
"chars": 1868,
"preview": "name: Web Smoke tests\n\non:\n pull_request:\n paths:\n - apps/web/**\n - packages/**\n push:\n branches:\n "
},
{
"path": ".github/workflows/web-nextjs-bundle-analysis.yml",
"chars": 3186,
"preview": "# Copyright (c) HashiCorp, Inc.\n# SPDX-License-Identifier: MPL-2.0\n\nname: 'Web Next.js Bundle Analysis'\n\non:\n pull_requ"
},
{
"path": ".github/workflows/web-release-start.yml",
"chars": 11022,
"preview": "name: 🚀 Start Web Release\n\non:\n workflow_dispatch:\n inputs:\n version:\n description: 'Release version (e."
},
{
"path": ".github/workflows/web-storybook-screenshots-build.yml",
"chars": 6152,
"preview": "# Build half of a two-workflow pair. This half runs with `permissions: {}`,\n# does not reference secrets, and does not w"
},
{
"path": ".github/workflows/web-storybook-screenshots-publish.yml",
"chars": 3552,
"preview": "# Publish half of a two-workflow pair. Runs against the default branch\n# checkout only and consumes the named artifact p"
},
{
"path": ".github/workflows/web-storybook-tests.yml",
"chars": 1138,
"preview": "name: Web Storybook Snapshot Tests\n\npermissions:\n contents: read\n\non:\n pull_request:\n paths:\n - apps/web/**\n "
},
{
"path": ".github/workflows/web-tag-release.yml",
"chars": 12095,
"preview": "name: Web Tag, Release & Deploy\n\non:\n pull_request_target:\n branches:\n - main\n types: [closed]\n paths:\n "
},
{
"path": ".github/workflows/web-unit-tests.yml",
"chars": 2516,
"preview": "name: Web Unit tests\non:\n pull_request:\n paths:\n - apps/web/**\n - packages/**\n\n push:\n branches:\n "
},
{
"path": ".gitignore",
"chars": 1532,
"preview": "# dependencies\n/node_modules\n**/node_modules/*\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n/packages/utils/coverage\n/reports\nrepo"
},
{
"path": ".husky/commit-msg",
"chars": 1500,
"preview": "#!/bin/bash\nset -euo pipefail\n\n# Validate commit message follows conventional commit format\n# Format: type(scope): descr"
},
{
"path": ".husky/pre-commit",
"chars": 33,
"preview": "#!/bin/bash\nset -eu\n\nlint-staged\n"
},
{
"path": ".husky/pre-push",
"chars": 1321,
"preview": "#!/bin/bash\nset -eu\n\n# Store the initial git status\ninitial_status=$(git status --porcelain)\n\n# Run the lint command\nyar"
},
{
"path": ".lintstagedrc.mjs",
"chars": 247,
"preview": "export default {\n '**/*': ['prettier --write --ignore-unknown'],\n 'apps/mobile/assets/fonts/safe-icons/safe-icons.icom"
},
{
"path": ".nvmrc",
"chars": 9,
"preview": "v24.14.0\n"
},
{
"path": ".prettierignore",
"chars": 805,
"preview": "# Ignore artifacts:\n**/build\n**/coverage\n.idea\n**/node_modules/\n.yarn\n.pnp.cjs\n.pnp.loader.mjs\n.env\n.env.*\n\n# Turborepo "
},
{
"path": ".prettierrc",
"chars": 128,
"preview": "{\n \"tabWidth\": 2,\n \"printWidth\": 120,\n \"trailingComma\": \"all\",\n \"singleQuote\": true,\n \"semi\": false,\n \"endOfLine\":"
},
{
"path": ".specify/memory/constitution.md",
"chars": 7514,
"preview": "<!--\nSync Impact Report\n==================\nVersion change: 1.0.0 (initial)\nModified principles: N/A (initial constitutio"
},
{
"path": ".specify/scripts/bash/check-prerequisites.sh",
"chars": 4981,
"preview": "#!/usr/bin/env bash\n\n# Consolidated prerequisite checking script\n#\n# This script provides unified prerequisite checking "
},
{
"path": ".specify/scripts/bash/common.sh",
"chars": 4893,
"preview": "#!/usr/bin/env bash\n# Common functions and variables for all scripts\n\n# Get repository root, with fallback for non-git r"
},
{
"path": ".specify/scripts/bash/create-new-feature.sh",
"chars": 10189,
"preview": "#!/usr/bin/env bash\n\nset -e\n\nJSON_MODE=false\nSHORT_NAME=\"\"\nBRANCH_NUMBER=\"\"\nARGS=()\ni=1\nwhile [ $i -le $# ]; do\n arg="
},
{
"path": ".specify/scripts/bash/setup-plan.sh",
"chars": 1627,
"preview": "#!/usr/bin/env bash\n\nset -e\n\n# Parse command line arguments\nJSON_MODE=false\nARGS=()\n\nfor arg in \"$@\"; do\n case \"$arg\""
},
{
"path": ".specify/scripts/bash/update-agent-context.sh",
"chars": 25554,
"preview": "#!/usr/bin/env bash\n\n# Update agent context files with information from plan.md\n#\n# This script maintains AI agent conte"
},
{
"path": ".specify/templates/agent-file-template.md",
"chars": 464,
"preview": "# [PROJECT NAME] Development Guidelines\n\nAuto-generated from all feature plans. Last updated: [DATE]\n\n## Active Technolo"
},
{
"path": ".specify/templates/checklist-template.md",
"chars": 1307,
"preview": "# [CHECKLIST TYPE] Checklist: [FEATURE NAME]\n\n**Purpose**: [Brief description of what this checklist covers]\n**Created**"
},
{
"path": ".specify/templates/plan-template.md",
"chars": 3580,
"preview": "# Implementation Plan: [FEATURE]\n\n**Branch**: `[###-feature-name]` | **Date**: [DATE] | **Spec**: [link]\n**Input**: Feat"
},
{
"path": ".specify/templates/spec-template.md",
"chars": 3956,
"preview": "# Feature Specification: [FEATURE NAME]\n\n**Feature Branch**: `[###-feature-name]` \n**Created**: [DATE] \n**Status**: Dr"
},
{
"path": ".specify/templates/tasks-template.md",
"chars": 9138,
"preview": "---\ndescription: 'Task list template for feature implementation'\n---\n\n# Tasks: [FEATURE NAME]\n\n**Input**: Design documen"
},
{
"path": ".vscode/settings.json",
"chars": 137,
"preview": "{\n \"typescript.tsdk\": \"node_modules/typescript/lib\",\n \"typescript.enablePromptUseWorkspaceTsdk\": true,\n \"editor.forma"
},
{
"path": ".yarn/patches/@tamagui-image-npm-2.0.0-rc.26-04087a216c.patch",
"chars": 10794,
"preview": "diff --git a/dist/cjs/createImage.cjs b/dist/cjs/createImage.cjs\nindex d4d0550500cc84bb13ab80f599123371f183312c..67e792f"
},
{
"path": ".yarn/patches/next-npm-15.5.8-7d525d02b9.patch",
"chars": 673,
"preview": "diff --git a/dist/client/route-loader.js b/dist/client/route-loader.js\nindex 888fc23e628cd87fbbf60742aeaaea37b9703f6e..e"
},
{
"path": ".yarn/patches/react-native-ble-plx+3.5.0.patch",
"chars": 6324,
"preview": "diff --git a/android/src/main/java/com/bleplx/BlePlxModule.java b/android/src/main/java/com/bleplx/BlePlxModule.java\nind"
},
{
"path": ".yarn/patches/react-native-device-crypto-npm-0.1.7-dbd2698fc4.patch",
"chars": 5492,
"preview": "diff --git a/android/build.gradle b/android/build.gradle\nindex 8eb758ed063d1905f538f72e3ee55a8c41e01d18..d1ee770a3594017"
},
{
"path": ".yarn/patches/react-native-npm-0.83.4-77634a290c.patch",
"chars": 795,
"preview": "diff --git a/Libraries/Utilities/Appearance.js b/Libraries/Utilities/Appearance.js\nindex 9b7758c3afa3c9874c911045e258abf"
},
{
"path": ".yarn/patches/react-native-qrcode-styled-npm-0.3.3-b5336fc77c.patch",
"chars": 403,
"preview": "diff --git a/package.json b/package.json\nindex 228948278bbbd33e0637fb59397e4f4751efdf1b..37e8f4de7600b39c8fbc409f1095be2"
},
{
"path": ".yarnrc.yml",
"chars": 704,
"preview": "compressionLevel: mixed\n\nenableConstraintsChecks: true\n\nenableGlobalCache: true\n\nenableScripts: false\n\nnodeLinker: node-"
},
{
"path": "AGENTS.md",
"chars": 23692,
"preview": "# AI Contributor Guidelines\n\nThis repository is the Safe{Wallet} monorepo, containing both web and mobile applications f"
},
{
"path": "CLAUDE.md",
"chars": 81,
"preview": "Read @AGENTS.md for comprehensive guidelines on contributing to this repository.\n"
},
{
"path": "CONTRIBUTING.md",
"chars": 3992,
"preview": "# Contributing\n\n### tl;dr\n\n- Pull requests are very welcome\n- Check [**good first issues**](https://github.com/safe-glob"
},
{
"path": "Dockerfile",
"chars": 617,
"preview": "FROM node:18-alpine\nRUN apk add --no-cache libc6-compat git python3 py3-pip make g++ libusb-dev eudev-dev linux-headers\n"
},
{
"path": "LICENSE",
"chars": 35148,
"preview": " GNU GENERAL PUBLIC LICENSE\n Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
},
{
"path": "README.md",
"chars": 7439,
"preview": "# <img src=\"https://github.com/user-attachments/assets/b8249113-d515-4c91-a12a-f134813614e8\" height=\"60\" valign=\"middle\""
},
{
"path": "apps/mobile/.eas/build/build-and-maestro-test.yml",
"chars": 2058,
"preview": "build:\n name: Create a build and run Maestro tests on it\n steps:\n - eas/checkout\n\n - run:\n name: Enable c"
},
{
"path": "apps/mobile/.easignore",
"chars": 785,
"preview": "# Auto generated storybook file\n.storybook/storybook.requires.ts\n\n# From jest\nhtml\ncoverage\n\n# macOS\n.DS_Store\n\n/.idea\n#"
},
{
"path": "apps/mobile/.gitignore",
"chars": 896,
"preview": "# Auto generated storybook file\n.storybook/storybook.requires.ts\n\n# From jest\nhtml\ncoverage\n\n# macOS\n.DS_Store\n\n/.idea\n#"
},
{
"path": "apps/mobile/.storybook/index.ts",
"chars": 283,
"preview": "import AsyncStorage from '@react-native-async-storage/async-storage'\nimport { view } from './storybook.requires'\n\nconst "
},
{
"path": "apps/mobile/.storybook/main.ts",
"chars": 2919,
"preview": "import type { StorybookConfig as WebStorybookConfig } from '@storybook/react-webpack5'\nimport type { StorybookConfig as "
},
{
"path": "apps/mobile/.storybook/mocks/expo-fast-refresh.js",
"chars": 228,
"preview": "/* eslint-disable */\n// Mock Expo fast refresh for Storybook\n// Prevents \"React Refresh runtime should not be included i"
},
{
"path": "apps/mobile/.storybook/mocks/react-native-quick-crypto.js",
"chars": 1045,
"preview": "/* eslint-disable */\n// Mock react-native-quick-crypto for Storybook\n// Uses Node.js crypto as fallback\n\nconst crypto = "
},
{
"path": "apps/mobile/.storybook/mocks/react-native-reanimated.js",
"chars": 3297,
"preview": "/* eslint-disable */\n// Standalone mock for react-native-reanimated in Storybook\n// Based on the official mock but self-"
},
{
"path": "apps/mobile/.storybook/mocks/react-native-worklets/index.js",
"chars": 979,
"preview": "/* eslint-disable */\n// Mock for react-native-worklets in Storybook web environment\n// This prevents \"Failed to create a"
},
{
"path": "apps/mobile/.storybook/mocks/react-native-worklets/package.json",
"chars": 60,
"preview": "{\n \"name\": \"react-native-worklets\",\n \"version\": \"0.5.0\"\n}\n"
},
{
"path": "apps/mobile/.storybook/mocks/react-refresh.js",
"chars": 972,
"preview": "/* eslint-disable */\n// Mock react-refresh for Storybook to prevent production bundle errors\n// Provides no-op implement"
},
{
"path": "apps/mobile/.storybook/preview.tsx",
"chars": 4291,
"preview": "import type { Preview } from '@storybook/react'\nimport { useColorScheme } from 'react-native'\nimport { NavigationContain"
},
{
"path": "apps/mobile/.storybook/storybook.requires.d.ts",
"chars": 265,
"preview": "// Type declaration for the auto-generated storybook.requires file.\n// The actual file is created by sb-rn-get-stories /"
},
{
"path": "apps/mobile/.storybook/tsconfig.json",
"chars": 165,
"preview": "{\n \"extends\": \"../tsconfig.json\",\n \"compilerOptions\": {\n \"module\": \"nodenext\",\n \"moduleResolution\": \"nodenext\"\n "
},
{
"path": "apps/mobile/AGENTS.md",
"chars": 1960,
"preview": "# Mobile App AI Contributor Guidelines\n\nMobile-specific guidance for the Expo/React Native app under `apps/mobile/`. For"
},
{
"path": "apps/mobile/README.md",
"chars": 6022,
"preview": "# Safe{Mobile} app 📱\n\nThis project is now part of the **@safe-global/safe-wallet** monorepo! The monorepo setup allows c"
},
{
"path": "apps/mobile/__mocks__/fileMock.js",
"chars": 34,
"preview": "module.exports = 'test-file-stub'\n"
},
{
"path": "apps/mobile/__mocks__/react-native-capture-protection.js",
"chars": 391,
"preview": "/* eslint-disable */\n// Manual mock for react-native-capture-protection\nconst mockPrevent = jest.fn()\nconst mockAllow = "
},
{
"path": "apps/mobile/__mocks__/react-native-collapsible-tab-view.tsx",
"chars": 681,
"preview": "import React from 'react'\nimport { View, FlatList } from 'react-native'\n\nexport const Tabs = {\n Container: ({ children,"
},
{
"path": "apps/mobile/app.config.ts",
"chars": 6695,
"preview": "import { ExpoConfig } from 'expo/config'\n\nconst IS_DEV = process.env.APP_VARIANT === 'development'\n\nconst appleDevTeamId"
},
{
"path": "apps/mobile/assets/android/drawable/baseline_arrow_outward_24.xml",
"chars": 349,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\" android:height=\"24dp\" android:tint=\"#000000\" android:"
},
{
"path": "apps/mobile/assets/android/drawable/baseline_auto_awesome_motion_24.xml",
"chars": 471,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\" android:height=\"24dp\" android:tint=\"#000000\" android:"
},
{
"path": "apps/mobile/assets/android/drawable/baseline_content_copy_24.xml",
"chars": 499,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\" android:width=\"24dp\" android:height=\"24dp\" android:ti"
},
{
"path": "apps/mobile/assets/android/drawable/baseline_create_24.xml",
"chars": 450,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\" android:height=\"24dp\" android:tint=\"#000000\" android:"
},
{
"path": "apps/mobile/assets/android/drawable/baseline_delete_24.xml",
"chars": 367,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\" android:height=\"24dp\" android:tint=\"#DE0303\" android:"
},
{
"path": "apps/mobile/assets/android/drawable/baseline_explore_24.xml",
"chars": 497,
"preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\" android:height=\"24dp\" android:tint=\"#000000\" android:"
},
{
"path": "apps/mobile/assets/android/drawable/ic_notification.xml",
"chars": 1198,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n android:wi"
},
{
"path": "apps/mobile/assets/fonts/safe-icons/safe-icons.icomoon.json",
"chars": 782662,
"preview": "{\"palettes\":{\"index\":0,\"table\":[[{\"background\":{\"tag\":\"AutomaticColor\",\"args\":[]},\"foreground\":{\"tag\":\"AutomaticColor\",\""
},
{
"path": "apps/mobile/babel.config.js",
"chars": 446,
"preview": "module.exports = function (api) {\n api.cache(true)\n return {\n // Enables the `unstable_transformImportMeta` option "
},
{
"path": "apps/mobile/docs/analytics.md",
"chars": 4846,
"preview": "# Mobile Analytics Service\n\nThis document explains how analytics are implemented in the Safe{Mobile} app using Firebase "
},
{
"path": "apps/mobile/docs/code-style.md",
"chars": 2204,
"preview": "# Code Style Guidelines\n\n> Cyclomatic-complexity guidelines (lookup tables, early returns, switch for type discriminatio"
},
{
"path": "apps/mobile/docs/e2e-tests-guidelines.md",
"chars": 2088,
"preview": "# E2E Testing Guidelines for React Native\n\nThis document outlines best practices for writing and maintaining end-to-end "
},
{
"path": "apps/mobile/docs/push-notifications.md",
"chars": 5099,
"preview": "# Push Notifications\n\nThis document explains how push notifications are implemented in the Safe{Mobile} app. It covers t"
},
{
"path": "apps/mobile/docs/release-procedure.md",
"chars": 903,
"preview": "# Releasing to Production\n\nThe code is being actively developed on the `dev` branch. Pull requests are made against this"
},
{
"path": "apps/mobile/e2e/README.md",
"chars": 2069,
"preview": "# E2E Tests\n\nThe E2E tests are written for [Maestro](https://docs.maestro.dev)\n\n## Recommended setup for writing tests\n\n"
},
{
"path": "apps/mobile/e2e/config.yaml",
"chars": 375,
"preview": "# Maestro E2E Test Configuration\n#\n# Documentation: https://docs.maestro.dev/api-reference/configuration\n\nflows:\n - 'te"
},
{
"path": "apps/mobile/e2e/tests/app-update/force-update.yml",
"chars": 1138,
"preview": "appId: ${APP_ID}\ntags:\n - app-update\n - smoke\n---\n# Force Update Screen E2E Test\n# Verifies that when a force update i"
},
{
"path": "apps/mobile/e2e/tests/app-update/soft-update.yml",
"chars": 1503,
"preview": "appId: ${APP_ID}\ntags:\n - app-update\n - smoke\n---\n# Soft Update Prompt E2E Test\n# Verifies that when a soft update is "
},
{
"path": "apps/mobile/e2e/tests/assets/__suite__.yml",
"chars": 536,
"preview": "appId: ${APP_ID}\ntags:\n - assets\n - suite\n---\n# Assets Test Suite\n# Runs all assets tests with a single app launch for"
},
{
"path": "apps/mobile/e2e/tests/assets/change-currency.yml",
"chars": 5496,
"preview": "appId: ${APP_ID}\ntags:\n - assets\n - settings\n---\n# Currency Change Happy Path Test\n# Tests changing the display curren"
},
{
"path": "apps/mobile/e2e/tests/assets/view-positions.yml",
"chars": 3795,
"preview": "appId: ${APP_ID}\ntags:\n - assets\n - positions\n---\n# Positions Feature Test\n# Tests viewing positions list and protocol"
},
{
"path": "apps/mobile/e2e/tests/assets/view-tokens-and-nfts.yml",
"chars": 2779,
"preview": "appId: ${APP_ID}\ntags:\n - assets\n - smoke\n---\n- runScript:\n file: ../../utils/scripts/defaults.js\n\n- runFlow:\n f"
},
{
"path": "apps/mobile/e2e/tests/connect-signer/__suite__.yml",
"chars": 506,
"preview": "appId: ${APP_ID}\ntags:\n - connect-signer\n - suite\n---\n# Connect Signer Test Suite. Each test calls resetReduxForE2E be"
},
{
"path": "apps/mobile/e2e/tests/connect-signer/connect-signer-collision.yml",
"chars": 1302,
"preview": "appId: ${APP_ID}\ntags:\n - connect-signer\n - collision\n---\n# Type-mismatch collision: importing a wallet whose address "
},
{
"path": "apps/mobile/e2e/tests/connect-signer/connect-signer-not-owner.yml",
"chars": 1438,
"preview": "appId: ${APP_ID}\ntags:\n - connect-signer\n---\n# Error path: Connect wallet that is NOT an owner of the active Safe\n\n- ru"
},
{
"path": "apps/mobile/e2e/tests/connect-signer/connect-signer-success.yml",
"chars": 2768,
"preview": "appId: ${APP_ID}\ntags:\n - connect-signer\n---\n# Happy path: Connect wallet → Name signer → Success → Signers list\n\n- run"
},
{
"path": "apps/mobile/e2e/tests/connect-signer/reconnect-wrong-wallet.yml",
"chars": 1304,
"preview": "appId: ${APP_ID}\ntags:\n - connect-signer\n - wc-gate\n - reconnect-error\n---\n# WalletConnect reconnect mismatch: wrong-"
},
{
"path": "apps/mobile/e2e/tests/connect-signer/wc-gate-reconnect.yml",
"chars": 991,
"preview": "appId: ${APP_ID}\ntags:\n - connect-signer\n - wc-gate\n---\n# WalletConnect Gate: Session expired → \"Reconnect wallet to c"
},
{
"path": "apps/mobile/e2e/tests/connect-signer/wc-gate-switch-network.yml",
"chars": 976,
"preview": "appId: ${APP_ID}\ntags:\n - connect-signer\n - wc-gate\n---\n# WalletConnect Gate: Wrong network → \"Switch network to conti"
},
{
"path": "apps/mobile/e2e/tests/onboarding/__suite__.yml",
"chars": 713,
"preview": "appId: ${APP_ID}\ntags:\n - onboarding\n - suite\n---\n# Onboarding Test Suite\n# Runs all onboarding tests with a single ap"
},
{
"path": "apps/mobile/e2e/tests/onboarding/add-existing-safe.yml",
"chars": 955,
"preview": "appId: ${APP_ID}\ntags:\n - onboarding\n---\n- runFlow:\n file: ../../utils/setup/app-start.yml\n\n- tapOn:\n id: 'e2eOnb"
},
{
"path": "apps/mobile/e2e/tests/onboarding/add-safe-and-import-signer.yml",
"chars": 4591,
"preview": "appId: ${APP_ID}\ntags:\n - onboarding\n - import-signer\n - add-safe\n---\n# Test adding a safe during onboarding and then"
},
{
"path": "apps/mobile/e2e/tests/onboarding/enhanced-onboarding-flow.yml",
"chars": 4290,
"preview": "appId: ${APP_ID}\ntags:\n - onboarding\n - smoke\n---\n# Complete Onboarding Flow Test\n# Tests the onboarding flow includin"
},
{
"path": "apps/mobile/e2e/tests/onboarding/import-signer-private-key.yml",
"chars": 5355,
"preview": "appId: ${APP_ID}\ntags:\n - onboarding\n - import-signer\n - private-key\n---\n# Test importing a signer using a raw privat"
},
{
"path": "apps/mobile/e2e/tests/onboarding/import-signer-seed-phrase.yml",
"chars": 4895,
"preview": "appId: ${APP_ID}\ntags:\n - onboarding\n - import-signer\n - seed-phrase\n---\n# Test importing a signer using a seed phras"
},
{
"path": "apps/mobile/e2e/tests/onboarding/import-signer.yml",
"chars": 933,
"preview": "appId: ${APP_ID}\ntags:\n - onboarding\n - import-signer\n---\n- runFlow:\n file: ../../utils/setup/app-start.yml\n- tapOn"
},
{
"path": "apps/mobile/e2e/tests/onboarding/new-user-onboarding.yml",
"chars": 1064,
"preview": "appId: 'global.safe.mobileapp.ios'\ntags:\n - onboarding\n - smoke\n---\n- runFlow:\n file: ../../utils/setup/app-start.y"
},
{
"path": "apps/mobile/e2e/tests/settings/__suite__.yml",
"chars": 623,
"preview": "appId: ${APP_ID}\ntags:\n - settings\n - suite\n---\n# Settings Test Suite\n# Runs all settings tests with a single app laun"
},
{
"path": "apps/mobile/e2e/tests/settings/address-book.yml",
"chars": 8775,
"preview": "appId: ${APP_ID}\ntags:\n - settings\n - address-book\n - smoke\n---\n# Address Book E2E Test\n# Tests the complete address "
},
{
"path": "apps/mobile/e2e/tests/settings/change-theme.yml",
"chars": 4325,
"preview": "appId: ${APP_ID}\ntags:\n - settings\n - smoke\n---\n# Theme Selection E2E Test\n# Tests switching between light, dark, and "
},
{
"path": "apps/mobile/e2e/tests/settings/state-preservation.yml",
"chars": 3362,
"preview": "appId: ${APP_ID}\ntags:\n - settings\n - state-preservation\n---\n# ============================================\n# Tests th"
},
{
"path": "apps/mobile/e2e/tests/settings/view-account-info.yml",
"chars": 9943,
"preview": "appId: ${APP_ID}\ntags:\n - settings\n - smoke\n---\n# Safe Account Information Display E2E Test\n# Tests viewing detailed i"
},
{
"path": "apps/mobile/e2e/tests/transactions/history/__suite__.yml",
"chars": 2228,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - history\n - suite\n---\n# Transaction History Test Suite - Complete Coverage\n#"
},
{
"path": "apps/mobile/e2e/tests/transactions/history/add-owner-threshold.yml",
"chars": 408,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - history\n - settings\n---\n- runFlow:\n file: ../../../utils/setup/app-start"
},
{
"path": "apps/mobile/e2e/tests/transactions/history/batch-transaction.yml",
"chars": 583,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - history\n - smoke\n---\n- runFlow:\n file: ../../../utils/setup/app-start.ym"
},
{
"path": "apps/mobile/e2e/tests/transactions/history/bulk-transactions.yml",
"chars": 678,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - history\n---\n- runFlow:\n file: ../../../utils/setup/app-start.yml\n\n# Navig"
},
{
"path": "apps/mobile/e2e/tests/transactions/history/change-threshold.yml",
"chars": 392,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - history\n - settings\n---\n- runFlow:\n file: ../../../utils/setup/app-start"
},
{
"path": "apps/mobile/e2e/tests/transactions/history/contract-interaction-delete-allowance.yml",
"chars": 666,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - history\n---\n- runFlow:\n file: ../../../utils/setup/app-start.yml\n\n# Navig"
},
{
"path": "apps/mobile/e2e/tests/transactions/history/contract-interaction-deposit.yml",
"chars": 1004,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - history\n---\n- runFlow:\n file: ../../../utils/setup/app-start.yml\n\n# Navig"
},
{
"path": "apps/mobile/e2e/tests/transactions/history/disable-module.yml",
"chars": 529,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - history\n - settings\n---\n- runFlow:\n file: ../../../utils/setup/app-start"
},
{
"path": "apps/mobile/e2e/tests/transactions/history/limit-order.yml",
"chars": 867,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - history\n - cow-protocol\n---\n- runFlow:\n file: ../../../utils/setup/app-s"
},
{
"path": "apps/mobile/e2e/tests/transactions/history/received-transaction.yml",
"chars": 363,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - history\n---\n- runFlow:\n file: ../../../utils/setup/app-start.yml\n\n# Navig"
},
{
"path": "apps/mobile/e2e/tests/transactions/history/rejected-transaction.yml",
"chars": 361,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - history\n---\n- runFlow:\n file: ../../../utils/setup/app-start.yml\n\n# Navig"
},
{
"path": "apps/mobile/e2e/tests/transactions/history/remove-owner.yml",
"chars": 523,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - history\n - settings\n---\n- runFlow:\n file: ../../../utils/setup/app-start"
},
{
"path": "apps/mobile/e2e/tests/transactions/history/sent-transaction.yml",
"chars": 355,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - history\n---\n- runFlow:\n file: ../../../utils/setup/app-start.yml\n\n# Navig"
},
{
"path": "apps/mobile/e2e/tests/transactions/history/stake-claim.yml",
"chars": 850,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - history\n---\n- runFlow:\n file: ../../../utils/setup/app-start.yml\n\n# Navig"
},
{
"path": "apps/mobile/e2e/tests/transactions/history/stake-deposit.yml",
"chars": 858,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - history\n---\n- runFlow:\n file: ../../../utils/setup/app-start.yml\n\n# Navig"
},
{
"path": "apps/mobile/e2e/tests/transactions/history/swap-order.yml",
"chars": 918,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - history\n - cow-protocol\n---\n- runFlow:\n file: ../../../utils/setup/app-s"
},
{
"path": "apps/mobile/e2e/tests/transactions/history/swap-owner.yml",
"chars": 527,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - history\n - settings\n---\n- runFlow:\n file: ../../../utils/setup/app-start"
},
{
"path": "apps/mobile/e2e/tests/transactions/history/view-transaction-history.yml",
"chars": 1341,
"preview": "appId: test\ntags:\n - transactions\n - history\n - smoke\n---\n# Transaction History E2E Test\n# Tests viewing transaction "
},
{
"path": "apps/mobile/e2e/tests/transactions/pending/batch-transaction.yml",
"chars": 398,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - pending\n - smoke\n---\n- runFlow:\n file: ../../../utils/setup/app-start.ym"
},
{
"path": "apps/mobile/e2e/tests/transactions/pending/conflicting-transactions.yml",
"chars": 1021,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - pending\n - smoke\n---\n- runFlow:\n file: ../../../utils/setup/app-start.ym"
},
{
"path": "apps/mobile/e2e/tests/transactions/pending/limit-order.yml",
"chars": 417,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - pending\n - cow-protocol\n---\n- runFlow:\n file: ../../../utils/setup/app-s"
},
{
"path": "apps/mobile/e2e/tests/transactions/pending/on-chain-rejection.yml",
"chars": 414,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - pending\n---\n- runFlow:\n file: ../../../utils/setup/app-start.yml\n\n# Direc"
},
{
"path": "apps/mobile/e2e/tests/transactions/pending/safe-shield/approve-malicious.yml",
"chars": 1909,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - pending\n - safe-shield\n---\n# ===========================================\n# "
},
{
"path": "apps/mobile/e2e/tests/transactions/pending/safe-shield/batch-2-actions.yml",
"chars": 1985,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - pending\n - safe-shield\n---\n# ===========================================\n# "
},
{
"path": "apps/mobile/e2e/tests/transactions/pending/safe-shield/batch-3-actions-benign.yml",
"chars": 2236,
"preview": "appId: ${APP_ID}\ntags:\n - safe-shield\n - pending-tx\n---\n# ===========================================\n# SafeShield Tes"
},
{
"path": "apps/mobile/e2e/tests/transactions/pending/safe-shield/batch-3-actions-warn.yml",
"chars": 2234,
"preview": "appId: ${APP_ID}\ntags:\n - safe-shield\n - pending-tx\n---\n# ===========================================\n# SafeShield Tes"
},
{
"path": "apps/mobile/e2e/tests/transactions/pending/safe-shield/batch-malicious.yml",
"chars": 2320,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - pending\n - safe-shield\n---\n# ===========================================\n# "
},
{
"path": "apps/mobile/e2e/tests/transactions/pending/safe-shield/contract-interaction-malicious.yml",
"chars": 1881,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - pending\n - safe-shield\n---\n# ===========================================\n# "
},
{
"path": "apps/mobile/e2e/tests/transactions/pending/safe-shield/pending-bridge-unknown-network.yml",
"chars": 2280,
"preview": "appId: ${APP_ID}\ntags:\n - safe-shield\n - pending-tx\n---\n# ===========================================\n# SafeShield Tes"
},
{
"path": "apps/mobile/e2e/tests/transactions/pending/safe-shield/pending-bridge.yml",
"chars": 2663,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - pending\n - safe-shield\n---\n# ===========================================\n# "
},
{
"path": "apps/mobile/e2e/tests/transactions/pending/safe-shield/send-dai-malicious.yml",
"chars": 2273,
"preview": "appId: ${APP_ID}\ntags:\n - transactions\n - pending\n - safe-shield\n---\n# ===========================================\n# "
}
]
// ... and 5730 more files (download for full content)
About this extraction
This page contains the full source code of the safe-global/web-core GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 5930 files (22.0 MB), approximately 6.1M tokens, and a symbol index with 7344 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.