diff --git a/android/app/build.gradle b/android/app/build.gradle
index 6a1c42629..9e81b1bed 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -79,8 +79,8 @@ android {
applicationId "network.hathor.wallet"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
- versionCode 85
- versionName "0.30.1-rc.1"
+ versionCode 86
+ versionName "0.30.1"
missingDimensionStrategy "react-native-camera", "general"
}
signingConfigs {
diff --git a/ios/HathorMobile.xcodeproj/project.pbxproj b/ios/HathorMobile.xcodeproj/project.pbxproj
index bb3252289..02a9e022a 100644
--- a/ios/HathorMobile.xcodeproj/project.pbxproj
+++ b/ios/HathorMobile.xcodeproj/project.pbxproj
@@ -476,7 +476,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = HathorMobile/HathorMobile.entitlements;
- CURRENT_PROJECT_VERSION = 0.1.0;
+ CURRENT_PROJECT_VERSION = 1.0.0;
DEVELOPMENT_TEAM = 55SHY647CG;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = HathorMobile/Info.plist;
@@ -506,7 +506,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = HathorMobile/HathorMobile.entitlements;
- CURRENT_PROJECT_VERSION = 0.1.0;
+ CURRENT_PROJECT_VERSION = 1.0.0;
DEVELOPMENT_TEAM = 55SHY647CG;
INFOPLIST_FILE = HathorMobile/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
diff --git a/locale/da/texts.po b/locale/da/texts.po
index 70359a8a6..ec327d2e0 100644
--- a/locale/da/texts.po
+++ b/locale/da/texts.po
@@ -57,11 +57,11 @@ msgid "[Last] dddd [•] HH:mm"
msgstr "[Sidste] dddd [•] HH:mm"
#. See https://momentjs.com/docs/#/displaying/calendar-time/
-#: src/models.js:107 src/utils.js:553
+#: src/models.js:107 src/utils.js:567
msgid "DD MMM YYYY [•] HH:mm"
msgstr "DD MMM YYYY [•] HH:mm"
-#: src/utils.js:227
+#: src/utils.js:241
msgid "Invalid address"
msgstr "Ugyldig adresse"
@@ -340,20 +340,16 @@ msgid "E.g. HTR"
msgstr "F.eks. HTR"
#. Only show the toggle button when Nano Contract is enabled to the wallet
-#: src/screens/Dashboard.js:130 src/screens/Dashboard.js:187
+#: src/screens/Dashboard.js:131 src/screens/Dashboard.js:186
msgid "Tokens"
msgstr "Tokens"
#. Only show the toggle button when Nano Contract is enabled to the wallet
#: src/components/NanoContract/NanoContractsList.js:75
-#: src/screens/Dashboard.js:131
+#: src/screens/Dashboard.js:132
msgid "Nano Contracts"
msgstr ""
-#: src/screens/Dashboard.js:178 src/screens/RegisterTokenManual.js:147
-msgid "Register token"
-msgstr "Registrer token"
-
#: src/screens/InitWallet.js:62
msgid "Welcome to Hathor Wallet!"
msgstr "Velkommen til Hathor Wallet!"
@@ -438,7 +434,7 @@ msgstr "Indtast dine seed-ord adskilt med mellemrum"
#: src/components/NanoContract/NanoContractDetails.js:238
#: src/components/Reown/CreateTokenRequest.js:197
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:358
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:399
#: src/screens/LoadHistoryScreen.js:51 src/screens/LoadWalletErrorScreen.js:20
#: src/screens/NanoContract/NanoContractRegisterScreen.js:168
#: src/screens/PinScreen.js:285
@@ -499,13 +495,14 @@ msgstr "Låst"
#. translator: Used when the QR Code Scanner is opened, and user will manually
#. enter the information.
#: src/screens/NanoContractRegisterQrCodeScreen.js:26
-#: src/screens/Reown/ReownScan.js:41
+#: src/screens/Reown/ReownScan.js:41 src/screens/UnifiedQRScanner.js:88
msgid "Manual"
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:260
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:289
#: src/screens/NanoContract/NanoContractRegisterScreen.js:233
#: src/screens/NanoContractRegisterQrCodeScreen.js:48
+#: src/screens/RegisterOptionsScreen.js:77
msgid "Register Nano Contract"
msgstr ""
@@ -551,11 +548,11 @@ msgstr "Venter på bekræftelse"
msgid "Incorrect PIN Code. Try again."
msgstr "Forkert PIN-kode. Prøv igen."
-#: src/screens/PinScreen.js:77
+#: src/screens/PinScreen.js:76
msgid "Enter your PIN Code "
msgstr "Indtast din pinkode "
-#: src/screens/PinScreen.js:78
+#: src/screens/PinScreen.js:77
msgid "Unlock Hathor Wallet"
msgstr "Lås Hathor-wallet op"
@@ -604,6 +601,54 @@ msgstr "Betalingsanmodning"
msgid "RECEIVE"
msgstr "MODTAG"
+#: src/screens/RegisterOptionsScreen.js:26
+msgid "You can register Tokens manually."
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:30
+msgid "You can register Tokens and Nano Contracts manually."
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:34
+msgid "You can register Tokens and use Reown manually."
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:37
+msgid "You can register Tokens, Nano Contracts or Reown manually."
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:43
+#: src/screens/RegisterOptionsScreen.js:55 src/screens/UnifiedQRScanner.js:52
+#: src/screens/UnifiedQRScanner.js:69
+msgid "Feature Not Available"
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:44 src/screens/UnifiedQRScanner.js:69
+msgid "The nano contract feature is not enabled."
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:45
+#: src/screens/RegisterOptionsScreen.js:57 src/screens/SendScanQRCode.js:39
+#: src/screens/UnifiedQRScanner.js:36
+msgid "OK"
+msgstr "Okay"
+
+#: src/screens/RegisterOptionsScreen.js:56 src/screens/UnifiedQRScanner.js:52
+msgid "The reown feature is not enabled."
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:67
+msgid "Register"
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:83
+msgid "Register Token"
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:89
+msgid "Reown Connection"
+msgstr ""
+
#. translator: Used when the QR Code Scanner is opened, and user will manually
#. enter the information.
#: src/screens/RegisterToken.js:27 src/screens/SendScanQRCode.js:87
@@ -634,6 +679,10 @@ msgstr "Symbol: "
msgid "Configuration string"
msgstr "Konfigurationsstreng"
+#: src/screens/RegisterTokenManual.js:147
+msgid "Register token"
+msgstr "Registrer token"
+
#: src/screens/ResetWallet.js:104
msgid "RESET WALLET"
msgstr "NULSTIL WALLET"
@@ -669,36 +718,36 @@ msgstr ""
msgid "Reset Wallet"
msgstr "Nulstil wallet"
-#: src/screens/Security.js:131
+#: src/screens/Security.js:130
msgid "Disable biometry"
msgstr "Deaktiver biometri"
-#: src/screens/Security.js:132
+#: src/screens/Security.js:131
msgid "Disabling biometry"
msgstr "Deaktiverer biometri"
-#: src/screens/Security.js:144
+#: src/screens/Security.js:143
msgid "Enter your 6-digit pin to enable biometry"
msgstr "Indtast din 6-cifrede pin for at aktivere biometri"
-#: src/screens/Security.js:155
+#: src/screens/Security.js:156
msgid "No biometry supported"
msgstr "Ingen biometri understøttet"
-#: src/screens/Security.js:155
+#: src/screens/Security.js:156
#, javascript-format
msgid "Use ${ this.supportedBiometry }"
msgstr "Brug ${ this.supportedBiometry }"
-#: src/screens/Security.js:160
+#: src/screens/Security.js:164
msgid "SECURITY"
msgstr "SIKKERHED"
-#: src/screens/Security.js:184
+#: src/screens/Security.js:186
msgid "Change PIN"
msgstr "Skift pinkode"
-#: src/screens/Security.js:189
+#: src/screens/Security.js:191
msgid "Lock wallet"
msgstr "Lås wallet"
@@ -758,16 +807,13 @@ msgstr "Send"
msgid "Invalid QR code"
msgstr "Ugyldig QR-kode"
-#: src/screens/SendScanQRCode.js:39
-msgid "OK"
-msgstr "Okay"
-
#: src/screens/SendScanQRCode.js:71
#, javascript-format
msgid "You don't have the requested token [${ tokenLabel }]"
msgstr "Du har ikke den anmodede token [${ tokenLabel }]"
#: src/screens/Reown/ReownScan.js:49 src/screens/SendScanQRCode.js:103
+#: src/screens/UnifiedQRScanner.js:96
msgid "Scan the QR code"
msgstr "Scan QR-koden"
@@ -815,6 +861,20 @@ msgstr ""
msgid "Unregister"
msgstr "Afmeld"
+#. If none of the patterns match, show an error or handle accordingly
+#: src/screens/UnifiedQRScanner.js:77
+msgid "Invalid QR Code"
+msgstr ""
+
+#. If none of the patterns match, show an error or handle accordingly
+#: src/screens/UnifiedQRScanner.js:77
+msgid "The scanned QR code is not in a recognized format."
+msgstr ""
+
+#: src/screens/UnifiedQRScanner.js:83
+msgid "Scan QR Code"
+msgstr ""
+
#: src/screens/UnregisterToken.js:108
msgid "UNREGISTER TOKEN"
msgstr "AFREGISTRER TOKEN"
@@ -1012,8 +1072,8 @@ msgstr ""
#: src/components/NanoContract/NanoContractDetails.js:202
#: src/components/NanoContract/SelectAddressModal.js:105
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:243
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:284
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:272
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:313
#: src/screens/NanoContract/NanoContractRegisterScreen.js:184
msgid "Loading"
msgstr ""
@@ -1145,21 +1205,21 @@ msgstr ""
msgid "Error loading the details of some tokens."
msgstr ""
-#: src/sagas/wallet.js:805
+#: src/sagas/wallet.js:781
msgid "Wallet is not ready to load addresses."
msgstr ""
#. This will show the message in the feedback content at SelectAddressModal
-#: src/sagas/wallet.js:821
+#: src/sagas/wallet.js:797
msgid "There was an error while loading wallet addresses. Try again."
msgstr ""
-#: src/sagas/wallet.js:831
+#: src/sagas/wallet.js:807
msgid "Wallet is not ready to load the first address."
msgstr ""
#. This will show the message in the feedback content
-#: src/sagas/wallet.js:847
+#: src/sagas/wallet.js:823
msgid "There was an error while loading first wallet address. Try again."
msgstr ""
@@ -1466,12 +1526,12 @@ msgid "Decline Request"
msgstr ""
#: src/components/Reown/CreateTokenRequest.js:172
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:294
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:323
msgid "Sending transaction"
msgstr ""
#: src/components/Reown/CreateTokenRequest.js:173
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:295
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:324
msgid "Please wait."
msgstr ""
@@ -1610,47 +1670,57 @@ msgstr ""
msgid "Review transaction details"
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:205
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:234
msgid "Success!"
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:206
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:235
msgid "Transaction successfully sent."
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:244
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:273
msgid "Registering Nano Contract."
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:253
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:282
msgid "Nano Contract Not Found"
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:254
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:283
msgid ""
"The Nano Contract requested is not registered. First register the Nano "
"Contract to interact with it."
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:265
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:279
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:330
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:294
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:308
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:371
msgid "Decline Transaction"
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:277
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:306
msgid "Error while registering Nano Contract."
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:285
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:314
msgid "Loading transaction information."
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:326
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:358
+msgid "Insufficient Funds"
+msgstr ""
+
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:359
+msgid ""
+"Ensure your wallet balance covers the required amount to accept this "
+"transaction."
+msgstr ""
+
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:364
msgid "Accept Transaction"
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:356
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:397
msgid "Error while sending transaction."
msgstr ""
@@ -1754,11 +1824,11 @@ msgstr ""
msgid "See transaction details"
msgstr ""
-#: src/components/NanoContract/NanoContractsList.js:85
+#: src/components/NanoContract/NanoContractsList.js:82
msgid "No Nano Contracts"
msgstr ""
-#: src/components/NanoContract/NanoContractsList.js:86
+#: src/components/NanoContract/NanoContractsList.js:83
msgid ""
"You can keep track of your registered Nano Contracts here once you have "
"registered them."
diff --git a/locale/pt-br/texts.po b/locale/pt-br/texts.po
index 01e276396..2ebd22313 100644
--- a/locale/pt-br/texts.po
+++ b/locale/pt-br/texts.po
@@ -57,11 +57,11 @@ msgid "[Last] dddd [•] HH:mm"
msgstr "[Última] dddd [•] HH:mm"
#. See https://momentjs.com/docs/#/displaying/calendar-time/
-#: src/models.js:107 src/utils.js:553
+#: src/models.js:107 src/utils.js:567
msgid "DD MMM YYYY [•] HH:mm"
msgstr "DD MMM YYYY [•] HH:mm"
-#: src/utils.js:227
+#: src/utils.js:241
msgid "Invalid address"
msgstr "Endereço inválido"
@@ -349,20 +349,16 @@ msgid "E.g. HTR"
msgstr "Por exemplo, HTR"
#. Only show the toggle button when Nano Contract is enabled to the wallet
-#: src/screens/Dashboard.js:130 src/screens/Dashboard.js:187
+#: src/screens/Dashboard.js:131 src/screens/Dashboard.js:186
msgid "Tokens"
msgstr "Tokens"
#. Only show the toggle button when Nano Contract is enabled to the wallet
#: src/components/NanoContract/NanoContractsList.js:75
-#: src/screens/Dashboard.js:131
+#: src/screens/Dashboard.js:132
msgid "Nano Contracts"
msgstr "Nano Contracts"
-#: src/screens/Dashboard.js:178 src/screens/RegisterTokenManual.js:147
-msgid "Register token"
-msgstr "Registrar um token"
-
#: src/screens/InitWallet.js:62
msgid "Welcome to Hathor Wallet!"
msgstr "Bem vindo à Hathor Wallet!"
@@ -449,7 +445,7 @@ msgstr "Digite suas palavras separadas por espaços"
#: src/components/NanoContract/NanoContractDetails.js:238
#: src/components/Reown/CreateTokenRequest.js:197
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:358
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:399
#: src/screens/LoadHistoryScreen.js:51 src/screens/LoadWalletErrorScreen.js:20
#: src/screens/NanoContract/NanoContractRegisterScreen.js:168
#: src/screens/PinScreen.js:285
@@ -512,13 +508,14 @@ msgstr "Bloqueado"
#. translator: Used when the QR Code Scanner is opened, and user will manually
#. enter the information.
#: src/screens/NanoContractRegisterQrCodeScreen.js:26
-#: src/screens/Reown/ReownScan.js:41
+#: src/screens/Reown/ReownScan.js:41 src/screens/UnifiedQRScanner.js:88
msgid "Manual"
msgstr "Digitar"
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:260
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:289
#: src/screens/NanoContract/NanoContractRegisterScreen.js:233
#: src/screens/NanoContractRegisterQrCodeScreen.js:48
+#: src/screens/RegisterOptionsScreen.js:77
msgid "Register Nano Contract"
msgstr "Registrar Nano Contract"
@@ -564,11 +561,11 @@ msgstr "Aguardando confirmação"
msgid "Incorrect PIN Code. Try again."
msgstr "PIN incorreto. Tente novamente."
-#: src/screens/PinScreen.js:77
+#: src/screens/PinScreen.js:76
msgid "Enter your PIN Code "
msgstr "Digite seu PIN "
-#: src/screens/PinScreen.js:78
+#: src/screens/PinScreen.js:77
msgid "Unlock Hathor Wallet"
msgstr "Desbloqueie sua Hathor Wallet"
@@ -619,6 +616,54 @@ msgstr "Requisição de Pagamento"
msgid "RECEIVE"
msgstr "RECEBER"
+#: src/screens/RegisterOptionsScreen.js:26
+msgid "You can register Tokens manually."
+msgstr "Você pode registrar Tokens manualmente."
+
+#: src/screens/RegisterOptionsScreen.js:30
+msgid "You can register Tokens and Nano Contracts manually."
+msgstr "Você pode registrar Tokens e Nano Contracts manualmente."
+
+#: src/screens/RegisterOptionsScreen.js:34
+msgid "You can register Tokens and use Reown manually."
+msgstr "Você pode registrar Tokens e usar o Reown manualmente."
+
+#: src/screens/RegisterOptionsScreen.js:37
+msgid "You can register Tokens, Nano Contracts or Reown manually."
+msgstr "Você pode registrar Tokens, Nano Contracts ou o Reown manualmente."
+
+#: src/screens/RegisterOptionsScreen.js:43
+#: src/screens/RegisterOptionsScreen.js:55 src/screens/UnifiedQRScanner.js:52
+#: src/screens/UnifiedQRScanner.js:69
+msgid "Feature Not Available"
+msgstr "Funcionalidade não disponível."
+
+#: src/screens/RegisterOptionsScreen.js:44 src/screens/UnifiedQRScanner.js:69
+msgid "The nano contract feature is not enabled."
+msgstr "Nano Contracts não estão habilitados."
+
+#: src/screens/RegisterOptionsScreen.js:45
+#: src/screens/RegisterOptionsScreen.js:57 src/screens/SendScanQRCode.js:39
+#: src/screens/UnifiedQRScanner.js:36
+msgid "OK"
+msgstr "OK"
+
+#: src/screens/RegisterOptionsScreen.js:56 src/screens/UnifiedQRScanner.js:52
+msgid "The reown feature is not enabled."
+msgstr "Reown não está habilitado."
+
+#: src/screens/RegisterOptionsScreen.js:67
+msgid "Register"
+msgstr "Registrar"
+
+#: src/screens/RegisterOptionsScreen.js:83
+msgid "Register Token"
+msgstr "Registrar um token"
+
+#: src/screens/RegisterOptionsScreen.js:89
+msgid "Reown Connection"
+msgstr "Reown"
+
#. translator: Used when the QR Code Scanner is opened, and user will manually
#. enter the information.
#: src/screens/RegisterToken.js:27 src/screens/SendScanQRCode.js:87
@@ -649,6 +694,10 @@ msgstr "Símbolo: "
msgid "Configuration string"
msgstr "Configuração"
+#: src/screens/RegisterTokenManual.js:147
+msgid "Register token"
+msgstr "Registrar um token"
+
#: src/screens/ResetWallet.js:104
msgid "RESET WALLET"
msgstr "RESETAR WALLET"
@@ -685,36 +734,36 @@ msgstr ""
msgid "Reset Wallet"
msgstr "Resetar Wallet"
-#: src/screens/Security.js:131
+#: src/screens/Security.js:130
msgid "Disable biometry"
msgstr "Desativar biometria"
-#: src/screens/Security.js:132
+#: src/screens/Security.js:131
msgid "Disabling biometry"
msgstr "Desativando biometria"
-#: src/screens/Security.js:144
+#: src/screens/Security.js:143
msgid "Enter your 6-digit pin to enable biometry"
msgstr "Digite seu PIN de 6 dígitos para habilitar biometria"
-#: src/screens/Security.js:155
+#: src/screens/Security.js:156
msgid "No biometry supported"
msgstr "Nenhuma biometria suportada"
-#: src/screens/Security.js:155
+#: src/screens/Security.js:156
#, javascript-format
msgid "Use ${ this.supportedBiometry }"
msgstr "Usar ${ this.supportedBiometry }"
-#: src/screens/Security.js:160
+#: src/screens/Security.js:164
msgid "SECURITY"
msgstr "SEGURANÇA"
-#: src/screens/Security.js:184
+#: src/screens/Security.js:186
msgid "Change PIN"
msgstr "Mudar PIN"
-#: src/screens/Security.js:189
+#: src/screens/Security.js:191
msgid "Lock wallet"
msgstr "Bloquear a wallet"
@@ -774,16 +823,13 @@ msgstr "Enviar"
msgid "Invalid QR code"
msgstr "QR code inválido"
-#: src/screens/SendScanQRCode.js:39
-msgid "OK"
-msgstr "OK"
-
#: src/screens/SendScanQRCode.js:71
#, javascript-format
msgid "You don't have the requested token [${ tokenLabel }]"
msgstr "Você não tem o token requisitado [${ tokenLabel }]"
#: src/screens/Reown/ReownScan.js:49 src/screens/SendScanQRCode.js:103
+#: src/screens/UnifiedQRScanner.js:96
msgid "Scan the QR code"
msgstr "Leia o QR code"
@@ -831,6 +877,20 @@ msgstr "Configurações de Rede"
msgid "Unregister"
msgstr "Desregistrar"
+#. If none of the patterns match, show an error or handle accordingly
+#: src/screens/UnifiedQRScanner.js:77
+msgid "Invalid QR Code"
+msgstr "QR code inválido"
+
+#. If none of the patterns match, show an error or handle accordingly
+#: src/screens/UnifiedQRScanner.js:77
+msgid "The scanned QR code is not in a recognized format."
+msgstr "O QR code escaneado não está em um formato reconhecível."
+
+#: src/screens/UnifiedQRScanner.js:83
+msgid "Scan QR Code"
+msgstr "Leia o QR code"
+
#: src/screens/UnregisterToken.js:108
msgid "UNREGISTER TOKEN"
msgstr "DESREGISTRAR TOKEN"
@@ -1040,8 +1100,8 @@ msgstr "Erro ao carregar primeiro endereço da wallet"
#: src/components/NanoContract/NanoContractDetails.js:202
#: src/components/NanoContract/SelectAddressModal.js:105
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:243
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:284
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:272
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:313
#: src/screens/NanoContract/NanoContractRegisterScreen.js:184
msgid "Loading"
msgstr "Carregando"
@@ -1174,21 +1234,21 @@ msgstr "A wallet não está pronta ainda."
msgid "Error loading the details of some tokens."
msgstr "Ocorreu um erro durante o carregamento de detalhes de alguns tokens."
-#: src/sagas/wallet.js:805
+#: src/sagas/wallet.js:781
msgid "Wallet is not ready to load addresses."
msgstr "A wallet não está pronta para carregar os endereços."
#. This will show the message in the feedback content at SelectAddressModal
-#: src/sagas/wallet.js:821
+#: src/sagas/wallet.js:797
msgid "There was an error while loading wallet addresses. Try again."
msgstr "Ocorreu um erro ao carregar os endereços da wallet. Tente novamente."
-#: src/sagas/wallet.js:831
+#: src/sagas/wallet.js:807
msgid "Wallet is not ready to load the first address."
msgstr "A wallet não está pronta para carregar o primeiro endereço."
#. This will show the message in the feedback content
-#: src/sagas/wallet.js:847
+#: src/sagas/wallet.js:823
msgid "There was an error while loading first wallet address. Try again."
msgstr ""
"Ocorreu um erro ao carregar o primeiro endereço da wallet. Tente novamente."
@@ -1502,12 +1562,12 @@ msgid "Decline Request"
msgstr "Recusar Solicitação"
#: src/components/Reown/CreateTokenRequest.js:172
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:294
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:323
msgid "Sending transaction"
msgstr "Enviando transação"
#: src/components/Reown/CreateTokenRequest.js:173
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:295
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:324
msgid "Please wait."
msgstr "Por favor, espere."
@@ -1649,23 +1709,23 @@ msgstr ""
msgid "Review transaction details"
msgstr "Revisar detalhes da transação"
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:205
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:234
msgid "Success!"
msgstr "Sucesso!"
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:206
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:235
msgid "Transaction successfully sent."
msgstr "Transação enviada com sucesso."
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:244
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:273
msgid "Registering Nano Contract."
msgstr "Registrando Nano Contract"
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:253
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:282
msgid "Nano Contract Not Found"
msgstr "Nano Contract não encontrado"
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:254
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:283
msgid ""
"The Nano Contract requested is not registered. First register the Nano "
"Contract to interact with it."
@@ -1673,25 +1733,36 @@ msgstr ""
"O Nano Contract solicitado não está registrado. Primeiro registre o Nano "
"Contract para interagir com ele."
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:265
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:279
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:330
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:294
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:308
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:371
msgid "Decline Transaction"
msgstr "Recusar transação"
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:277
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:306
msgid "Error while registering Nano Contract."
msgstr "Erro ao tentar registrar o Nano Contract."
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:285
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:314
msgid "Loading transaction information."
msgstr "Carregando informações da transação."
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:326
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:358
+msgid "Insufficient Funds"
+msgstr "Saldo insuficiente"
+
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:359
+msgid ""
+"Ensure your wallet balance covers the required amount to accept this "
+"transaction."
+msgstr "Certifique-se de que o saldo da sua carteira cubra o valor necessário"
+"para aceitar esta transação."
+
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:364
msgid "Accept Transaction"
msgstr "Aceitar transação"
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:356
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:397
msgid "Error while sending transaction."
msgstr "Ocorreu um erro durante o envio da transação."
@@ -1797,11 +1868,11 @@ msgstr "Desta wallet"
msgid "See transaction details"
msgstr "Ver detalhes"
-#: src/components/NanoContract/NanoContractsList.js:85
+#: src/components/NanoContract/NanoContractsList.js:82
msgid "No Nano Contracts"
msgstr "Nenhum Nano Contract"
-#: src/components/NanoContract/NanoContractsList.js:86
+#: src/components/NanoContract/NanoContractsList.js:83
msgid ""
"You can keep track of your registered Nano Contracts here once you have "
"registered them."
diff --git a/locale/ru-ru/texts.po b/locale/ru-ru/texts.po
index b4716b8f4..68b671187 100644
--- a/locale/ru-ru/texts.po
+++ b/locale/ru-ru/texts.po
@@ -58,11 +58,11 @@ msgid "[Last] dddd [•] HH:mm"
msgstr "[Последний] dddd [•] HH:mm"
#. See https://momentjs.com/docs/#/displaying/calendar-time/
-#: src/models.js:107 src/utils.js:553
+#: src/models.js:107 src/utils.js:567
msgid "DD MMM YYYY [•] HH:mm"
msgstr "DD MMM YYYY [•] HH:mm"
-#: src/utils.js:227
+#: src/utils.js:241
msgid "Invalid address"
msgstr "Неправильный адрес"
@@ -341,20 +341,16 @@ msgid "E.g. HTR"
msgstr "Например, HTR"
#. Only show the toggle button when Nano Contract is enabled to the wallet
-#: src/screens/Dashboard.js:130 src/screens/Dashboard.js:187
+#: src/screens/Dashboard.js:131 src/screens/Dashboard.js:186
msgid "Tokens"
msgstr "ТокенЫ"
#. Only show the toggle button when Nano Contract is enabled to the wallet
#: src/components/NanoContract/NanoContractsList.js:75
-#: src/screens/Dashboard.js:131
+#: src/screens/Dashboard.js:132
msgid "Nano Contracts"
msgstr ""
-#: src/screens/Dashboard.js:178 src/screens/RegisterTokenManual.js:147
-msgid "Register token"
-msgstr "Зарегистрировать токен"
-
#: src/screens/InitWallet.js:62
msgid "Welcome to Hathor Wallet!"
msgstr "Добро пожаловать в Hathor Wallet!"
@@ -439,7 +435,7 @@ msgstr "Введите seed-фразу"
#: src/components/NanoContract/NanoContractDetails.js:238
#: src/components/Reown/CreateTokenRequest.js:197
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:358
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:399
#: src/screens/LoadHistoryScreen.js:51 src/screens/LoadWalletErrorScreen.js:20
#: src/screens/NanoContract/NanoContractRegisterScreen.js:168
#: src/screens/PinScreen.js:285
@@ -501,13 +497,14 @@ msgstr "Заблокированный"
#. translator: Used when the QR Code Scanner is opened, and user will manually
#. enter the information.
#: src/screens/NanoContractRegisterQrCodeScreen.js:26
-#: src/screens/Reown/ReownScan.js:41
+#: src/screens/Reown/ReownScan.js:41 src/screens/UnifiedQRScanner.js:88
msgid "Manual"
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:260
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:289
#: src/screens/NanoContract/NanoContractRegisterScreen.js:233
#: src/screens/NanoContractRegisterQrCodeScreen.js:48
+#: src/screens/RegisterOptionsScreen.js:77
msgid "Register Nano Contract"
msgstr ""
@@ -553,11 +550,11 @@ msgstr "Ожидание подтверждения"
msgid "Incorrect PIN Code. Try again."
msgstr "Неверный PIN-код. Попробуйте еще раз."
-#: src/screens/PinScreen.js:77
+#: src/screens/PinScreen.js:76
msgid "Enter your PIN Code "
msgstr "Введите свой PIN-код "
-#: src/screens/PinScreen.js:78
+#: src/screens/PinScreen.js:77
msgid "Unlock Hathor Wallet"
msgstr "Разблокировать Hathor Wallet"
@@ -606,6 +603,54 @@ msgstr "Запрос Средств"
msgid "RECEIVE"
msgstr "ПОЛУЧИТЬ"
+#: src/screens/RegisterOptionsScreen.js:26
+msgid "You can register Tokens manually."
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:30
+msgid "You can register Tokens and Nano Contracts manually."
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:34
+msgid "You can register Tokens and use Reown manually."
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:37
+msgid "You can register Tokens, Nano Contracts or Reown manually."
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:43
+#: src/screens/RegisterOptionsScreen.js:55 src/screens/UnifiedQRScanner.js:52
+#: src/screens/UnifiedQRScanner.js:69
+msgid "Feature Not Available"
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:44 src/screens/UnifiedQRScanner.js:69
+msgid "The nano contract feature is not enabled."
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:45
+#: src/screens/RegisterOptionsScreen.js:57 src/screens/SendScanQRCode.js:39
+#: src/screens/UnifiedQRScanner.js:36
+msgid "OK"
+msgstr "OK"
+
+#: src/screens/RegisterOptionsScreen.js:56 src/screens/UnifiedQRScanner.js:52
+msgid "The reown feature is not enabled."
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:67
+msgid "Register"
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:83
+msgid "Register Token"
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:89
+msgid "Reown Connection"
+msgstr ""
+
#. translator: Used when the QR Code Scanner is opened, and user will manually
#. enter the information.
#: src/screens/RegisterToken.js:27 src/screens/SendScanQRCode.js:87
@@ -636,6 +681,10 @@ msgstr "Символ: "
msgid "Configuration string"
msgstr "Конфигурация"
+#: src/screens/RegisterTokenManual.js:147
+msgid "Register token"
+msgstr "Зарегистрировать токен"
+
#: src/screens/ResetWallet.js:104
msgid "RESET WALLET"
msgstr "СБРОСИТЬ КОШЕЛЕК"
@@ -670,36 +719,36 @@ msgstr ""
msgid "Reset Wallet"
msgstr "Сбросить Кошелек"
-#: src/screens/Security.js:131
+#: src/screens/Security.js:130
msgid "Disable biometry"
msgstr "Отключить биометрию"
-#: src/screens/Security.js:132
+#: src/screens/Security.js:131
msgid "Disabling biometry"
msgstr "Отключение биометрии"
-#: src/screens/Security.js:144
+#: src/screens/Security.js:143
msgid "Enter your 6-digit pin to enable biometry"
msgstr "Введите 6-значный PIN-код, чтобы включить биометрию"
-#: src/screens/Security.js:155
+#: src/screens/Security.js:156
msgid "No biometry supported"
msgstr "Биометрия не поддерживается"
-#: src/screens/Security.js:155
+#: src/screens/Security.js:156
#, javascript-format
msgid "Use ${ this.supportedBiometry }"
msgstr "Использовать ${ this.supportedBiometry }"
-#: src/screens/Security.js:160
+#: src/screens/Security.js:164
msgid "SECURITY"
msgstr "БЕЗОПАСНОСТЬ"
-#: src/screens/Security.js:184
+#: src/screens/Security.js:186
msgid "Change PIN"
msgstr "Изменить PIN-код"
-#: src/screens/Security.js:189
+#: src/screens/Security.js:191
msgid "Lock wallet"
msgstr "Заблокировать кошелек"
@@ -760,16 +809,13 @@ msgstr "Отправить"
msgid "Invalid QR code"
msgstr "Неверный QR-код"
-#: src/screens/SendScanQRCode.js:39
-msgid "OK"
-msgstr "OK"
-
#: src/screens/SendScanQRCode.js:71
#, javascript-format
msgid "You don't have the requested token [${ tokenLabel }]"
msgstr "У вас нет запрошенного токена [${ tokenLabel }]"
#: src/screens/Reown/ReownScan.js:49 src/screens/SendScanQRCode.js:103
+#: src/screens/UnifiedQRScanner.js:96
msgid "Scan the QR code"
msgstr "Сканировать QR-код"
@@ -817,6 +863,20 @@ msgstr ""
msgid "Unregister"
msgstr "Отменить регистрацию"
+#. If none of the patterns match, show an error or handle accordingly
+#: src/screens/UnifiedQRScanner.js:77
+msgid "Invalid QR Code"
+msgstr ""
+
+#. If none of the patterns match, show an error or handle accordingly
+#: src/screens/UnifiedQRScanner.js:77
+msgid "The scanned QR code is not in a recognized format."
+msgstr ""
+
+#: src/screens/UnifiedQRScanner.js:83
+msgid "Scan QR Code"
+msgstr ""
+
#: src/screens/UnregisterToken.js:108
msgid "UNREGISTER TOKEN"
msgstr "ОТМЕНИТЬ РЕГИСТРАЦИЮ ТОКЕНА"
@@ -1016,8 +1076,8 @@ msgstr ""
#: src/components/NanoContract/NanoContractDetails.js:202
#: src/components/NanoContract/SelectAddressModal.js:105
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:243
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:284
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:272
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:313
#: src/screens/NanoContract/NanoContractRegisterScreen.js:184
msgid "Loading"
msgstr ""
@@ -1149,21 +1209,21 @@ msgstr ""
msgid "Error loading the details of some tokens."
msgstr ""
-#: src/sagas/wallet.js:805
+#: src/sagas/wallet.js:781
msgid "Wallet is not ready to load addresses."
msgstr ""
#. This will show the message in the feedback content at SelectAddressModal
-#: src/sagas/wallet.js:821
+#: src/sagas/wallet.js:797
msgid "There was an error while loading wallet addresses. Try again."
msgstr ""
-#: src/sagas/wallet.js:831
+#: src/sagas/wallet.js:807
msgid "Wallet is not ready to load the first address."
msgstr ""
#. This will show the message in the feedback content
-#: src/sagas/wallet.js:847
+#: src/sagas/wallet.js:823
msgid "There was an error while loading first wallet address. Try again."
msgstr ""
@@ -1455,12 +1515,12 @@ msgid "Decline Request"
msgstr ""
#: src/components/Reown/CreateTokenRequest.js:172
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:294
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:323
msgid "Sending transaction"
msgstr ""
#: src/components/Reown/CreateTokenRequest.js:173
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:295
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:324
msgid "Please wait."
msgstr ""
@@ -1599,47 +1659,57 @@ msgstr ""
msgid "Review transaction details"
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:205
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:234
msgid "Success!"
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:206
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:235
msgid "Transaction successfully sent."
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:244
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:273
msgid "Registering Nano Contract."
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:253
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:282
msgid "Nano Contract Not Found"
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:254
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:283
msgid ""
"The Nano Contract requested is not registered. First register the Nano "
"Contract to interact with it."
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:265
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:279
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:330
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:294
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:308
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:371
msgid "Decline Transaction"
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:277
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:306
msgid "Error while registering Nano Contract."
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:285
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:314
msgid "Loading transaction information."
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:326
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:358
+msgid "Insufficient Funds"
+msgstr ""
+
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:359
+msgid ""
+"Ensure your wallet balance covers the required amount to accept this "
+"transaction."
+msgstr ""
+
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:364
msgid "Accept Transaction"
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:356
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:397
msgid "Error while sending transaction."
msgstr ""
@@ -1743,11 +1813,11 @@ msgstr ""
msgid "See transaction details"
msgstr ""
-#: src/components/NanoContract/NanoContractsList.js:85
+#: src/components/NanoContract/NanoContractsList.js:82
msgid "No Nano Contracts"
msgstr ""
-#: src/components/NanoContract/NanoContractsList.js:86
+#: src/components/NanoContract/NanoContractsList.js:83
msgid ""
"You can keep track of your registered Nano Contracts here once you have "
"registered them."
diff --git a/locale/texts.pot b/locale/texts.pot
index 04397ddc6..d35a25a3f 100644
--- a/locale/texts.pot
+++ b/locale/texts.pot
@@ -48,12 +48,12 @@ msgid "[Last] dddd [•] HH:mm"
msgstr ""
#: src/models.js:107
-#: src/utils.js:553
+#: src/utils.js:567
#. See https://momentjs.com/docs/#/displaying/calendar-time/
msgid "DD MMM YYYY [•] HH:mm"
msgstr ""
-#: src/utils.js:227
+#: src/utils.js:241
msgid "Invalid address"
msgstr ""
@@ -334,23 +334,18 @@ msgstr ""
msgid "E.g. HTR"
msgstr ""
-#: src/screens/Dashboard.js:130
-#: src/screens/Dashboard.js:187
+#: src/screens/Dashboard.js:131
+#: src/screens/Dashboard.js:186
#. Only show the toggle button when Nano Contract is enabled to the wallet
msgid "Tokens"
msgstr ""
#: src/components/NanoContract/NanoContractsList.js:75
-#: src/screens/Dashboard.js:131
+#: src/screens/Dashboard.js:132
#. Only show the toggle button when Nano Contract is enabled to the wallet
msgid "Nano Contracts"
msgstr ""
-#: src/screens/Dashboard.js:178
-#: src/screens/RegisterTokenManual.js:147
-msgid "Register token"
-msgstr ""
-
#: src/screens/InitWallet.js:62
msgid "Welcome to Hathor Wallet!"
msgstr ""
@@ -428,7 +423,7 @@ msgstr ""
#: src/components/NanoContract/NanoContractDetails.js:238
#: src/components/Reown/CreateTokenRequest.js:197
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:358
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:399
#: src/screens/LoadHistoryScreen.js:51
#: src/screens/LoadWalletErrorScreen.js:20
#: src/screens/NanoContract/NanoContractRegisterScreen.js:168
@@ -491,14 +486,16 @@ msgstr ""
#: src/screens/NanoContractRegisterQrCodeScreen.js:26
#: src/screens/Reown/ReownScan.js:41
+#: src/screens/UnifiedQRScanner.js:88
#. translator: Used when the QR Code Scanner is opened, and user will manually
#. enter the information.
msgid "Manual"
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:260
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:289
#: src/screens/NanoContract/NanoContractRegisterScreen.js:233
#: src/screens/NanoContractRegisterQrCodeScreen.js:48
+#: src/screens/RegisterOptionsScreen.js:77
msgid "Register Nano Contract"
msgstr ""
@@ -547,11 +544,11 @@ msgstr ""
msgid "Incorrect PIN Code. Try again."
msgstr ""
-#: src/screens/PinScreen.js:77
+#: src/screens/PinScreen.js:76
msgid "Enter your PIN Code "
msgstr ""
-#: src/screens/PinScreen.js:78
+#: src/screens/PinScreen.js:77
msgid "Unlock Hathor Wallet"
msgstr ""
@@ -603,6 +600,58 @@ msgstr ""
msgid "RECEIVE"
msgstr ""
+#: src/screens/RegisterOptionsScreen.js:26
+msgid "You can register Tokens manually."
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:30
+msgid "You can register Tokens and Nano Contracts manually."
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:34
+msgid "You can register Tokens and use Reown manually."
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:37
+msgid "You can register Tokens, Nano Contracts or Reown manually."
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:43
+#: src/screens/RegisterOptionsScreen.js:55
+#: src/screens/UnifiedQRScanner.js:52
+#: src/screens/UnifiedQRScanner.js:69
+msgid "Feature Not Available"
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:44
+#: src/screens/UnifiedQRScanner.js:69
+msgid "The nano contract feature is not enabled."
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:45
+#: src/screens/RegisterOptionsScreen.js:57
+#: src/screens/SendScanQRCode.js:39
+#: src/screens/UnifiedQRScanner.js:36
+msgid "OK"
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:56
+#: src/screens/UnifiedQRScanner.js:52
+msgid "The reown feature is not enabled."
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:67
+msgid "Register"
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:83
+msgid "Register Token"
+msgstr ""
+
+#: src/screens/RegisterOptionsScreen.js:89
+msgid "Reown Connection"
+msgstr ""
+
#: src/screens/RegisterToken.js:27
#: src/screens/SendScanQRCode.js:87
#. translator: Used when the QR Code Scanner is opened, and user will manually
@@ -635,6 +684,10 @@ msgstr ""
msgid "Configuration string"
msgstr ""
+#: src/screens/RegisterTokenManual.js:147
+msgid "Register token"
+msgstr ""
+
#: src/screens/ResetWallet.js:104
msgid "RESET WALLET"
msgstr ""
@@ -665,36 +718,36 @@ msgstr ""
msgid "Reset Wallet"
msgstr ""
-#: src/screens/Security.js:131
+#: src/screens/Security.js:130
msgid "Disable biometry"
msgstr ""
-#: src/screens/Security.js:132
+#: src/screens/Security.js:131
msgid "Disabling biometry"
msgstr ""
-#: src/screens/Security.js:144
+#: src/screens/Security.js:143
msgid "Enter your 6-digit pin to enable biometry"
msgstr ""
-#: src/screens/Security.js:155
+#: src/screens/Security.js:156
msgid "No biometry supported"
msgstr ""
-#: src/screens/Security.js:155
+#: src/screens/Security.js:156
#, javascript-format
msgid "Use ${ this.supportedBiometry }"
msgstr ""
-#: src/screens/Security.js:160
+#: src/screens/Security.js:164
msgid "SECURITY"
msgstr ""
-#: src/screens/Security.js:184
+#: src/screens/Security.js:186
msgid "Change PIN"
msgstr ""
-#: src/screens/Security.js:189
+#: src/screens/Security.js:191
msgid "Lock wallet"
msgstr ""
@@ -759,10 +812,6 @@ msgstr ""
msgid "Invalid QR code"
msgstr ""
-#: src/screens/SendScanQRCode.js:39
-msgid "OK"
-msgstr ""
-
#: src/screens/SendScanQRCode.js:71
#, javascript-format
msgid "You don't have the requested token [${ tokenLabel }]"
@@ -770,6 +819,7 @@ msgstr ""
#: src/screens/Reown/ReownScan.js:49
#: src/screens/SendScanQRCode.js:103
+#: src/screens/UnifiedQRScanner.js:96
msgid "Scan the QR code"
msgstr ""
@@ -817,6 +867,20 @@ msgstr ""
msgid "Unregister"
msgstr ""
+#: src/screens/UnifiedQRScanner.js:77
+#. If none of the patterns match, show an error or handle accordingly
+msgid "Invalid QR Code"
+msgstr ""
+
+#: src/screens/UnifiedQRScanner.js:77
+#. If none of the patterns match, show an error or handle accordingly
+msgid "The scanned QR code is not in a recognized format."
+msgstr ""
+
+#: src/screens/UnifiedQRScanner.js:83
+msgid "Scan QR Code"
+msgstr ""
+
#: src/screens/UnregisterToken.js:108
msgid "UNREGISTER TOKEN"
msgstr ""
@@ -1014,8 +1078,8 @@ msgstr ""
#: src/components/NanoContract/NanoContractDetails.js:202
#: src/components/NanoContract/SelectAddressModal.js:105
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:243
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:284
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:272
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:313
#: src/screens/NanoContract/NanoContractRegisterScreen.js:184
msgid "Loading"
msgstr ""
@@ -1147,20 +1211,20 @@ msgstr ""
msgid "Error loading the details of some tokens."
msgstr ""
-#: src/sagas/wallet.js:805
+#: src/sagas/wallet.js:781
msgid "Wallet is not ready to load addresses."
msgstr ""
-#: src/sagas/wallet.js:821
+#: src/sagas/wallet.js:797
#. This will show the message in the feedback content at SelectAddressModal
msgid "There was an error while loading wallet addresses. Try again."
msgstr ""
-#: src/sagas/wallet.js:831
+#: src/sagas/wallet.js:807
msgid "Wallet is not ready to load the first address."
msgstr ""
-#: src/sagas/wallet.js:847
+#: src/sagas/wallet.js:823
#. This will show the message in the feedback content
msgid "There was an error while loading first wallet address. Try again."
msgstr ""
@@ -1453,12 +1517,12 @@ msgid "Decline Request"
msgstr ""
#: src/components/Reown/CreateTokenRequest.js:172
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:294
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:323
msgid "Sending transaction"
msgstr ""
#: src/components/Reown/CreateTokenRequest.js:173
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:295
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:324
msgid "Please wait."
msgstr ""
@@ -1596,47 +1660,57 @@ msgstr ""
msgid "Review transaction details"
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:205
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:234
msgid "Success!"
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:206
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:235
msgid "Transaction successfully sent."
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:244
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:273
msgid "Registering Nano Contract."
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:253
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:282
msgid "Nano Contract Not Found"
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:254
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:283
msgid ""
"The Nano Contract requested is not registered. First register the Nano "
"Contract to interact with it."
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:265
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:279
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:330
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:294
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:308
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:371
msgid "Decline Transaction"
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:277
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:306
msgid "Error while registering Nano Contract."
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:285
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:314
msgid "Loading transaction information."
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:326
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:358
+msgid "Insufficient Funds"
+msgstr ""
+
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:359
+msgid ""
+"Ensure your wallet balance covers the required amount to accept this "
+"transaction."
+msgstr ""
+
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:364
msgid "Accept Transaction"
msgstr ""
-#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:356
+#: src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js:397
msgid "Error while sending transaction."
msgstr ""
@@ -1740,11 +1814,11 @@ msgstr ""
msgid "See transaction details"
msgstr ""
-#: src/components/NanoContract/NanoContractsList.js:85
+#: src/components/NanoContract/NanoContractsList.js:82
msgid "No Nano Contracts"
msgstr ""
-#: src/components/NanoContract/NanoContractsList.js:86
+#: src/components/NanoContract/NanoContractsList.js:83
msgid ""
"You can keep track of your registered Nano Contracts here once you have "
"registered them."
diff --git a/package-lock.json b/package-lock.json
index 66382c81e..28eeafb51 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "HathorMobile",
- "version": "0.30.1-rc.1",
+ "version": "0.30.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "HathorMobile",
- "version": "0.30.1-rc.1",
+ "version": "0.30.1",
"dependencies": {
"@ethersproject/shims": "5.7.0",
"@fortawesome/fontawesome-svg-core": "1.2.36",
diff --git a/package.json b/package.json
index 9f7adbc11..f233ffa72 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "HathorMobile",
- "version": "0.30.1-rc.1",
+ "version": "0.30.1",
"engines": {
"node": ">=18.0.0",
"npm": ">=9.0.0"
diff --git a/src/App.js b/src/App.js
index c4c7ec049..dffe58a36 100644
--- a/src/App.js
+++ b/src/App.js
@@ -97,6 +97,8 @@ import { SignMessageRequestScreen } from './screens/Reown/SignMessageRequestScre
import { SignOracleDataRequestScreen } from './screens/Reown/SignOracleDataRequestScreen';
import { CreateTokenRequestScreen } from './screens/Reown/CreateTokenScreen';
import { SuccessFeedbackScreen } from './screens/Reown/SuccessFeedbackScreen';
+import UnifiedQRScanner from './screens/UnifiedQRScanner';
+import RegisterOptionsScreen from './screens/RegisterOptionsScreen';
/**
* This Stack Navigator is exhibited when there is no wallet initialized on the local storage.
@@ -430,6 +432,9 @@ const AppStack = () => {
case 'CreateTokenStack':
case 'About':
case 'ResetWallet':
+ case 'UnifiedQRScanner':
+ case 'RegisterOptions':
+ case 'RegisterTokenManual':
newEdges = ['bottom'];
break;
default:
@@ -453,6 +458,9 @@ const AppStack = () => {
initialParams={{ hName: 'Main' }}
component={TabNavigator}
/>
+
+
+
diff --git a/src/actions.js b/src/actions.js
index a5a72a1da..fa0476daf 100644
--- a/src/actions.js
+++ b/src/actions.js
@@ -209,6 +209,7 @@ export const types = {
APPSTATE_UPDATED: 'APPSTATE_UPDATED',
SET_USE_SAFE_BIOMETRY_MODE: 'SET_USE_SAFE_BIOMETRY_MODE',
SHOW_SIGN_ORACLE_DATA_REQUEST_MODAL: 'SHOW_SIGN_ORACLE_DATA_REQUEST_MODAL',
+ SET_FULLNODE_NETWORK_NAME: 'SET_FULLNODE_NETWORK_NAME',
};
export const featureToggleInitialized = () => ({
@@ -398,11 +399,6 @@ export const setUseWalletService = (data) => ({
payload: data,
});
-export const setUseSafeBiometryMode = (data) => ({
- type: types.SET_USE_SAFE_BIOMETRY_MODE,
- payload: data,
-});
-
export const setUniqueDeviceId = (uniqueId) => ({
type: types.SET_UNIQUE_DEVICE_ID,
payload: uniqueId,
@@ -1512,3 +1508,11 @@ export const appStateUpdate = (oldState, newState) => ({
newState,
}
});
+
+/**
+ * @param {string} fullNodeNetworkName The name of the connected network.
+ */
+export const setFullNodeNetworkName = (fullNodeNetworkName) => ({
+ type: types.SET_FULLNODE_NETWORK_NAME,
+ payload: fullNodeNetworkName,
+});
diff --git a/src/components/Icons/QRCodeIcon.js b/src/components/Icons/QRCodeIcon.js
new file mode 100644
index 000000000..58b60aa3c
--- /dev/null
+++ b/src/components/Icons/QRCodeIcon.js
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) Hathor Labs and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import React from 'react';
+import Svg, { Path } from 'react-native-svg';
+import { COLORS } from '../../styles/themes';
+
+const QRCodeIcon = ({ size = 25, color = COLORS.primary }) => (
+
+);
+
+export default QRCodeIcon;
diff --git a/src/components/NanoContract/NanoContractsList.js b/src/components/NanoContract/NanoContractsList.js
index 418797083..8fc002d84 100644
--- a/src/components/NanoContract/NanoContractsList.js
+++ b/src/components/NanoContract/NanoContractsList.js
@@ -74,9 +74,6 @@ const Header = () => (
{t`Nano Contracts`}
-
-
-
);
@@ -96,7 +93,7 @@ const styles = StyleSheet.create({
backgroundColor: COLORS.lowContrastDetail, // Defines an outer area on the main list content
},
headerTitle: {
- fontSize: 24,
+ fontSize: 20,
lineHeight: 24,
fontWeight: 'bold',
},
diff --git a/src/components/NetworkSettings/NetworkStatusBar.js b/src/components/NetworkSettings/NetworkStatusBar.js
index ac4481877..d036abae7 100644
--- a/src/components/NetworkSettings/NetworkStatusBar.js
+++ b/src/components/NetworkSettings/NetworkStatusBar.js
@@ -48,10 +48,15 @@ const style = {
};
export const NetworkStatusBar = () => {
- const getStatusText = (networkSettings) => `${customNetworkText}: ${networkSettings.network}`;
- const networkSettings = useSelector((state) => state.networkSettings);
+ const { networkSettings, fullNodeNetworkName } = useSelector((state) => ({
+ networkSettings: state.networkSettings,
+ fullNodeNetworkName: state.fullNodeNetworkName,
+ }));
- return notMainnet(networkSettings) && (
-
+ const getStatusText = (name) => `${customNetworkText}: ${name}`;
+
+ // Only show the bar if we have a network name and we're not on mainnet
+ return fullNodeNetworkName && notMainnet(networkSettings) && (
+
);
};
diff --git a/src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js b/src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js
index d89e05ecc..ecf5e0d4a 100644
--- a/src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js
+++ b/src/components/Reown/NanoContract/NewNanoContractTransactionRequest.js
@@ -15,7 +15,8 @@ import {
View,
ScrollView,
TouchableWithoutFeedback,
- Image
+ Image,
+ Text
} from 'react-native';
import { useDispatch, useSelector } from 'react-redux';
import { useNavigation } from '@react-navigation/native';
@@ -70,6 +71,7 @@ export const NewNanoContractTransactionRequest = ({ ncTxRequest }) => {
// Nullable if the nano contract method is 'initialize'
const registeredNc = useSelector((state) => state.nanoContract.registered[nc.ncId]);
const knownTokens = useSelector((state) => ({ ...state.tokens, ...state.unregisteredTokens }));
+ const tokensBalance = useSelector((state) => state.tokensBalance);
const blueprintInfo = useSelector((state) => state.nanoContract.blueprint[nc.blueprintId]);
const registerStatus = useSelector((state) => state.nanoContract.registerStatus);
const isNcRegistering = (
@@ -94,6 +96,33 @@ export const NewNanoContractTransactionRequest = ({ ncTxRequest }) => {
caller: ncAddress,
}), [ncAddress])
+ // Check if we have enough balance for deposit actions
+ const hasInsufficientBalance = useMemo(() => {
+ if (!nc.actions) return false;
+
+ // Track running balance per token
+ const tokenBalances = {};
+
+ for (const { type, token, amount } of nc.actions) {
+ if (type === 'deposit') {
+ // Initialize token balance if first time seeing this token
+ if (!(token in tokenBalances)) {
+ const balance = tokensBalance[token]?.data?.available || 0;
+ tokenBalances[token] = balance;
+ }
+
+ tokenBalances[token] -= amount;
+
+ if (tokenBalances[token] < 0) {
+ // Early exit if we go negative
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }, [nc.actions, tokensBalance]);
+
const toggleSelectAddressModal = () => setShowSelectAddressModal(!showSelectAddressModal);
const handleAddressSelection = (newAddress) => {
setNcAddress(newAddress);
@@ -322,9 +351,21 @@ export const NewNanoContractTransactionRequest = ({ ncTxRequest }) => {
{/* User actions */}
+ {hasInsufficientBalance && (
+
+ ⚠
+
+ {t`Insufficient Funds`}.
+ {t`Ensure your wallet balance covers the required amount to accept this transaction.`}
+
+
+ )}
(
const styles = StyleSheet.create({
wrapper: {
- display: 'flex',
flexDirection: 'row',
- width: '80%',
- marginTop: 16,
+ alignItems: 'center',
borderRadius: 24,
backgroundColor: 'hsla(220, 10%, 94%, 1)',
},
button: {
width: '50%',
borderRadius: 24,
- paddingTop: 9,
- paddingBottom: 10,
+ paddingVertical: 12,
color: COLORS.textColor,
},
buttonFocus: {
@@ -82,5 +79,5 @@ const styles = StyleSheet.create({
},
textFocus: {
fontWeight: 'bold',
- },
+ }
});
diff --git a/src/config.js b/src/config.js
index 8ddfb9049..316fcaa99 100644
--- a/src/config.js
+++ b/src/config.js
@@ -61,4 +61,4 @@ export const _SENTRY_DSN = 'https://c1ebae9159f741e8937abdbfbeba8e8a@o239606.ing
/**
* Whether we should skip the initial modal on reown requests
*/
-export const REOWN_SKIP_CONFIRMATION_MODAL = false;
+export const REOWN_SKIP_CONFIRMATION_MODAL = true;
diff --git a/src/reducers/reducer.js b/src/reducers/reducer.js
index a145c3504..b6d3e7885 100644
--- a/src/reducers/reducer.js
+++ b/src/reducers/reducer.js
@@ -518,8 +518,14 @@ const initialState = {
address: null,
error: null,
},
-
- safeBiometryEnabled: false,
+ /**
+ * The full network name of the connected server (e.g. testnet-golf instead
+ * of only testnet).
+ *
+ * @type {null|string} null if uninitialized, string after it's set in
+ * the wallet saga.
+ */
+ fullNodeNetworkName: null,
};
export const reducer = (state = initialState, action) => {
@@ -736,8 +742,8 @@ export const reducer = (state = initialState, action) => {
return onNewNanoContractTransactionRetry(state);
case types.REOWN_NEW_NANOCONTRACT_RETRY_DISMISS:
return onNewNanoContractTransactionRetryDismiss(state);
- case types.SET_USE_SAFE_BIOMETRY_MODE:
- return onSetUseSafeBiometryMode(state, action);
+ case types.SET_FULLNODE_NETWORK_NAME:
+ return onSetFullNodeNetworkName(state, action);
default:
return state;
}
@@ -890,7 +896,6 @@ const onSetTokens = (state, { payload }) => {
selectedToken,
};
};
-
/**
* Set loadHistoryStatus
*/
@@ -932,22 +937,15 @@ const onSetUseWalletService = (state, action) => ({
useWalletService: action.payload,
});
-const onSetUseSafeBiometryMode = (state, action) => ({
- ...state,
- safeBiometryEnabled: action.payload,
-});
-
const onResetWalletSuccess = (state) => {
const oldUnleashClient = state.unleashClient;
const oldFeatureTogglesInitialized = state.featureTogglesInitialized;
const oldFeatureToggles = state.featureToggles;
- const oldSafeBiometryEnabled = state.safeBiometryEnabled;
return {
...initialState,
unleashClient: oldUnleashClient,
featureTogglesInitialized: oldFeatureTogglesInitialized,
featureToggles: oldFeatureToggles,
- safeBiometryEnabled: oldSafeBiometryEnabled,
};
};
@@ -2142,3 +2140,15 @@ export const onUnregisteredTokensDownloadEnd = (state) => ({
isLoading: false,
},
});
+
+/**
+ * Handle network name changes
+ *
+ * @param {Object} state
+ * @param {string} action.payload Name of the connected network. This should be
+ * the full network name (e.g. testnet-golf instead of just testnet).
+ */
+export const onSetFullNodeNetworkName = (state, { payload }) => ({
+ ...state,
+ fullNodeNetworkName: payload,
+});
diff --git a/src/sagas/featureToggle.js b/src/sagas/featureToggle.js
index 781e19951..f03754c09 100644
--- a/src/sagas/featureToggle.js
+++ b/src/sagas/featureToggle.js
@@ -26,7 +26,6 @@ import {
setUnleashClient,
setFeatureToggles,
featureToggleInitialized,
- setUseSafeBiometryMode,
} from '../actions';
import {
UNLEASH_URL,
@@ -34,10 +33,10 @@ import {
UNLEASH_POLLING_INTERVAL,
STAGE,
FEATURE_TOGGLE_DEFAULTS,
- SAFE_BIOMETRY_MODE_FEATURE_TOGGLE,
} from '../constants';
import { disableFeaturesIfNeeded } from './helpers';
import { logger } from '../logger';
+import { STORE, FEATURE_TOGGLES_LAST_KNOWN_VALUES_KEY } from '../store';
const MAX_RETRIES = 5;
@@ -89,6 +88,7 @@ export function* handleToggleUpdate() {
const toggles = unleashClient.getToggles();
const featureToggles = disableFeaturesIfNeeded(networkSettings, mapFeatureToggles(toggles));
+ STORE.setItem(FEATURE_TOGGLES_LAST_KNOWN_VALUES_KEY, featureToggles);
yield put(setFeatureToggles(featureToggles));
yield put({ type: types.FEATURE_TOGGLE_UPDATED });
@@ -126,9 +126,9 @@ export function* monitorFeatureFlags(currentRetry = 0) {
// At this point, unleashClient.fetchToggles() already fetched the toggles
// (this will throw if it hasn't)
const featureToggles = mapFeatureToggles(unleashClient.getToggles());
+ STORE.setItem(FEATURE_TOGGLES_LAST_KNOWN_VALUES_KEY, featureToggles);
yield put(setFeatureToggles(featureToggles));
- yield put(setUseSafeBiometryMode(featureToggles[SAFE_BIOMETRY_MODE_FEATURE_TOGGLE]));
yield put(featureToggleInitialized());
} catch (e) {
log.error(e);
diff --git a/src/sagas/networkSettings.js b/src/sagas/networkSettings.js
index daa457cfb..b3158b46a 100644
--- a/src/sagas/networkSettings.js
+++ b/src/sagas/networkSettings.js
@@ -13,6 +13,7 @@ import {
onExceptionCaptured,
networkSettingsUpdateReady,
networkChanged,
+ setFullNodeNetworkName,
} from '../actions';
import {
NETWORK_MAINNET,
@@ -283,6 +284,9 @@ export function* persistNetworkSettings(action) {
return;
}
+ // Reset network name when changing networks
+ yield put(setFullNodeNetworkName(''));
+
// Dispatch network changed so listeners can use it in other sagas
// e.g. the Reown saga uses this to clear sessions
yield put(networkChanged());
diff --git a/src/sagas/wallet.js b/src/sagas/wallet.js
index bd43b1843..cc3ef7ced 100644
--- a/src/sagas/wallet.js
+++ b/src/sagas/wallet.js
@@ -37,7 +37,6 @@ import {
DEFAULT_TOKEN,
WALLET_SERVICE_FEATURE_TOGGLE,
PUSH_NOTIFICATION_FEATURE_TOGGLE,
- SAFE_BIOMETRY_MODE_FEATURE_TOGGLE,
networkSettingsKeyMap,
} from '../constants';
import { STORE } from '../store';
@@ -71,9 +70,8 @@ import {
selectAddressAddressesFailure,
firstAddressFailure,
firstAddressSuccess,
- setUseSafeBiometryMode,
- lockScreen,
firstAddressRequest,
+ setFullNodeNetworkName,
} from '../actions';
import { fetchTokenData } from './tokens';
import {
@@ -90,7 +88,6 @@ import {
getAllAddresses,
getFirstAddress,
setKeychainPin,
- isBiometryEnabled,
} from '../utils';
import { logger } from '../logger';
@@ -264,6 +261,17 @@ export function* startWallet(action) {
});
yield put(setServerInfo(serverInfo));
+
+ let network = get(serverInfo, 'network');
+ if (useWalletService) {
+ // In the wallet-service facade, serverInfo is null, so we need to get
+ // version data
+ const versionData = yield call([wallet, wallet.getVersionData]);
+ network = versionData.network;
+ }
+
+ // Set the network name in redux
+ yield put(setFullNodeNetworkName(network));
} catch (e) {
// WalletRequestError can either be a network error making the request
// fail or the wallet might have failed to start and returned status: error.
@@ -438,11 +446,6 @@ export function* onPushNotificationDisabled() {
yield put(setAvailablePushNotification(false));
}
-export function* onSafeBiometryToggleChanged() {
- log.debug('Safe biometry mode feature toggle changed state, locking wallet.');
- yield put(lockScreen());
-}
-
/**
* This saga will wait for feature toggle updates and react when a toggle state
* transition is done
@@ -457,22 +460,6 @@ export function* featureToggleUpdateListener() {
const oldPushNotificationToggle = yield select((state) => state.pushNotification.available);
const newPushNotificationToggle = yield call(isPushNotificationEnabled);
- const oldSafeBiometryEnabled = yield select(({ safeBiometryEnabled }) => safeBiometryEnabled);
- const newSafeBiometryEnabled = yield call(
- checkForFeatureFlag,
- SAFE_BIOMETRY_MODE_FEATURE_TOGGLE,
- );
-
- if (oldSafeBiometryEnabled !== newSafeBiometryEnabled) {
- // Safe biometry feature changed, need to update the state.
- yield put(setUseSafeBiometryMode(newSafeBiometryEnabled));
- if (isBiometryEnabled()) {
- // Since biometry is enabled, a migration is required, this means the wallet
- // needs to restart and the migration will fix the next time it opens.
- yield call(onSafeBiometryToggleChanged);
- }
- }
-
// WalletService is currently ON and the featureToggle is now OFF
if (!newWalletServiceToggle && oldWalletServiceToggle) {
yield call(onWalletServiceDisabled);
diff --git a/src/screens/Dashboard.js b/src/screens/Dashboard.js
index 0e7f1ada3..df6dc5544 100644
--- a/src/screens/Dashboard.js
+++ b/src/screens/Dashboard.js
@@ -18,6 +18,7 @@ import TokenSelect from '../components/TokenSelect';
import SimpleButton from '../components/SimpleButton';
import OfflineBar from '../components/OfflineBar';
import { TwoOptionsToggle } from '../components/TwoOptionsToggle';
+import QRCodeIcon from '../components/Icons/QRCodeIcon';
import { tokenFetchBalanceRequested, updateSelectedToken } from '../actions';
import AskForPushNotificationRefresh from '../components/AskForPushNotificationRefresh';
import { COLORS } from '../styles/themes';
@@ -165,19 +166,17 @@ const Wrapper = ({ children }) => (
);
-const DashBoardHeader = ({ children }) => (
-
- {children}
-
-);
-
-const RegisterToken = () => {
+const DashBoardHeader = ({ children }) => {
const navigation = useNavigation();
return (
- navigation.navigate('RegisterToken')}
- />
+
+
+ {children}
+
+ navigation.navigate('UnifiedQRScanner')} style={{ marginLeft: 16 }}>
+
+
+
);
};
@@ -186,24 +185,30 @@ const TokensHeader = () => (
{t`Tokens`}
-
-
-
);
const styles = StyleSheet.create({
wrapper: {
flex: 1,
+ marginTop: 8,
},
headerWrapper: {
- display: 'flex',
flexDirection: 'row',
- justifyContent: 'center',
+ alignItems: 'center',
backgroundColor: COLORS.lowContrastDetail,
+ paddingHorizontal: 16,
+ height: 48,
+ },
+ toggleContainer: {
+ flex: 1,
+ alignItems: 'center',
+ flexDirection: 'row',
+ justifyContent: 'center',
+ paddingLeft: 8,
},
headerTitle: {
- fontSize: 24,
+ fontSize: 20,
lineHeight: 24,
fontWeight: 'bold',
},
diff --git a/src/screens/NanoContract/NanoContractRegisterScreen.js b/src/screens/NanoContract/NanoContractRegisterScreen.js
index d5bed315c..7b7a16bcc 100644
--- a/src/screens/NanoContract/NanoContractRegisterScreen.js
+++ b/src/screens/NanoContract/NanoContractRegisterScreen.js
@@ -192,7 +192,7 @@ export function NanoContractRegisterScreen({ navigation, route }) {
({
loadHistoryActive: state.loadHistoryStatus.active,
wallet: state.wallet,
- safeBiometryEnabled: state.featureToggles[SAFE_BIOMETRY_MODE_FEATURE_TOGGLE],
});
const mapDispatchToProps = (dispatch) => ({
@@ -82,6 +81,7 @@ class PinScreen extends React.Component {
this.biometryText = props.route.params.biometryText ?? this.biometryText;
this.biometryLoadingText = props.route.params.biometryLoadingText ?? '';
}
+ this.useSafeBiometryFeature = STORE.getItem(SAFE_BIOMETRY_FEATURE_FLAG_KEY);
this.biometryEnabled = isBiometryEnabled();
this.focusEvent = null;
@@ -152,14 +152,14 @@ class PinScreen extends React.Component {
// method an change redux state. No need to execute callback or go back on navigation
try {
await STORE.handleDataMigration(pin);
- const newPin = await biometricsMigration(pin, this.props.safeBiometryEnabled);
+ const actualPin = await biometricsMigration(pin);
if (!this.props.wallet) {
// We have already made sure we have an available accessData
// The handleDataMigration method ensures we have already migrated if necessary
// This means the wallet is loaded and the access data is ready to be used.
- const words = await STORE.getWalletWords(newPin);
- this.props.startWalletRequested({ words, pin: newPin });
+ const words = await STORE.getWalletWords(actualPin);
+ this.props.startWalletRequested({ words, pin: actualPin });
}
this.props.unlockScreen();
} catch (e) {
@@ -298,12 +298,12 @@ class PinScreen extends React.Component {
);
const renderButton = () => {
- if ((!this.state.biometryFailed) && this.props.safeBiometryEnabled && this.biometryEnabled) {
+ if ((!this.state.biometryFailed) && this.useSafeBiometryFeature && this.biometryEnabled) {
// Biometry has not failed, so we should not show a cancellation button.
return null;
}
const biometryFailed = this.state.biometryFailed
- && this.props.safeBiometryEnabled
+ && this.useSafeBiometryFeature
&& this.biometryEnabled;
let title;
let onPress;
@@ -372,7 +372,7 @@ class PinScreen extends React.Component {
);
const renderBody = () => {
- if (this.props.safeBiometryEnabled && this.biometryEnabled) {
+ if (this.useSafeBiometryFeature && this.biometryEnabled) {
// Safe biometry mode is enabled, we should not render the pin input.
return safeBiometryMessage();
}
diff --git a/src/screens/RegisterOptionsScreen.js b/src/screens/RegisterOptionsScreen.js
new file mode 100644
index 000000000..76d8858c5
--- /dev/null
+++ b/src/screens/RegisterOptionsScreen.js
@@ -0,0 +1,123 @@
+/**
+ * Copyright (c) Hathor Labs and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import React from 'react';
+import { StyleSheet, Text, View, Alert } from 'react-native';
+import { t } from 'ttag';
+import { useSelector } from 'react-redux';
+import { get } from 'lodash';
+import HathorHeader from '../components/HathorHeader';
+import NewHathorButton from '../components/NewHathorButton';
+import { COLORS } from '../styles/themes';
+import { NANO_CONTRACT_FEATURE_TOGGLE, REOWN_FEATURE_TOGGLE } from '../constants';
+
+const RegisterOptionsScreen = ({ navigation }) => {
+ const featureToggles = useSelector((state) => state.featureToggles);
+ const serverInfo = useSelector((state) => state.serverInfo);
+ const isReownEnabled = featureToggles[REOWN_FEATURE_TOGGLE] && get(serverInfo, 'nano_contracts_enabled', false);
+ const isNanoContractEnabled = featureToggles[NANO_CONTRACT_FEATURE_TOGGLE] && get(serverInfo, 'nano_contracts_enabled', false);
+
+ const getDescriptionText = () => {
+ if (!isNanoContractEnabled && !isReownEnabled) {
+ return t`You can register Tokens manually.`;
+ }
+
+ if (isNanoContractEnabled && !isReownEnabled) {
+ return t`You can register Tokens and Nano Contracts manually.`;
+ }
+
+ if (!isNanoContractEnabled && isReownEnabled) {
+ return t`You can register Tokens and use Reown manually.`;
+ }
+
+ return t`You can register Tokens, Nano Contracts or Reown manually.`;
+ };
+
+ const handleNanoContractNavigation = () => {
+ if (!isNanoContractEnabled) {
+ Alert.alert(
+ t`Feature Not Available`,
+ t`The nano contract feature is not enabled.`,
+ [{ text: t`OK` }]
+ );
+ return;
+ }
+ navigation.navigate('NanoContractRegisterScreen');
+ };
+
+ const handleReownNavigation = () => {
+ if (!isReownEnabled) {
+ Alert.alert(
+ t`Feature Not Available`,
+ t`The reown feature is not enabled.`,
+ [{ text: t`OK` }]
+ );
+ return;
+ }
+ navigation.navigate('ReownManual');
+ };
+
+ return (
+
+ navigation.goBack()}
+ />
+
+
+ {getDescriptionText()}
+
+
+ {isNanoContractEnabled && (
+
+ )}
+ navigation.navigate('RegisterTokenManual')}
+ style={styles.button}
+ />
+ {isReownEnabled && (
+
+ )}
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: COLORS.white,
+ },
+ content: {
+ flex: 1,
+ paddingHorizontal: 16,
+ paddingTop: 24,
+ },
+ description: {
+ fontSize: 16,
+ color: COLORS.textColor,
+ marginBottom: 24,
+ },
+ buttonContainer: {
+ gap: 16,
+ },
+ button: {
+ backgroundColor: COLORS.black,
+ },
+});
+
+export default RegisterOptionsScreen;
diff --git a/src/screens/RegisterTokenManual.js b/src/screens/RegisterTokenManual.js
index 0b07655ac..335e7e34d 100644
--- a/src/screens/RegisterTokenManual.js
+++ b/src/screens/RegisterTokenManual.js
@@ -130,7 +130,7 @@ class RegisterTokenManual extends React.Component {
({
wallet: state.wallet,
- safeBiometryEnabled: state.featureToggles[SAFE_BIOMETRY_MODE_FEATURE_TOGGLE],
});
const mapDispatchToProps = (dispatch) => ({
@@ -67,16 +65,17 @@ export class Security extends React.Component {
};
}
- onBiometrySwitchChange = (value) => {
- this.setState({ biometryEnabled: value });
- setBiometryEnabled(value);
- }
-
- onSafeBiometrySwitchChange = (value) => {
- if (value) {
- this.onSafeBiometryEnabled();
+ onBiometrySwitchChange(value) {
+ const useSafeBiometryFeature = STORE.getItem(SAFE_BIOMETRY_FEATURE_FLAG_KEY);
+ if (useSafeBiometryFeature) {
+ if (value) {
+ this.onSafeBiometryEnabled();
+ } else {
+ this.onSafeBiometryDisabled();
+ }
} else {
- this.onSafeBiometryDisabled();
+ this.setState({ biometryEnabled: value });
+ setBiometryEnabled(value);
}
}
@@ -147,13 +146,18 @@ export class Security extends React.Component {
}
onLockWallet = () => {
+ // After the screen is unlocked the Home screen will be shown
+ this.props.navigation.navigate('Home');
this.props.lockScreen();
}
render() {
const switchDisabled = !this.supportedBiometry;
const biometryText = (switchDisabled ? t`No biometry supported` : t`Use ${this.supportedBiometry}`);
- const safeBiometryActive = this.state.biometryEnabled && this.props.safeBiometryEnabled;
+
+ const useSafeBiometryFeature = STORE.getItem(SAFE_BIOMETRY_FEATURE_FLAG_KEY);
+ const safeBiometryActive = this.state.biometryEnabled && useSafeBiometryFeature;
+
return (
diff --git a/src/screens/UnifiedQRScanner.js b/src/screens/UnifiedQRScanner.js
new file mode 100644
index 000000000..b331de595
--- /dev/null
+++ b/src/screens/UnifiedQRScanner.js
@@ -0,0 +1,105 @@
+/**
+ * Copyright (c) Hathor Labs and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import React, { useState } from 'react';
+import { View, Alert, SafeAreaView } from 'react-native';
+import { useDispatch, useSelector } from 'react-redux';
+import { t } from 'ttag';
+import { get } from 'lodash';
+
+import QRCodeReader from '../components/QRCodeReader';
+import HathorHeader from '../components/HathorHeader';
+import SimpleButton from '../components/SimpleButton';
+import OfflineBar from '../components/OfflineBar';
+import { reownUriInputted } from '../actions';
+import { COLORS } from '../styles/themes';
+import { NANO_CONTRACT_FEATURE_TOGGLE, REOWN_FEATURE_TOGGLE } from '../constants';
+
+const UnifiedQRScanner = ({ navigation }) => {
+ const dispatch = useDispatch();
+ const [isProcessing, setIsProcessing] = useState(false);
+ const featureToggles = useSelector((state) => state.featureToggles);
+ const serverInfo = useSelector((state) => state.serverInfo);
+ const isReownEnabled = featureToggles[REOWN_FEATURE_TOGGLE] && get(serverInfo, 'nano_contracts_enabled', false);
+ const isNanoContractEnabled = featureToggles[NANO_CONTRACT_FEATURE_TOGGLE] && get(serverInfo, 'nano_contracts_enabled', false);
+
+ const showAlert = (title, message) => {
+ if (isProcessing) return;
+ setIsProcessing(true);
+ Alert.alert(
+ title,
+ message,
+ [{ text: t`OK`, onPress: () => setIsProcessing(false) }]
+ );
+ };
+
+ const onSuccess = (e) => {
+ if (isProcessing) return;
+ const qrData = e.data;
+
+ // Regex patterns for different types
+ const reownPattern = /^wc:[a-f0-9]+@\d+\?.*$/;
+ const tokenPattern = /^\[.*:.*:.*:.*\]$/;
+ const nanoContractPattern = /^[a-f0-9]{64}$/;
+
+ // Check if it's a reown URI
+ if (reownPattern.test(qrData)) {
+ if (!isReownEnabled) {
+ showAlert(t`Feature Not Available`, t`The reown feature is not enabled.`);
+ return;
+ }
+ dispatch(reownUriInputted(qrData));
+ navigation.replace('ReownList');
+ return;
+ }
+
+ // Check if it's a token registration QR code
+ if (tokenPattern.test(qrData)) {
+ navigation.replace('RegisterTokenManual', { configurationString: qrData });
+ return;
+ }
+
+ // Check if it's a nano contract ID
+ if (nanoContractPattern.test(qrData)) {
+ if (!isNanoContractEnabled) {
+ showAlert(t`Feature Not Available`, t`The nano contract feature is not enabled.`);
+ return;
+ }
+ navigation.replace('NanoContractRegisterScreen', { ncId: qrData });
+ return;
+ }
+
+ // If none of the patterns match, show an error or handle accordingly
+ showAlert(t`Invalid QR Code`, t`The scanned QR code is not in a recognized format.`);
+ };
+
+ return (
+
+ navigation.pop()}
+ rightElement={(
+ navigation.navigate('RegisterOptions')}
+ />
+ )}
+ />
+
+
+
+
+
+ );
+};
+
+export default UnifiedQRScanner;
diff --git a/src/store.js b/src/store.js
index e04ef712d..4bcbd3366 100644
--- a/src/store.js
+++ b/src/store.js
@@ -15,9 +15,18 @@ export const REGISTERED_TOKENS_KEY = 'asyncstorage:registeredTokens';
export const STORE_VERSION_KEY = 'asyncstorage:version';
export const REGISTERED_NANO_CONTRACTS_KEY = 'asyncstorage:registeredNanoContracts';
export const PIN_BACKUP_KEY = 'asyncstorage:pinBackup';
+// Wheather old biometry mode is active (by the user request)
export const IS_OLD_BIOMETRY_ENABLED_KEY = 'mobile:isBiometryEnabled';
+// Wheather safe biometry is active (by the user request)
export const IS_BIOMETRY_ENABLED_KEY = 'mobile:isSafeBiometryEnabled';
+// Which type of biometry the device can handle.
export const SUPPORTED_BIOMETRY_KEY = 'mobile:supportedBiometry';
+// This key determines under which biometry mode the wallet is operating on.
+// The value here only changes during a migration (when the user unlocks the wallet)
+export const SAFE_BIOMETRY_FEATURE_FLAG_KEY = 'asyncstorage:featureFlagSafeBiometryMode';
+// These are the last known values of the unleash feature toggles
+// These are updated on every call to unleash
+export const FEATURE_TOGGLES_LAST_KNOWN_VALUES_KEY = 'asyncstorage:featureTogglesLastKnownValues';
export const walletKeys = [
ACCESS_DATA_KEY,
diff --git a/src/utils.js b/src/utils.js
index 7e1447d1e..9c168903b 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -15,8 +15,8 @@ import { Linking, Platform, Text } from 'react-native';
import { getStatusBarHeight } from 'react-native-status-bar-height';
import moment from 'moment';
import baseStyle from './styles/init';
-import { KEYCHAIN_USER, NETWORK_MAINNET, NANO_CONTRACT_FEATURE_TOGGLE } from './constants';
-import { STORE, IS_BIOMETRY_ENABLED_KEY, IS_OLD_BIOMETRY_ENABLED_KEY, SUPPORTED_BIOMETRY_KEY } from './store';
+import { KEYCHAIN_USER, NETWORK_MAINNET, NANO_CONTRACT_FEATURE_TOGGLE, SAFE_BIOMETRY_MODE_FEATURE_TOGGLE } from './constants';
+import { STORE, IS_BIOMETRY_ENABLED_KEY, IS_OLD_BIOMETRY_ENABLED_KEY, SUPPORTED_BIOMETRY_KEY, SAFE_BIOMETRY_FEATURE_FLAG_KEY, FEATURE_TOGGLES_LAST_KNOWN_VALUES_KEY } from './store';
import { TxHistory } from './models';
import { COLORS, STYLE } from './styles/themes';
import { logger } from './logger';
@@ -94,17 +94,28 @@ export const getTokenLabel = (token) => `${token.name} (${token.symbol})`;
/**
* Migrate the biometry configuration state if needed.
*
- * @param {string} currentPassword
- * @param {bool} safeBiometryEnabled
+ * @param {string} currentPassword - The password returned from the system keychain.
* @return {Promise} The actual pin/password for the application.
*/
-export async function biometricsMigration(currentPassword, safeBiometryEnabled) {
- const oldBiometry = STORE.getItem(IS_OLD_BIOMETRY_ENABLED_KEY);
- const safeBiometry = STORE.getItem(IS_BIOMETRY_ENABLED_KEY);
+export async function biometricsMigration(currentPassword) {
+ const storeSafeBiometryFeature = !!STORE.getItem(SAFE_BIOMETRY_FEATURE_FLAG_KEY);
+ const unleashToggles = STORE.getItem(FEATURE_TOGGLES_LAST_KNOWN_VALUES_KEY) ?? {};
+ const unleashSafeBiometryFeature = !!unleashToggles[SAFE_BIOMETRY_MODE_FEATURE_TOGGLE];
+
+ if (storeSafeBiometryFeature === unleashSafeBiometryFeature) {
+ // No migration is required since the store and unleash flags are the same
+ return currentPassword;
+ }
+
+ STORE.setItem(SAFE_BIOMETRY_FEATURE_FLAG_KEY, unleashSafeBiometryFeature);
+ // The safe biometry feature flag has changed, we need to check if a migration is required.
- if (safeBiometryEnabled) {
- // Safe biometry mode, need to migrate if old biometry is enabled.
- if (oldBiometry) {
+ if (unleashSafeBiometryFeature) {
+ // Unleash flag is enabling safe biometry
+ // if we have the old mode active a migration is required.
+ // else we can ignore migration since the user is not using biometry.
+ const oldBiometryActive = STORE.getItem(IS_OLD_BIOMETRY_ENABLED_KEY);
+ if (oldBiometryActive) {
// currentPassword is the pin, we need to generate a new random password
// and encrypt the pin.
const password = generateRandomPassword();
@@ -116,9 +127,12 @@ export async function biometricsMigration(currentPassword, safeBiometryEnabled)
return password;
}
} else {
- // Old biometry mode, need to migrate if safe biometry is enabled.
+ // Unleash flag is disabling safe biometry
+ // if we have safe mode active a migration is required.
+ // else we can ignore migration since the use is not using biometry.
+ const safeBiometryActive = STORE.getItem(IS_BIOMETRY_ENABLED_KEY);
// eslint-disable-next-line no-lonely-if
- if (safeBiometry) {
+ if (safeBiometryActive) {
// currentPassword is the random password, we need to decrypt the pin and
// toggle the old biometry key
const pin = STORE.disableSafeBiometry(currentPassword);