From 5c680eca9e85a14aa7acd7678127351a7770e229 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Tue, 28 Jul 2026 19:00:57 +0000
Subject: [PATCH 1/3] chore: bump app version to v1.21.27
---
android/app/build.gradle | 2 +-
ios/freighter-mobile.xcodeproj/project.pbxproj | 8 ++++----
ios/freighter-mobile/Info-Dev.plist | 2 +-
ios/freighter-mobile/Info.plist | 2 +-
package.json | 2 +-
5 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/android/app/build.gradle b/android/app/build.gradle
index bf3def91d..e595b2741 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -141,7 +141,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1234567890
- versionName "1.20.27"
+ versionName "1.21.27"
}
buildTypes {
diff --git a/ios/freighter-mobile.xcodeproj/project.pbxproj b/ios/freighter-mobile.xcodeproj/project.pbxproj
index 4aa51913c..0dd191005 100644
--- a/ios/freighter-mobile.xcodeproj/project.pbxproj
+++ b/ios/freighter-mobile.xcodeproj/project.pbxproj
@@ -505,7 +505,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.20.27;
+ MARKETING_VERSION = 1.21.27;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -542,7 +542,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.20.27;
+ MARKETING_VERSION = 1.21.27;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -740,7 +740,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.20.27;
+ MARKETING_VERSION = 1.21.27;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -775,7 +775,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 1.20.27;
+ MARKETING_VERSION = 1.21.27;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
diff --git a/ios/freighter-mobile/Info-Dev.plist b/ios/freighter-mobile/Info-Dev.plist
index a7506988c..5d5829401 100644
--- a/ios/freighter-mobile/Info-Dev.plist
+++ b/ios/freighter-mobile/Info-Dev.plist
@@ -17,7 +17,7 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 1.20.27
+ 1.21.27
CFBundleSignature
????
CFBundleURLTypes
diff --git a/ios/freighter-mobile/Info.plist b/ios/freighter-mobile/Info.plist
index 3ef0fd0b9..07185ae24 100644
--- a/ios/freighter-mobile/Info.plist
+++ b/ios/freighter-mobile/Info.plist
@@ -17,7 +17,7 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 1.20.27
+ 1.21.27
CFBundleSignature
????
CFBundleURLTypes
diff --git a/package.json b/package.json
index c4a936af7..869b75dfb 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "freighter-mobile",
- "version": "1.20.27",
+ "version": "1.21.27",
"license": "Apache-2.0",
"scripts": {
"android": "yarn android-dev",
From 4b06f87f380b74f278bc806fb3e96c7300dc84d4 Mon Sep 17 00:00:00 2001
From: Piyal Basu
Date: Wed, 29 Jul 2026 17:46:43 -0400
Subject: [PATCH 2/3] fix(sentry): turn Sentry fully off when data sharing is
off (mirror extension) (#955)
Squashed for the v1.21.27 release branch (retargeted from main). Consent now
controls Sentry initialization, event delivery, and runtime shutdown:
- initializeSentry() no-ops during e2e, when already initialized (idempotent),
or when data sharing is OFF (master switch).
- beforeSend hard-drops every event while sharing is off.
- syncSentryEnablement() reconciles on toggle: inits when turned on, and on
opt-out clears the user and disables the client by flipping enabled=false
(NOT close()/close(0), which full-drain the transport backlog); guarded on
persist.hasHydrated() so the store subscription can't init off the
pre-hydration Android default.
- App startup + updateSentryContext consent-gate the Sentry user identity.
Co-authored-by: Claude Opus 4.8 (1M context)
---
__tests__/config/sentryConfig.test.ts | 117 +++++++++++++++++++++++++-
src/components/App.tsx | 14 ++-
src/config/sentryConfig.ts | 82 +++++++++++++++++-
src/services/analytics/core.ts | 14 +++
4 files changed, 224 insertions(+), 3 deletions(-)
diff --git a/__tests__/config/sentryConfig.test.ts b/__tests__/config/sentryConfig.test.ts
index e4efa6513..9ca06e13b 100644
--- a/__tests__/config/sentryConfig.test.ts
+++ b/__tests__/config/sentryConfig.test.ts
@@ -5,11 +5,21 @@ import {
PASSWORD_TYPO_MESSAGES,
initializeSentry,
scrubStrKeys,
+ syncSentryEnablement,
updateSentryContext,
} from "config/sentryConfig";
+// Shared client options object so tests can assert that opt-out flips
+// `enabled` to false (the non-flushing disable) rather than calling close().
+const mockClientOptions: { enabled: boolean } = { enabled: true };
+const mockClientClose = jest.fn();
jest.mock("@sentry/react-native", () => ({
init: jest.fn(),
+ close: jest.fn(),
+ getClient: jest.fn(() => ({
+ close: mockClientClose,
+ getOptions: () => mockClientOptions,
+ })),
setContext: jest.fn(),
setTag: jest.fn(),
setUser: jest.fn(),
@@ -34,8 +44,14 @@ const mockAnalyticsState: { isEnabled: boolean; userId: string | null } = {
isEnabled: true,
userId: null,
};
+// Persisted-consent hydration flag. Default true so direct-call tests exercise
+// the post-hydration path; a dedicated test flips it false to cover the race.
+const mockHydration = { hydrated: true };
jest.mock("ducks/analytics", () => ({
- useAnalyticsStore: { getState: () => mockAnalyticsState },
+ useAnalyticsStore: {
+ getState: () => mockAnalyticsState,
+ persist: { hasHydrated: () => mockHydration.hydrated },
+ },
}));
jest.mock("ducks/auth", () => ({
useAuthenticationStore: {
@@ -84,6 +100,21 @@ const runBeforeSendWith = (event: Partial): ErrorEvent | null => {
return initOpts.beforeSend(event as ErrorEvent, {}) as ErrorEvent | null;
};
+// initializeSentry() is idempotent — it guards on an internal
+// `isSentryInitialized` flag. Reset that module state before every test (drive
+// it to "not initialized" via the public syncSentryEnablement path) so each
+// test starts fresh and stays isolated.
+beforeEach(() => {
+ mockHydration.hydrated = true;
+ mockAnalyticsState.isEnabled = false;
+ syncSentryEnablement();
+ mockAnalyticsState.isEnabled = true;
+ // Reset AFTER the syncSentryEnablement reset above, which flips enabled off
+ // when a prior test left the client initialized.
+ mockClientOptions.enabled = true;
+ jest.clearAllMocks();
+});
+
describe("updateSentryContext user-identity consent gate", () => {
beforeEach(() => {
jest.clearAllMocks();
@@ -498,3 +529,87 @@ describe("sentryConfig.beforeSend filters", () => {
});
});
});
+
+// Mirrors the extension: the data-sharing toggle is the master switch for
+// Sentry — off means the client is never initialized (cold start) and every
+// event is dropped (runtime), and toggling flips the client on/off.
+describe("data-sharing master switch", () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ mockAnalyticsState.isEnabled = true;
+ });
+
+ it("does NOT initialize Sentry when data sharing is off", () => {
+ mockAnalyticsState.isEnabled = false;
+ initializeSentry();
+ expect(mockedSentry.init).not.toHaveBeenCalled();
+ });
+
+ it("initializes Sentry when data sharing is on", () => {
+ mockAnalyticsState.isEnabled = true;
+ initializeSentry();
+ expect(mockedSentry.init).toHaveBeenCalledTimes(1);
+ });
+
+ it("beforeSend drops every event while data sharing is off, passes when on", () => {
+ mockAnalyticsState.isEnabled = true;
+ initializeSentry();
+ const beforeSend = mockedSentry.init.mock.calls[0]?.[0]?.beforeSend;
+ expect(beforeSend).toBeDefined();
+
+ const event = {
+ exception: { values: [{ type: "Error", value: "a real bug" }] },
+ } as unknown as ErrorEvent;
+
+ // Enabled: a normal event passes through.
+ expect(beforeSend!(event, {})).not.toBeNull();
+
+ // Disabled: the same event is dropped.
+ mockAnalyticsState.isEnabled = false;
+ expect(beforeSend!(event, {})).toBeNull();
+ });
+
+ it("syncSentryEnablement disables the client on toggle-off without flushing", () => {
+ // Bring the client up first so the internal flag is set.
+ mockAnalyticsState.isEnabled = true;
+ initializeSentry();
+ jest.clearAllMocks();
+
+ mockAnalyticsState.isEnabled = false;
+ syncSentryEnablement();
+ expect(mockedSentry.setUser).toHaveBeenCalledWith(null);
+ // Disable by flipping enabled=false directly — NOT via close()/close(0),
+ // both of which full-drain the transport (PromiseBuffer.drain treats a
+ // falsy timeout as "wait for the whole queue"). We must not push out the
+ // backlog buffered under prior consent.
+ expect(mockClientOptions.enabled).toBe(false);
+ expect(mockClientClose).not.toHaveBeenCalled();
+ expect(mockedSentry.close).not.toHaveBeenCalled();
+ expect(mockedSentry.init).not.toHaveBeenCalled();
+ });
+
+ it("syncSentryEnablement re-initializes the client on toggle-on", () => {
+ // Drive to a shut-down state (init, then disable via sync).
+ mockAnalyticsState.isEnabled = true;
+ initializeSentry();
+ mockAnalyticsState.isEnabled = false;
+ syncSentryEnablement();
+ jest.clearAllMocks();
+
+ mockAnalyticsState.isEnabled = true;
+ syncSentryEnablement();
+ expect(mockedSentry.init).toHaveBeenCalledTimes(1);
+ });
+
+ it("syncSentryEnablement is a no-op before persisted consent hydrates", () => {
+ // Returning opted-out user on Android: store default is `true`, but the
+ // persisted preference (still un-hydrated) is `false`. The subscription
+ // must not initialize Sentry off the pre-hydration default.
+ mockHydration.hydrated = false;
+ mockAnalyticsState.isEnabled = true;
+
+ syncSentryEnablement();
+
+ expect(mockedSentry.init).not.toHaveBeenCalled();
+ });
+});
diff --git a/src/components/App.tsx b/src/components/App.tsx
index 66c16eab3..234c9ca58 100644
--- a/src/components/App.tsx
+++ b/src/components/App.tsx
@@ -88,7 +88,19 @@ export const App = (): React.JSX.Element => {
}
};
- initSentry();
+ // Defer until the persisted data-sharing preference has hydrated from
+ // AsyncStorage. Zustand's pre-hydration default is `true` (Android), so
+ // running initSentry() before hydration could initialize Sentry for a
+ // returning opted-out user in the brief window before the stored `false`
+ // restores — breaking the cold-start opt-out. Mirrors the analytics
+ // module's onFinishHydration handling in services/analytics/core.ts.
+ if (useAnalyticsStore.persist.hasHydrated()) {
+ initSentry();
+ return undefined;
+ }
+ return useAnalyticsStore.persist.onFinishHydration(() => {
+ initSentry();
+ });
}, []);
return (
diff --git a/src/config/sentryConfig.ts b/src/config/sentryConfig.ts
index 93b798823..903e6eb6c 100644
--- a/src/config/sentryConfig.ts
+++ b/src/config/sentryConfig.ts
@@ -179,8 +179,21 @@ export const updateSentryContext = (): void => {
}
};
+// Tracks whether the Sentry client is currently running, so the data-sharing
+// toggle can (re)initialize or shut it down idempotently (see
+// syncSentryEnablement).
+let isSentryInitialized = false;
+
/**
- * Initialize Sentry with privacy-conscious configuration
+ * Initialize Sentry with privacy-conscious configuration.
+ *
+ * No-ops (does not call Sentry.init) in three cases:
+ * - during e2e tests;
+ * - if Sentry is already initialized (idempotent — safe to call from both
+ * App's startup effect and the analytics-store subscription regardless of
+ * order);
+ * - if data sharing is currently OFF (master switch; mirrors the extension).
+ * syncSentryEnablement() re-invokes this when the user turns sharing back on.
*/
export const initializeSentry = (): void => {
// Disable Sentry during e2e tests
@@ -188,6 +201,21 @@ export const initializeSentry = (): void => {
return;
}
+ // Idempotent: never run Sentry.init() twice. Both App's startup effect and
+ // the analytics-store subscription (via syncSentryEnablement) can reach here,
+ // and their order isn't guaranteed — guard the initializer itself so whichever
+ // runs second is a no-op.
+ if (isSentryInitialized) {
+ return;
+ }
+
+ // Master switch: with data sharing OFF, do not initialize Sentry at all —
+ // mirrors the extension (no init when sharing is disabled), so nothing is
+ // reported. syncSentryEnablement() re-initializes if the user turns it on.
+ if (!useAnalyticsStore.getState().isEnabled) {
+ return;
+ }
+
Sentry.init({
dsn: SENTRY_CONFIG.DSN,
sendDefaultPii: false,
@@ -208,6 +236,13 @@ export const initializeSentry = (): void => {
appHangTimeoutInterval: 5,
beforeSend(event) {
+ // Master switch (defense-in-depth): if data sharing is off, drop every
+ // event. Covers the window between a runtime toggle-off and client
+ // teardown, and any event from a lingering or native-layer client.
+ if (!useAnalyticsStore.getState().isEnabled) {
+ return null;
+ }
+
// Drop or downgrade known-noise patterns before any PII scrubbing
// or context updates. Each entry should describe a noise source
// we've seen in production (third-party SDK quirks, native auth
@@ -328,6 +363,51 @@ export const initializeSentry = (): void => {
},
});
+ isSentryInitialized = true;
+
// Set initial context and tags
updateSentryContext();
};
+
+/**
+ * Reconcile Sentry with the current data-sharing preference. Idempotent and
+ * safe to call on any analytics-store change: when sharing is ON it
+ * (re)initializes Sentry; when sharing is OFF it clears the user and disables
+ * the client so nothing further is reported. Mirrors the extension's
+ * init-when-allowed / disable-on-opt-out behavior.
+ */
+export const syncSentryEnablement = (): void => {
+ // Consent (isEnabled) is persisted to AsyncStorage and hydrates
+ // asynchronously; before hydration the store holds its default, which is
+ // `true` on Android (ANALYTICS_CONFIG.DEFAULT_ENABLED). This runs from the
+ // analytics-store subscription, which can fire pre-hydration (e.g. setUserId
+ // during identify), so reading isEnabled now could initialize Sentry for a
+ // returning opted-out user. Treat persisted consent as authoritative and
+ // skip until hydration completes — App's startup effect performs the initial
+ // reconcile from onFinishHydration. Mirrors syncIdentifyTraits in
+ // services/analytics/core.ts.
+ if (!useAnalyticsStore.persist.hasHydrated()) return;
+
+ const { isEnabled } = useAnalyticsStore.getState();
+
+ if (isEnabled && !isSentryInitialized) {
+ initializeSentry();
+ } else if (!isEnabled && isSentryInitialized) {
+ // Drop the identity, then disable the client WITHOUT flushing. Neither
+ // Sentry.close() nor client.close(0) work here: close() always runs
+ // flush(timeout) first, and PromiseBuffer.drain treats a falsy timeout
+ // (0 or undefined) as "wait until the whole queue drains" — so both would
+ // push out events buffered under prior consent (e.g. from an offline
+ // window), contradicting "off means off". Flip `enabled = false` directly
+ // (what close() does after its flush): captureEvent's `_isEnabled()` guard
+ // then blocks every future send, and beforeSend hard-drops anything caught
+ // in the gap. In-flight network requests already handed off can't be
+ // recalled, but nothing new is drained.
+ Sentry.setUser(null);
+ const client = Sentry.getClient();
+ if (client) {
+ client.getOptions().enabled = false;
+ }
+ isSentryInitialized = false;
+ }
+};
diff --git a/src/services/analytics/core.ts b/src/services/analytics/core.ts
index 0baaf179c..c0fded40b 100644
--- a/src/services/analytics/core.ts
+++ b/src/services/analytics/core.ts
@@ -3,6 +3,7 @@ import { Experiment } from "@amplitude/experiment-react-native-client";
import { hash } from "@stellar/stellar-sdk";
import { AnalyticsEvent, isScreenViewEvent } from "config/analyticsConfig";
import { logger } from "config/logger";
+import { syncSentryEnablement } from "config/sentryConfig";
import { useAnalyticsStore } from "ducks/analytics";
import { useAuthenticationStore } from "ducks/auth";
import { useBalancesStore } from "ducks/balances";
@@ -505,6 +506,19 @@ useAnalyticsStore.subscribe((state) => {
);
}
+ // Turn Sentry fully on/off with the same toggle (mirrors the extension):
+ // (re)initialize when sharing is enabled, shut the client down when disabled.
+ // Also covers consent that hydrates/enables AFTER the initial init ran.
+ try {
+ syncSentryEnablement();
+ } catch (error) {
+ logger.error(
+ DEBUG_CONFIG.LOG_PREFIX,
+ "Failed to sync Sentry enablement",
+ error,
+ );
+ }
+
// Consent may hydrate/enable AFTER init runs, so the in-init sync can
// correctly skip (opted-out, nothing cached). Re-sync here so traits reach
// Amplitude once consent becomes allowed. The dirty-check + consent-gate in
From 9b877f025e3e4dea4437556078fa7a8eb5460f10 Mon Sep 17 00:00:00 2001
From: Piyal Basu
Date: Wed, 29 Jul 2026 17:46:57 -0400
Subject: [PATCH 3/3] copy(preferences): "Usage data sharing" toggle + accurate
disclosure (#956)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* copy(preferences): rename data-sharing toggle to "Usage data sharing" + accurate disclosure
The toggle was labeled "Anonymous data sharing" and claimed we collect "public keys, transaction amounts, and balances" only. Relabel to "Usage data sharing" (i18n key anonymousDataSharing -> usageDataSharing) and replace the description with an accurate disclosure covering usage/device/activity data, public keys, IP address, and the persistent cross-platform ID sent to our analytics and crash-reporting providers. Also aligns the ATT permission-modal wording. Removes the stale pt strings so they fall back to English until a professional pt translation is added.
Co-Authored-By: Claude Opus 4.8 (1M context)
* i18n(pt): translate usage-data-sharing copy + drop "anônimos" from ATT modal
Addresses review feedback on #956, which caught that removing only the pt
`anonymousDataSharing` block left the ATT permission modal saying
"compartilhamento de dados anônimos" — the exact term this PR retires. A
Portuguese user toggling the setting saw the modal contradict the (English
fallback) toggle description, and still saw "anonymous", which is the
inaccuracy the change exists to fix.
Fixed by translating rather than deleting, so Portuguese users stay in
Portuguese:
- Restored `preferences.usageDataSharing` in pt with Brazilian Portuguese
for title + description.
- `permissionModal.enable.description` and `.disable.description`:
"compartilhamento de dados anônimos" -> "compartilhamento de dados de uso",
matching the en strings this PR already aligned.
The reviewer's suggested fix was to delete the two modal descriptions too
and let `fallbackLng: "en"` cover them. That resolves the contradiction but
regresses two already-translated strings to English; since the toggle copy
needed pt anyway, translating all four keeps the screen in one language.
Copy is byte-identical to stellar/freighter#2922 (extension) for all four
en/pt strings, verified programmatically — these two PRs exist to make the
disclosure consistent across platforms, so drift between them would defeat
the point. Terminology follows the existing catalog: "Política de
Privacidade", "chave pública", "dispositivo", "carteira", "extensão", and
the "o Freighter" article convention.
Verified: 940/940 en/pt leaf-key parity (was 938/940 on this branch, so the
gap this PR opened is closed); zero occurrences of "anônim" left in pt and
zero of "anonymous" in en; `yarn lint:translations` reports no
missing-translations errors; `yarn lint:ts` clean; prettier clean; 13 tests
pass across PreferencesScreen.test.tsx and ducks/preferences.test.ts.
The 6 `import/order` errors from `lint:translations` are pre-existing on
main in parseTransaction.ts / buildAuthJwt.ts / deriveAuthKeypair.ts and
unrelated to this change — confirmed by running eslint on those files at
main.
Co-Authored-By: Claude Opus 5 (1M context)
---------
Co-authored-by: Claude Opus 4.8 (1M context)
---
.../PreferencesScreen/PreferencesScreen.tsx | 4 ++--
src/i18n/locales/en/translations.json | 10 +++++-----
src/i18n/locales/pt/translations.json | 10 +++++-----
3 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/src/components/screens/SettingsScreen/PreferencesScreen/PreferencesScreen.tsx b/src/components/screens/SettingsScreen/PreferencesScreen/PreferencesScreen.tsx
index 7feb590a8..c31972d0f 100644
--- a/src/components/screens/SettingsScreen/PreferencesScreen/PreferencesScreen.tsx
+++ b/src/components/screens/SettingsScreen/PreferencesScreen/PreferencesScreen.tsx
@@ -98,9 +98,9 @@ const PreferencesScreen: React.FC = () => {
const preferencesItems: PreferenceListItem[] = useMemo(
() => [
{
- title: t("preferences.anonymousDataSharing.title"),
+ title: t("preferences.usageDataSharing.title"),
titleColor: themeColors.text.primary,
- description: t("preferences.anonymousDataSharing.description"),
+ description: t("preferences.usageDataSharing.description"),
trailingContent: renderAnalyticsToggle(),
testID: "anonymous-data-sharing-item",
},
diff --git a/src/i18n/locales/en/translations.json b/src/i18n/locales/en/translations.json
index a774a525b..02514ace2 100644
--- a/src/i18n/locales/en/translations.json
+++ b/src/i18n/locales/en/translations.json
@@ -85,19 +85,19 @@
"deleteAccountConfirmMessage": "Make sure you have your recovery phrase in a safe place. You will not be able to recover your wallet without it."
},
"preferences": {
- "anonymousDataSharing": {
- "title": "Anonymous data sharing",
- "description": "Allow Freighter to collect limited information about usage. We will collect public keys, transaction amounts, and balances. This information will not be used for marketing or to identify you personally. We will not collect information such as name, address, email addresses, phone numbers, etc."
+ "usageDataSharing": {
+ "title": "Usage data sharing",
+ "description": "Help us improve Freighter by sharing usage, device, and activity data, including your public keys, IP address, and a persistent ID that links your wallet across extension and mobile, with our analytics and crash-reporting providers. You can turn this off at any time. See our Privacy Policy for details."
},
"permissionModal": {
"enable": {
"title": "Enable Analytics",
- "description": "To enable anonymous data sharing, you'll need to allow tracking permissions in your device settings.",
+ "description": "To enable usage data sharing, you'll need to allow tracking permissions in your device settings.",
"instruction": "Tap \"Open Settings\" below, then find Freighter and enable \"Allow Tracking\"."
},
"disable": {
"title": "Disable Analytics",
- "description": "To disable anonymous data sharing, you'll need to change tracking permissions in your device settings.",
+ "description": "To disable usage data sharing, you'll need to change tracking permissions in your device settings.",
"instruction": "Tap \"Open Settings\" below, then find Freighter and disable \"Allow Tracking\"."
},
"openSettings": "Open Settings",
diff --git a/src/i18n/locales/pt/translations.json b/src/i18n/locales/pt/translations.json
index 7f167fabd..95ce6607a 100644
--- a/src/i18n/locales/pt/translations.json
+++ b/src/i18n/locales/pt/translations.json
@@ -85,19 +85,19 @@
"deleteAccountConfirmMessage": "Certifique-se de que você tem sua frase de recuperação em um local seguro. Você não conseguirá recuperar sua carteira sem ela."
},
"preferences": {
- "anonymousDataSharing": {
- "title": "Compartilhamento de dados anônimos",
- "description": "Permitir que o Freighter colete informações limitadas sobre o uso. Coletaremos chaves públicas, valores de transações e saldos. Essas informações não serão usadas para marketing ou para identificar você pessoalmente. Não coletaremos informações como nome, endereço, e-mails, números de telefone, etc."
+ "usageDataSharing": {
+ "title": "Compartilhamento de dados de uso",
+ "description": "Ajude-nos a melhorar o Freighter compartilhando dados de uso, do dispositivo e de atividade — incluindo suas chaves públicas, endereço IP e um ID persistente que vincula sua carteira entre a extensão e o aplicativo móvel — com nossos provedores de análise de dados e de relatórios de falhas. Você pode desativar essa opção a qualquer momento. Consulte nossa Política de Privacidade para mais detalhes."
},
"permissionModal": {
"enable": {
"title": "Habilitar Analytics",
- "description": "Para habilitar o compartilhamento de dados anônimos, você precisará permitir permissões de rastreamento nas configurações do seu dispositivo.",
+ "description": "Para habilitar o compartilhamento de dados de uso, você precisará permitir permissões de rastreamento nas configurações do seu dispositivo.",
"instruction": "Toque em \"Abrir Configurações\" abaixo, depois encontre Freighter e habilite \"Permitir Rastreamento\"."
},
"disable": {
"title": "Desabilitar Analytics",
- "description": "Para desabilitar o compartilhamento de dados anônimos, você precisará alterar as permissões de rastreamento nas configurações do seu dispositivo.",
+ "description": "Para desabilitar o compartilhamento de dados de uso, você precisará alterar as permissões de rastreamento nas configurações do seu dispositivo.",
"instruction": "Toque em \"Abrir Configurações\" abaixo, depois encontre Freighter e desabilite \"Permitir Rastreamento\"."
},
"openSettings": "Abrir Configurações",