From 924abc6b9d6a9b9b8cbda9e7f02e9bde93e6381e Mon Sep 17 00:00:00 2001 From: Paul Puey Date: Wed, 24 May 2023 00:22:00 -0700 Subject: [PATCH 001/104] Commit project and lock file changes --- ios/Podfile.lock | 12 ++++++------ ios/edge.xcodeproj/project.pbxproj | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 52926ed2f24..302672ead01 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -562,14 +562,14 @@ PODS: - React-Core - SDWebImage (~> 5.11.1) - SDWebImageWebPCoder (~> 0.8.4) - - RNFBAnalytics (14.12.0): + - RNFBAnalytics (14.9.1): - Firebase/AnalyticsWithoutAdIdSupport (= 8.15.0) - React-Core - RNFBApp - - RNFBApp (14.12.0): + - RNFBApp (14.9.1): - Firebase/CoreOnly (= 8.15.0) - React-Core - - RNFBMessaging (14.12.0): + - RNFBMessaging (14.9.1): - Firebase/Messaging (= 8.15.0) - React-Core - RNFBApp @@ -1201,9 +1201,9 @@ SPEC CHECKSUMS: RNDateTimePicker: 04b805a3cb4d386e5e6aff54b47ace7bad706fda RNDeviceInfo: aad3c663b25752a52bf8fce93f2354001dd185aa RNFastImage: 1f2cab428712a4baaf78d6169eaec7f622556dd7 - RNFBAnalytics: c5740a00a436398796639189f82b58b1ebe4c705 - RNFBApp: e4439717c23252458da2b41b81b4b475c86f90c4 - RNFBMessaging: 40dac204b4197a2661dec5be964780c6ec39bf65 + RNFBAnalytics: fae7572493095e19d22498650c97507f988e627d + RNFBApp: fd23737680ed2bdde41ca27d8bfb171b6d668c6b + RNFBMessaging: cd273b4dcacf98c83a25ce1711c8c85511573990 RNFBRemoteConfig: 92fbb75ceb69fec44ae727b70d23c5d1798f7648 RNFlashList: 8ec7f7454721145fe84566bb9e88bcf58981c9fe RNFS: 4ac0f0ea233904cb798630b3c077808c06931688 diff --git a/ios/edge.xcodeproj/project.pbxproj b/ios/edge.xcodeproj/project.pbxproj index 5f1fb1285d1..bf36a16f36f 100644 --- a/ios/edge.xcodeproj/project.pbxproj +++ b/ios/edge.xcodeproj/project.pbxproj @@ -346,7 +346,7 @@ name = "[CP-User] [RNFB] Core Configuration"; runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\n_MAX_LOOKUPS=2;\n_SEARCH_RESULT=''\n_RN_ROOT_EXISTS=''\n_CURRENT_LOOKUPS=1\n_JSON_ROOT=\"'react-native'\"\n_JSON_FILE_NAME='firebase.json'\n_JSON_OUTPUT_BASE64='e30=' # { }\n_CURRENT_SEARCH_DIR=${PROJECT_DIR}\n_PLIST_BUDDY=/usr/libexec/PlistBuddy\n_TARGET_PLIST=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n_DSYM_PLIST=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n# plist arrays\n_PLIST_ENTRY_KEYS=()\n_PLIST_ENTRY_TYPES=()\n_PLIST_ENTRY_VALUES=()\n\nfunction setPlistValue {\n echo \"info: setting plist entry '$1' of type '$2' in file '$4'\"\n ${_PLIST_BUDDY} -c \"Add :$1 $2 '$3'\" $4 || echo \"info: '$1' already exists\"\n}\n\nfunction getFirebaseJsonKeyValue () {\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$1'); puts output[$_JSON_ROOT]['$2']\"\n else\n echo \"\"\n fi;\n}\n\nfunction jsonBoolToYesNo () {\n if [[ $1 == \"false\" ]]; then\n echo \"NO\"\n elif [[ $1 == \"true\" ]]; then\n echo \"YES\"\n else echo \"NO\"\n fi\n}\n\necho \"info: -> RNFB build script started\"\necho \"info: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"info: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | /usr/bin/head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"info: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n _RN_ROOT_EXISTS=$(ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\" || echo '')\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n if ! python3 --version >/dev/null 2>&1; then echo \"python3 not found, firebase.json file processing error.\" && exit 1; fi\n _JSON_OUTPUT_BASE64=$(python3 -c 'import json,sys,base64;print(base64.b64encode(bytes(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"', '\"'rb'\"').read())['${_JSON_ROOT}']), '\"'utf-8'\"')).decode())' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.app_data_collection_default_enabled\n _APP_DATA_COLLECTION_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_data_collection_default_enabled\")\n if [[ $_APP_DATA_COLLECTION_ENABLED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseDataCollectionDefaultEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_DATA_COLLECTION_ENABLED\")\")\n fi\n\n # config.analytics_auto_collection_enabled\n _ANALYTICS_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_auto_collection_enabled\")\n if [[ $_ANALYTICS_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_COLLECTION\")\")\n fi\n\n # config.analytics_collection_deactivated\n _ANALYTICS_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_collection_deactivated\")\n if [[ $_ANALYTICS_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_DEACTIVATED\")\")\n fi\n\n # config.analytics_idfv_collection_enabled\n _ANALYTICS_IDFV_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_idfv_collection_enabled\")\n if [[ $_ANALYTICS_IDFV_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_IDFV_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_IDFV_COLLECTION\")\")\n fi\n\n # config.analytics_default_allow_ad_personalization_signals\n _ANALYTICS_PERSONALIZATION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_personalization_signals\")\n if [[ $_ANALYTICS_PERSONALIZATION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_PERSONALIZATION_SIGNALS\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_PERSONALIZATION\")\")\n fi\n\n # config.google_analytics_automatic_screen_reporting_enabled\n _ANALYTICS_AUTO_SCREEN_REPORTING=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"google_analytics_automatic_screen_reporting_enabled\")\n if [[ $_ANALYTICS_AUTO_SCREEN_REPORTING ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAutomaticScreenReportingEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_SCREEN_REPORTING\")\")\n fi\n\n # config.perf_auto_collection_enabled\n _PERF_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_auto_collection_enabled\")\n if [[ $_PERF_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_enabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_AUTO_COLLECTION\")\")\n fi\n\n # config.perf_collection_deactivated\n _PERF_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_collection_deactivated\")\n if [[ $_PERF_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_deactivated\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_DEACTIVATED\")\")\n fi\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.in_app_messaging_auto_colllection_enabled\n _FIAM_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"in_app_messaging_auto_collection_enabled\")\n if [[ $_FIAM_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseInAppMessagingAutomaticDataCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_FIAM_AUTO_INIT\")\")\n fi\n\n # config.app_check_token_auto_refresh\n _APP_CHECK_TOKEN_AUTO_REFRESH=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_check_token_auto_refresh\")\n if [[ $_APP_CHECK_TOKEN_AUTO_REFRESH ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAppCheckTokenAutoRefreshEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_CHECK_TOKEN_AUTO_REFRESH\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"info: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"info: <- RNFB build script finished\"\n"; + shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\n_MAX_LOOKUPS=2;\n_SEARCH_RESULT=''\n_RN_ROOT_EXISTS=''\n_CURRENT_LOOKUPS=1\n_JSON_ROOT=\"'react-native'\"\n_JSON_FILE_NAME='firebase.json'\n_JSON_OUTPUT_BASE64='e30=' # { }\n_CURRENT_SEARCH_DIR=${PROJECT_DIR}\n_PLIST_BUDDY=/usr/libexec/PlistBuddy\n_TARGET_PLIST=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n_DSYM_PLIST=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n# plist arrays\n_PLIST_ENTRY_KEYS=()\n_PLIST_ENTRY_TYPES=()\n_PLIST_ENTRY_VALUES=()\n\nfunction setPlistValue {\n echo \"info: setting plist entry '$1' of type '$2' in file '$4'\"\n ${_PLIST_BUDDY} -c \"Add :$1 $2 '$3'\" $4 || echo \"info: '$1' already exists\"\n}\n\nfunction getFirebaseJsonKeyValue () {\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$1'); puts output[$_JSON_ROOT]['$2']\"\n else\n echo \"\"\n fi;\n}\n\nfunction jsonBoolToYesNo () {\n if [[ $1 == \"false\" ]]; then\n echo \"NO\"\n elif [[ $1 == \"true\" ]]; then\n echo \"YES\"\n else echo \"NO\"\n fi\n}\n\necho \"info: -> RNFB build script started\"\necho \"info: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"info: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | /usr/bin/head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"info: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n _RN_ROOT_EXISTS=$(ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\" || echo '')\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n _JSON_OUTPUT_BASE64=$(python -c 'import json,sys,base64;print(base64.b64encode(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"').read())['${_JSON_ROOT}'])))' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.app_data_collection_default_enabled\n _APP_DATA_COLLECTION_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_data_collection_default_enabled\")\n if [[ $_APP_DATA_COLLECTION_ENABLED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseDataCollectionDefaultEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_DATA_COLLECTION_ENABLED\")\")\n fi\n\n # config.analytics_auto_collection_enabled\n _ANALYTICS_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_auto_collection_enabled\")\n if [[ $_ANALYTICS_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_COLLECTION\")\")\n fi\n\n # config.analytics_collection_deactivated\n _ANALYTICS_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_collection_deactivated\")\n if [[ $_ANALYTICS_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_DEACTIVATED\")\")\n fi\n\n # config.analytics_idfv_collection_enabled\n _ANALYTICS_IDFV_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_idfv_collection_enabled\")\n if [[ $_ANALYTICS_IDFV_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_IDFV_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_IDFV_COLLECTION\")\")\n fi\n\n # config.analytics_default_allow_ad_personalization_signals\n _ANALYTICS_PERSONALIZATION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_personalization_signals\")\n if [[ $_ANALYTICS_PERSONALIZATION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_PERSONALIZATION_SIGNALS\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_PERSONALIZATION\")\")\n fi\n\n # config.google_analytics_automatic_screen_reporting_enabled\n _ANALYTICS_AUTO_SCREEN_REPORTING=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"google_analytics_automatic_screen_reporting_enabled\")\n if [[ $_ANALYTICS_AUTO_SCREEN_REPORTING ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAutomaticScreenReportingEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_SCREEN_REPORTING\")\")\n fi\n\n # config.perf_auto_collection_enabled\n _PERF_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_auto_collection_enabled\")\n if [[ $_PERF_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_enabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_AUTO_COLLECTION\")\")\n fi\n\n # config.perf_collection_deactivated\n _PERF_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_collection_deactivated\")\n if [[ $_PERF_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_deactivated\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_DEACTIVATED\")\")\n fi\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.in_app_messaging_auto_colllection_enabled\n _FIAM_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"in_app_messaging_auto_collection_enabled\")\n if [[ $_FIAM_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseInAppMessagingAutomaticDataCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_FIAM_AUTO_INIT\")\")\n fi\n\n # config.app_check_token_auto_refresh\n _APP_CHECK_TOKEN_AUTO_REFRESH=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_check_token_auto_refresh\")\n if [[ $_APP_CHECK_TOKEN_AUTO_REFRESH ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAppCheckTokenAutoRefreshEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_CHECK_TOKEN_AUTO_REFRESH\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"info: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"info: <- RNFB build script finished\"\n"; }; 66E3B72D0FE8946FF30D15F8 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; From 5f170bd986aec1f37c62d11ca22f7018b651ebba Mon Sep 17 00:00:00 2001 From: Matthew Date: Wed, 10 May 2023 14:21:48 -0700 Subject: [PATCH 002/104] v3.9.0 Changelog From 7baa246c5d6955310f54f15c3a60e386a8aceecd Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Wed, 24 May 2023 13:34:00 -0700 Subject: [PATCH 003/104] Fix RewardCardWelcomeScene minimum font scaling --- src/plugins/gui/scenes/RewardsCardWelcomeScene.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/gui/scenes/RewardsCardWelcomeScene.tsx b/src/plugins/gui/scenes/RewardsCardWelcomeScene.tsx index 060f23ba59d..dba6833feb5 100644 --- a/src/plugins/gui/scenes/RewardsCardWelcomeScene.tsx +++ b/src/plugins/gui/scenes/RewardsCardWelcomeScene.tsx @@ -28,7 +28,7 @@ export const RewardsCardWelcomeScene = (props: Props) => { - + {lstrings.rewards_card_welcome_intro} From 51d319692fc70a30ad64d09fe2821d073326821d Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Wed, 24 May 2023 14:07:42 -0700 Subject: [PATCH 004/104] Enable Visa Card Program for production track (remove beta flag) --- .../TransactionListTop.test.tsx.snap | 107 ++++++++++++++++++ src/components/themed/ControlPanel.tsx | 2 +- src/components/themed/TransactionListTop.tsx | 3 +- src/constants/plugins/GuiPlugins.ts | 3 +- 4 files changed, 110 insertions(+), 5 deletions(-) diff --git a/src/__tests__/components/__snapshots__/TransactionListTop.test.tsx.snap b/src/__tests__/components/__snapshots__/TransactionListTop.test.tsx.snap index c3ee1faf7b3..cb823f6498b 100644 --- a/src/__tests__/components/__snapshots__/TransactionListTop.test.tsx.snap +++ b/src/__tests__/components/__snapshots__/TransactionListTop.test.tsx.snap @@ -763,6 +763,113 @@ Array [ } /> + + + + + + + + Buy Prepaid Visa® Cards + + + + , { dispatch(executePluginAction(navigation, 'rewardscard', 'sell')) diff --git a/src/components/themed/TransactionListTop.tsx b/src/components/themed/TransactionListTop.tsx index e59a1639467..a1f0e469485 100644 --- a/src/components/themed/TransactionListTop.tsx +++ b/src/components/themed/TransactionListTop.tsx @@ -10,7 +10,6 @@ import { selectWalletToken } from '../../actions/WalletActions' import { toggleAccountBalanceVisibility } from '../../actions/WalletListActions' import { Fontello } from '../../assets/vector' import { getSymbolFromCurrency, SPECIAL_CURRENCY_INFO, STAKING_BALANCES } from '../../constants/WalletAndCurrencyConstants' -import { ENV } from '../../env' import { useHandler } from '../../hooks/useHandler' import { useWalletName } from '../../hooks/useWalletName' import { useWatch } from '../../hooks/useWatch' @@ -414,7 +413,7 @@ export class TransactionListTopComponent extends React.PureComponent )} - {ENV.BETA_FEATURES && !isEmpty && !searching ? : null} + {!isEmpty && !searching ? : null} {!isEmpty && !searching && ( diff --git a/src/constants/plugins/GuiPlugins.ts b/src/constants/plugins/GuiPlugins.ts index f2cd875c9e2..e59ebd9d2f9 100644 --- a/src/constants/plugins/GuiPlugins.ts +++ b/src/constants/plugins/GuiPlugins.ts @@ -124,8 +124,7 @@ export const guiPlugins: { [pluginId: string]: GuiPlugin } = { baseUri: '', lockUriPath: true, nativePlugin: makeRewardsCardPlugin, - displayName: 'Edge Reward Card', - betaOnly: true + displayName: 'Edge Reward Card' }, xanpool: { pluginId: 'xanpool', From 3f16d16ce716749f89d7d5a01bced3a6902b59de Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Wed, 17 May 2023 16:36:01 -0700 Subject: [PATCH 005/104] Add hide card feature to RewardsCardPlugin --- src/plugins/gui/RewardsCardPlugin.tsx | 21 ++++++++++------ src/plugins/gui/providers/ioniaProvider.ts | 25 ++++++++++++++++--- .../gui/scenes/RewardsCardDashboardScene.tsx | 9 +++---- 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/src/plugins/gui/RewardsCardPlugin.tsx b/src/plugins/gui/RewardsCardPlugin.tsx index a7acb44f0a1..e13732dd538 100644 --- a/src/plugins/gui/RewardsCardPlugin.tsx +++ b/src/plugins/gui/RewardsCardPlugin.tsx @@ -5,7 +5,7 @@ import { sprintf } from 'sprintf-js' import { addressWarnings } from '../../actions/ScanActions' import { ButtonsModal } from '../../components/modals/ButtonsModal' -import { Airship, showError, showToast } from '../../components/services/AirshipInstance' +import { Airship, showError } from '../../components/services/AirshipInstance' import { lstrings } from '../../locales/strings' import { EdgeTokenId } from '../../types/types' import { runWithTimeout, snooze } from '../../util/utils' @@ -19,7 +19,7 @@ import { initializeProviders } from './util/initializeProviders' const SUPPORT_URL = 'https://edge.app/cards/' export interface RewardsCardItem { - id: string + id: number expiration: Date url: string } @@ -42,13 +42,13 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { async function getRewardCards(): Promise { const giftCards = await provider.otherMethods.getGiftCards() - const rewardCards: RewardsCardItem[] = giftCards.map(card => { + const rewardCards: RewardsCardItem[] = giftCards.cards.map(card => { // Expires 6 calendar months from the creation date const expirationDate = new Date(card.CreatedDate.valueOf()) expirationDate.setMonth(card.CreatedDate.getMonth() + 6) return { - id: card.Id.toString(), + id: card.Id, // Expires in 180 days (6 months) from creation date expiration: expirationDate, url: card.CardNumber @@ -106,7 +106,7 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { }) } - const showDeleteItemModal = async (item: RewardsCardItem) => { + const showDeleteItemModal = async (card: RewardsCardItem) => { const answer = await Airship.show<'delete' | 'keep' | undefined>(bridge => ( { delete: { label: lstrings.string_delete, type: 'escape' } }} title={lstrings.rewards_card_delete_modal_title} - message={sprintf(lstrings.rewards_card_delete_modal_message_s, item.expiration)} + message={sprintf(lstrings.rewards_card_delete_modal_message_s, card.expiration)} /> )) - if (answer === 'delete') showToast('Deleted it!') + if (answer === 'delete') { + // Hide the card + provider.otherMethods.hideCard(card.id) + // Remove card from plugin state + rewardCards = rewardCards.filter(c => c.id !== card.id) + // Reset state for dashboard + showDashboard() + } } const showNewCardEnterAmount = async (walletListResult: FiatPluginWalletPickerResult) => { diff --git a/src/plugins/gui/providers/ioniaProvider.ts b/src/plugins/gui/providers/ioniaProvider.ts index fd27575f10d..1a909ce907b 100644 --- a/src/plugins/gui/providers/ioniaProvider.ts +++ b/src/plugins/gui/providers/ioniaProvider.ts @@ -1,5 +1,5 @@ import { div, mul } from 'biggystring' -import { asArray, asBoolean, asDate, asEither, asJSON, asMaybe, asNull, asNumber, asObject, asOptional, asString, asValue, Cleaner } from 'cleaners' +import { asArray, asBoolean, asDate, asEither, asJSON, asMaybe, asNull, asNumber, asObject, asOptional, asString, asValue, Cleaner, uncleaner } from 'cleaners' import { sprintf } from 'sprintf-js' import URL from 'url-parse' @@ -60,9 +60,13 @@ const asIoniaResponse = (asData: Cleaner) => ErrorMessage: asString }) +const asStoreHiddenCards = asOptional(asJSON(asArray(asNumber)), []) +const wasStoreHiddenCards = uncleaner(asStoreHiddenCards) + export interface IoniaMethods { authenticate: (shouldCreate?: boolean) => Promise - getGiftCards: () => Promise + getGiftCards: () => Promise<{ cards: GiftCard[]; archivedCards: GiftCard[] }> + hideCard: (cardId: number) => Promise queryPurchaseCard: (currencyCode: string, cardAmount: number) => Promise } @@ -75,6 +79,7 @@ export const makeIoniaProvider: FiatProviderFactory = { const STORE_USERNAME_KEY = `${pluginKeys.scope}:userName` const STORE_EMAIL_KEY = `${pluginKeys.scope}:uuidEmail` + const STORE_HIDDEN_CARDS_KEY = `${pluginKeys.scope}:hiddenCards` // // Fetch API @@ -223,6 +228,7 @@ export const makeIoniaProvider: FiatProviderFactory = { // State: // + let hiddenCardIds: number[] = asStoreHiddenCards(await store.getItem(STORE_HIDDEN_CARDS_KEY).catch(_ => undefined)) const ratesCache: { [currencyCode: string]: { expiry: number; rateQueryPromise: Promise } } = {} // @@ -391,12 +397,25 @@ export const makeIoniaProvider: FiatProviderFactory = { return true }, + hideCard: async cardId => { + const set = new Set(hiddenCardIds) + set.add(cardId) + hiddenCardIds = Array.from(set) + await store.setItem(STORE_HIDDEN_CARDS_KEY, wasStoreHiddenCards(hiddenCardIds)) + }, async getGiftCards() { const giftCardsResponse = await fetchGetGiftCards({ headers: userAuthenticatedFetchOptions.headers }) const { Data: giftCards } = giftCardsResponse - return giftCards + + const out: { cards: GiftCard[]; archivedCards: GiftCard[] } = { cards: [], archivedCards: [] } + // Filter all deleted cards: + for (const card of giftCards) { + if (hiddenCardIds.includes(card.Id)) out.archivedCards.push(card) + else out.cards.push(card) + } + return out }, queryPurchaseCard } diff --git a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx index 92a44faaa2d..084f536ed9d 100644 --- a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx +++ b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx @@ -73,12 +73,9 @@ export const RewardsCardDashboardScene = (props: Props) => { {item.expiration.toLocaleString()} {/* TODO: Add delete button after card presentation redesign */} - {Math.random() === -1 ? ( - handleRemovePress(item)}> - - - ) : null} - + handleRemovePress(item)}> + + From d18e7ea290638ba3a97f58a9f688b8aa83a95a57 Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Tue, 23 May 2023 17:38:58 -0700 Subject: [PATCH 006/104] Don't reverse the card list order --- src/plugins/gui/RewardsCardPlugin.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/gui/RewardsCardPlugin.tsx b/src/plugins/gui/RewardsCardPlugin.tsx index e13732dd538..c91a578797b 100644 --- a/src/plugins/gui/RewardsCardPlugin.tsx +++ b/src/plugins/gui/RewardsCardPlugin.tsx @@ -49,13 +49,12 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { return { id: card.Id, - // Expires in 180 days (6 months) from creation date expiration: expirationDate, url: card.CardNumber } }) // Reverse order to show latest first - return rewardCards.reverse() + return rewardCards } async function refreshRewardsCards(retries: number) { From 0f9ebb63fd8359a2073380f29479f06ec82c7352 Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Tue, 23 May 2023 11:47:22 -0700 Subject: [PATCH 007/104] Redesign CardListItem on RewardCardsDashboardScene --- .../AutoLogoutModal.test.tsx.snap | 1 + .../FioAddressListScene.test.tsx.snap | 2 + src/plugins/gui/RewardsCardPlugin.tsx | 4 +- .../gui/scenes/RewardsCardDashboardScene.tsx | 63 ++++++++++++------- src/theme/variables/edgeDark.ts | 1 + src/theme/variables/edgeLight.ts | 1 + src/theme/variables/testDark.ts | 1 + src/theme/variables/testLight.ts | 1 + src/types/Theme.ts | 1 + 9 files changed, 49 insertions(+), 26 deletions(-) diff --git a/src/__tests__/modals/__snapshots__/AutoLogoutModal.test.tsx.snap b/src/__tests__/modals/__snapshots__/AutoLogoutModal.test.tsx.snap index aa44a82054b..88c8ca9fd35 100644 --- a/src/__tests__/modals/__snapshots__/AutoLogoutModal.test.tsx.snap +++ b/src/__tests__/modals/__snapshots__/AutoLogoutModal.test.tsx.snap @@ -49,6 +49,7 @@ exports[`AutoLogoutModal should render with loading props 1`] = ` "confirmationSliderThumbWidth": 55, "confirmationSliderWidth": 295, "confirmationThumbDeactivated": "#87939E", + "dangerIcon": "#E85466", "dangerText": "#E85466", "dateModalBackgroundDark": "#1b2f3b", "dateModalBackgroundLight": "#FFFFFF", diff --git a/src/__tests__/scenes/__snapshots__/FioAddressListScene.test.tsx.snap b/src/__tests__/scenes/__snapshots__/FioAddressListScene.test.tsx.snap index ca33a6f93b6..79db16194ca 100644 --- a/src/__tests__/scenes/__snapshots__/FioAddressListScene.test.tsx.snap +++ b/src/__tests__/scenes/__snapshots__/FioAddressListScene.test.tsx.snap @@ -81,6 +81,7 @@ exports[`FioAddressList should render with loading props 1`] = ` "confirmationSliderThumbWidth": 55, "confirmationSliderWidth": 295, "confirmationThumbDeactivated": "#87939E", + "dangerIcon": "#E85466", "dangerText": "#E85466", "dateModalBackgroundDark": "#1b2f3b", "dateModalBackgroundLight": "#FFFFFF", @@ -530,6 +531,7 @@ exports[`FioAddressList should render with loading props 1`] = ` "confirmationSliderThumbWidth": 55, "confirmationSliderWidth": 295, "confirmationThumbDeactivated": "#87939E", + "dangerIcon": "#E85466", "dangerText": "#E85466", "dateModalBackgroundDark": "#1b2f3b", "dateModalBackgroundLight": "#FFFFFF", diff --git a/src/plugins/gui/RewardsCardPlugin.tsx b/src/plugins/gui/RewardsCardPlugin.tsx index c91a578797b..7a4639871dc 100644 --- a/src/plugins/gui/RewardsCardPlugin.tsx +++ b/src/plugins/gui/RewardsCardPlugin.tsx @@ -110,8 +110,8 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { { ) : ( items.map(item => { return ( - - onCardPress(item)}> - -
- - {lstrings.rewards_card_dashboard_expires_label} - {item.expiration.toLocaleString()} -
- {/* TODO: Add delete button after card presentation redesign */} - handleRemovePress(item)}> - - -
- -
-
+ + + onCardPress(item)}> + +
+ + + {lstrings.rewards_card_dashboard_expires_label} + {item.expiration.toLocaleString()} + +
+ handleRemovePress(item)}> + + +
+
+
+
) }) )} @@ -96,19 +98,30 @@ export const RewardsCardDashboardScene = (props: Props) => { const CardListContainer = styled(View)<{ bottomSpace: number }>(props => ({ justifyContent: 'space-around', - marginBottom: props.bottomSpace + marginBottom: props.bottomSpace, + padding: props.theme.rem(1.5) })) +const CardListItemWrapper = styled(View)(props => ({ + height: props.theme.rem(7) +})) const CardListItem = styled(View)(props => ({ - marginLeft: props.theme.rem(1) + backgroundColor: props.theme.modal, + // Math for figuring out 1/8th inches border radius ((1/8)/3.375 * 314)/16: + borderRadius: props.theme.rem(0.7268518519), + borderWidth: 1, + borderTopColor: 'rgba(255,255,255,.2)', + borderColor: 'rgba(255,255,255,.1)', + shadowOpacity: 0.5, + shadowRadius: props.theme.rem(0.5) })) const CardListItemContainer = styled(View)(props => ({ + aspectRatio: 1.5882352941, flexDirection: 'row', - alignItems: 'center', justifyContent: 'space-between', - marginVertical: props.theme.rem(1), - marginRight: props.theme.rem(1) + padding: props.theme.rem(1.25), + width: '100%' })) const BottomFloat = styled(View)(props => ({ @@ -139,15 +152,17 @@ const Icon = styled(Ionicon)(props => ({})) const Details = styled(View)(props => ({})) +const DetailItem = styled(View)(prop => ({})) + const VisaBrandImage = styled(Image)(props => ({ resizeMode: 'contain', height: props.theme.rem(1.75), width: props.theme.rem(4), - marginBottom: props.theme.rem(0.5) + marginBottom: props.theme.rem(1.25) })) const ExpiryLabel = styled(Text)(props => ({ - color: props.theme.primaryText, + color: props.theme.secondaryText, fontFamily: props.theme.fontFaceDefault, fontSize: props.theme.rem(0.75), includeFontPadding: false @@ -156,6 +171,6 @@ const ExpiryLabel = styled(Text)(props => ({ const DateLabel = styled(Text)(props => ({ color: props.theme.primaryText, fontFamily: props.theme.fontFaceDefault, - fontSize: props.theme.rem(1), + fontSize: props.theme.rem(0.75), includeFontPadding: false })) diff --git a/src/theme/variables/edgeDark.ts b/src/theme/variables/edgeDark.ts index 37f8bab02d3..f8811655e87 100644 --- a/src/theme/variables/edgeDark.ts +++ b/src/theme/variables/edgeDark.ts @@ -85,6 +85,7 @@ export const edgeDark: Theme = { icon: palette.white, iconTappable: palette.edgeMint, iconDeactivated: palette.whiteOp75, + dangerIcon: palette.accentRed, warningIcon: palette.accentOrange, iconLoadingOverlay: palette.whiteOp75, transactionListIconBackground: palette.darkAqua, diff --git a/src/theme/variables/edgeLight.ts b/src/theme/variables/edgeLight.ts index 79b99abae79..5df04fb8172 100644 --- a/src/theme/variables/edgeLight.ts +++ b/src/theme/variables/edgeLight.ts @@ -81,6 +81,7 @@ export const edgeLight: Theme = { icon: palette.black, iconTappable: palette.edgeBlue, iconDeactivated: palette.whiteOp75, + dangerIcon: palette.accentRed, warningIcon: palette.accentOrange, iconLoadingOverlay: palette.whiteOp75, transactionListIconBackground: palette.white, diff --git a/src/theme/variables/testDark.ts b/src/theme/variables/testDark.ts index 402e72969e2..3de25570d1f 100644 --- a/src/theme/variables/testDark.ts +++ b/src/theme/variables/testDark.ts @@ -89,6 +89,7 @@ export const testDark: Theme = { icon: palette.white, iconTappable: palette.glowPurple, iconDeactivated: palette.whiteOp75, + dangerIcon: palette.accentRed, warningIcon: palette.accentOrange, iconLoadingOverlay: palette.whiteOp75, transactionListIconBackground: palette.darkBlue, diff --git a/src/theme/variables/testLight.ts b/src/theme/variables/testLight.ts index 798a9497647..417ba4ba8bf 100644 --- a/src/theme/variables/testLight.ts +++ b/src/theme/variables/testLight.ts @@ -80,6 +80,7 @@ export const testLight: Theme = { icon: palette.black, iconTappable: palette.edgeBlue, iconDeactivated: palette.whiteOp75, + dangerIcon: palette.accentRed, warningIcon: palette.accentOrange, iconLoadingOverlay: palette.whiteOp75, transactionListIconBackground: palette.white, diff --git a/src/types/Theme.ts b/src/types/Theme.ts index b1b161bc624..fef4109ec17 100644 --- a/src/types/Theme.ts +++ b/src/types/Theme.ts @@ -70,6 +70,7 @@ export interface Theme { iconTappable: string iconDeactivated: string warningIcon: string + dangerIcon: string iconLoadingOverlay: string transactionListIconBackground: string buySellCustomPluginModalIcon: string From 25e56c9f7c2c7449eb8ac6aedf3f1c8fbc9342c3 Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Wed, 24 May 2023 12:49:25 -0700 Subject: [PATCH 008/104] Update delete card modal --- src/locales/en_US.ts | 2 +- src/locales/strings/enUS.json | 2 +- src/plugins/gui/RewardsCardPlugin.tsx | 30 +++++++------ src/plugins/gui/fiatPluginTypes.ts | 4 +- .../gui/scenes/RewardsCardDashboardScene.tsx | 42 ++++++++++++------- 5 files changed, 46 insertions(+), 34 deletions(-) diff --git a/src/locales/en_US.ts b/src/locales/en_US.ts index f944722494f..f4e8e76c13a 100644 --- a/src/locales/en_US.ts +++ b/src/locales/en_US.ts @@ -1519,7 +1519,7 @@ const strings = { rewards_card_dashboard_expires_label: `Expires`, rewards_card_dashboard_title: `Visa® Card Program`, rewards_card_delete_modal_title: 'Delete Card?', - rewards_card_delete_modal_message_s: `Are you sure you want to delete the Visa® Card with expiration?\n\n%s`, + rewards_card_delete_modal_message: `Are you sure you want to delete this Visa® Card?`, rewards_card_error_missing_payment_address: `Missing payment address from provider`, rewards_card_error_amount_max_s: `Maximum card purchase amount is $%s`, rewards_card_error_amount_min_s: `Minimum card purchase amount is $%s`, diff --git a/src/locales/strings/enUS.json b/src/locales/strings/enUS.json index fbac038dc72..7ffb39d2514 100644 --- a/src/locales/strings/enUS.json +++ b/src/locales/strings/enUS.json @@ -1340,7 +1340,7 @@ "rewards_card_dashboard_expires_label": "Expires", "rewards_card_dashboard_title": "Visa® Card Program", "rewards_card_delete_modal_title": "Delete Card?", - "rewards_card_delete_modal_message_s": "Are you sure you want to delete the Visa® Card with expiration?\n\n%s", + "rewards_card_delete_modal_message": "Are you sure you want to delete this Visa® Card?", "rewards_card_error_missing_payment_address": "Missing payment address from provider", "rewards_card_error_amount_max_s": "Maximum card purchase amount is $%s", "rewards_card_error_amount_min_s": "Minimum card purchase amount is $%s", diff --git a/src/plugins/gui/RewardsCardPlugin.tsx b/src/plugins/gui/RewardsCardPlugin.tsx index 7a4639871dc..258593548ce 100644 --- a/src/plugins/gui/RewardsCardPlugin.tsx +++ b/src/plugins/gui/RewardsCardPlugin.tsx @@ -4,8 +4,8 @@ import React from 'react' import { sprintf } from 'sprintf-js' import { addressWarnings } from '../../actions/ScanActions' -import { ButtonsModal } from '../../components/modals/ButtonsModal' -import { Airship, showError } from '../../components/services/AirshipInstance' +import { Space } from '../../components/layout/Space' +import { showError } from '../../components/services/AirshipInstance' import { lstrings } from '../../locales/strings' import { EdgeTokenId } from '../../types/types' import { runWithTimeout, snooze } from '../../util/utils' @@ -14,6 +14,7 @@ import { FiatPlugin, FiatPluginFactory, FiatPluginStartParams, FiatPluginWalletP import { FiatProviderGetQuoteParams } from './fiatProviderTypes' import { getRateFromQuote } from './pluginUtils' import { IoniaMethods, makeIoniaProvider } from './providers/ioniaProvider' +import { RewardCard } from './scenes/RewardsCardDashboardScene' import { initializeProviders } from './util/initializeProviders' const SUPPORT_URL = 'https://edge.app/cards/' @@ -106,17 +107,20 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { } const showDeleteItemModal = async (card: RewardsCardItem) => { - const answer = await Airship.show<'delete' | 'keep' | undefined>(bridge => ( - - )) + const answer = await showUi.buttonModal({ + buttons: { + delete: { label: lstrings.string_delete, type: 'secondary' }, + keep: { label: lstrings.string_keep, type: 'escape' } + }, + title: lstrings.rewards_card_delete_modal_title, + message: lstrings.rewards_card_delete_modal_message, + children: ( + + + + ) + }) + if (answer === 'delete') { // Hide the card provider.otherMethods.hideCard(card.id) diff --git a/src/plugins/gui/fiatPluginTypes.ts b/src/plugins/gui/fiatPluginTypes.ts index fd38b52f10a..8b9a3122021 100644 --- a/src/plugins/gui/fiatPluginTypes.ts +++ b/src/plugins/gui/fiatPluginTypes.ts @@ -80,9 +80,7 @@ export interface FiatPluginWalletPickerResult { } export interface FiatPluginUi { - buttonModal: ( - params: Omit, 'bridge' | 'children'> - ) => Promise + buttonModal: (params: Omit, 'bridge'>) => Promise showToastSpinner: (message: string, promise: Promise) => Promise openWebView: (params: FiatPluginOpenWebViewParams) => Promise walletPicker: (params: { headerTitle: string; allowedAssets?: EdgeTokenId[]; showCreateWallet?: boolean }) => Promise diff --git a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx index 1c6801289f5..e69c190a97f 100644 --- a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx +++ b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx @@ -65,22 +65,7 @@ export const RewardsCardDashboardScene = (props: Props) => { items.map(item => { return ( - - onCardPress(item)}> - -
- - - {lstrings.rewards_card_dashboard_expires_label} - {item.expiration.toLocaleString()} - -
- handleRemovePress(item)}> - - -
-
-
+ onCardPress(item)} onRemovePress={() => handleRemovePress(item)} />
) }) @@ -96,6 +81,31 @@ export const RewardsCardDashboardScene = (props: Props) => { ) } +export const RewardCard = ({ item, onPress, onRemovePress }: { item: RewardsCardItem; onPress?: () => void; onRemovePress?: () => void }) => { + const theme = useTheme() + + return ( + + + +
+ + + {lstrings.rewards_card_dashboard_expires_label} + {item.expiration.toLocaleString()} + +
+ {onRemovePress == null ? null : ( + + + + )} +
+
+
+ ) +} + const CardListContainer = styled(View)<{ bottomSpace: number }>(props => ({ justifyContent: 'space-around', marginBottom: props.bottomSpace, From 41a385e649f424b43d8fde03296364865a897290 Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Wed, 24 May 2023 14:49:18 -0700 Subject: [PATCH 009/104] =?UTF-8?q?Re-enable=20DASH=20for=20Visa=C2=AE=20C?= =?UTF-8?q?ard=20Program?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constants/WalletAndCurrencyConstants.ts | 2 +- src/plugins/gui/RewardsCardPlugin.tsx | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/constants/WalletAndCurrencyConstants.ts b/src/constants/WalletAndCurrencyConstants.ts index 8efc11017cb..15dd9426b19 100644 --- a/src/constants/WalletAndCurrencyConstants.ts +++ b/src/constants/WalletAndCurrencyConstants.ts @@ -472,7 +472,7 @@ export const SPECIAL_CURRENCY_INFO: { maxSpendTargets: UTXO_MAX_SPEND_TARGETS, initWalletName: lstrings.string_first_dash_wallet_name, chainCode: 'DASH', - displayIoniaRewards: false, + displayIoniaRewards: true, isImportKeySupported: true, isPrivateKeySweepable: true, isPaymentProtocolSupported: true diff --git a/src/plugins/gui/RewardsCardPlugin.tsx b/src/plugins/gui/RewardsCardPlugin.tsx index 258593548ce..c0b1371baba 100644 --- a/src/plugins/gui/RewardsCardPlugin.tsx +++ b/src/plugins/gui/RewardsCardPlugin.tsx @@ -31,12 +31,14 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { const { showUi, account, guiPlugin } = params const { pluginId } = guiPlugin - const SUPPORTED_ASSETS: EdgeTokenId[] = ['bitcoin', 'bitcoincash', 'dogecoin', 'litecoin'].map(pluginId => ({ pluginId })) - const providers = await initializeProviders(PROVIDER_FACTORIES, params) if (providers.length === 0) throw new Error('No enabled providers for RewardsCardPlugin') const provider = providers[0] + // Get supported crypto assets: + const supportedAssetMap = await provider.getSupportedAssets([]) + const allowedAssets: EdgeTokenId[] = Object.keys(supportedAssetMap.crypto).map(pluginId => ({ pluginId })) + // // Helpers: // @@ -244,7 +246,7 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { const showNewCardWalletListModal = async () => { const walletListResult: FiatPluginWalletPickerResult = await showUi.walletPicker({ headerTitle: lstrings.rewards_card_select_wallet, - allowedAssets: SUPPORTED_ASSETS, + allowedAssets, showCreateWallet: false }) showNewCardEnterAmount(walletListResult) From 19737dae9d02804041dee3f63a7fed88ba49708f Mon Sep 17 00:00:00 2001 From: Jon Tzeng Date: Wed, 24 May 2023 14:01:31 -0700 Subject: [PATCH 010/104] Remove error on remote config failure --- src/components/scenes/GettingStartedScene.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/scenes/GettingStartedScene.tsx b/src/components/scenes/GettingStartedScene.tsx index d3862c65991..600a7d7d66f 100644 --- a/src/components/scenes/GettingStartedScene.tsx +++ b/src/components/scenes/GettingStartedScene.tsx @@ -136,7 +136,7 @@ export const GettingStartedScene = (props: Props) => { await remoteConfig.setDefaults(REMOTE_CONFIG_DEFAULT) await remoteConfig.fetchAndActivate().catch((err: any) => { const errorMessage = err instanceof Error ? err.message : String(err) - console.error(`Failed to fetch and activate remote config, using default values. Error: ${errorMessage}`) + console.warn(`Failed to fetch and activate remote config, using default values. Error: ${errorMessage}`) }) const featureVal = remoteConfig.getValue('swipe_last_usp').asBoolean() From 0b6c1a236ae6c29798bab300f2894b79cf4dc53c Mon Sep 17 00:00:00 2001 From: Jon Tzeng Date: Wed, 24 May 2023 14:02:25 -0700 Subject: [PATCH 011/104] Fix tracking events - Add missing tracking event for swiping vs clicking past USPs - Add escape hatch for reporting any variant-specific params --- src/components/scenes/GettingStartedScene.tsx | 12 ++++++++++-- src/util/tracking.ts | 11 ++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/components/scenes/GettingStartedScene.tsx b/src/components/scenes/GettingStartedScene.tsx index 600a7d7d66f..7fc9a4dbdec 100644 --- a/src/components/scenes/GettingStartedScene.tsx +++ b/src/components/scenes/GettingStartedScene.tsx @@ -91,6 +91,8 @@ export const GettingStartedScene = (props: Props) => { const paginationCount = sections.length + (isFinalSwipeEnabled ? 1 : 0) const swipeOffset = useSharedValue(0) + const variantId = isFinalSwipeEnabled ? 'A' : 'B' + const handleFinalSwipe = useHandler(() => { if (isFinalSwipeEnabled) { // This delay is necessary to properly reset the scene since it remains on @@ -100,7 +102,13 @@ export const GettingStartedScene = (props: Props) => { }, 500) if (localUsersLength > 0) navigation.navigate('login', { loginUiInitialRoute: 'login-password' }) - else navigation.navigate('login', { loginUiInitialRoute: 'new-account' }) + else { + logEvent('Signup_Account_Review_Done', { + variantId, + variantParams: { method: 'swipe' } + }) + navigation.navigate('login', { loginUiInitialRoute: 'new-account' }) + } } }) @@ -111,7 +119,7 @@ export const GettingStartedScene = (props: Props) => { navigation.navigate('login', { loginUiInitialRoute: 'login-password' }) }) const handlePressSignUp = useHandler(() => { - logEvent('Signup_Account_Review_Done', { variantId: isFinalSwipeEnabled ? 'A' : 'B' }) + logEvent('Signup_Account_Review_Done', { variantId, variantParams: { method: 'click' } }) navigation.navigate('login', { loginUiInitialRoute: 'new-account' }) }) const handlePressSkip = useHandler(() => { diff --git a/src/util/tracking.ts b/src/util/tracking.ts index 97a332c56b5..02080a8a510 100644 --- a/src/util/tracking.ts +++ b/src/util/tracking.ts @@ -42,6 +42,7 @@ export interface TrackingValues { // This prop can also arbitrarily be named depending on the context of the // event, i.e.: 'Plan A' | 'Experiment B' | 'Mod C' | 'Something Else' variantId?: string + variantParams?: { [key: string]: string | number } // Any additional params to report accountDate?: string // Account creation date currencyCode?: string // Wallet currency code @@ -76,7 +77,7 @@ export async function logEvent(event: TrackingEventName, values: TrackingValues * Send a raw event to Firebase. */ async function logToFirebase(name: TrackingEventName, values: TrackingValues) { - const { accountDate, currencyCode, dollarValue, installerId, pluginId, error } = values + const { accountDate, currencyCode, dollarValue, installerId, pluginId, error, variantId, variantParams } = values // @ts-expect-error if (!global.firebase) return @@ -92,6 +93,14 @@ async function logToFirebase(name: TrackingEventName, values: TrackingValues) { if (installerId != null) params.aid = installerId if (pluginId != null) params.plugin = pluginId if (error != null) params.error = error + + if (variantId != null) params.variant = variantId + if (variantParams != null) { + for (const variantParamKey of Object.keys(variantParams)) { + params[`${variantId}_${variantParamKey}`] = variantParams[variantParamKey] + } + } + // @ts-expect-error global.firebase.analytics().logEvent(name, params) From 44258e86645debda88216d008dd864b8a4246d3c Mon Sep 17 00:00:00 2001 From: William Swanson Date: Wed, 24 May 2023 15:57:58 -0700 Subject: [PATCH 012/104] Upgrade to edge-core-js v0.21.4 --- ios/Podfile.lock | 6 +++--- package.json | 2 +- yarn.lock | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 302672ead01..d9def5f4b8d 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -18,7 +18,7 @@ PODS: - disklet (0.5.2): - React - DoubleConversion (1.1.6) - - edge-core-js (0.21.3): + - edge-core-js (0.21.4): - React-Core - edge-currency-accountbased (1.2.9): - React-Core @@ -1109,7 +1109,7 @@ SPEC CHECKSUMS: CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 disklet: e7ed3e673ccad9d175a1675f9f3589ffbf69a5fd DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662 - edge-core-js: 0d3d136f755de5f37a438e117986145eb1362a2a + edge-core-js: bd6760a2efcca8610d961d71fe9c34f103add462 edge-currency-accountbased: 39a708c32f30a3db81ca5259880dcaa14315549d edge-login-ui-rn: f6711ffc1cb89e1449290dbceef40d76e67a3a3b FBLazyVector: d2db9d00883282819d03bbd401b2ad4360d47580 @@ -1242,4 +1242,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 9a9e60804856c91c38098f56e90032c2f1f967ea -COCOAPODS: 1.12.0 +COCOAPODS: 1.12.1 diff --git a/package.json b/package.json index 45075bb35e5..6408fe9f1d0 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ "deepmerge": "^4.3.1", "detect-bundler": "^1.1.0", "disklet": "^0.5.2", - "edge-core-js": "^0.21.3", + "edge-core-js": "^0.21.4", "edge-currency-accountbased": "^1.2.9", "edge-currency-monero": "^1.0.0", "edge-currency-plugins": "^2.0.2", diff --git a/yarn.lock b/yarn.lock index 2e5afd6faaf..8c32b48d6dc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7257,10 +7257,10 @@ edge-core-js@^0.19.48: yaob "^0.3.9" yavent "^0.1.3" -edge-core-js@^0.21.3: - version "0.21.3" - resolved "https://registry.yarnpkg.com/edge-core-js/-/edge-core-js-0.21.3.tgz#dd2c73154926370ad628bb305aeec8ab1882568e" - integrity sha512-K7UV1X19+2y/EDHgRMbL7NlQTNUKH6gLdym4lMRvi8ZEND1Xo75Ape/DnnLF3LGBHXKZqgLHlhZLc48rLtzh4g== +edge-core-js@^0.21.4: + version "0.21.4" + resolved "https://registry.yarnpkg.com/edge-core-js/-/edge-core-js-0.21.4.tgz#b07dcbf8292b10d0376759b38537c748fa51b17a" + integrity sha512-6Q2AmEP1l2nCovcqca/4ziEI98aLK/HV91XSWtpjAFanZ4LG2Ju6k7m32rBOpN1PXBkLHfIVdZN3ATLXd0656w== dependencies: aes-js "^3.1.0" base-x "^1.0.4" From 41d2605e160151f132c3e7fb5096e333b799c07a Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Wed, 24 May 2023 16:06:01 -0700 Subject: [PATCH 013/104] Increase the card refresh duration and optimize network resources --- src/plugins/gui/RewardsCardPlugin.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/gui/RewardsCardPlugin.tsx b/src/plugins/gui/RewardsCardPlugin.tsx index c0b1371baba..f915fc19f11 100644 --- a/src/plugins/gui/RewardsCardPlugin.tsx +++ b/src/plugins/gui/RewardsCardPlugin.tsx @@ -61,12 +61,12 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { } async function refreshRewardsCards(retries: number) { - if (retries > 9) return + if (retries > 15) return await getRewardCards() .then(async cards => { if (cards.length === rewardCards.length) { console.log(`Retrying rewards card refresh`) - await snooze(1000) + await snooze(retries * 1000) return await refreshRewardsCards(retries + 1) } rewardCards = cards From 90349dde17813bc32e26b9a916a9ef001c7b39da Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Wed, 24 May 2023 16:07:21 -0700 Subject: [PATCH 014/104] Only show loading indicator for accounts with an existing Ionia user --- src/plugins/gui/RewardsCardPlugin.tsx | 29 +++++++++++++-------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/plugins/gui/RewardsCardPlugin.tsx b/src/plugins/gui/RewardsCardPlugin.tsx index f915fc19f11..2d1f296c4ad 100644 --- a/src/plugins/gui/RewardsCardPlugin.tsx +++ b/src/plugins/gui/RewardsCardPlugin.tsx @@ -297,25 +297,24 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { pluginId, startPlugin: async (startParams: FiatPluginStartParams) => { // Auth User: - const startPluginInner = async (): Promise => { - const isAuthenticated = await provider.otherMethods.authenticate().catch(e => { - throw new Error(lstrings.rewards_card_error_authenticate) - }) + const isAuthenticated = await provider.otherMethods.authenticate().catch(e => { + throw new Error(lstrings.rewards_card_error_authenticate) + }) + if (isAuthenticated) { // Get/refresh rewards cards: - if (isAuthenticated) { - return await getRewardCards().catch(e => { - throw new Error(lstrings.rewards_card_error_retrieving_cards) - }) - } - return rewardCards + rewardCards = await showUi.showToastSpinner( + lstrings.loading, + runWithTimeout( + getRewardCards().catch(e => { + throw new Error(lstrings.rewards_card_error_retrieving_cards) + }), + 11000, + new Error(lstrings.rewards_card_error_timeout_loading) + ) + ) } - rewardCards = await showUi.showToastSpinner( - lstrings.loading, - runWithTimeout(startPluginInner(), 11000, new Error(lstrings.rewards_card_error_timeout_loading)) - ) - redundantQuoteParams = { direction: startParams.direction, paymentTypes: startParams.paymentTypes, From 4ec8aea6e633351c501fee432f44c7c57a776182 Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Wed, 24 May 2023 16:07:39 -0700 Subject: [PATCH 015/104] Redesigned Visa Card Program loading handling and messaging --- src/locales/en_US.ts | 4 +- src/locales/strings/enUS.json | 2 +- src/plugins/gui/RewardsCardPlugin.tsx | 15 +++--- .../gui/scenes/RewardsCardDashboardScene.tsx | 52 ++++++++++++------- 4 files changed, 45 insertions(+), 28 deletions(-) diff --git a/src/locales/en_US.ts b/src/locales/en_US.ts index f4e8e76c13a..cc6d68ae577 100644 --- a/src/locales/en_US.ts +++ b/src/locales/en_US.ts @@ -1508,8 +1508,8 @@ const strings = { rewards_card_error_retrieving_cards: 'Error retrieving Visa cards. Please try again later.', rewards_card_error_authenticate: 'Error authenticating with Visa Card program. Please try again later.', rewards_card_error_timeout_loading: 'Timeout error loading Visa Card program. Please try again later.', - rewards_card_purchase_successful: - 'Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.', + rewards_card_purchase_disclaimer: + 'Newly purchased cards take a few seconds to become available. Cards purchased with BTC require 1 confirmation and could take 10-30 minutes to become available.', rewards_card_loading: 'Loading your Visa® Cards...', rewards_card_add_new_input_amount_title: `Buy Visa® Card`, rewards_card_welcome_intro: `Purchase Visa® prepaid cards that can be used at millions of merchants in the U.S. Cards can be purchased up to $1,000 in value, with a daily limit of $10,000.`, diff --git a/src/locales/strings/enUS.json b/src/locales/strings/enUS.json index 7ffb39d2514..bd81842c89d 100644 --- a/src/locales/strings/enUS.json +++ b/src/locales/strings/enUS.json @@ -1330,7 +1330,7 @@ "rewards_card_error_retrieving_cards": "Error retrieving Visa cards. Please try again later.", "rewards_card_error_authenticate": "Error authenticating with Visa Card program. Please try again later.", "rewards_card_error_timeout_loading": "Timeout error loading Visa Card program. Please try again later.", - "rewards_card_purchase_successful": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", + "rewards_card_purchase_disclaimer": "Newly purchased cards take a few seconds to become available. Cards purchased with BTC require 1 confirmation and could take 10-30 minutes to become available.", "rewards_card_loading": "Loading your Visa® Cards...", "rewards_card_add_new_input_amount_title": "Buy Visa® Card", "rewards_card_welcome_intro": "Purchase Visa® prepaid cards that can be used at millions of merchants in the U.S. Cards can be purchased up to $1,000 in value, with a daily limit of $10,000.", diff --git a/src/plugins/gui/RewardsCardPlugin.tsx b/src/plugins/gui/RewardsCardPlugin.tsx index 2d1f296c4ad..1dd4ce93b86 100644 --- a/src/plugins/gui/RewardsCardPlugin.tsx +++ b/src/plugins/gui/RewardsCardPlugin.tsx @@ -70,7 +70,7 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { return await refreshRewardsCards(retries + 1) } rewardCards = cards - showDashboard() + showDashboard({ showLoading: false }) }) .catch(async error => { console.error(`Error refreshing rewards cards: ${String(error)}`) @@ -90,9 +90,10 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { // State Machine: // - const showDashboard = async () => { + const showDashboard = async ({ showLoading }: { showLoading: boolean }) => { showUi.rewardsCardDashboard({ items: rewardCards, + showLoading, onCardPress({ url }) { showUi.openWebView({ url }) }, @@ -129,7 +130,7 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { // Remove card from plugin state rewardCards = rewardCards.filter(c => c.id !== card.id) // Reset state for dashboard - showDashboard() + showDashboard({ showLoading: false }) } } @@ -227,8 +228,10 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { } const onDone = () => { - showDashboard() - showUi.showToastSpinner(lstrings.rewards_card_purchase_successful, refreshRewardsCards(0).catch(showError)) + showDashboard({ showLoading: true }) + refreshRewardsCards(0) + .then(async () => await showDashboard({ showLoading: false })) + .catch(showError) } const metadata: EdgeMetadata = { @@ -322,7 +325,7 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { } if (rewardCards.length > 0) { - await showDashboard() + await showDashboard({ showLoading: false }) } else { await showWelcome() } diff --git a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx index e69c190a97f..0da266b04f6 100644 --- a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx +++ b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx @@ -22,6 +22,7 @@ export interface RewardsCardDashboardParams { onHelpPress: () => void onNewPress: () => void onRemovePress: (item: RewardsCardItem) => void + showLoading?: boolean } interface Props { @@ -30,7 +31,7 @@ interface Props { export const RewardsCardDashboardScene = (props: Props) => { const { route } = props - const { items, onCardPress, onHelpPress, onNewPress, onRemovePress } = route.params + const { items, onCardPress, onHelpPress, onNewPress, onRemovePress, showLoading = false } = route.params const theme = useTheme() const [bottomFloatHeight, setBottomFloatHeight] = useState(0) @@ -56,20 +57,26 @@ export const RewardsCardDashboardScene = (props: Props) => { /> - {items.length === 0 ? ( - - {lstrings.rewards_card_loading} - - - ) : ( - items.map(item => { - return ( - - onCardPress(item)} onRemovePress={() => handleRemovePress(item)} /> - - ) - }) - )} + {items.map(item => { + return ( + + onCardPress(item)} onRemovePress={() => handleRemovePress(item)} /> + + ) + })} + {items.length === 0 || showLoading ? ( + + + + + {lstrings.rewards_card_loading} + + {lstrings.rewards_card_purchase_disclaimer} + + + + + ) : null} setBottomFloatHeight(event.nativeEvent.layout.height)}> @@ -143,8 +150,8 @@ const BottomFloat = styled(View)(props => ({ const LoadingContainer = styled(View)(props => ({ alignItems: 'center', flex: 1, - marginHorizontal: props.theme.rem(1), - justifyContent: 'flex-start' + justifyContent: 'center', + paddingVertical: props.theme.rem(1) })) const LoadingText = styled(Text)(props => ({ @@ -153,8 +160,15 @@ const LoadingText = styled(Text)(props => ({ fontFamily: props.theme.fontFaceDefault, fontSize: props.theme.rem(1), includeFontPadding: false, - margin: props.theme.rem(1), - marginBottom: props.theme.rem(1.5), + marginBottom: props.theme.rem(0.5), + textAlign: 'left' +})) + +const LoadingTextDisclaimer = styled(Text)(props => ({ + alignSelf: 'stretch', + color: props.theme.secondaryText, + fontFamily: props.theme.fontFaceDefault, + includeFontPadding: false, textAlign: 'left' })) From 5c9e459debdb678add5fd7c1f744e9b23b223fa8 Mon Sep 17 00:00:00 2001 From: Paul Puey Date: Sat, 13 May 2023 23:10:31 -0700 Subject: [PATCH 016/104] Add branch & buildnum to output IPA/APK files --- scripts/deploy.ts | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/scripts/deploy.ts b/scripts/deploy.ts index d1b7de9de62..344ad76bc2b 100644 --- a/scripts/deploy.ts +++ b/scripts/deploy.ts @@ -53,6 +53,7 @@ interface BuildObj extends BuildConfigFile { tmpDir: string buildArchivesDir: string bundleToolPath: string + productNameClean: string // Set in makeCommonPost: buildNum: string @@ -143,6 +144,7 @@ function makeCommonPost(buildObj: BuildObj) { buildObj.bundleUrl = 'main.jsbundle' buildObj.bundleMapFile = '../ios-release.bundle.map' } + buildObj.productNameClean = buildObj.productName.replace(' ', '') } // function buildCommonPre() { @@ -195,8 +197,9 @@ function buildIos(buildObj: BuildObj) { buildObj.dSymFile = escapePath(`${buildDir}/${archiveDir}/dSYMs/${buildObj.productName}.app.dSYM`) // const appFile = sprintf('%s/%s/Products/Applications/%s.app', buildDir, archiveDir, buildObj.xcodeScheme) - buildObj.dSymZip = escapePath(`${buildObj.tmpDir}/${buildObj.productName}.dSYM.zip`) - buildObj.ipaFile = escapePath(`${buildObj.tmpDir}/${buildObj.productName}.ipa`) + const buildOutputIpaFile = escapePath(`${buildObj.tmpDir}/${buildObj.productName}.ipa`) + buildObj.dSymZip = escapePath(`${buildObj.tmpDir}/${buildObj.productNameClean}-${buildObj.repoBranch}-${buildObj.buildNum}.dSYM.zip`) + buildObj.ipaFile = escapePath(`${buildObj.tmpDir}/${buildObj.productNameClean}-${buildObj.repoBranch}-${buildObj.buildNum}.ipa`) if (fs.existsSync(buildObj.ipaFile)) { call('rm ' + buildObj.ipaFile) @@ -226,6 +229,9 @@ function buildIos(buildObj: BuildObj) { cmdStr = `/usr/bin/zip -r ${buildObj.dSymZip} ${buildObj.dSymFile}` call(cmdStr) + mylog(`Renaming IPA file to ${buildObj.ipaFile}`) + fs.renameSync(buildOutputIpaFile, buildObj.ipaFile) + cmdStr = `cp -a "${buildDir}/${archiveDir}/Products/Applications/${buildObj.productName}.app/main.jsbundle" ${buildObj.guiPlatformDir}/` call(cmdStr) } @@ -265,11 +271,12 @@ function buildAndroid(buildObj: BuildObj) { call(sprintf('./gradlew %s', buildObj.androidTask)) // Process the AAB files created into APK format and place in archive directory + const outfile = `${buildObj.productNameClean}-${buildObj.repoBranch}-${buildObj.buildNum}` const archiveDir = join(buildArchivesDir, repoBranch, platformType, String(buildNum)) fs.mkdirSync(archiveDir, { recursive: true }) - const aabPath = join(archiveDir, 'app-release.aab') - const apksPath = join(archiveDir, 'app-release.apks') - const apkPathDir = join(archiveDir, 'apk_container') + const aabPath = join(archiveDir, `${outfile}.aab`) + const apksPath = join(archiveDir, `${outfile}.apks`) + const apkPathDir = join(archiveDir, `${outfile}_apk_container`) fs.copyFileSync(join(guiPlatformDir, '/app/build/outputs/bundle/release/app-release.aab'), aabPath) call( @@ -277,7 +284,9 @@ function buildAndroid(buildObj: BuildObj) { ) call(`unzip ${apksPath} -d ${apkPathDir}`) - buildObj.ipaFile = join(apkPathDir, 'universal.apk') + const universalApk = join(apkPathDir, 'universal.apk') + buildObj.ipaFile = join(apkPathDir, `${outfile}.apk`) + fs.renameSync(universalApk, buildObj.ipaFile) } function buildCommonPost(buildObj: BuildObj) { From 5493271383c79d779dc23b7cc907d656faed49fc Mon Sep 17 00:00:00 2001 From: Matthew Date: Wed, 24 May 2023 13:50:59 -0700 Subject: [PATCH 017/104] v3.10.0 Changelog --- CHANGELOG.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3f7feb1987..688a9bb2b54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,59 @@ # edge-react-gui +## 3.10.0 (2023-04-25) + +- Add Pepe (PEPE) +- Added Visa® Debit Card (beta) +- Add ZEC/ARRR import wallet support +- Add Tron Stake v2 support +- Add default fiat support to Markets scene +- Fix Wallet Connect personal_sign method +- Fix background audio pause while playing send/receive chimes +- Refactor Request Scene to use ExchangedFlipInput2 +- Cleanup SEPA details input scene +- Remove deprecated allowed/excluded currencyCode props from WalletListModal +- Deprecate Tomb Finance v1/v2 staking +- Deprecate Tron Stake v1 +- Fix sync circle discrepancy between wallet list and transaction list view +- Fix section header date display in FIO requests lists +- Lock Next button in fiat plugin while amounts are fetched +- Update translations +- Various visual fixes +- Upgrade edge-core-js to v0.21.3 + - fixed: Return transactions from getTransactions, even if they have no on-disk metadata + - changed: Remove deprecated methods in unit tests + - fixed: Return transactions from getTransactions, even if they have no on-disk metadata + - added: EdgeUserInfo.username. + - added: Provide EdgeAccount methods for reading public and private keys: + - getDisplayPrivateKey + - getDisplayPublicKey + - getRawPrivateKey + - getRawPublicKey + - added: Matching EdgeCurrencyTools methods for getting display keys. + - deprecated: EdgeCurrencyEngine methods for getting display keys. + - deprecated: EdgeAccount and EdgeCurrencyWallet key properties. +- Upgrade edge-currency-accountbased to v1.2.9 + - FIO: Handle empty otherParams objects as null + - Add Pepe token + - Tron: Pass nativeAmount directly to TRC20 encoder + - Tron: Make fee optional in asTRC20TransactionInfo cleaner + - EVM: Fix null gas price handling in txRpcParamsToSpendInfo + - Ripple: Fix api reconnect logic + - Fixed: Find XLM memos in all three makeSpend API locations + - ZEC/ARR: Add import private key birthdayHeight option handling + - FIO: Replace public key with recipient public key + - Rename files to the network name, not the currency code + - Use uppercase names for files that export classes and use loweracse names for files that export types and utilities + - Fix: Added dynamic gas limit calculation for zkSync + - Add Tron Stake v2 + - Algorand: Support signing multiple transactions in wallet connect request +- Upgrade edge-exchange-plugins to v0.19.5 + - Fixed: Fix swapuz refund address + - Fixed: Prevent Thorchain swaps that would receive negative amount + - Changed: Update exolix to v2 api +- Upgrade edge-login-ui-rn to v1.4.6 + - Fixed: Background brand image handling and display. + ## 3.9.0 (2023-05-10) - Add zkSync From 532d7dd5c022ea23eaded129346da9572f99f341 Mon Sep 17 00:00:00 2001 From: Paul V Puey Date: Wed, 24 May 2023 15:05:19 -0700 Subject: [PATCH 018/104] Add USE_WELCOME_SCREENS to env.json --- src/components/Main.tsx | 3 ++- src/envConfig.ts | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/Main.tsx b/src/components/Main.tsx index 3c8a6244a88..a018af1eba8 100644 --- a/src/components/Main.tsx +++ b/src/components/Main.tsx @@ -11,6 +11,7 @@ import { checkEnabledExchanges } from '../actions/CryptoExchangeActions' import { logout } from '../actions/LoginActions' import { showReEnableOtpModal } from '../actions/SettingsActions' import { CryptoExchangeScene as CryptoExchangeSceneComponent } from '../components/scenes/CryptoExchangeScene' +import { ENV } from '../env' import { useMount } from '../hooks/useMount' import { useUnmount } from '../hooks/useUnmount' import { lstrings } from '../locales/strings' @@ -239,7 +240,7 @@ export const Main = () => { return ( Date: Thu, 25 May 2023 19:38:10 -0700 Subject: [PATCH 019/104] Do not escape dir name for rename fs.renameSync() does not need spaces escaped --- scripts/deploy.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/deploy.ts b/scripts/deploy.ts index 344ad76bc2b..e1f9cdca0e4 100644 --- a/scripts/deploy.ts +++ b/scripts/deploy.ts @@ -99,8 +99,8 @@ function makeCommonPre(argv: string[], buildObj: BuildObj) { buildObj.repoBranch = argv[4] // master or develop buildObj.platformType = argv[3] // ios or android buildObj.projectName = argv[2] - buildObj.guiPlatformDir = buildObj.guiDir + '/' + buildObj.platformType - buildObj.tmpDir = `${buildObj.guiDir}/temp` + buildObj.guiPlatformDir = buildObj.guiDir + buildObj.platformType + buildObj.tmpDir = `${buildObj.guiDir}temp` buildObj.buildArchivesDir = '/Users/jenkins/buildArchives' } @@ -197,7 +197,6 @@ function buildIos(buildObj: BuildObj) { buildObj.dSymFile = escapePath(`${buildDir}/${archiveDir}/dSYMs/${buildObj.productName}.app.dSYM`) // const appFile = sprintf('%s/%s/Products/Applications/%s.app', buildDir, archiveDir, buildObj.xcodeScheme) - const buildOutputIpaFile = escapePath(`${buildObj.tmpDir}/${buildObj.productName}.ipa`) buildObj.dSymZip = escapePath(`${buildObj.tmpDir}/${buildObj.productNameClean}-${buildObj.repoBranch}-${buildObj.buildNum}.dSYM.zip`) buildObj.ipaFile = escapePath(`${buildObj.tmpDir}/${buildObj.productNameClean}-${buildObj.repoBranch}-${buildObj.buildNum}.ipa`) @@ -230,6 +229,7 @@ function buildIos(buildObj: BuildObj) { call(cmdStr) mylog(`Renaming IPA file to ${buildObj.ipaFile}`) + const buildOutputIpaFile = `${buildObj.tmpDir}/${buildObj.productName}.ipa` fs.renameSync(buildOutputIpaFile, buildObj.ipaFile) cmdStr = `cp -a "${buildDir}/${archiveDir}/Products/Applications/${buildObj.productName}.app/main.jsbundle" ${buildObj.guiPlatformDir}/` From 1a0be95469b50ce2ecb5b2cbccfa87f509dcbd6f Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Thu, 25 May 2023 16:13:17 -0700 Subject: [PATCH 020/104] Update Visa Card Program support URL --- src/plugins/gui/RewardsCardPlugin.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/gui/RewardsCardPlugin.tsx b/src/plugins/gui/RewardsCardPlugin.tsx index 1dd4ce93b86..2f7230f0db7 100644 --- a/src/plugins/gui/RewardsCardPlugin.tsx +++ b/src/plugins/gui/RewardsCardPlugin.tsx @@ -17,7 +17,7 @@ import { IoniaMethods, makeIoniaProvider } from './providers/ioniaProvider' import { RewardCard } from './scenes/RewardsCardDashboardScene' import { initializeProviders } from './util/initializeProviders' -const SUPPORT_URL = 'https://edge.app/cards/' +const SUPPORT_URL = 'https://edge.app/visa-card-how-to' export interface RewardsCardItem { id: number From 782db68b90ecb82944a83cb6ed742ec6191bc703 Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Mon, 22 May 2023 11:35:15 -0700 Subject: [PATCH 021/104] Propagate errors thrown from Airship in dismissScamWarning --- src/actions/ScamWarningActions.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/actions/ScamWarningActions.tsx b/src/actions/ScamWarningActions.tsx index 9a30d97e8fd..6616fcb7946 100644 --- a/src/actions/ScamWarningActions.tsx +++ b/src/actions/ScamWarningActions.tsx @@ -15,7 +15,7 @@ export const triggerScamWarningModal = async (disklet: Disklet) => { try { await disklet.getText(SCAM_WARNING) } catch (error: any) { - Airship.show(bridge => { + await Airship.show(bridge => { const warningMessage = `\u2022 ${lstrings.warning_scam_message_financial_advice}\n\n\u2022 ${lstrings.warning_scam_message_irreversibility}\n\n\u2022 ${lstrings.warning_scam_message_unknown_recipients}` return ( @@ -23,10 +23,9 @@ export const triggerScamWarningModal = async (disklet: Disklet) => { {warningMessage} ) - }).then(async () => { - await disklet.setText(SCAM_WARNING, '') - - isWarningChecked = true }) + await disklet.setText(SCAM_WARNING, '') + + isWarningChecked = true } } From 9381b16ddd7380aa4ffdd74d7f58b48ab94e76b1 Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Mon, 22 May 2023 14:57:41 -0700 Subject: [PATCH 022/104] Make scamWarning explicitly shown for SendScene2 routing --- src/actions/ScanActions.tsx | 2 +- src/components/themed/TransactionListTop.tsx | 2 +- src/components/themed/WalletListSwipeableCurrencyRow.tsx | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/actions/ScanActions.tsx b/src/actions/ScanActions.tsx index 14fdaa95ee0..38e0401edda 100644 --- a/src/actions/ScanActions.tsx +++ b/src/actions/ScanActions.tsx @@ -221,7 +221,7 @@ export function handleWalletUris( // React navigation doesn't like passing non-serializable objects as params. Convert date to string first // https://github.com/react-navigation/react-navigation/issues/7925 const isoExpireDate = parsedUri?.expireDate?.toISOString() - navigation.push('send2', { walletId: wallet.id, minNativeAmount, spendInfo, isoExpireDate }) + navigation.push('send2', { walletId: wallet.id, minNativeAmount, spendInfo, isoExpireDate, hiddenFeaturesMap: { scamWarning: false } }) } catch (error: any) { // INVALID URI await Airship.show<'ok' | undefined>(bridge => ( diff --git a/src/components/themed/TransactionListTop.tsx b/src/components/themed/TransactionListTop.tsx index a1f0e469485..9c1a25c8f4b 100644 --- a/src/components/themed/TransactionListTop.tsx +++ b/src/components/themed/TransactionListTop.tsx @@ -302,7 +302,7 @@ export class TransactionListTopComponent extends React.PureComponent { diff --git a/src/components/themed/WalletListSwipeableCurrencyRow.tsx b/src/components/themed/WalletListSwipeableCurrencyRow.tsx index ecc1d45e8db..1009b0f4749 100644 --- a/src/components/themed/WalletListSwipeableCurrencyRow.tsx +++ b/src/components/themed/WalletListSwipeableCurrencyRow.tsx @@ -76,7 +76,10 @@ function WalletListSwipeableCurrencyRowComponent(props: Props) { navigation.navigate('send2', { walletId: wallet.id, tokenId, - openCamera: true + openCamera: true, + hiddenFeaturesMap: { + scamWarning: false + } }) } }) From 38a3a77b34e8dcb904da823ed41efe51674d2782 Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Mon, 22 May 2023 15:13:26 -0700 Subject: [PATCH 023/104] Make scamWarning explicitly shown for Payment Protocol deep-linking --- src/actions/DeepLinkingActions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/actions/DeepLinkingActions.ts b/src/actions/DeepLinkingActions.ts index bcfd40b1d56..4b18c3676a6 100644 --- a/src/actions/DeepLinkingActions.ts +++ b/src/actions/DeepLinkingActions.ts @@ -175,7 +175,7 @@ export async function handleLink(navigation: NavigationBase, dispatch: Dispatch, case 'paymentProto': { if (!allWalletsLoaded) return false - launchPaymentProto(navigation, account, link.uri, {}).catch(showError) + launchPaymentProto(navigation, account, link.uri, { hideScamWarning: false }).catch(showError) return true } From cc70d45929dc4dc22b7ccfc6c6bce9a7d2e5f4a4 Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Mon, 22 May 2023 15:14:42 -0700 Subject: [PATCH 024/104] Require explicit scamWarning setting to disable hiding in SendScene2 --- src/components/scenes/SendScene2.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/scenes/SendScene2.tsx b/src/components/scenes/SendScene2.tsx index bc32c21e123..0916f0b75fe 100644 --- a/src/components/scenes/SendScene2.tsx +++ b/src/components/scenes/SendScene2.tsx @@ -181,7 +181,7 @@ const SendComponent = (props: Props) => { spendInfo.currencyCode = currencyCode if (initialMount.current) { - if (hiddenFeaturesMap.scamWarning !== true) { + if (hiddenFeaturesMap.scamWarning === false) { triggerScamWarningModal(account.disklet) } initialMount.current = false From 71e5b0b24fd09ea630337e5d2b4ea1c1986d4080 Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Fri, 26 May 2023 11:06:36 -0700 Subject: [PATCH 025/104] Changed Visa Card Program menu icon --- src/components/themed/ControlPanel.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/themed/ControlPanel.tsx b/src/components/themed/ControlPanel.tsx index 360b1b72195..8f9695daaaf 100644 --- a/src/components/themed/ControlPanel.tsx +++ b/src/components/themed/ControlPanel.tsx @@ -273,7 +273,7 @@ export function ControlPanel(props: DrawerContentComponentProps) { dispatch(executePluginAction(navigation, 'rewardscard', 'sell')) navigation.dispatch(DrawerActions.closeDrawer()) }, - iconNameFontAwesome: 'cc-visa', + iconNameFontAwesome: 'credit-card', title: sprintf(lstrings.rewards_card_call_to_action, defaultFiat) }) } @@ -364,7 +364,7 @@ export function ControlPanel(props: DrawerContentComponentProps) { {rowData.iconName != null ? : null} {rowData.iconNameFontAwesome != null ? ( - + ) : null} From 7db2aef889c6af2b94504361b042ab584f137072 Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Fri, 26 May 2023 11:39:26 -0700 Subject: [PATCH 026/104] Fix incorrect pluginId for DOGE --- src/plugins/gui/providers/ioniaProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/gui/providers/ioniaProvider.ts b/src/plugins/gui/providers/ioniaProvider.ts index 1a909ce907b..55443ac6c99 100644 --- a/src/plugins/gui/providers/ioniaProvider.ts +++ b/src/plugins/gui/providers/ioniaProvider.ts @@ -337,7 +337,7 @@ export const makeIoniaProvider: FiatProviderFactory = { bitcoin: { BTC: true }, bitcoincash: { BCH: true }, dash: { DASH: true }, - doge: { DOGE: true }, + dogecoin: { DOGE: true }, litecoin: { LTC: true } }, fiat: { From 8b0f54f0b809cae1f96b46325e6bce534141dfae Mon Sep 17 00:00:00 2001 From: Matthew Date: Fri, 26 May 2023 13:05:02 -0700 Subject: [PATCH 027/104] Fix date --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 688a9bb2b54..db114567ac7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # edge-react-gui -## 3.10.0 (2023-04-25) +## 3.10.0 (2023-05-25) - Add Pepe (PEPE) - Added Visa® Debit Card (beta) From bd6f8cfe745fbbd163d55e0bfd20d873684ceb0b Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Fri, 26 May 2023 12:46:25 -0700 Subject: [PATCH 028/104] Fix last card delete handling --- src/locales/en_US.ts | 1 + src/locales/strings/enUS.json | 1 + src/plugins/gui/RewardsCardPlugin.tsx | 3 ++- src/plugins/gui/scenes/RewardsCardDashboardScene.tsx | 10 +++++++++- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/locales/en_US.ts b/src/locales/en_US.ts index cc6d68ae577..c54ae65fc24 100644 --- a/src/locales/en_US.ts +++ b/src/locales/en_US.ts @@ -1523,6 +1523,7 @@ const strings = { rewards_card_error_missing_payment_address: `Missing payment address from provider`, rewards_card_error_amount_max_s: `Maximum card purchase amount is $%s`, rewards_card_error_amount_min_s: `Minimum card purchase amount is $%s`, + rewards_card_no_cards: 'You have no active cards.', rewards_card_select_wallet: `Select wallet to use to purchase card`, rewards_card_terms_of_use_message: `Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds.` } diff --git a/src/locales/strings/enUS.json b/src/locales/strings/enUS.json index bd81842c89d..77a64227747 100644 --- a/src/locales/strings/enUS.json +++ b/src/locales/strings/enUS.json @@ -1344,6 +1344,7 @@ "rewards_card_error_missing_payment_address": "Missing payment address from provider", "rewards_card_error_amount_max_s": "Maximum card purchase amount is $%s", "rewards_card_error_amount_min_s": "Minimum card purchase amount is $%s", + "rewards_card_no_cards": "You have no active cards.", "rewards_card_select_wallet": "Select wallet to use to purchase card", "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds." } \ No newline at end of file diff --git a/src/plugins/gui/RewardsCardPlugin.tsx b/src/plugins/gui/RewardsCardPlugin.tsx index 2f7230f0db7..33fc3bc1722 100644 --- a/src/plugins/gui/RewardsCardPlugin.tsx +++ b/src/plugins/gui/RewardsCardPlugin.tsx @@ -129,6 +129,7 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { provider.otherMethods.hideCard(card.id) // Remove card from plugin state rewardCards = rewardCards.filter(c => c.id !== card.id) + // Reset state for dashboard showDashboard({ showLoading: false }) } @@ -230,7 +231,7 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { const onDone = () => { showDashboard({ showLoading: true }) refreshRewardsCards(0) - .then(async () => await showDashboard({ showLoading: false })) + .finally(async () => await showDashboard({ showLoading: false })) .catch(showError) } diff --git a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx index 0da266b04f6..22c73d4cbe2 100644 --- a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx +++ b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx @@ -8,6 +8,7 @@ import { styled } from '../../../components/hoc/styled' import { Space } from '../../../components/layout/Space' import { useTheme } from '../../../components/services/ThemeContext' import { DividerLine } from '../../../components/themed/DividerLine' +import { EdgeText } from '../../../components/themed/EdgeText' import { MainButton } from '../../../components/themed/MainButton' import { SceneHeader } from '../../../components/themed/SceneHeader' import { useHandler } from '../../../hooks/useHandler' @@ -64,7 +65,8 @@ export const RewardsCardDashboardScene = (props: Props) => { ) })} - {items.length === 0 || showLoading ? ( + {items.length === 0 && !showLoading ? {lstrings.rewards_card_no_cards} : null} + {showLoading ? ( @@ -113,6 +115,12 @@ export const RewardCard = ({ item, onPress, onRemovePress }: { item: RewardsCard ) } +const MessageText = styled(EdgeText)(props => ({ + fontFamily: props.theme.fontFaceMedium, + color: props.theme.secondaryText, + textAlign: 'center' +})) + const CardListContainer = styled(View)<{ bottomSpace: number }>(props => ({ justifyContent: 'space-around', marginBottom: props.bottomSpace, From f84638250fae21bde7780f55be33069a7822f9e6 Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Fri, 26 May 2023 13:06:06 -0700 Subject: [PATCH 029/104] Only show welcome scene for Visa Card Program non-users --- src/plugins/gui/RewardsCardPlugin.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/gui/RewardsCardPlugin.tsx b/src/plugins/gui/RewardsCardPlugin.tsx index 33fc3bc1722..3df099c20b3 100644 --- a/src/plugins/gui/RewardsCardPlugin.tsx +++ b/src/plugins/gui/RewardsCardPlugin.tsx @@ -325,7 +325,7 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { regionCode: startParams.regionCode } - if (rewardCards.length > 0) { + if (isAuthenticated) { await showDashboard({ showLoading: false }) } else { await showWelcome() From 30b4b90877699b54c116b430ddd62b796ca3c517 Mon Sep 17 00:00:00 2001 From: Itay <4023066+itayplav@users.noreply.github.com> Date: Sat, 20 May 2023 03:01:58 -0500 Subject: [PATCH 030/104] Add `android:dev` & `android:dev:test-release` commands - `android:dev`: `--active-arch-only`, `--variant=debug` - `android:dev:test-release`: `--active-arch-only`, `--variant=release` --- package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package.json b/package.json index 6408fe9f1d0..8df29d9ce90 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,8 @@ ], "scripts": { "android:clean": "cd android && ./gradlew clean && rm -rf build && cd ../", + "android:dev": "react-native run-android --active-arch-only --variant=debug", + "android:dev:test-release": "react-native run-android --active-arch-only --variant=release", "android:logcat": "adb logcat *:S ReactNative:V ReactNativeJS:V", "android:release-clean-install": "npm run android:clean && npm run android:release && adb install -r android/app/build/outputs/apk/release/app-release.apk", "android:release-install": "npm run android:release && adb install -r android/app/build/outputs/apk/release/app-release.apk", From 3317cbe2d056bb46c3c0dbbb1f566c51abd06079 Mon Sep 17 00:00:00 2001 From: Paul Puey Date: Fri, 26 May 2023 18:15:21 -0700 Subject: [PATCH 031/104] Track errors in onLogin to Bugsnag --- src/components/scenes/LoginScene.tsx | 4 +++- src/util/tracking.ts | 29 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/components/scenes/LoginScene.tsx b/src/components/scenes/LoginScene.tsx index 01f8542c4c9..5c11846cdde 100644 --- a/src/components/scenes/LoginScene.tsx +++ b/src/components/scenes/LoginScene.tsx @@ -20,6 +20,7 @@ import { Dispatch } from '../../types/reduxTypes' import { NavigationBase, NavigationProp, RouteProp } from '../../types/routerTypes' import { ImageProp } from '../../types/Theme' import { GuiTouchIdInfo } from '../../types/types' +import { trackError } from '../../util/tracking' import { pickRandom } from '../../util/utils' import { withServices } from '../hoc/withServices' import { showHelpModal } from '../modals/HelpModal' @@ -169,7 +170,8 @@ class LoginSceneComponent extends React.PureComponent { data: serverSettingsToNotificationSettings(newSettings) }) } catch (e) { - console.error(String(e)) + trackError(e, 'LoginScene:onLogin:setDeviceSettings') + console.error(e) } } } diff --git a/src/util/tracking.ts b/src/util/tracking.ts index 02080a8a510..347a34f1254 100644 --- a/src/util/tracking.ts +++ b/src/util/tracking.ts @@ -1,3 +1,4 @@ +import Bugsnag from '@bugsnag/react-native' import analytics from '@react-native-firebase/analytics' import { getUniqueId, getVersion } from 'react-native-device-info' @@ -65,6 +66,34 @@ if (ENV.USE_FIREBASE) { } } +/** + * Track error to external reporting service (ie. Bugsnag) + */ + +export async function trackError( + error: unknown, + tag?: string, + metadata?: { + [key: string]: any + } +): Promise { + let err: Error | string + if (error instanceof Error || typeof error === 'string') { + err = error + } else { + // At least send an error which should give us the callstack + err = 'Unknown error occurred' + } + + if (tag == null) { + Bugsnag.notify(err) + } else { + Bugsnag.notify(err, report => { + report.addMetadata(tag, metadata ?? {}) + }) + } +} + /** * Send a raw event to all backends. */ From 46d2cafea49db934b10531ed6323bbbf7cd29088 Mon Sep 17 00:00:00 2001 From: Paul Puey Date: Mon, 29 May 2023 15:16:38 -0700 Subject: [PATCH 032/104] Properly refresh markets view on fiat code change --- src/components/scenes/CoinRankingScene.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/components/scenes/CoinRankingScene.tsx b/src/components/scenes/CoinRankingScene.tsx index 3dfe214e920..0e9cbb5d214 100644 --- a/src/components/scenes/CoinRankingScene.tsx +++ b/src/components/scenes/CoinRankingScene.tsx @@ -54,6 +54,7 @@ const CoinRankingComponent = (props: Props) => { const { navigation } = props const defaultIsoFiat = useSelector(state => `iso:${getDefaultFiat(state)}`) + const [lastUsedFiat, setLastUsedFiat] = useState(defaultIsoFiat) const mounted = React.useRef(true) const textInput = React.useRef(null) @@ -65,7 +66,7 @@ const CoinRankingComponent = (props: Props) => { const [searching, setSearching] = useState(false) const [percentChangeTimeFrame, setPercentChangeTimeFrame] = useState('hours24') const [assetSubText, setPriceSubText] = useState('marketCap') - const extraData = React.useMemo(() => ({ assetSubText, percentChangeTimeFrame }), [assetSubText, percentChangeTimeFrame]) + const extraData = React.useMemo(() => ({ assetSubText, lastUsedFiat, percentChangeTimeFrame }), [assetSubText, lastUsedFiat, percentChangeTimeFrame]) const { coinRankingDatas } = coinRanking @@ -73,7 +74,7 @@ const CoinRankingComponent = (props: Props) => { const { index, item } = itemObj const currencyCode = coinRankingDatas[index]?.currencyCode ?? 'NO_CURRENCY_CODE' const rank = coinRankingDatas[index]?.rank ?? 'NO_RANK' - const key = `${index}-${item}-${rank}-${currencyCode}` + const key = `${index}-${item}-${rank}-${currencyCode}-${lastUsedFiat}` debugLog(LOG_COINRANK, `renderItem ${key.toString()}`) return ( @@ -141,7 +142,7 @@ const CoinRankingComponent = (props: Props) => { const queryLoop = async () => { try { let start = 1 - debugLog(LOG_COINRANK, `queryLoop dataSize=${dataSize} requestDataSize=${requestDataSize}`) + debugLog(LOG_COINRANK, `queryLoop ${defaultIsoFiat} dataSize=${dataSize} requestDataSize=${requestDataSize}`) while (start < requestDataSize) { const url = `v2/coinrank?fiatCode=${defaultIsoFiat}&start=${start}&length=${QUERY_PAGE_SIZE}` const response = await fetchRates(url) @@ -161,6 +162,9 @@ const CoinRankingComponent = (props: Props) => { start += QUERY_PAGE_SIZE } setDataSize(coinRankingDatas.length) + if (lastUsedFiat !== defaultIsoFiat) { + setLastUsedFiat(defaultIsoFiat) + } } catch (e: any) { console.warn(e.message) } @@ -170,7 +174,7 @@ const CoinRankingComponent = (props: Props) => { clearTimeout(timeoutHandler.current) } queryLoop().catch(e => debugLog(LOG_COINRANK, e.message)) - }, [requestDataSize]) + }, [requestDataSize, defaultIsoFiat]) const listdata: number[] = React.useMemo(() => { debugLog(LOG_COINRANK, `Updating listdata dataSize=${dataSize} searchText=${searchText}`) From 732a19da1a280b5086ad6f77f16506e74b86cc04 Mon Sep 17 00:00:00 2001 From: Paul Puey Date: Fri, 26 May 2023 18:38:02 -0700 Subject: [PATCH 033/104] Tag useAsyncEffect with caller to find source of showError --- .../services/AccountCallbackManager.tsx | 40 ++++---- src/components/services/ActionQueueService.ts | 24 +++-- src/components/services/AirshipInstance.tsx | 23 +++-- src/components/services/LoanManagerService.ts | 96 ++++++++++--------- .../services/PermissionsManager.tsx | 12 ++- src/components/services/Services.tsx | 42 ++++---- src/hooks/useAsyncEffect.ts | 10 +- 7 files changed, 143 insertions(+), 104 deletions(-) diff --git a/src/components/services/AccountCallbackManager.tsx b/src/components/services/AccountCallbackManager.tsx index d9d31a35700..6f597b191ee 100644 --- a/src/components/services/AccountCallbackManager.tsx +++ b/src/components/services/AccountCallbackManager.tsx @@ -134,24 +134,28 @@ export function AccountCallbackManager(props: Props) { }) // Do the expensive work with rate limiting: - useAsyncEffect(async () => { - setDirty(notDirty) - - // Update wallets: - if (dirty.walletList) { - // Update all wallets (hammer mode): - console.log('Updating wallet list') - await dispatch(updateWalletsRequest()) - await snooze(1000) - } - - // Update exchange rates: - if (dirty.rates) { - console.log('Updating exchange rates') - await dispatch(updateExchangeRates()) - await snooze(1000) - } - }, [dirty]) + useAsyncEffect( + async () => { + setDirty(notDirty) + + // Update wallets: + if (dirty.walletList) { + // Update all wallets (hammer mode): + console.log('Updating wallet list') + await dispatch(updateWalletsRequest()) + await snooze(1000) + } + + // Update exchange rates: + if (dirty.rates) { + console.log('Updating exchange rates') + await dispatch(updateExchangeRates()) + await snooze(1000) + } + }, + [dirty], + 'AccountCallbackManager' + ) return null } diff --git a/src/components/services/ActionQueueService.ts b/src/components/services/ActionQueueService.ts index 3e4fb1e52dc..ec3631acda1 100644 --- a/src/components/services/ActionQueueService.ts +++ b/src/components/services/ActionQueueService.ts @@ -65,16 +65,20 @@ export const ActionQueueService = () => { // Initialization // - useAsyncEffect(async () => { - if (account?.dataStore != null) { - const store = makeActionQueueStore(account, clientId) - const queue = await store.getActionQueueMap() - dispatch({ - type: 'ACTION_QUEUE/LOAD_QUEUE', - data: queue - }) - } - }, [account, dispatch]) + useAsyncEffect( + async () => { + if (account?.dataStore != null) { + const store = makeActionQueueStore(account, clientId) + const queue = await store.getActionQueueMap() + dispatch({ + type: 'ACTION_QUEUE/LOAD_QUEUE', + data: queue + }) + } + }, + [account, dispatch], + 'ActionQueueService' + ) // // Runtime Loop diff --git a/src/components/services/AirshipInstance.tsx b/src/components/services/AirshipInstance.tsx index 0fa6e399b7e..d916cb95c32 100644 --- a/src/components/services/AirshipInstance.tsx +++ b/src/components/services/AirshipInstance.tsx @@ -8,13 +8,21 @@ import { AirshipToast } from '../common/AirshipToast' import { AlertDropdown } from '../navigation/AlertDropdown' export const Airship = makeAirship() +export interface ShowErrorWarningOptions { + // Report error to external bug tracking tool (ie. Bugsnag) + trackError?: boolean + tag?: string +} /** * Shows an error to the user. * Used when some user-requested operation fails. */ -export function showError(error: unknown): void { - const translatedError = translateError(error) - Bugsnag.notify(`showError: ${translatedError}`) +export function showError(error: unknown, options: ShowErrorWarningOptions = {}): void { + const { trackError = true, tag } = options + const translatedError = tag ? `Tag: ${tag}. ` + translateError(error) : translateError(error) + if (trackError) { + Bugsnag.notify(`showError: ${translatedError}`) + } console.log(redText('Showing error drop-down alert: ' + makeErrorLog(error))) Airship.show(bridge => ) } @@ -23,9 +31,12 @@ export function showError(error: unknown): void { * Shows a warning to the user. * Used when some user-requested operation succeeds but with a warning. */ -export function showWarning(error: unknown): void { - const translatedError = translateError(error) - Bugsnag.notify(`showWarning: ${translatedError}`) +export function showWarning(error: unknown, options: ShowErrorWarningOptions = {}): void { + const { trackError = true, tag } = options + const translatedError = tag ? `Tag: ${tag}. ` + translateError(error) : translateError(error) + if (trackError) { + Bugsnag.notify(`showWarning: ${translatedError}`) + } console.log(yellowText('Showing warning drop-down alert: ' + makeErrorLog(error))) Airship.show(bridge => ) } diff --git a/src/components/services/LoanManagerService.ts b/src/components/services/LoanManagerService.ts index f62bbf57f64..54c047e11da 100644 --- a/src/components/services/LoanManagerService.ts +++ b/src/components/services/LoanManagerService.ts @@ -53,11 +53,15 @@ export const LoanManagerService = (props: Props) => { // Initialization // - useAsyncEffect(async () => { - if (account.disklet != null) { - dispatch(loadLoanAccounts(account)) - } - }, [account, dispatch]) + useAsyncEffect( + async () => { + if (account.disklet != null) { + dispatch(loadLoanAccounts(account)) + } + }, + [account, dispatch], + 'LoanManagerService 1' + ) // // Cleanup Routine @@ -95,50 +99,54 @@ export const LoanManagerService = (props: Props) => { // Cache changes to specific watched properties of the loan accounts to detect // deltas - useAsyncEffect(async () => { - for (const loanAccountId of Object.keys(loanAccountMap)) { - await waitForBorrowEngineSync(loanAccountMap[loanAccountId].borrowEngine) - const { borrowEngine } = loanAccountMap[loanAccountId] - const { debts, collaterals } = borrowEngine - - // Cache accounts only if we can support liquidation price calculations - const filteredDebts = debts.filter(debt => !zeroString(debt.nativeAmount)) - const filteredCollaterals = collaterals.filter(collateral => !zeroString(collateral.nativeAmount)) - const onlyOneCollateral = filteredCollaterals.length === 1 - // TODO: Find a less crude way to determine if a token is USD-based - const onlyUsdBasedDebts = filteredDebts.every(debt => (debt.tokenId != null ? USD_BASED_TOKEN_IDS.includes(debt.tokenId.toLowerCase()) : false)) - - if (onlyOneCollateral && onlyUsdBasedDebts) { - // Only trigger push events after the exchange rates are available for - // all loan assets on this account - const loanAssetTokenIds = [...filteredDebts, ...filteredCollaterals].map(loanAsset => loanAsset.tokenId) - if (loanAssetTokenIds.every(tokenId => tokenId == null || !zeroString(exchangeRates[`${getCurrencyCode(borrowEngine, tokenId)}_iso:USD`]))) { - if (debts.length > 0) { - // If it's the first time the account has been seen, we want to - // avoid a notification if it already exceeds the liquidation price - // right when the app is booted. Newly created loans can never - // exceed the liquidation price. - if (cachedLoanAssetsMap[loanAccountId] == null) { - cachedLoanAssetsMap[loanAccountId] = JSON.stringify([...debts, ...collaterals]) + useAsyncEffect( + async () => { + for (const loanAccountId of Object.keys(loanAccountMap)) { + await waitForBorrowEngineSync(loanAccountMap[loanAccountId].borrowEngine) + const { borrowEngine } = loanAccountMap[loanAccountId] + const { debts, collaterals } = borrowEngine + + // Cache accounts only if we can support liquidation price calculations + const filteredDebts = debts.filter(debt => !zeroString(debt.nativeAmount)) + const filteredCollaterals = collaterals.filter(collateral => !zeroString(collateral.nativeAmount)) + const onlyOneCollateral = filteredCollaterals.length === 1 + // TODO: Find a less crude way to determine if a token is USD-based + const onlyUsdBasedDebts = filteredDebts.every(debt => (debt.tokenId != null ? USD_BASED_TOKEN_IDS.includes(debt.tokenId.toLowerCase()) : false)) + + if (onlyOneCollateral && onlyUsdBasedDebts) { + // Only trigger push events after the exchange rates are available for + // all loan assets on this account + const loanAssetTokenIds = [...filteredDebts, ...filteredCollaterals].map(loanAsset => loanAsset.tokenId) + if (loanAssetTokenIds.every(tokenId => tokenId == null || !zeroString(exchangeRates[`${getCurrencyCode(borrowEngine, tokenId)}_iso:USD`]))) { + if (debts.length > 0) { + // If it's the first time the account has been seen, we want to + // avoid a notification if it already exceeds the liquidation price + // right when the app is booted. Newly created loans can never + // exceed the liquidation price. + if (cachedLoanAssetsMap[loanAccountId] == null) { + cachedLoanAssetsMap[loanAccountId] = JSON.stringify([...debts, ...collaterals]) + await uploadLiquidationPushEvents(loanAccountId, false) + } + // If we already have a cache of this account and the LTV changed, + // upload a push notification even if the liquidation price has been + // exceeded + else if (JSON.stringify([...debts, ...collaterals]) !== cachedLoanAssetsMap[loanAccountId]) { + cachedLoanAssetsMap[loanAccountId] = JSON.stringify([...debts, ...collaterals]) + await uploadLiquidationPushEvents(loanAccountId, true) + } + } else { + // Ensure push event is cleared if account is closed or debts no + // longer exist await uploadLiquidationPushEvents(loanAccountId, false) } - // If we already have a cache of this account and the LTV changed, - // upload a push notification even if the liquidation price has been - // exceeded - else if (JSON.stringify([...debts, ...collaterals]) !== cachedLoanAssetsMap[loanAccountId]) { - cachedLoanAssetsMap[loanAccountId] = JSON.stringify([...debts, ...collaterals]) - await uploadLiquidationPushEvents(loanAccountId, true) - } - } else { - // Ensure push event is cleared if account is closed or debts no - // longer exist - await uploadLiquidationPushEvents(loanAccountId, false) } } + setCachedLoanAssetsMap({ ...cachedLoanAssetsMap }) } - setCachedLoanAssetsMap({ ...cachedLoanAssetsMap }) - } - }, [loanAccountMap, exchangeRates]) + }, + [loanAccountMap, exchangeRates], + 'LoanManagerService 2' + ) const uploadLiquidationPushEvents = React.useCallback( async (loanAccountId: string, isSkipPriceCheck: boolean) => { diff --git a/src/components/services/PermissionsManager.tsx b/src/components/services/PermissionsManager.tsx index 20c4369c633..8e267c3f444 100644 --- a/src/components/services/PermissionsManager.tsx +++ b/src/components/services/PermissionsManager.tsx @@ -20,10 +20,14 @@ export const PermissionsManager = () => { const statePermissions = useSelector(state => state.permissions) const isAppForeground = useIsAppForeground() - useAsyncEffect(async () => { - if (!isAppForeground) return - await dispatch(setNewPermissions(statePermissions)) - }, [isAppForeground, statePermissions]) + useAsyncEffect( + async () => { + if (!isAppForeground) return + await dispatch(setNewPermissions(statePermissions)) + }, + [isAppForeground, statePermissions], + 'PermissionsManager' + ) return null } diff --git a/src/components/services/Services.tsx b/src/components/services/Services.tsx index 9c250649ad8..135bc2de767 100644 --- a/src/components/services/Services.tsx +++ b/src/components/services/Services.tsx @@ -76,27 +76,35 @@ export function Services(props: Props) { }) // Methods to call immediately after login: - useAsyncEffect(async () => { - if (account != null) { - maybeShowFioHandleModal(account) - } - }, [account, maybeShowFioHandleModal]) + useAsyncEffect( + async () => { + if (account != null) { + maybeShowFioHandleModal(account) + } + }, + [account, maybeShowFioHandleModal], + 'Services 1' + ) // Methods to call once all of the currency wallets have been loaded - useAsyncEffect(async () => { - if (account?.waitForAllWallets == null) return - await account.waitForAllWallets() + useAsyncEffect( + async () => { + if (account?.waitForAllWallets == null) return + await account.waitForAllWallets() - dispatch(registerNotificationsV2()).catch(e => { - console.warn('registerNotificationsV2 error:', e) - }) + dispatch(registerNotificationsV2()).catch(e => { + console.warn('registerNotificationsV2 error:', e) + }) - // HACK: The balances object isn't full when the above promise resolves so we need to wait a few seconds before proceeding - await snooze(5000) - dispatch(checkCompromisedKeys(navigation)).catch(e => { - console.warn('checkCompromisedKeys error:', e) - }) - }, [account]) + // HACK: The balances object isn't full when the above promise resolves so we need to wait a few seconds before proceeding + await snooze(5000) + dispatch(checkCompromisedKeys(navigation)).catch(e => { + console.warn('checkCompromisedKeys error:', e) + }) + }, + [account], + 'Services 2' + ) // Methods to call periodically useRefresher( diff --git a/src/hooks/useAsyncEffect.ts b/src/hooks/useAsyncEffect.ts index aa4c306ef41..3df9c36d902 100644 --- a/src/hooks/useAsyncEffect.ts +++ b/src/hooks/useAsyncEffect.ts @@ -18,7 +18,7 @@ interface State { * Runs an effect when its dependencies change, just like `useEffect`, * but awaits the returned promise before starting the next run. */ -export function useAsyncEffect(effect: AsyncEffect, deps?: unknown[]): void { +export function useAsyncEffect(effect: AsyncEffect, deps?: unknown[], tag?: string): void { const state = React.useRef({ closed: false, dirty: false, @@ -32,9 +32,9 @@ export function useAsyncEffect(effect: AsyncEffect, deps?: unknown[]): void { React.useEffect( () => () => { state.current.closed = true - wakeup(state.current) + wakeup(state.current, tag) }, - [] + [tag] ) // Check for differences: @@ -59,7 +59,7 @@ function matchDeps(a?: unknown[], b?: unknown[]): boolean { /** * Does the next thing based on the current state. */ -function wakeup(state: State): void { +function wakeup(state: State, tag?: string): void { // We can't do anything if the effect is already running: if (state.running) return @@ -82,7 +82,7 @@ function wakeup(state: State): void { wakeup(state) }) .catch(error => { - showError(error) + showError(error, { tag }) state.running = false wakeup(state) }) From b0933a7b5bbf61cfa3ac075a3a5ddd264865c45f Mon Sep 17 00:00:00 2001 From: Paul Puey Date: Sun, 28 May 2023 22:56:21 -0700 Subject: [PATCH 034/104] Do not track internet disconnected showErrors This gets noisy in Bugsnag and isn't the type of error we want to find. --- src/components/services/NetworkActivity.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/services/NetworkActivity.ts b/src/components/services/NetworkActivity.ts index 3e28045e4f9..41756f6571b 100644 --- a/src/components/services/NetworkActivity.ts +++ b/src/components/services/NetworkActivity.ts @@ -17,7 +17,7 @@ class NetworkActivityComponent extends React.Component { console.log('NetworkActivity - isConnected changed: ', info.isConnected) this.props.changeConnectivity(info.isConnected ?? false) if (!info.isConnected) { - showError(`${lstrings.network_alert_title}`) + showError(`${lstrings.network_alert_title}`, { trackError: false }) } } From 07607e5ae7df07322f4b4c521dd85de20dce13b6 Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Tue, 30 May 2023 11:11:35 -0700 Subject: [PATCH 035/104] Upgrade edge-currency-accountbased@^1.2.10 --- ios/Podfile.lock | 4 ++-- package.json | 2 +- yarn.lock | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index d9def5f4b8d..dd589ab47db 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -20,7 +20,7 @@ PODS: - DoubleConversion (1.1.6) - edge-core-js (0.21.4): - React-Core - - edge-currency-accountbased (1.2.9): + - edge-currency-accountbased (1.2.10): - React-Core - edge-login-ui-rn (1.4.7): - React @@ -1110,7 +1110,7 @@ SPEC CHECKSUMS: disklet: e7ed3e673ccad9d175a1675f9f3589ffbf69a5fd DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662 edge-core-js: bd6760a2efcca8610d961d71fe9c34f103add462 - edge-currency-accountbased: 39a708c32f30a3db81ca5259880dcaa14315549d + edge-currency-accountbased: a8e30112ffb0b994e5bad97492b31b5d9526970d edge-login-ui-rn: f6711ffc1cb89e1449290dbceef40d76e67a3a3b FBLazyVector: d2db9d00883282819d03bbd401b2ad4360d47580 FBReactNativeSpec: 94da4d84ba3b1acf459103320882daa481a2b62d diff --git a/package.json b/package.json index 8df29d9ce90..61e649974da 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "detect-bundler": "^1.1.0", "disklet": "^0.5.2", "edge-core-js": "^0.21.4", - "edge-currency-accountbased": "^1.2.9", + "edge-currency-accountbased": "^1.2.10", "edge-currency-monero": "^1.0.0", "edge-currency-plugins": "^2.0.2", "edge-exchange-plugins": "^0.19.5", diff --git a/yarn.lock b/yarn.lock index 8c32b48d6dc..1e4ecd38b1f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7284,10 +7284,10 @@ edge-core-js@^0.21.4: yaob "^0.3.9" yavent "^0.1.3" -edge-currency-accountbased@^1.2.9: - version "1.2.9" - resolved "https://registry.yarnpkg.com/edge-currency-accountbased/-/edge-currency-accountbased-1.2.9.tgz#3b4e725e49cee84f65b2db3b6b6a5beb70c49a9a" - integrity sha512-jRtTpCo9J1K8JJwOVaqaYleeNiHfpGF2ic2Hs/oawTk4+/5zknyW1JISbL7DSsRq/8LyGgTUxpLzLBr6/cZrvg== +edge-currency-accountbased@^1.2.10: + version "1.2.10" + resolved "https://registry.yarnpkg.com/edge-currency-accountbased/-/edge-currency-accountbased-1.2.10.tgz#bd08fcbd3a80283b43f732130b7b85cf271b2f34" + integrity sha512-mD5rwPcrZbIaij/2cxWacwzpRyDdK0ACgQMJegLROw3zfGuUZBb7ULv0J4ZsTkG14QS7xh1oA5FX4G3fn/WoJA== dependencies: "@binance-chain/javascript-sdk" "^4.2.0" "@ethereumjs/common" "^2.4.0" From 5aaae42d018d605b7e85cb243fa19912cefe1b15 Mon Sep 17 00:00:00 2001 From: Paul Puey Date: Mon, 29 May 2023 21:41:34 -0700 Subject: [PATCH 036/104] Set rewardsNotClaimable for TC Savers --- src/plugins/stake-plugins/thorchainSavers/tcSaversPlugin.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/stake-plugins/thorchainSavers/tcSaversPlugin.ts b/src/plugins/stake-plugins/thorchainSavers/tcSaversPlugin.ts index 7b3e4645631..67de0415b09 100644 --- a/src/plugins/stake-plugins/thorchainSavers/tcSaversPlugin.ts +++ b/src/plugins/stake-plugins/thorchainSavers/tcSaversPlugin.ts @@ -135,6 +135,7 @@ const policyDefault = { apy: 0, stakeProviderInfo, disableMaxStake: true, + rewardsNotClaimable: true, stakeWarning: null, unstakeWarning: null, claimWarning: null From 8aabcc0ba06961b3612dad8128b49761acce74c0 Mon Sep 17 00:00:00 2001 From: Matthew Date: Tue, 30 May 2023 17:58:29 -0700 Subject: [PATCH 037/104] Remove Bitaccess --- .../__snapshots__/GuiPlugins.test.ts.snap | 22 ------ .../AutoLogoutModal.test.tsx.snap | 3 - .../FioAddressListScene.test.tsx.snap | 6 -- .../guiPlugins/guiPluginLogoBitaccessDark.png | Bin 1404 -> 0 bytes src/components/scenes/GuiPluginListScene.tsx | 5 +- src/constants/plugins/GuiPlugins.ts | 7 -- src/constants/plugins/sellPluginList.json | 74 ------------------ src/theme/variables/edgeDark.ts | 2 - src/theme/variables/edgeLight.ts | 2 - src/theme/variables/testDark.ts | 2 - src/theme/variables/testLight.ts | 2 - src/types/Theme.ts | 1 - 12 files changed, 2 insertions(+), 124 deletions(-) delete mode 100644 src/assets/images/guiPlugins/guiPluginLogoBitaccessDark.png diff --git a/src/__tests__/__snapshots__/GuiPlugins.test.ts.snap b/src/__tests__/__snapshots__/GuiPlugins.test.ts.snap index 567bb1721a0..e21d73f123b 100644 --- a/src/__tests__/__snapshots__/GuiPlugins.test.ts.snap +++ b/src/__tests__/__snapshots__/GuiPlugins.test.ts.snap @@ -259,28 +259,6 @@ Limit: $1,000 per card, $10,000 per day "pluginId": "rewardscard", "title": "Visa® Card Program", }, - Object { - "cryptoCodes": Array [ - "BTC", - "ETH", - "LINK", - "DAI", - "LTC", - ], - "deepPath": "", - "deepQuery": Object { - "country": "US", - }, - "description": "Fee: Varies / Settlement: 10 - 20 minutes -Limit: Varies", - "partnerIconPath": "mktg/bitaccess.png", - "paymentTypeLogoKey": "cash", - "paymentTypes": Array [ - "cash", - ], - "pluginId": "bitaccess", - "title": "Cash", - }, Object { "cryptoCodes": Array [ "BTC", diff --git a/src/__tests__/modals/__snapshots__/AutoLogoutModal.test.tsx.snap b/src/__tests__/modals/__snapshots__/AutoLogoutModal.test.tsx.snap index 88c8ca9fd35..838894137bd 100644 --- a/src/__tests__/modals/__snapshots__/AutoLogoutModal.test.tsx.snap +++ b/src/__tests__/modals/__snapshots__/AutoLogoutModal.test.tsx.snap @@ -110,9 +110,6 @@ exports[`AutoLogoutModal should render with loading props 1`] = ` "fontFaceDefault": "Quicksand-Regular", "fontFaceMedium": "Quicksand-Medium", "fontFaceSymbols": "Quicksand-Regular", - "guiPluginLogoBitaccess": Object { - "testUri": "../../../src/assets/images/guiPlugins/guiPluginLogoBitaccessDark.png", - }, "guiPluginLogoMoonpay": Object { "testUri": "../../../src/assets/images/guiPlugins/guiPluginLogoMoonpayDark.png", }, diff --git a/src/__tests__/scenes/__snapshots__/FioAddressListScene.test.tsx.snap b/src/__tests__/scenes/__snapshots__/FioAddressListScene.test.tsx.snap index 79db16194ca..faa333aec53 100644 --- a/src/__tests__/scenes/__snapshots__/FioAddressListScene.test.tsx.snap +++ b/src/__tests__/scenes/__snapshots__/FioAddressListScene.test.tsx.snap @@ -142,9 +142,6 @@ exports[`FioAddressList should render with loading props 1`] = ` "fontFaceDefault": "Quicksand-Regular", "fontFaceMedium": "Quicksand-Medium", "fontFaceSymbols": "Quicksand-Regular", - "guiPluginLogoBitaccess": Object { - "testUri": "../../../src/assets/images/guiPlugins/guiPluginLogoBitaccessDark.png", - }, "guiPluginLogoMoonpay": Object { "testUri": "../../../src/assets/images/guiPlugins/guiPluginLogoMoonpayDark.png", }, @@ -592,9 +589,6 @@ exports[`FioAddressList should render with loading props 1`] = ` "fontFaceDefault": "Quicksand-Regular", "fontFaceMedium": "Quicksand-Medium", "fontFaceSymbols": "Quicksand-Regular", - "guiPluginLogoBitaccess": Object { - "testUri": "../../../src/assets/images/guiPlugins/guiPluginLogoBitaccessDark.png", - }, "guiPluginLogoMoonpay": Object { "testUri": "../../../src/assets/images/guiPlugins/guiPluginLogoMoonpayDark.png", }, diff --git a/src/assets/images/guiPlugins/guiPluginLogoBitaccessDark.png b/src/assets/images/guiPlugins/guiPluginLogoBitaccessDark.png deleted file mode 100644 index 3c98172a9792111ddbfaa1b9f6e9e4ac14f38fab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1404 zcmV-?1%vvDP)bw%1vnMhTfzUB6M514F~9)w zCcpQ1evx2+0S1_iZfIcuwDza7>9b9(OO5-TbF}H~emQ-&>G|g7=13n6+v(1xCz}k) zF*a>jCcS5D0~?!GHl45>#-^{BX4U)PN*(vH`R$5uqjBwy&*8dPRKN{o;55IX$+&5F zHFD4H@1O4X6HSJ($&g7-=9jA&Oy#I^zKu;i5~i!mTSC!nNa_4jVnaquJ3&)P_SU5o zo@fb>Haa6Rwku3VRAM*F*Cs0B0EO~vblxCypN@3i+YzS-gKH=uq4Vq9iZI!ekW$-7 z`61G_1C@aA=&*t7DHB`v0R^3($>|WD4I9b<;nCsF-%%!978N=_lNVbOj~aQe0#6Hd zJ|?@R3=))(-sWn8bd4-hY=ZnWdw}WCBB7f~>5XH0ssO^vYlsyNHF8avp!OP#*Y_yY z!?Uaj6<)QsN)+Mx13}S^uYk1n z^Y&4ya=Br$FF247N`o)65i+-=1kAe8@?^ziL1wx929`azR}gyA*GUgIuMrggIaA|2ms`s#Up@7f_w{}U-e`0l{) znrs5)Tf{Fo>ifRXKQph?hsyW`(d%3oaqesSpXMk@i{UjZo=h?o7pWcn$-t$Vkv|c>V8dgB- zd7<3`eMZ-p1hGaxX{&r}ad)+b8m=zDleAA=e`ey^?!$SN|x;?0uOf#{<(*CP)u#@=+2m(5n>+dBnI-(XrMkf*Z9%TAX2aya2*pbgYYsv&u%wfo$ z)g~fi6)2w-(~HTL#KLd3RD%R17zh>?@p#~z&fg;*EWM?gAni1_!OYm8QatcXUWc?h z#+H@<>1X>9VIyi%JCA9q_ej57WgF8}C2+?|K9q`XNq9RpZ=m};M{Vs(KAPfNVoQ3C zH2ERV^lOX|b4PDqmTK7B^!L@jGIgV5@cYOb_1a3{={j6l5hp|fuC5N=)~&&EyuXh7 zz_eX$D=EWZI+1p?09i&*115uc=hEvZ^s&$9`M Date: Mon, 29 May 2023 15:07:20 -0700 Subject: [PATCH 038/104] Rename tracking event for usp swipe The event was incorrectly named implying the end of the signup process, while in reality it happens at the very beginning of the signup flow (after USPs are viewed). --- src/components/scenes/GettingStartedScene.tsx | 15 ++++++++------- src/util/tracking.ts | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/components/scenes/GettingStartedScene.tsx b/src/components/scenes/GettingStartedScene.tsx index 7fc9a4dbdec..5d51bf517fa 100644 --- a/src/components/scenes/GettingStartedScene.tsx +++ b/src/components/scenes/GettingStartedScene.tsx @@ -101,12 +101,13 @@ export const GettingStartedScene = (props: Props) => { swipeOffset.value = 0 }, 500) - if (localUsersLength > 0) navigation.navigate('login', { loginUiInitialRoute: 'login-password' }) - else { - logEvent('Signup_Account_Review_Done', { - variantId, - variantParams: { method: 'swipe' } - }) + logEvent('Signup_Welcome', { + variantId, + variantParams: { doneMethod: 'swipe' } + }) + if (localUsersLength > 0) { + navigation.navigate('login', { loginUiInitialRoute: 'login-password' }) + } else { navigation.navigate('login', { loginUiInitialRoute: 'new-account' }) } } @@ -119,7 +120,7 @@ export const GettingStartedScene = (props: Props) => { navigation.navigate('login', { loginUiInitialRoute: 'login-password' }) }) const handlePressSignUp = useHandler(() => { - logEvent('Signup_Account_Review_Done', { variantId, variantParams: { method: 'click' } }) + logEvent('Signup_Welcome', { variantId, variantParams: { doneMethod: 'click' } }) navigation.navigate('login', { loginUiInitialRoute: 'new-account' }) }) const handlePressSkip = useHandler(() => { diff --git a/src/util/tracking.ts b/src/util/tracking.ts index 347a34f1254..bc19766f0bb 100644 --- a/src/util/tracking.ts +++ b/src/util/tracking.ts @@ -28,7 +28,7 @@ export type TrackingEventName = | 'Sell_Quote' | 'Sell_Quote_Change_Provider' | 'Sell_Quote_Next' - | 'Signup_Account_Review_Done' + | 'Signup_Welcome' | 'Signup_Wallets_Created_Failed' | 'Signup_Wallets_Created_Success' | 'Start_App' From 909cbd8a15343625d9069affe1a0cf50588abc1f Mon Sep 17 00:00:00 2001 From: William Swanson Date: Fri, 19 May 2023 10:19:52 -0700 Subject: [PATCH 039/104] Consolidate recieve drop-down logic into an action The old component didn't do any rendering - it just formatted a message. We can do that in a redux action, as well as playing sounds and checking spam limits. --- src/actions/ReceiveDropdown.tsx | 82 ++++++++++++++ src/actions/TransactionListActions.ts | 21 +--- .../navigation/TransactionDropdown.tsx | 100 ------------------ .../services/AccountCallbackManager.tsx | 12 +++ 4 files changed, 97 insertions(+), 118 deletions(-) create mode 100644 src/actions/ReceiveDropdown.tsx delete mode 100644 src/components/navigation/TransactionDropdown.tsx diff --git a/src/actions/ReceiveDropdown.tsx b/src/actions/ReceiveDropdown.tsx new file mode 100644 index 00000000000..3bfb5bf44e0 --- /dev/null +++ b/src/actions/ReceiveDropdown.tsx @@ -0,0 +1,82 @@ +import { lt } from 'biggystring' +import { EdgeTransaction } from 'edge-core-js' +import * as React from 'react' +import { sprintf } from 'sprintf-js' + +import { FlashNotification } from '../components/navigation/FlashNotification' +import { Airship, showError } from '../components/services/AirshipInstance' +import { lstrings } from '../locales/strings' +import { getDisplayDenomination, getExchangeDenomination } from '../selectors/DenominationSelectors' +import { ThunkAction } from '../types/reduxTypes' +import { NavigationBase } from '../types/routerTypes' +import { getTokenId } from '../util/CurrencyInfoHelpers' +import { calculateSpamThreshold, convertNativeToDisplay, zeroString } from '../util/utils' +import { playReceiveSound } from './SoundActions' +import { selectWalletToken } from './WalletActions' + +let receiveDropdownShowing = false + +/** + * Shows a drop-down alert for an incoming transaction. + */ +export function showReceiveDropdown(navigation: NavigationBase, transaction: EdgeTransaction): ThunkAction { + return (dispatch, getState) => { + const { currencyCode, nativeAmount, walletId } = transaction + + // Grab the matching wallet: + const state = getState() + const { account } = state.core + const wallet = account.currencyWallets[walletId] + if (wallet == null) return + + const { currencyInfo, fiatCurrencyCode } = wallet + const tokenId = getTokenId(account, currencyInfo.pluginId, currencyCode) + + // Never stack dropdowns: + if (receiveDropdownShowing) return + + // Check the spam limits: + const { spamFilterOn } = state.ui.settings + const exchangeRate = state.exchangeRates[`${currencyCode}_${fiatCurrencyCode}`] + const exchangeDenom = getExchangeDenomination(state, currencyInfo.pluginId, currencyCode) + const spamThreshold = calculateSpamThreshold(exchangeRate, exchangeDenom) + if (spamFilterOn && (zeroString(exchangeRate) || lt(nativeAmount, spamThreshold))) { + return + } + + // Format the message: + const displayDenomination = getDisplayDenomination(state, currencyInfo.pluginId, currencyCode) + const { symbol, name, multiplier } = displayDenomination + const displayAmount = convertNativeToDisplay(multiplier)(nativeAmount) + const message = sprintf(lstrings.bitcoin_received, `${symbol ? symbol + ' ' : ''}${displayAmount} ${name}`) + + // Display the dropdown: + receiveDropdownShowing = true + playReceiveSound().catch(() => {}) + Airship.show(bridge => ( + { + bridge.resolve() + + if (!account.loggedIn) return + dispatch( + selectWalletToken({ + navigation, + walletId, + tokenId + }) + ).catch(showError) + + navigation.navigate('transactionDetails', { + edgeTransaction: transaction, + walletId + }) + }} + /> + )).finally(() => { + receiveDropdownShowing = false + }) + } +} diff --git a/src/actions/TransactionListActions.ts b/src/actions/TransactionListActions.ts index 68353d5ecbc..c2a6bccc73e 100644 --- a/src/actions/TransactionListActions.ts +++ b/src/actions/TransactionListActions.ts @@ -1,14 +1,10 @@ -import { gte } from 'biggystring' import { EdgeCurrencyWallet, EdgeGetTransactionsOptions, EdgeTransaction } from 'edge-core-js' -import { showTransactionDropdown } from '../components/navigation/TransactionDropdown' import { showError } from '../components/services/AirshipInstance' -import { getExchangeDenomination } from '../selectors/DenominationSelectors' import { Dispatch, RootState, ThunkAction } from '../types/reduxTypes' import { NavigationBase } from '../types/routerTypes' import { TransactionListTx } from '../types/types' -import { calculateSpamThreshold, unixToLocaleDateTime, zeroString } from '../util/utils' -import { checkFioObtData } from './FioActions' +import { unixToLocaleDateTime } from '../util/utils' const SUBSEQUENT_TRANSACTION_BATCH_QUANTITY = 30 const INITIAL_TRANSACTION_BATCH_QUANTITY = 10 @@ -144,21 +140,15 @@ export function refreshTransactionsRequest(wallet: EdgeCurrencyWallet, transacti export function newTransactionsRequest(navigation: NavigationBase, wallet: EdgeCurrencyWallet, edgeTransactions: EdgeTransaction[]): ThunkAction { return (dispatch, getState) => { - const edgeTransaction: EdgeTransaction = edgeTransactions[0] const state = getState() - const exchangeRate = state.exchangeRates[`${edgeTransaction.currencyCode}_${wallet.fiatCurrencyCode}`] + const currentViewableTransactions = state.ui.transactionList.transactions const selectedWalletId = state.ui.wallets.selectedWalletId const selectedCurrencyCode = state.ui.wallets.selectedCurrencyCode - const spamFilterOn = state.ui.settings.spamFilterOn - const exchangeDenom = getExchangeDenomination(state, wallet.currencyInfo.pluginId, edgeTransaction.currencyCode) + let numberOfRelevantTransactions = 0 let isTransactionForSelectedWallet = false - const receivedTxs: EdgeTransaction[] = [] for (const transaction of edgeTransactions) { - if (!transaction.isSend) { - receivedTxs.push(transaction) - } if (transaction.currencyCode === selectedCurrencyCode && transaction.walletId === selectedWalletId) { isTransactionForSelectedWallet = true // this next part may be unnecessary @@ -173,11 +163,6 @@ export function newTransactionsRequest(navigation: NavigationBase, wallet: EdgeC startEntries: state.ui.transactionList.currentEndIndex + 1 + numberOfRelevantTransactions } if (isTransactionForSelectedWallet) dispatch(fetchTransactions(wallet, selectedCurrencyCode, options)) - if (receivedTxs.length) dispatch(checkFioObtData(wallet, receivedTxs)) - if (edgeTransaction.isSend) return - if (!spamFilterOn || (!zeroString(exchangeRate) && gte(edgeTransaction.nativeAmount, calculateSpamThreshold(exchangeRate, exchangeDenom)))) { - showTransactionDropdown(navigation, edgeTransaction) - } } } diff --git a/src/components/navigation/TransactionDropdown.tsx b/src/components/navigation/TransactionDropdown.tsx deleted file mode 100644 index 5e310c19b40..00000000000 --- a/src/components/navigation/TransactionDropdown.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import { EdgeAccount, EdgeTransaction } from 'edge-core-js/types' -import * as React from 'react' -import { AirshipBridge } from 'react-native-airship' -import { sprintf } from 'sprintf-js' - -import { playReceiveSound } from '../../actions/SoundActions' -import { selectWalletToken } from '../../actions/WalletActions' -import { lstrings } from '../../locales/strings' -import { getDisplayDenomination } from '../../selectors/DenominationSelectors' -import { connect } from '../../types/reactRedux' -import { NavigationBase } from '../../types/routerTypes' -import { getTokenId } from '../../util/CurrencyInfoHelpers' -import { convertNativeToDisplay } from '../../util/utils' -import { Airship } from '../services/AirshipInstance' -import { FlashNotification } from './FlashNotification' - -let showing = false - -export function showTransactionDropdown(navigation: NavigationBase, tx: EdgeTransaction) { - if (!showing) { - showing = true - playReceiveSound().catch(error => console.log(error)) // Fail quietly - Airship.show(bridge => ).then(() => { - showing = false - }) - } -} - -interface OwnProps { - navigation: NavigationBase - bridge: AirshipBridge - tx: EdgeTransaction -} - -interface StateProps { - account: EdgeAccount - message: string -} - -interface DispatchProps { - selectWalletToken: (navigation: NavigationBase, walletId: string, tokenId?: string) => void -} - -type Props = OwnProps & StateProps & DispatchProps - -export function TransactionDropdown(props: Props) { - const { account, bridge, message, tx, selectWalletToken, navigation } = props - const wallet = account.currencyWallets[tx.walletId] - const tokenId = getTokenId(account, wallet.currencyInfo.pluginId, tx.currencyCode) - - return ( - { - bridge.resolve() - selectWalletToken(navigation, tx.walletId, tokenId) - navigation.navigate('transactionDetails', { - edgeTransaction: tx, - walletId: tx.walletId - }) - }} - message={message} - /> - ) -} - -const ConnectedTransactionDropdown = connect( - (state, ownProps) => { - const { tx } = ownProps - const { account } = state.core - - if (!state.ui.settings.loginStatus) { - return { account, message: '' } - } - - const { nativeAmount, currencyCode } = tx - const wallet = state.core.account.currencyWallets[tx.walletId] - // wallet and walletId are both optional and if neither are present we can't show an amount with a denomination. - // In that case we can still show a message with the currency code - if (wallet != null) { - const displayDenomination = getDisplayDenomination(state, wallet.currencyInfo.pluginId, currencyCode) - const { symbol, name, multiplier } = displayDenomination - const displayAmount = convertNativeToDisplay(multiplier)(nativeAmount) - return { - account, - message: sprintf(lstrings.bitcoin_received, `${symbol ? symbol + ' ' : ''}${displayAmount} ${name}`) - } - } else { - return { - account, - message: sprintf(lstrings.bitcoin_received, currencyCode) - } - } - }, - dispatch => ({ - selectWalletToken: (navigation: NavigationBase, walletId: string, tokenId?: string) => { - dispatch(selectWalletToken({ navigation, walletId, tokenId })) - } - }) -)(TransactionDropdown) diff --git a/src/components/services/AccountCallbackManager.tsx b/src/components/services/AccountCallbackManager.tsx index 6f597b191ee..4056850e343 100644 --- a/src/components/services/AccountCallbackManager.tsx +++ b/src/components/services/AccountCallbackManager.tsx @@ -3,6 +3,8 @@ import { watchSecurityAlerts } from 'edge-login-ui-rn' import * as React from 'react' import { updateExchangeRates } from '../../actions/ExchangeRateActions' +import { checkFioObtData } from '../../actions/FioActions' +import { showReceiveDropdown } from '../../actions/ReceiveDropdown' import { checkPasswordRecovery } from '../../actions/RecoveryReminderActions' import { newTransactionsRequest, refreshTransactionsRequest } from '../../actions/TransactionListActions' import { updateWalletLoadingProgress, updateWalletsRequest } from '../../actions/WalletActions' @@ -90,6 +92,16 @@ export function AccountCallbackManager(props: Props) { dispatch(refreshTransactionsRequest(wallet, transactions)) dispatch(newTransactionsRequest(navigation, wallet, transactions)) + // Check for incoming FIO requests: + const receivedTxs = transactions.filter(tx => !tx.isSend) + if (receivedTxs.length > 0) dispatch(checkFioObtData(wallet, receivedTxs)) + + // Show the dropdown for the first transaction: + const [firstReceive] = receivedTxs + if (firstReceive != null) { + dispatch(showReceiveDropdown(navigation, firstReceive)) + } + // Check if password recovery is set up: const finalTxIndex = transactions.length - 1 if (!transactions[finalTxIndex].isSend) { From f3646f3ee6341f6cf0943cdb5e2aa397c1fc8e06 Mon Sep 17 00:00:00 2001 From: William Swanson Date: Mon, 29 May 2023 15:31:28 -0700 Subject: [PATCH 040/104] Avoid deprecated seed access in stake plugins --- .../scenes/Staking/StakeModifyScene.tsx | 4 +- .../scenes/Staking/StakeOverviewScene.tsx | 4 +- src/components/themed/TransactionListTop.tsx | 10 +++- .../thorchainSavers/tcSaversPlugin.ts | 54 +++++++++++-------- src/plugins/stake-plugins/types.ts | 4 +- .../uniswapV2/policies/cemeteryPolicy.ts | 9 ++-- .../uniswapV2/policies/masonryPolicy.ts | 9 ++-- src/plugins/stake-plugins/util/getSeed.ts | 6 --- 8 files changed, 55 insertions(+), 45 deletions(-) delete mode 100644 src/plugins/stake-plugins/util/getSeed.ts diff --git a/src/components/scenes/Staking/StakeModifyScene.tsx b/src/components/scenes/Staking/StakeModifyScene.tsx index 161f0c039dc..725dadcc316 100644 --- a/src/components/scenes/Staking/StakeModifyScene.tsx +++ b/src/components/scenes/Staking/StakeModifyScene.tsx @@ -55,12 +55,14 @@ const StakeModifySceneComponent = (props: Props) => { const { quoteInfo } = changeQuote ?? {} // Request that the user will modify, triggering a ChangeQuote recalculation + const account = useSelector(state => state.core.account) const [changeQuoteRequest, setChangeQuoteRequest] = React.useState({ action: modification, stakePolicyId: stakePolicy.stakePolicyId, currencyCode: '', nativeAmount: '0', - wallet + wallet, + account }) // Slider state diff --git a/src/components/scenes/Staking/StakeOverviewScene.tsx b/src/components/scenes/Staking/StakeOverviewScene.tsx index 696d8c5841f..49098eb4431 100644 --- a/src/components/scenes/Staking/StakeOverviewScene.tsx +++ b/src/components/scenes/Staking/StakeOverviewScene.tsx @@ -65,7 +65,7 @@ const StakeOverviewSceneComponent = (props: Props) => { React.useEffect(() => { let abort = false stakePlugin - .fetchStakePosition({ stakePolicyId, wallet }) + .fetchStakePosition({ stakePolicyId, wallet, account }) .then(async stakePosition => { if (abort) return const guiAllocations = getPositionAllocations(stakePosition) @@ -81,7 +81,7 @@ const StakeOverviewSceneComponent = (props: Props) => { return () => { abort = true } - }, [wallet, stakePolicyId, stakePlugin, updateCounter]) + }, [account, stakePlugin, stakePolicyId, updateCounter, wallet]) // Handlers const handleModifyPress = (modification: ChangeQuoteRequest['action']) => () => { diff --git a/src/components/themed/TransactionListTop.tsx b/src/components/themed/TransactionListTop.tsx index 9c1a25c8f4b..91b06c4781d 100644 --- a/src/components/themed/TransactionListTop.tsx +++ b/src/components/themed/TransactionListTop.tsx @@ -1,5 +1,5 @@ import { add, gt, mul, round } from 'biggystring' -import { EdgeBalances, EdgeCurrencyWallet, EdgeDenomination } from 'edge-core-js' +import { EdgeAccount, EdgeBalances, EdgeCurrencyWallet, EdgeDenomination } from 'edge-core-js' import * as React from 'react' import { ActivityIndicator, TouchableOpacity, View } from 'react-native' import AntDesignIcon from 'react-native-vector-icons/AntDesign' @@ -51,6 +51,7 @@ interface OwnProps { } interface StateProps { + account: EdgeAccount balances: EdgeBalances displayDenomination: EdgeDenomination exchangeDenomination: EdgeDenomination @@ -137,7 +138,11 @@ export class TransactionListTopComponent extends React.PureComponent { const { staked, earned } = getPositionAllocations(stakePosition) return this.getTotalPosition(this.props.currencyCode, [...staked, ...earned]) @@ -560,6 +565,7 @@ export function TransactionListTop(props: OwnProps) { return ( => { - const { stakePolicyId, wallet } = request + const { stakePolicyId, wallet, account } = request const policy = getPolicyFromId(stakePolicyId) const { currencyCode } = policy.stakeAssets[0] - const { primaryAddress } = await getPrimaryAddress(wallet, currencyCode) + const { primaryAddress } = await getPrimaryAddress(account, wallet, currencyCode) return await getStakePositionInner(opts, request, primaryAddress) } @@ -360,7 +360,7 @@ const getPolicyFromId = (policyId: string): StakePolicy => { const stakeRequest = async (opts: EdgeGuiPluginOptions, request: ChangeQuoteRequest): Promise => { const { ninerealmsClientId } = asInitOptions(opts.initOptions) - const { wallet, nativeAmount, currencyCode, stakePolicyId } = request + const { wallet, nativeAmount, currencyCode, stakePolicyId, account } = request const { pluginId } = wallet.currencyInfo const walletBalance = wallet.balances[currencyCode] @@ -374,7 +374,7 @@ const stakeRequest = async (opts: EdgeGuiPluginOptions, request: ChangeQuoteRequ await updateInboundAddresses(opts) const mainnetCode = MAINNET_CODE_TRANSCRIPTION[wallet.currencyInfo.pluginId] - const { primaryAddress, addressBalance } = await getPrimaryAddress(wallet, currencyCode) + const { primaryAddress, addressBalance } = await getPrimaryAddress(account, wallet, currencyCode) const asset = `${mainnetCode}.${mainnetCode}` @@ -531,8 +531,8 @@ const stakeRequest = async (opts: EdgeGuiPluginOptions, request: ChangeQuoteRequ const unstakeRequest = async (opts: EdgeGuiPluginOptions, request: ChangeQuoteRequest): Promise => { const { allocations } = await getStakePosition(opts, request) - const { wallet, currencyCode } = request - const { addressBalance, primaryAddress } = await getPrimaryAddress(wallet, currencyCode) + const { wallet, currencyCode, account } = request + const { addressBalance, primaryAddress } = await getPrimaryAddress(account, wallet, currencyCode) return await unstakeRequestInner(opts, request, { addressBalance, allocations, primaryAddress }) } @@ -545,7 +545,7 @@ interface UnstakeRequestParams { const unstakeRequestInner = async (opts: EdgeGuiPluginOptions, request: ChangeQuoteRequest, params: UnstakeRequestParams): Promise => { const { allocations, primaryAddress, addressBalance } = params const { ninerealmsClientId } = asInitOptions(opts.initOptions) - const { action, wallet, nativeAmount: requestNativeAmount, currencyCode } = request + const { action, wallet, nativeAmount: requestNativeAmount, currencyCode, account } = request const { pluginId } = wallet.currencyInfo const policyCurrencyInfo = policyCurrencyInfos[pluginId] @@ -616,7 +616,7 @@ const unstakeRequestInner = async (opts: EdgeGuiPluginOptions, request: ChangeQu const slippageThorAmount = sub(totalUnstakeThorAmount, expectedAmountOut) const slippageDisplayAmount = div(slippageThorAmount, THOR_LIMIT_UNITS, DIVIDE_PRECISION) const slippageNativeAmount = await wallet.denominationToNative(slippageDisplayAmount, currencyCode) - const { primaryAddress: utxoSourceAddress } = await getPrimaryAddress(wallet, currencyCode) + const { primaryAddress: utxoSourceAddress } = await getPrimaryAddress(account, wallet, currencyCode) const forceChangeAddress = utxoSourceAddress let needsFundingPrimary = false @@ -739,7 +739,7 @@ const headers = { // total amount of the largest staked address // ---------------------------------------------------------------------------- const estimateUnstakeFee = async (opts: EdgeGuiPluginOptions, request: ChangeQuoteRequest, asset: string, ninerealmsClientId: string): Promise => { - const { nativeAmount, stakePolicyId, wallet } = request + const { nativeAmount, stakePolicyId, wallet, account } = request const saversResponse = await fetchWaterfall(thornodeServers, `thorchain/pool/${asset}/savers`, { headers: { 'x-client-id': ninerealmsClientId } }) if (!saversResponse.ok) { const responseText = await saversResponse.text() @@ -752,7 +752,7 @@ const estimateUnstakeFee = async (opts: EdgeGuiPluginOptions, request: ChangeQuo const bigSaver = savers.reduce((prev, current) => (gt(current.units, prev.units) ? current : prev)) const primaryAddress = bigSaver.asset_address - const stakePositionRequest: StakePositionRequest = { stakePolicyId, wallet } + const stakePositionRequest: StakePositionRequest = { stakePolicyId, wallet, account } const stakePosition = await getStakePositionInner(opts, stakePositionRequest, primaryAddress) const { allocations } = stakePosition @@ -814,18 +814,26 @@ const updateInboundAddresses = async (opts: EdgeGuiPluginOptions): Promise } } -const getPrimaryAddress = async (wallet: EdgeCurrencyWallet, currencyCode: string): Promise<{ primaryAddress: string; addressBalance: string }> => { - const { publicAddress, nativeBalance } = await wallet.getReceiveAddress({ forceIndex: 0, currencyCode }) - const primaryAddress = publicAddress - let addressBalance = '0' +const getPrimaryAddress = async ( + account: EdgeAccount, + wallet: EdgeCurrencyWallet, + currencyCode: string +): Promise<{ + primaryAddress: string + addressBalance: string +}> => { + const displayPublicKey = await account.getDisplayPublicKey(wallet.id) + const { publicAddress, nativeBalance } = await wallet.getReceiveAddress({ + forceIndex: 0, + currencyCode + }) + + // If this is a single address chain (ie ETH, AVAX) + // then the address balance is always the wallet balance + const hasSingleAddress = displayPublicKey.toLowerCase() === publicAddress.toLowerCase() - if (wallet.displayPublicSeed?.toLowerCase() === primaryAddress.toLowerCase()) { - // If this is a single address chain (ie ETH, AVAX) then the address balance is always - // the wallet balance - addressBalance = await wallet.balances[currencyCode] - } else { - addressBalance = nativeBalance ?? '0' + return { + primaryAddress: publicAddress, + addressBalance: hasSingleAddress ? wallet.balances[currencyCode] : nativeBalance ?? '0' } - - return { primaryAddress, addressBalance } } diff --git a/src/plugins/stake-plugins/types.ts b/src/plugins/stake-plugins/types.ts index 85173deba55..24d4f7ef853 100644 --- a/src/plugins/stake-plugins/types.ts +++ b/src/plugins/stake-plugins/types.ts @@ -2,7 +2,7 @@ // Stake Policy // ----------------------------------------------------------------------------- -import { EdgeCurrencyWallet } from 'edge-core-js' +import { EdgeAccount, EdgeCurrencyWallet } from 'edge-core-js' // ----------------------------------------------------------------------------- // Errors @@ -106,6 +106,7 @@ export interface ChangeQuoteRequest { currencyCode: string nativeAmount: string wallet: EdgeCurrencyWallet + account: EdgeAccount } export interface QuoteAllocation { @@ -132,6 +133,7 @@ export interface ChangeQuote { export interface StakePositionRequest { stakePolicyId: string wallet: EdgeCurrencyWallet + account: EdgeAccount } export interface PositionAllocation { diff --git a/src/plugins/stake-plugins/uniswapV2/policies/cemeteryPolicy.ts b/src/plugins/stake-plugins/uniswapV2/policies/cemeteryPolicy.ts index 2470a157d70..584c4b22f06 100644 --- a/src/plugins/stake-plugins/uniswapV2/policies/cemeteryPolicy.ts +++ b/src/plugins/stake-plugins/uniswapV2/policies/cemeteryPolicy.ts @@ -10,7 +10,6 @@ import { AssetId, ChangeQuote, ChangeQuoteRequest, PositionAllocation, QuoteAllo import { makeBigAccumulator } from '../../util/accumulator' import { round } from '../../util/biggystringplus' import { makeBuilder } from '../../util/builder' -import { getSeed } from '../../util/getSeed' import { fromHex } from '../../util/hex' import { getContractInfo, makeContract, makeSigner, multipass } from '../contracts' import { pluginInfo } from '../pluginInfo' @@ -99,7 +98,7 @@ export const makeCemeteryPolicy = (options: CemeteryPolicyOptions): StakePluginP const instance: StakePluginPolicy = { async fetchChangeQuote(request: ChangeQuoteRequest): Promise { - const { action, stakePolicyId, wallet } = request + const { action, stakePolicyId, wallet, account } = request const policyInfo = pluginInfo.policyInfo.find(p => p.stakePolicyId === stakePolicyId) if (policyInfo == null) throw new Error(`Stake policy '${stakePolicyId}' not found`) @@ -119,7 +118,7 @@ export const makeCemeteryPolicy = (options: CemeteryPolicyOptions): StakePluginP const metadataLpName = `${tokenACurrencyCode} - ${tokenBCurrencyCode}` // Get the signer for the wallet - const signerSeed = getSeed(wallet) + const signerSeed = await account.getDisplayPrivateKey(wallet.id) const signerAddress = await makeSigner(signerSeed).getAddress() // TODO: Infer this policy from the `options` if/when we support more than two stake assets @@ -607,8 +606,8 @@ export const makeCemeteryPolicy = (options: CemeteryPolicyOptions): StakePluginP } }, async fetchStakePosition(request: StakePositionRequest): Promise { - const { stakePolicyId, wallet } = request - const signerSeed = getSeed(wallet) + const { stakePolicyId, wallet, account } = request + const signerSeed = await account.getDisplayPrivateKey(wallet.id) const policyInfo = pluginInfo.policyInfo.find(p => p.stakePolicyId === stakePolicyId) if (policyInfo == null) throw new Error(`Stake policy '${stakePolicyId}' not found`) diff --git a/src/plugins/stake-plugins/uniswapV2/policies/masonryPolicy.ts b/src/plugins/stake-plugins/uniswapV2/policies/masonryPolicy.ts index 0fb17ff131e..1d515cb0526 100644 --- a/src/plugins/stake-plugins/uniswapV2/policies/masonryPolicy.ts +++ b/src/plugins/stake-plugins/uniswapV2/policies/masonryPolicy.ts @@ -7,7 +7,6 @@ import { cacheTxMetadata } from '../../metadataCache' import { ChangeQuote, ChangeQuoteRequest, PositionAllocation, QuoteAllocation, StakePosition, StakePositionRequest } from '../../types' import { makeBigAccumulator } from '../../util/accumulator' import { makeBuilder } from '../../util/builder' -import { getSeed } from '../../util/getSeed' import { fromHex } from '../../util/hex' import { makeContract, makeSigner, multipass } from '../contracts' import { pluginInfo } from '../pluginInfo' @@ -91,7 +90,7 @@ export const makeMasonryPolicy = (options?: MasonryPolicyOptions): StakePluginPo const instance: StakePluginPolicy = { async fetchChangeQuote(request: ChangeQuoteRequest): Promise { - const { action, stakePolicyId, wallet } = request + const { action, stakePolicyId, wallet, account } = request const policyInfo = pluginInfo.policyInfo.find(p => p.stakePolicyId === stakePolicyId) if (policyInfo == null) throw new Error(`Stake policy '${stakePolicyId}' not found`) @@ -103,7 +102,7 @@ export const makeMasonryPolicy = (options?: MasonryPolicyOptions): StakePluginPo const metadataRewardCurrencyCode = policyInfo.rewardAssets.map(asset => asset.currencyCode)[0] // Get the signer for the wallet - const signerSeed = getSeed(wallet) + const signerSeed = await account.getDisplayPrivateKey(wallet.id) const signerAddress = makeSigner(signerSeed).getAddress() // TODO: Replace this assertion with an LP-contract call to get the liquidity pool ratios @@ -356,8 +355,8 @@ export const makeMasonryPolicy = (options?: MasonryPolicyOptions): StakePluginPo }, // TODO: Implement support for multi-asset staking async fetchStakePosition(request: StakePositionRequest): Promise { - const { stakePolicyId, wallet } = request - const signerSeed = getSeed(wallet) + const { stakePolicyId, wallet, account } = request + const signerSeed = await account.getDisplayPrivateKey(wallet.id) const policyInfo = pluginInfo.policyInfo.find(p => p.stakePolicyId === stakePolicyId) if (policyInfo == null) throw new Error(`Stake policy '${stakePolicyId}' not found`) diff --git a/src/plugins/stake-plugins/util/getSeed.ts b/src/plugins/stake-plugins/util/getSeed.ts deleted file mode 100644 index d126d4d4840..00000000000 --- a/src/plugins/stake-plugins/util/getSeed.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { EdgeCurrencyWallet } from 'edge-core-js' - -export const getSeed = (wallet: EdgeCurrencyWallet): string => { - if (wallet.displayPrivateSeed == null) throw new Error('Cannot stake with a read-only wallet') - return wallet.displayPrivateSeed -} From cd6ec4180a59d15c8c29d431349b3022dac155ea Mon Sep 17 00:00:00 2001 From: William Swanson Date: Mon, 29 May 2023 15:49:45 -0700 Subject: [PATCH 041/104] Avoid deprecated methods during log assembly --- src/actions/LogActions.tsx | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/actions/LogActions.tsx b/src/actions/LogActions.tsx index 1f381f7b019..ae2433fb736 100644 --- a/src/actions/LogActions.tsx +++ b/src/actions/LogActions.tsx @@ -137,16 +137,18 @@ export function getLogOutput(): ThunkAction> { } if (account.loggedIn) { - const { currencyWallets, rootLoginId, keys, username } = account + const { currencyWallets, rootLoginId, username } = account const { actionQueueMap } = actionQueue + const { syncKey } = await account.getRawPrivateKey(account.id) + logOutput.loggedInUser = { userId: rootLoginId, userName: username, wallets: [], actions: [] } - logOutput.acctRepoId = getRepoId(keys.syncKey) + logOutput.acctRepoId = getRepoId(syncKey) logOutput.data += '***Account Wallet Summary***\n' // @@ -155,23 +157,25 @@ export function getLogOutput(): ThunkAction> { for (const walletId of Object.keys(currencyWallets)) { // Wallet TX summary - const codes = await currencyWallets[walletId].getEnabledTokens() + const wallet = currencyWallets[walletId] + const { enabledTokenIds } = wallet + const codes = enabledTokenIds.map(id => wallet.currencyConfig.allTokens[id].currencyCode) if (codes.length === 0) { - codes.push(currencyWallets[walletId].currencyInfo.currencyCode) + codes.push(wallet.currencyInfo.currencyCode) } - for (let i = 0; i < codes.length; i++) { - const txs = await currencyWallets[walletId].getNumTransactions({ currencyCode: codes[i] }) - logOutput.data += `${codes[i]}: ${txs} txs\n` + for (const code of codes) { + const txs = await wallet.getNumTransactions({ currencyCode: code }) + logOutput.data += `${code}: ${txs} txs\n` } + const { imported, syncKey } = await account.getRawPrivateKey(wallet.id) // Wallet info - const wallet = currencyWallets[walletId] if (wallet && logOutput.loggedInUser) { const currencyCode = wallet.currencyInfo.currencyCode ?? '' logOutput.loggedInUser.wallets.push({ currencyCode, - imported: wallet.keys.imported, - repoId: getRepoId(wallet.keys.syncKey), + imported, + repoId: getRepoId(syncKey), pluginDump: await wallet.dumpData() }) } From 0099b97928079473a75ce7da6cb157068b7c48d1 Mon Sep 17 00:00:00 2001 From: William Swanson Date: Mon, 29 May 2023 15:53:54 -0700 Subject: [PATCH 042/104] Avoid deprecated methods in wallet actions --- src/actions/WalletActions.tsx | 2 +- src/actions/WalletListMenuActions.tsx | 18 +++++++++++------- src/modules/FioAddress/util.ts | 15 +++++++-------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/actions/WalletActions.tsx b/src/actions/WalletActions.tsx index 5ab9b543ac0..7ca7f783aad 100644 --- a/src/actions/WalletActions.tsx +++ b/src/actions/WalletActions.tsx @@ -343,7 +343,7 @@ export function checkCompromisedKeys(navigation: NavigationBase): ThunkAction { + return async (dispatch, getState) => { const state = getState() - const { currencyWallets } = state.core.account - const { displayPublicSeed, currencyInfo } = currencyWallets[walletId] - const { xpubExplorer } = currencyInfo + const { account } = state.core + const wallet = account.currencyWallets[walletId] + const { xpubExplorer } = wallet.currencyInfo + + const displayPublicSeed = await account.getDisplayPublicKey(wallet.id) const copy: ButtonInfo = { label: lstrings.fragment_request_copy_title, @@ -161,7 +163,7 @@ export function walletListMenuAction( const title = switchString === 'viewPrivateViewKey' ? lstrings.fragment_wallets_view_private_view_key : lstrings.fragment_wallets_view_xpub Airship.show<'copy' | 'link' | undefined>(bridge => ( - + {switchString === 'viewXPub' ? null : ( { switch (result) { case 'copy': - Clipboard.setString(displayPublicSeed ?? '') + Clipboard.setString(displayPublicSeed) showToast(lstrings.fragment_wallets_pubkey_copied_title) break case 'link': @@ -225,11 +227,13 @@ export function walletListMenuAction( // @ts-expect-error if (global.__DEV__) devButtons = { copy: { label: lstrings.fragment_wallets_copy_seed } } + const privateKey = await account.getDisplayPrivateKey(wallet.id) + await Airship.show<'copy' | 'ok' | undefined>(bridge => ( )).then(buttonPressed => { diff --git a/src/modules/FioAddress/util.ts b/src/modules/FioAddress/util.ts index b62886c345e..23e9f5ea134 100644 --- a/src/modules/FioAddress/util.ts +++ b/src/modules/FioAddress/util.ts @@ -223,17 +223,16 @@ export const refreshConnectedWalletsForFioAddress = async ( const connectedWallets: StringMap = {} const connectedWalletsFromDisklet = await getConnectedWalletsForFioAddress(fioWallet, fioAddress) for (const wallet of wallets) { - const enabledTokens = await wallet.getEnabledTokens() - if (!enabledTokens.find((enabledToken: string) => enabledToken === wallet.currencyInfo.currencyCode)) { - enabledTokens.push(wallet.currencyInfo.currencyCode) - } + const { currencyConfig, enabledTokenIds } = wallet + const enabledCodes = enabledTokenIds.map(tokenId => currencyConfig.allTokens[tokenId].currencyCode) + enabledCodes.push(wallet.currencyInfo.currencyCode) const { public_addresses: connectedAddresses }: FioConnectedPublicAddresses = await fioWallet.otherMethods.fioAction('getPublicAddresses', { fioAddress }) - for (const enabledToken of enabledTokens) { - const fullCurrencyCode = `${wallet.currencyInfo.currencyCode}:${enabledToken}` - if (connectedWallets[fullCurrencyCode]) continue - if (await isWalletConnected(fioWallet, connectedAddresses, wallet, enabledToken, wallet.currencyInfo.currencyCode, connectedWalletsFromDisklet)) { + for (const currencyCode of enabledCodes) { + const fullCurrencyCode = `${wallet.currencyInfo.currencyCode}:${currencyCode}` + if (connectedWallets[fullCurrencyCode] != null) continue + if (await isWalletConnected(fioWallet, connectedAddresses, wallet, currencyCode, wallet.currencyInfo.currencyCode, connectedWalletsFromDisklet)) { connectedWallets[fullCurrencyCode] = wallet.id } } From ce32e27c3aee7b785bba29f16a2d0cbc77129de9 Mon Sep 17 00:00:00 2001 From: William Swanson Date: Mon, 29 May 2023 16:27:15 -0700 Subject: [PATCH 043/104] Avoid deprecated token methods --- src/components/themed/WalletListCreateRow.tsx | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/components/themed/WalletListCreateRow.tsx b/src/components/themed/WalletListCreateRow.tsx index aec788cff73..5cc3a4a2597 100644 --- a/src/components/themed/WalletListCreateRow.tsx +++ b/src/components/themed/WalletListCreateRow.tsx @@ -54,16 +54,17 @@ export const WalletListCreateRowComponent = (props: WalletListCreateRowProps) => const theme = useTheme() const styles = getStyles(theme) + const { tokenId } = guessFromCurrencyCode(account, { currencyCode, pluginId }) + const handlePress = useHandler(() => { - // @ts-expect-error - const handleRes = walletId => (onPress != null ? onPress(walletId, currencyCode) : null) + const handleRes = (walletId: string) => (onPress != null ? onPress(walletId, currencyCode) : null) if (walletType != null) { dispatch(createAndSelectWallet({ walletType })).then(handleRes) - } else if (pluginId != null) { + } else if (pluginId != null && tokenId != null) { if (createWalletIds.length < 2) { dispatch( createAndSelectToken({ - tokenCode: currencyCode, + tokenId, pluginId, createWalletId: createWalletIds[0], trackingEventFailed: trackingEventFailed, @@ -78,7 +79,7 @@ export const WalletListCreateRowComponent = (props: WalletListCreateRowProps) => onPress={walletId => { dispatch( createAndSelectToken({ - tokenCode: currencyCode, + tokenId, pluginId: currencyWallets[walletId].currencyInfo.pluginId, createWalletId: walletId, trackingEventFailed: trackingEventFailed, @@ -106,8 +107,6 @@ export const WalletListCreateRowComponent = (props: WalletListCreateRowProps) => } }) - const { tokenId } = guessFromCurrencyCode(account, { currencyCode, pluginId }) - return ( @@ -123,13 +122,13 @@ export const WalletListCreateRowComponent = (props: WalletListCreateRowProps) => } function createAndSelectToken({ - tokenCode, + tokenId, pluginId, createWalletId, trackingEventFailed, trackingEventSuccess }: { - tokenCode: string + tokenId: string pluginId: string trackingEventFailed?: TrackingEventName trackingEventSuccess?: TrackingEventName @@ -165,7 +164,7 @@ function createAndSelectToken({ }) })() ) - await wallet.enableTokens([tokenCode]) + await wallet.changeEnabledTokenIds([...wallet.enabledTokenIds, tokenId]) if (trackingEventSuccess != null) logEvent(trackingEventSuccess) return wallet.id } catch (error: any) { From 9edbf4891ab77ab8c5bb4ae288d85bc19d090dee Mon Sep 17 00:00:00 2001 From: William Swanson Date: Thu, 1 Jun 2023 12:11:58 -0700 Subject: [PATCH 044/104] Upgrade to edge-core-js v1.0.0 Also upgrade edge-login-ui-rn and fix any breaks. --- ios/Podfile.lock | 8 +- package.json | 4 +- src/actions/LogActions.tsx | 5 +- src/actions/TransactionExportActions.tsx | 19 +++-- .../scenes/TransactionsExportScene.tsx | 12 ++- src/components/themed/ControlPanel.tsx | 1 + src/util/fake/fakeCurrencyPlugin.ts | 3 +- yarn.lock | 85 ++++--------------- 8 files changed, 45 insertions(+), 92 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index dd589ab47db..68fe89c458e 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -18,11 +18,11 @@ PODS: - disklet (0.5.2): - React - DoubleConversion (1.1.6) - - edge-core-js (0.21.4): + - edge-core-js (1.0.0): - React-Core - edge-currency-accountbased (1.2.10): - React-Core - - edge-login-ui-rn (1.4.7): + - edge-login-ui-rn (2.0.0): - React - FBLazyVector (0.67.5) - FBReactNativeSpec (0.67.5): @@ -1109,9 +1109,9 @@ SPEC CHECKSUMS: CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 disklet: e7ed3e673ccad9d175a1675f9f3589ffbf69a5fd DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662 - edge-core-js: bd6760a2efcca8610d961d71fe9c34f103add462 + edge-core-js: 655cd63654df00c4e36d387381e7e90bc1b69340 edge-currency-accountbased: a8e30112ffb0b994e5bad97492b31b5d9526970d - edge-login-ui-rn: f6711ffc1cb89e1449290dbceef40d76e67a3a3b + edge-login-ui-rn: 321a5874cf31a25cf52f450af8d0e1d6efc440b5 FBLazyVector: d2db9d00883282819d03bbd401b2ad4360d47580 FBReactNativeSpec: 94da4d84ba3b1acf459103320882daa481a2b62d Firebase: 5f8193dff4b5b7c5d5ef72ae54bb76c08e2b841d diff --git a/package.json b/package.json index 61e649974da..1bdbadc38d8 100644 --- a/package.json +++ b/package.json @@ -119,12 +119,12 @@ "deepmerge": "^4.3.1", "detect-bundler": "^1.1.0", "disklet": "^0.5.2", - "edge-core-js": "^0.21.4", + "edge-core-js": "^1.0.0", "edge-currency-accountbased": "^1.2.10", "edge-currency-monero": "^1.0.0", "edge-currency-plugins": "^2.0.2", "edge-exchange-plugins": "^0.19.5", - "edge-login-ui-rn": "^1.4.7", + "edge-login-ui-rn": "^2.0.0", "edge-plugin-bity": "https://github.com/EdgeApp/edge-plugin-bity.git#2a52e6cb86512b98f69f8f5dd3105cdf6d0c2d8a", "edge-plugin-simplex": "https://github.com/EdgeApp/edge-plugin-simplex.git#b11def82d84f2735b91f4b8104a9e0d3e8c3600d", "edge-plugin-wyre": "https://github.com/EdgeApp/edge-plugin-wyre.git#28c143cd5828d3444bff62adc224839e33eb0bf9", diff --git a/src/actions/LogActions.tsx b/src/actions/LogActions.tsx index ae2433fb736..271778f6f59 100644 --- a/src/actions/LogActions.tsx +++ b/src/actions/LogActions.tsx @@ -132,7 +132,10 @@ export function getLogOutput(): ThunkAction> { if (context) { // Get local accounts for (const user of context.localUsers) { - logOutput.accounts.push({ username: user.username, userId: '' }) + logOutput.accounts.push({ + username: user.username ?? '', + userId: '' + }) } } diff --git a/src/actions/TransactionExportActions.tsx b/src/actions/TransactionExportActions.tsx index ef72d6049ed..009b0bafd12 100644 --- a/src/actions/TransactionExportActions.tsx +++ b/src/actions/TransactionExportActions.tsx @@ -1,6 +1,6 @@ import { abs, add, div, gt, lt, mul } from 'biggystring' import csvStringify from 'csv-stringify/lib/browser/sync' -import { EdgeCurrencyWallet, EdgeGetTransactionsOptions, EdgeTransaction } from 'edge-core-js' +import { EdgeCurrencyWallet, EdgeTransaction } from 'edge-core-js' import { getExchangeDenomination } from '../selectors/DenominationSelectors' import { ThunkAction } from '../types/reduxTypes' @@ -9,14 +9,21 @@ import { DECIMAL_PRECISION } from '../util/utils' const UPDATE_TXS_MAX_PROMISES = 10 -export async function exportTransactionsToQBO(wallet: EdgeCurrencyWallet, txs: EdgeTransaction[], opts: EdgeGetTransactionsOptions): Promise { - const { currencyCode = wallet.currencyInfo.currencyCode, denomination } = opts +export async function exportTransactionsToQBO( + wallet: EdgeCurrencyWallet, + txs: EdgeTransaction[], + currencyCode: string, + denomination?: string +): Promise { return exportTransactionsToQBOInner(txs, currencyCode, wallet.fiatCurrencyCode, denomination, Date.now()) } -export async function exportTransactionsToCSV(wallet: EdgeCurrencyWallet, txs: EdgeTransaction[], opts: EdgeGetTransactionsOptions = {}): Promise { - const { currencyCode = wallet.currencyInfo.currencyCode, denomination } = opts - +export async function exportTransactionsToCSV( + wallet: EdgeCurrencyWallet, + txs: EdgeTransaction[], + currencyCode: string, + denomination?: string +): Promise { let denomName = '' if (denomination != null) { const denomObj = wallet.currencyInfo.denominations.find(edgeDenom => edgeDenom.multiplier === denomination) diff --git a/src/components/scenes/TransactionsExportScene.tsx b/src/components/scenes/TransactionsExportScene.tsx index a8bd35a4fe5..79487078b4e 100644 --- a/src/components/scenes/TransactionsExportScene.tsx +++ b/src/components/scenes/TransactionsExportScene.tsx @@ -1,4 +1,4 @@ -import { EdgeCurrencyWallet, EdgeGetTransactionsOptions, EdgeTransaction } from 'edge-core-js' +import { EdgeCurrencyWallet, EdgeTransaction } from 'edge-core-js' import * as React from 'react' import { Platform, ScrollView } from 'react-native' import RNFS from 'react-native-fs' @@ -187,13 +187,11 @@ class TransactionsExportSceneComponent extends React.PureComponent .trim() .replace(/[-\s]+/g, '-') // Collapse spaces & dashes - const transactionOptions: EdgeGetTransactionsOptions = { - denomination: multiplier, + const txs = await sourceWallet.getTransactions({ currencyCode, startDate, endDate - } - const txs = await sourceWallet.getTransactions(transactionOptions) + }) const files: File[] = [] const formats: string[] = [] @@ -203,7 +201,7 @@ class TransactionsExportSceneComponent extends React.PureComponent // The non-string result appears to be a bug in the core, // which we are relying on to determine if the date range is empty: - const csvFile = await exportTransactionsToCSV(sourceWallet, txs, transactionOptions) + const csvFile = await exportTransactionsToCSV(sourceWallet, txs, currencyCode, multiplier) if (typeof csvFile !== 'string' || csvFile === '' || csvFile == null) { showError(lstrings.export_transaction_export_error) return @@ -219,7 +217,7 @@ class TransactionsExportSceneComponent extends React.PureComponent } if (isExportQbo) { - const qboFile = await exportTransactionsToQBO(sourceWallet, txs, transactionOptions) + const qboFile = await exportTransactionsToQBO(sourceWallet, txs, currencyCode, multiplier) files.push({ contents: qboFile, mimeType: 'application/vnd.intu.qbo', diff --git a/src/components/themed/ControlPanel.tsx b/src/components/themed/ControlPanel.tsx index 8f9695daaaf..dbab9add40a 100644 --- a/src/components/themed/ControlPanel.tsx +++ b/src/components/themed/ControlPanel.tsx @@ -403,6 +403,7 @@ function arrangeUsers(localUsers: EdgeUserInfo[], activeUsername: string): strin return bDate.valueOf() - aDate.valueOf() }) .map(info => info.username) + .filter((username): username is string => username != null) // Get the most recent 3 users that were logged in const recentUsers = inactiveUsers.slice(0, 3) diff --git a/src/util/fake/fakeCurrencyPlugin.ts b/src/util/fake/fakeCurrencyPlugin.ts index 269e06d5335..1f0fbc5e9cb 100644 --- a/src/util/fake/fakeCurrencyPlugin.ts +++ b/src/util/fake/fakeCurrencyPlugin.ts @@ -1,7 +1,6 @@ import { add, lt, mul } from 'biggystring' import { asArray, asNumber, asObject, asOptional, asString } from 'cleaners' import { - EdgeCreatePrivateKeyOptions, EdgeCurrencyCodeOptions, EdgeCurrencyEngine, EdgeCurrencyEngineCallbacks, @@ -319,7 +318,7 @@ class FakeCurrencyTools { this.currencyInfo = currencyInfo } - async createPrivateKey(walletType: string, opts?: EdgeCreatePrivateKeyOptions): Promise { + async createPrivateKey(walletType: string, opts?: JsonObject): Promise { if (walletType !== this.currencyInfo.walletType) { throw new Error('Unsupported key type') } diff --git a/yarn.lock b/yarn.lock index 1e4ecd38b1f..da761bbfbaa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1024,20 +1024,13 @@ pirates "^4.0.0" source-map-support "^0.5.16" -"@babel/runtime@^7.0.0": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.4", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.17.2", "@babel/runtime@^7.18.9", "@babel/runtime@^7.20.6", "@babel/runtime@^7.20.7", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.21.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.5.tgz#8492dddda9644ae3bda3b45eabe87382caee7200" integrity sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q== dependencies: regenerator-runtime "^0.13.11" -"@babel/runtime@^7.10.4", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.17.2", "@babel/runtime@^7.18.9", "@babel/runtime@^7.20.6", "@babel/runtime@^7.20.7", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.7.tgz#fcb41a5a70550e04a7b708037c7c32f7f356d8fd" - integrity sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ== - dependencies: - regenerator-runtime "^0.13.11" - "@babel/template@^7.0.0", "@babel/template@^7.18.6", "@babel/template@^7.20.7", "@babel/template@^7.3.3": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8" @@ -1497,7 +1490,7 @@ dependencies: "@ethersproject/logger" "^5.7.0" -"@ethersproject/providers@5.7.1", "@ethersproject/providers@^5.5.3": +"@ethersproject/providers@5.7.1": version "5.7.1" resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.1.tgz#b0799b616d5579cd1067a8ebf1fc1ec74c1e122c" integrity sha512-vZveG/DLyo+wk4Ga1yx6jSEHrLPgmTt+dFv0dv8URpVCRf0jVhalps1jq/emN/oXnMRsC7cQgAF32DcXLL7BPQ== @@ -1523,7 +1516,7 @@ bech32 "1.1.4" ws "7.4.6" -"@ethersproject/providers@5.7.2": +"@ethersproject/providers@5.7.2", "@ethersproject/providers@^5.5.3": version "5.7.2" resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== @@ -5110,12 +5103,7 @@ bignumber.js@^7.2.1: resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-7.2.1.tgz#80c048759d826800807c4bfd521e50edbba57a5f" integrity sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ== -bignumber.js@^9.0.0: - version "9.0.2" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.2.tgz#71c6c6bed38de64e24a65ebe16cfcf23ae693673" - integrity sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw== - -bignumber.js@^9.0.1: +bignumber.js@^9.0.0, bignumber.js@^9.0.1: version "9.1.1" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.1.tgz#c4df7dc496bd849d4c9464344c1aa74228b4dac6" integrity sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig== @@ -6869,12 +6857,7 @@ deepmerge@^3.2.0: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-3.3.0.tgz#d3c47fd6f3a93d517b14426b0628a17b0125f5f7" integrity sha512-GRQOafGHwMHpjPx9iCvTgpu9NojZ49q794EEL94JVEw6VaeA8XTUyBKvAkOOjBX9oJNiV6G3P+T+tihFjo2TqA== -deepmerge@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" - integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== - -deepmerge@^4.3.1: +deepmerge@^4.2.2, deepmerge@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== @@ -7257,10 +7240,10 @@ edge-core-js@^0.19.48: yaob "^0.3.9" yavent "^0.1.3" -edge-core-js@^0.21.4: - version "0.21.4" - resolved "https://registry.yarnpkg.com/edge-core-js/-/edge-core-js-0.21.4.tgz#b07dcbf8292b10d0376759b38537c748fa51b17a" - integrity sha512-6Q2AmEP1l2nCovcqca/4ziEI98aLK/HV91XSWtpjAFanZ4LG2Ju6k7m32rBOpN1PXBkLHfIVdZN3ATLXd0656w== +edge-core-js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/edge-core-js/-/edge-core-js-1.0.0.tgz#8ec013b6c59940582120b72a64290d09460718a7" + integrity sha512-r6UHDdzSO7vjfB+aOhDSfHjlm3aF53fhqQYASmy7vWAjcL46dJlSd7Vp+MLp/5Yn3HMPSLDP+q+dVsjY2/fIDg== dependencies: aes-js "^3.1.0" base-x "^1.0.4" @@ -7270,8 +7253,6 @@ edge-core-js@^0.21.4: disklet "^0.5.2" edge-sync-client "^0.2.7" elliptic "^6.4.0" - ethereumjs-tx "^1.3.7" - ethereumjs-util "^5.2.0" hash.js "^1.1.7" hmac-drbg "^1.0.1" node-fetch "^2.6.1" @@ -7377,10 +7358,10 @@ edge-exchange-plugins@^0.19.5: iso4217 "^0.2.0" utf8 "^3.0.0" -edge-login-ui-rn@^1.4.7: - version "1.4.7" - resolved "https://registry.yarnpkg.com/edge-login-ui-rn/-/edge-login-ui-rn-1.4.7.tgz#03b402beb9fc9f39814d5b538c6a0d599e963284" - integrity sha512-pVk/+PDKfssDt++ewBF2Rj4jEzJhl8tRuOmikuFBQCSmLuqXPorR7HcZXAHrdqBkaJLdKtgHi3X6gRCTKXJDSA== +edge-login-ui-rn@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/edge-login-ui-rn/-/edge-login-ui-rn-2.0.0.tgz#f253c4d3127ab25b754bc76c15e4a30a8cbd9729" + integrity sha512-P1Y+m/8QD7Rx7OW8jqB9TbC9nOvJyeHoI68Mk2/FY2CGr575SlE74ktsamDYY8LBy0YBjiFNsqcrEEJWtuHx/Q== dependencies: cleaners "^0.3.12" date-fns "^2.23.0" @@ -8237,7 +8218,7 @@ ethereumjs-wallet@^0.6.5: utf8 "^3.0.0" uuid "^3.3.2" -ethers@^5.4.4: +ethers@^5.4.4, ethers@^5.6.0, ethers@^5.7.0: version "5.7.2" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== @@ -8273,42 +8254,6 @@ ethers@^5.4.4: "@ethersproject/web" "5.7.1" "@ethersproject/wordlists" "5.7.0" -ethers@^5.6.0, ethers@^5.7.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.1.tgz#48c83a44900b5f006eb2f65d3ba6277047fd4f33" - integrity sha512-5krze4dRLITX7FpU8J4WscXqADiKmyeNlylmmDLbS95DaZpBhDe2YSwRQwKXWNyXcox7a3gBgm/MkGXV1O1S/Q== - dependencies: - "@ethersproject/abi" "5.7.0" - "@ethersproject/abstract-provider" "5.7.0" - "@ethersproject/abstract-signer" "5.7.0" - "@ethersproject/address" "5.7.0" - "@ethersproject/base64" "5.7.0" - "@ethersproject/basex" "5.7.0" - "@ethersproject/bignumber" "5.7.0" - "@ethersproject/bytes" "5.7.0" - "@ethersproject/constants" "5.7.0" - "@ethersproject/contracts" "5.7.0" - "@ethersproject/hash" "5.7.0" - "@ethersproject/hdnode" "5.7.0" - "@ethersproject/json-wallets" "5.7.0" - "@ethersproject/keccak256" "5.7.0" - "@ethersproject/logger" "5.7.0" - "@ethersproject/networks" "5.7.1" - "@ethersproject/pbkdf2" "5.7.0" - "@ethersproject/properties" "5.7.0" - "@ethersproject/providers" "5.7.1" - "@ethersproject/random" "5.7.0" - "@ethersproject/rlp" "5.7.0" - "@ethersproject/sha2" "5.7.0" - "@ethersproject/signing-key" "5.7.0" - "@ethersproject/solidity" "5.7.0" - "@ethersproject/strings" "5.7.0" - "@ethersproject/transactions" "5.7.0" - "@ethersproject/units" "5.7.0" - "@ethersproject/wallet" "5.7.0" - "@ethersproject/web" "5.7.1" - "@ethersproject/wordlists" "5.7.0" - ethjs-unit@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" @@ -13476,7 +13421,7 @@ react-native-mail@^6.1.1: resolved "https://registry.yarnpkg.com/react-native-mail/-/react-native-mail-6.1.1.tgz#f1b1f8034c84d2510a93e4a2a795f0db5a13595e" integrity sha512-pTs180wwyh7hN/iyTC9SfOX579U4YhDlHOLxi47IGvhPJENqO/QFdBq+wWKxyhNqdQuVSy+LoeIxLreWnIeYmg== -react-native-material-textfield@0.16.1, react-native-material-textfield@^0.16.1, "react-native-material-textfield@https://github.com/EdgeApp/react-native-material-textfield.git": +react-native-material-textfield@0.16.1, react-native-material-textfield@^0.16.1, "react-native-material-textfield@git+https://github.com/EdgeApp/react-native-material-textfield.git": version "0.16.1" resolved "https://registry.yarnpkg.com/react-native-material-textfield/-/react-native-material-textfield-0.16.1.tgz#649e71344bb8a7225d5cea7c7b51cd38bcb2bbfc" integrity sha512-pcV/ic3i6vYEODS7pvAMUYJ+evkzIB8cjXtSzkab9rBtYNGRpAlM0Yp8QNnjZ7foZqkj9Ynav0nguWcuJST10A== From 2acb2fcdc241410f3a9063c2ef2de45f0a1ad543 Mon Sep 17 00:00:00 2001 From: Matthew Date: Wed, 31 May 2023 13:49:20 -0700 Subject: [PATCH 045/104] Use stake method when calling getMaxSpendable --- src/components/scenes/Fio/FioStakingChangeScene.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/scenes/Fio/FioStakingChangeScene.tsx b/src/components/scenes/Fio/FioStakingChangeScene.tsx index 96665b300e3..c85346b4349 100644 --- a/src/components/scenes/Fio/FioStakingChangeScene.tsx +++ b/src/components/scenes/Fio/FioStakingChangeScene.tsx @@ -88,7 +88,15 @@ export const FioStakingChangeSceneComponent = (props: Props) => { currencyWallet .getMaxSpendable({ currencyCode, - spendTargets: [{ nativeAmount: '', otherParams: {}, publicAddress: '' }] + spendTargets: [{ publicAddress: '' }], + otherParams: { + action: { + name: 'stakeFioTokens', + params: { + fioAddress: selectedFioAddress + } + } + } }) .then(nativeAmount => { onAmountChanged(nativeAmount, add(convertNativeToDenomination(currencyDenomination.multiplier)(nativeAmount), '0')) From 18f362b7ce4a131614ca3b1e5f8f92a900e07fd8 Mon Sep 17 00:00:00 2001 From: Matthew Date: Thu, 1 Jun 2023 17:09:29 -0700 Subject: [PATCH 046/104] FIx yarn.lock --- yarn.lock | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/yarn.lock b/yarn.lock index da761bbfbaa..8daee68246e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1490,32 +1490,6 @@ dependencies: "@ethersproject/logger" "^5.7.0" -"@ethersproject/providers@5.7.1": - version "5.7.1" - resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.1.tgz#b0799b616d5579cd1067a8ebf1fc1ec74c1e122c" - integrity sha512-vZveG/DLyo+wk4Ga1yx6jSEHrLPgmTt+dFv0dv8URpVCRf0jVhalps1jq/emN/oXnMRsC7cQgAF32DcXLL7BPQ== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/base64" "^5.7.0" - "@ethersproject/basex" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/networks" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/web" "^5.7.0" - bech32 "1.1.4" - ws "7.4.6" - "@ethersproject/providers@5.7.2", "@ethersproject/providers@^5.5.3": version "5.7.2" resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" @@ -13421,7 +13395,7 @@ react-native-mail@^6.1.1: resolved "https://registry.yarnpkg.com/react-native-mail/-/react-native-mail-6.1.1.tgz#f1b1f8034c84d2510a93e4a2a795f0db5a13595e" integrity sha512-pTs180wwyh7hN/iyTC9SfOX579U4YhDlHOLxi47IGvhPJENqO/QFdBq+wWKxyhNqdQuVSy+LoeIxLreWnIeYmg== -react-native-material-textfield@0.16.1, react-native-material-textfield@^0.16.1, "react-native-material-textfield@git+https://github.com/EdgeApp/react-native-material-textfield.git": +react-native-material-textfield@0.16.1, react-native-material-textfield@^0.16.1, "react-native-material-textfield@https://github.com/EdgeApp/react-native-material-textfield.git": version "0.16.1" resolved "https://registry.yarnpkg.com/react-native-material-textfield/-/react-native-material-textfield-0.16.1.tgz#649e71344bb8a7225d5cea7c7b51cd38bcb2bbfc" integrity sha512-pcV/ic3i6vYEODS7pvAMUYJ+evkzIB8cjXtSzkab9rBtYNGRpAlM0Yp8QNnjZ7foZqkj9Ynav0nguWcuJST10A== From d6135a959b6fc101de2def06fa3906e013013743 Mon Sep 17 00:00:00 2001 From: Matthew Date: Thu, 1 Jun 2023 17:12:04 -0700 Subject: [PATCH 047/104] Upgrade edge-currency-accountbased to v1.2.11 --- ios/Podfile.lock | 4 ++-- package.json | 2 +- yarn.lock | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 68fe89c458e..f188d0a0547 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -20,7 +20,7 @@ PODS: - DoubleConversion (1.1.6) - edge-core-js (1.0.0): - React-Core - - edge-currency-accountbased (1.2.10): + - edge-currency-accountbased (1.2.11): - React-Core - edge-login-ui-rn (2.0.0): - React @@ -1110,7 +1110,7 @@ SPEC CHECKSUMS: disklet: e7ed3e673ccad9d175a1675f9f3589ffbf69a5fd DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662 edge-core-js: 655cd63654df00c4e36d387381e7e90bc1b69340 - edge-currency-accountbased: a8e30112ffb0b994e5bad97492b31b5d9526970d + edge-currency-accountbased: 0e1957b695de26a90d2f234fa96de35505b97f71 edge-login-ui-rn: 321a5874cf31a25cf52f450af8d0e1d6efc440b5 FBLazyVector: d2db9d00883282819d03bbd401b2ad4360d47580 FBReactNativeSpec: 94da4d84ba3b1acf459103320882daa481a2b62d diff --git a/package.json b/package.json index 1bdbadc38d8..6a9498a9fac 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "detect-bundler": "^1.1.0", "disklet": "^0.5.2", "edge-core-js": "^1.0.0", - "edge-currency-accountbased": "^1.2.10", + "edge-currency-accountbased": "^1.2.11", "edge-currency-monero": "^1.0.0", "edge-currency-plugins": "^2.0.2", "edge-exchange-plugins": "^0.19.5", diff --git a/yarn.lock b/yarn.lock index 8daee68246e..120820aa71e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7239,10 +7239,10 @@ edge-core-js@^1.0.0: yaob "^0.3.9" yavent "^0.1.3" -edge-currency-accountbased@^1.2.10: - version "1.2.10" - resolved "https://registry.yarnpkg.com/edge-currency-accountbased/-/edge-currency-accountbased-1.2.10.tgz#bd08fcbd3a80283b43f732130b7b85cf271b2f34" - integrity sha512-mD5rwPcrZbIaij/2cxWacwzpRyDdK0ACgQMJegLROw3zfGuUZBb7ULv0J4ZsTkG14QS7xh1oA5FX4G3fn/WoJA== +edge-currency-accountbased@^1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/edge-currency-accountbased/-/edge-currency-accountbased-1.2.11.tgz#343ee534ddf91791eae8df5421cc87bb0068c0bc" + integrity sha512-VMAserl5igp4CFejEKmVyRG0YYQfBdzcyUIGMylMxhQ5od2Eit8RFD9AWukk3dCKi+4Pz0Ek8zJQ9/IUv+SKpg== dependencies: "@binance-chain/javascript-sdk" "^4.2.0" "@ethereumjs/common" "^2.4.0" From ac996475402da9b7190fa1c0fb383fab165731f3 Mon Sep 17 00:00:00 2001 From: Matthew Date: Fri, 2 Jun 2023 15:33:39 -0700 Subject: [PATCH 048/104] Upgrade edge-currency-accountbased to v1.2.12 --- ios/Podfile.lock | 4 ++-- package.json | 2 +- yarn.lock | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index f188d0a0547..4f672e96688 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -20,7 +20,7 @@ PODS: - DoubleConversion (1.1.6) - edge-core-js (1.0.0): - React-Core - - edge-currency-accountbased (1.2.11): + - edge-currency-accountbased (1.2.12): - React-Core - edge-login-ui-rn (2.0.0): - React @@ -1110,7 +1110,7 @@ SPEC CHECKSUMS: disklet: e7ed3e673ccad9d175a1675f9f3589ffbf69a5fd DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662 edge-core-js: 655cd63654df00c4e36d387381e7e90bc1b69340 - edge-currency-accountbased: 0e1957b695de26a90d2f234fa96de35505b97f71 + edge-currency-accountbased: 1f3e48a4938016190984773b7221d985a2da40a4 edge-login-ui-rn: 321a5874cf31a25cf52f450af8d0e1d6efc440b5 FBLazyVector: d2db9d00883282819d03bbd401b2ad4360d47580 FBReactNativeSpec: 94da4d84ba3b1acf459103320882daa481a2b62d diff --git a/package.json b/package.json index 6a9498a9fac..cb01ef31c1f 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "detect-bundler": "^1.1.0", "disklet": "^0.5.2", "edge-core-js": "^1.0.0", - "edge-currency-accountbased": "^1.2.11", + "edge-currency-accountbased": "^1.2.12", "edge-currency-monero": "^1.0.0", "edge-currency-plugins": "^2.0.2", "edge-exchange-plugins": "^0.19.5", diff --git a/yarn.lock b/yarn.lock index 120820aa71e..c880ee41a92 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7239,10 +7239,10 @@ edge-core-js@^1.0.0: yaob "^0.3.9" yavent "^0.1.3" -edge-currency-accountbased@^1.2.11: - version "1.2.11" - resolved "https://registry.yarnpkg.com/edge-currency-accountbased/-/edge-currency-accountbased-1.2.11.tgz#343ee534ddf91791eae8df5421cc87bb0068c0bc" - integrity sha512-VMAserl5igp4CFejEKmVyRG0YYQfBdzcyUIGMylMxhQ5od2Eit8RFD9AWukk3dCKi+4Pz0Ek8zJQ9/IUv+SKpg== +edge-currency-accountbased@^1.2.12: + version "1.2.12" + resolved "https://registry.yarnpkg.com/edge-currency-accountbased/-/edge-currency-accountbased-1.2.12.tgz#aa6b3ee562c630a68080949dd4bf96339e8bc389" + integrity sha512-SQmKafhAq5Jas/1DBAI+NnbvQZsmY/1tKh67hg6NMd8eJuPaytrE2epK2Ite6ttuNSV2KeuUxBBtnC3Zaj4rlQ== dependencies: "@binance-chain/javascript-sdk" "^4.2.0" "@ethereumjs/common" "^2.4.0" From 0af84e024d9460e45bc48875a44d1dff2cfc250b Mon Sep 17 00:00:00 2001 From: Matthew Date: Fri, 2 Jun 2023 22:37:13 -0700 Subject: [PATCH 049/104] Upgrade edge-currency-accountbased to v1.2.13 --- ios/Podfile.lock | 4 ++-- package.json | 2 +- yarn.lock | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 4f672e96688..1fd67af3792 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -20,7 +20,7 @@ PODS: - DoubleConversion (1.1.6) - edge-core-js (1.0.0): - React-Core - - edge-currency-accountbased (1.2.12): + - edge-currency-accountbased (1.2.13): - React-Core - edge-login-ui-rn (2.0.0): - React @@ -1110,7 +1110,7 @@ SPEC CHECKSUMS: disklet: e7ed3e673ccad9d175a1675f9f3589ffbf69a5fd DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662 edge-core-js: 655cd63654df00c4e36d387381e7e90bc1b69340 - edge-currency-accountbased: 1f3e48a4938016190984773b7221d985a2da40a4 + edge-currency-accountbased: b5c9b417420254bcc5a92353eeb96bb82d84b24a edge-login-ui-rn: 321a5874cf31a25cf52f450af8d0e1d6efc440b5 FBLazyVector: d2db9d00883282819d03bbd401b2ad4360d47580 FBReactNativeSpec: 94da4d84ba3b1acf459103320882daa481a2b62d diff --git a/package.json b/package.json index cb01ef31c1f..a01495d4041 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "detect-bundler": "^1.1.0", "disklet": "^0.5.2", "edge-core-js": "^1.0.0", - "edge-currency-accountbased": "^1.2.12", + "edge-currency-accountbased": "^1.2.13", "edge-currency-monero": "^1.0.0", "edge-currency-plugins": "^2.0.2", "edge-exchange-plugins": "^0.19.5", diff --git a/yarn.lock b/yarn.lock index c880ee41a92..f9dfe176f0c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7239,10 +7239,10 @@ edge-core-js@^1.0.0: yaob "^0.3.9" yavent "^0.1.3" -edge-currency-accountbased@^1.2.12: - version "1.2.12" - resolved "https://registry.yarnpkg.com/edge-currency-accountbased/-/edge-currency-accountbased-1.2.12.tgz#aa6b3ee562c630a68080949dd4bf96339e8bc389" - integrity sha512-SQmKafhAq5Jas/1DBAI+NnbvQZsmY/1tKh67hg6NMd8eJuPaytrE2epK2Ite6ttuNSV2KeuUxBBtnC3Zaj4rlQ== +edge-currency-accountbased@^1.2.13: + version "1.2.13" + resolved "https://registry.yarnpkg.com/edge-currency-accountbased/-/edge-currency-accountbased-1.2.13.tgz#a0567d56be2b1d3c26558843e1d07688990b1a58" + integrity sha512-XOZrMV00NbAp1N00P0jfwOGOMKpzahlojCx+jcq2WK4/ONlpFKwLzVwCFnRz0c9jLoMBiCo/VKk3lC8ymHyFCg== dependencies: "@binance-chain/javascript-sdk" "^4.2.0" "@ethereumjs/common" "^2.4.0" From aeb9586313d92ca1f7138a27bca4b0c0f3df5f92 Mon Sep 17 00:00:00 2001 From: Paul Puey Date: Sat, 3 Jun 2023 00:07:36 -0700 Subject: [PATCH 050/104] Add fastlane to deploy.ts for provisioning profiles --- .fastlane/Matchfile | 1 + scripts/deploy.ts | 29 +++++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 .fastlane/Matchfile diff --git a/.fastlane/Matchfile b/.fastlane/Matchfile new file mode 100644 index 00000000000..06f1f917a23 --- /dev/null +++ b/.fastlane/Matchfile @@ -0,0 +1 @@ +git_url("BUILD_REPO_URL") diff --git a/scripts/deploy.ts b/scripts/deploy.ts index e1f9cdca0e4..a1ee795d39c 100644 --- a/scripts/deploy.ts +++ b/scripts/deploy.ts @@ -27,6 +27,7 @@ interface BuildConfigFile { appleDeveloperTeamId: string xcodeScheme: string xcodeWorkspace: string + bundleId: string // Upload options: appCenterApiToken: string @@ -153,6 +154,30 @@ function makeCommonPost(buildObj: BuildObj) { function buildIos(buildObj: BuildObj) { chdir(buildObj.guiDir) + if ( + process.env.BUILD_REPO_URL && + process.env.FASTLANE_USER != null && + process.env.FASTLANE_PASSWORD != null && + // process.env.GITHUB_SSH_KEY != null && + process.env.HOME != null && + process.env.MATCH_KEYCHAIN_PASSWORD != null && + process.env.MATCH_PASSWORD != null + ) { + const githubSshKey = process.env.GITHUB_SSH_KEY ?? join(_rootProjectDir, 'id_github') + + mylog('Using Fastlane for provisioning profiles') + const matchFileLoc = join(buildObj.guiDir, '.fastlane', 'Matchfile') + let matchFile = fs.readFileSync(matchFileLoc, { encoding: 'utf8' }) + matchFile = matchFile.replace('BUILD_REPO_URL', process.env.BUILD_REPO_URL) + fs.writeFileSync(matchFileLoc, matchFile, { encoding: 'utf8' }) + const profileDir = join(process.env.HOME, 'Library', 'MobileDevice', 'Provisioning Profiles') + call(`rm -rf ${escapePath(profileDir)}`) + call(`GIT_SSH_COMMAND="ssh -i ${githubSshKey}" fastlane match adhoc -a ${buildObj.bundleId} --team_id ${buildObj.appleDeveloperTeamId}`) + call(`GIT_SSH_COMMAND="ssh -i ${githubSshKey}" fastlane match development -a ${buildObj.bundleId} --team_id ${buildObj.appleDeveloperTeamId}`) + call(`GIT_SSH_COMMAND="ssh -i ${githubSshKey}" fastlane match appstore -a ${buildObj.bundleId} --team_id ${buildObj.appleDeveloperTeamId}`) + } else { + mylog('Missing or incomplete Fastlane params. Not using Fastlane') + } const patchDir = getPatchDir(buildObj) if (fs.existsSync(join(patchDir, 'GoogleService-Info.plist'))) { @@ -182,7 +207,7 @@ function buildIos(buildObj: BuildObj) { call(`security set-keychain-settings -l ${process.env.HOME || ''}/Library/Keychains/login.keychain`) - cmdStr = `xcodebuild -workspace ${buildObj.xcodeWorkspace} -scheme ${buildObj.xcodeScheme} archive` + cmdStr = `xcodebuild -allowProvisioningUpdates -workspace ${buildObj.xcodeWorkspace} -scheme ${buildObj.xcodeScheme} archive` if (process.env.DISABLE_XCPRETTY === 'false') cmdStr = cmdStr + ' | xcpretty' cmdStr = cmdStr + ' && exit ${PIPE' + 'STATUS[0]}' call(cmdStr) @@ -221,7 +246,7 @@ function buildIos(buildObj: BuildObj) { call(`security set-keychain-settings -l ${process.env.HOME || ''}/Library/Keychains/login.keychain`) - cmdStr = `xcodebuild -exportArchive -archivePath "${buildDir}/${archiveDir}" -exportPath ${buildObj.tmpDir}/ -exportOptionsPlist ./exportOptions.plist` + cmdStr = `xcodebuild -allowProvisioningUpdates -exportArchive -archivePath "${buildDir}/${archiveDir}" -exportPath ${buildObj.tmpDir}/ -exportOptionsPlist ./exportOptions.plist` call(cmdStr) mylog('Zipping dSYM for ' + buildObj.xcodeScheme) From 1a5b64109081de489f5863a58ca125a8551d6893 Mon Sep 17 00:00:00 2001 From: Itay <4023066+itayplav@users.noreply.github.com> Date: Tue, 30 May 2023 09:20:28 -0500 Subject: [PATCH 051/104] Add `accessibilityHint`s to icon-based buttons --- .../__snapshots__/PromoCard.test.tsx.snap | 1 + .../TransactionListTop.test.tsx.snap | 1 + .../AdvancedDetailsModal.test.tsx.snap | 2 +- .../__snapshots__/WalletListModal.test.tsx.snap | 2 +- .../CreateWalletImportScene.test.tsx.snap | 1 + .../CurrencySettings.ui.test.tsx.snap | 6 ++++++ .../__snapshots__/EdgeLoginScene.test.tsx.snap | 1 + src/components/cards/PromoCard.tsx | 3 ++- src/components/modals/ConfirmContinueModal.tsx | 2 +- src/components/modals/FiatListModal.tsx | 8 +++++++- src/components/modals/ListModal.tsx | 1 + src/components/modals/RadioListModal.tsx | 17 ++++++++++++++--- .../scenes/CreateWalletImportScene.tsx | 2 +- .../scenes/CreateWalletSelectCryptoScene.tsx | 4 ++++ src/components/scenes/EdgeLoginScene.tsx | 4 ++-- src/components/scenes/LoginScene.tsx | 5 ++--- src/components/scenes/SpendingLimitsScene.tsx | 2 +- src/components/themed/ControlPanel.tsx | 4 ++-- src/components/themed/ManageTokensRow.tsx | 8 ++++++-- src/components/themed/ModalParts.tsx | 5 +++-- src/components/themed/SettingsRadioRow.tsx | 9 +++++++-- src/components/themed/TransactionListTop.tsx | 2 +- src/components/themed/WalletListHeader.tsx | 4 ++-- src/locales/en_US.ts | 15 +++++++++++++++ src/locales/strings/enUS.json | 13 +++++++++++++ 25 files changed, 96 insertions(+), 26 deletions(-) diff --git a/src/__tests__/components/__snapshots__/PromoCard.test.tsx.snap b/src/__tests__/components/__snapshots__/PromoCard.test.tsx.snap index 50e48f2169a..a47e339736d 100644 --- a/src/__tests__/components/__snapshots__/PromoCard.test.tsx.snap +++ b/src/__tests__/components/__snapshots__/PromoCard.test.tsx.snap @@ -108,6 +108,7 @@ exports[`PromoCard should render 1`] = ` } > diff --git a/src/components/cards/PromoCard.tsx b/src/components/cards/PromoCard.tsx index 48847bda332..db02b420524 100644 --- a/src/components/cards/PromoCard.tsx +++ b/src/components/cards/PromoCard.tsx @@ -6,6 +6,7 @@ import AntDesignIcon from 'react-native-vector-icons/AntDesign' import { hideMessageTweak } from '../../actions/AccountReferralActions' import { linkReferralWithCurrencies } from '../../actions/WalletListActions' import { useHandler } from '../../hooks/useHandler' +import { lstrings } from '../../locales/strings' import { useDispatch, useSelector } from '../../types/reactRedux' import { NavigationBase } from '../../types/routerTypes' import { bestOfMessages } from '../../util/ReferralHelpers' @@ -49,7 +50,7 @@ export function PromoCard(props: Props) { {message.message} - + diff --git a/src/components/modals/ConfirmContinueModal.tsx b/src/components/modals/ConfirmContinueModal.tsx index 2e4b8e7abee..a35f120f168 100644 --- a/src/components/modals/ConfirmContinueModal.tsx +++ b/src/components/modals/ConfirmContinueModal.tsx @@ -65,7 +65,7 @@ export function ConfirmContinueModal(props: Props) { {lstrings.confirm_continue_modal_button_text} - {isAgreed && } + {isAgreed && } diff --git a/src/components/modals/FiatListModal.tsx b/src/components/modals/FiatListModal.tsx index 3f8a8f5f646..1870d7038b9 100644 --- a/src/components/modals/FiatListModal.tsx +++ b/src/components/modals/FiatListModal.tsx @@ -49,7 +49,13 @@ export const FiatListModal = (props: Props) => { return ( : } + icon={ + fiatCountry?.logoUrl != null ? ( + + ) : ( + + ) + } paddingRem={[0, 1]} subTitle={subTitle} title={item.value} diff --git a/src/components/modals/ListModal.tsx b/src/components/modals/ListModal.tsx index 17f6e62912c..e14543dbdef 100644 --- a/src/components/modals/ListModal.tsx +++ b/src/components/modals/ListModal.tsx @@ -84,6 +84,7 @@ export function ListModal({ autoCapitalize="words" returnKeyType="done" marginRem={[1, 0.5]} + testID={title} onChangeText={handleChangeText} onSubmitEditing={handleSubmitEditing} value={text} diff --git a/src/components/modals/RadioListModal.tsx b/src/components/modals/RadioListModal.tsx index 6eaa706bbfd..a579cafb817 100644 --- a/src/components/modals/RadioListModal.tsx +++ b/src/components/modals/RadioListModal.tsx @@ -3,6 +3,7 @@ import { Image, Text, TouchableOpacity, View } from 'react-native' import { AirshipBridge } from 'react-native-airship' import IonIcon from 'react-native-vector-icons/Ionicons' +import { lstrings } from '../../locales/strings' import { cacheStyles, Theme, useTheme } from '../services/ThemeContext' import { EdgeText } from '../themed/EdgeText' import { ListModal } from './ListModal' @@ -22,8 +23,10 @@ export function RadioListModal(props: Props) { // @ts-expect-error function renderRow({ name, icon, text }): React.ReactNode { const imageIcon = typeof icon === 'string' ? { uri: icon } : icon - const radio = selected === name ? { icon: 'ios-radio-button-on', color: theme.iconTappable } : { icon: 'ios-radio-button-off', color: theme.iconTappable } - + const isSelected = selected === name + const radio = isSelected ? { icon: 'ios-radio-button-on', color: theme.iconTappable } : { icon: 'ios-radio-button-off', color: theme.iconTappable } + const accessibilityState = isSelected ? { checked: true } : { checked: false } + const accessibilityHint = `${isSelected ? lstrings.on_hint : lstrings.off_hint} ${name}` return ( bridge.resolve(name)}> @@ -32,7 +35,15 @@ export function RadioListModal(props: Props) { {name} {text != null ? {text} : null} - + ) diff --git a/src/components/scenes/CreateWalletImportScene.tsx b/src/components/scenes/CreateWalletImportScene.tsx index e10df277b0e..ca3d7327964 100644 --- a/src/components/scenes/CreateWalletImportScene.tsx +++ b/src/components/scenes/CreateWalletImportScene.tsx @@ -148,7 +148,7 @@ const CreateWalletImportComponent = (props: Props) => { onKeyboardWillChangeFrame={() => setScrollEnabled(true)} > - + {lstrings.create_wallet_import_all_instructions} diff --git a/src/components/scenes/CreateWalletSelectCryptoScene.tsx b/src/components/scenes/CreateWalletSelectCryptoScene.tsx index b651d80579d..9935fc425af 100644 --- a/src/components/scenes/CreateWalletSelectCryptoScene.tsx +++ b/src/components/scenes/CreateWalletSelectCryptoScene.tsx @@ -203,8 +203,12 @@ const CreateWalletSelectCryptoComponent = (props: Props) => { const renderCreateWalletRow: ListRenderItem = useHandler(item => { const { key, displayName, pluginId, tokenId } = item.item + const accessibilityHint = sprintf(lstrings.create_wallet_hint, displayName) const toggle = ( { - + - + {lobby?.loginRequest?.displayName} diff --git a/src/components/scenes/LoginScene.tsx b/src/components/scenes/LoginScene.tsx index 5c11846cdde..4d72516a65b 100644 --- a/src/components/scenes/LoginScene.tsx +++ b/src/components/scenes/LoginScene.tsx @@ -215,14 +215,13 @@ class LoginSceneComponent extends React.PureComponent { } const dummyTouchIdInfo: GuiTouchIdInfo = { - isTouchEnabled: false, - isTouchSupported: false + isTouchEnabled: true, + isTouchSupported: true } const getStyles = cacheStyles((theme: Theme) => ({ container: { flex: 1, - position: 'relative', paddingTop: StatusBar.currentHeight, backgroundColor: theme.backgroundGradientColors[0] } diff --git a/src/components/scenes/SpendingLimitsScene.tsx b/src/components/scenes/SpendingLimitsScene.tsx index 693d9b3aaba..5e9db26e76b 100644 --- a/src/components/scenes/SpendingLimitsScene.tsx +++ b/src/components/scenes/SpendingLimitsScene.tsx @@ -65,7 +65,7 @@ class SpendingLimitsComponent extends React.Component { {lstrings.spending_limits_tx_title} {lstrings.spending_limits_tx_description} - + {username} - + ))} @@ -378,7 +378,7 @@ export function ControlPanel(props: DrawerContentComponentProps) { {/* === Translucent X Close Button Start === */} - + {/* === Translucent X Close Button End === */} diff --git a/src/components/themed/ManageTokensRow.tsx b/src/components/themed/ManageTokensRow.tsx index c13405df5bb..ee1debbc5b5 100644 --- a/src/components/themed/ManageTokensRow.tsx +++ b/src/components/themed/ManageTokensRow.tsx @@ -7,6 +7,7 @@ import FontAwesomeIcon from 'react-native-vector-icons/FontAwesome' import { approveTokenTerms } from '../../actions/TokenTermsActions' import { useHandler } from '../../hooks/useHandler' import { usePendingPressAnimation } from '../../hooks/usePendingPress' +import { lstrings } from '../../locales/strings' import { useSelector } from '../../types/reactRedux' import { NavigationProp } from '../../types/routerTypes' import { getWalletName } from '../../util/CurrencyWalletHelpers' @@ -86,13 +87,16 @@ export const ManageTokensRowComponent = (props: Props) => { {!isCustom ? null : ( - + )} - + - - + + {fadeOut !== true ? null : } diff --git a/src/components/themed/SettingsRadioRow.tsx b/src/components/themed/SettingsRadioRow.tsx index 979ce392cbd..1edf8ee8249 100644 --- a/src/components/themed/SettingsRadioRow.tsx +++ b/src/components/themed/SettingsRadioRow.tsx @@ -1,6 +1,7 @@ import * as React from 'react' import IonIcon from 'react-native-vector-icons/Ionicons' +import { lstrings } from '../../locales/strings' import { useTheme } from '../services/ThemeContext' import { SettingsRow } from './SettingsRow' @@ -34,8 +35,12 @@ const SettingsRadioRowComponent = (props: Props) => { fontSize: theme.rem(1.25), marginHorizontal: theme.rem(0.5) } - - const rightIcon = value ? : + const accessibilityHint = `${value ? lstrings.on_hint : lstrings.off_hint} ${label}` + const rightIcon = value ? ( + + ) : ( + + ) return ( {children} diff --git a/src/components/themed/TransactionListTop.tsx b/src/components/themed/TransactionListTop.tsx index 91b06c4781d..71dee2ba4c1 100644 --- a/src/components/themed/TransactionListTop.tsx +++ b/src/components/themed/TransactionListTop.tsx @@ -204,7 +204,7 @@ export class TransactionListTopComponent extends React.PureComponent - + diff --git a/src/components/themed/WalletListHeader.tsx b/src/components/themed/WalletListHeader.tsx index bc6d48e5fdd..83674b80c6c 100644 --- a/src/components/themed/WalletListHeader.tsx +++ b/src/components/themed/WalletListHeader.tsx @@ -76,10 +76,10 @@ export class WalletListHeaderComponent extends React.PureComponent { {lstrings.title_wallets} navigation.push('createWalletSelectCrypto', {})}> - + - + diff --git a/src/locales/en_US.ts b/src/locales/en_US.ts index c54ae65fc24..4725bcfe3fd 100644 --- a/src/locales/en_US.ts +++ b/src/locales/en_US.ts @@ -1502,6 +1502,21 @@ const strings = { // Accessibility Hints app_logo_hint: 'App logo', + check_icon_hint: 'Confirmed', + close_control_panel_hint: 'Close control panel', + close_hint: 'Close', + create_wallet_hint: 'Create Wallet %s', + edit_icon_hint: 'Edit', + import_key_icon_hint: 'Import Key', + modal_close_hint: 'Close modal', + off_hint: 'Off', + on_hint: 'On', + sort_wallets_hint: 'Sort Wallets', + spinner_hint: 'Loading', + toggle_button_hint: 'Toggle', + + // Accessibility Labels + wallet_settings_label: 'Wallet settings', // Reward Card rewards_card_getting_invoice: 'Getting payment invoice', diff --git a/src/locales/strings/enUS.json b/src/locales/strings/enUS.json index 77a64227747..dc69696c65e 100644 --- a/src/locales/strings/enUS.json +++ b/src/locales/strings/enUS.json @@ -1326,6 +1326,19 @@ "getting_started_welcome_prompt": "Swipe to Learn More", "getting_started_welcome_title": "Welcome to\nFinancial *Freedom*", "app_logo_hint": "App logo", + "check_icon_hint": "Confirmed", + "close_control_panel_hint": "Close control panel", + "close_hint": "Close", + "create_wallet_hint": "Create Wallet %s", + "edit_icon_hint": "Edit", + "import_key_icon_hint": "Import Key", + "modal_close_hint": "Close modal", + "off_hint": "Off", + "on_hint": "On", + "sort_wallets_hint": "Sort Wallets", + "spinner_hint": "Loading", + "toggle_button_hint": "Toggle", + "wallet_settings_label": "Wallet settings", "rewards_card_getting_invoice": "Getting payment invoice", "rewards_card_error_retrieving_cards": "Error retrieving Visa cards. Please try again later.", "rewards_card_error_authenticate": "Error authenticating with Visa Card program. Please try again later.", From 9dadf7d8c77f1c80de774521aff9af35a0f175da Mon Sep 17 00:00:00 2001 From: Itay <4023066+itayplav@users.noreply.github.com> Date: Tue, 30 May 2023 12:51:43 -0500 Subject: [PATCH 052/104] Fix undefined value after wallet creation --- src/actions/CryptoExchangeActions.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/actions/CryptoExchangeActions.tsx b/src/actions/CryptoExchangeActions.tsx index cfd782613ed..e59f84c4c13 100644 --- a/src/actions/CryptoExchangeActions.tsx +++ b/src/actions/CryptoExchangeActions.tsx @@ -383,6 +383,7 @@ export function checkEnabledExchanges(): ThunkAction { // make sure exchanges are enabled let isAnyExchangeEnabled = false const exchanges = account.swapConfig + if (exchanges == null) return for (const exchange of Object.keys(exchanges)) { if (exchanges[exchange].enabled) { isAnyExchangeEnabled = true From 94a51eacbca8c6034cafcd3ef58b333ed2a57e40 Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Wed, 31 May 2023 17:14:12 -0700 Subject: [PATCH 053/104] Require user to have purchased a card before skipping welcome screen --- src/plugins/gui/RewardsCardPlugin.tsx | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/plugins/gui/RewardsCardPlugin.tsx b/src/plugins/gui/RewardsCardPlugin.tsx index 3df099c20b3..33ba31e4bf5 100644 --- a/src/plugins/gui/RewardsCardPlugin.tsx +++ b/src/plugins/gui/RewardsCardPlugin.tsx @@ -13,7 +13,7 @@ import { openBrowserUri } from '../../util/WebUtils' import { FiatPlugin, FiatPluginFactory, FiatPluginStartParams, FiatPluginWalletPickerResult } from './fiatPluginTypes' import { FiatProviderGetQuoteParams } from './fiatProviderTypes' import { getRateFromQuote } from './pluginUtils' -import { IoniaMethods, makeIoniaProvider } from './providers/ioniaProvider' +import { GiftCard, IoniaMethods, makeIoniaProvider } from './providers/ioniaProvider' import { RewardCard } from './scenes/RewardsCardDashboardScene' import { initializeProviders } from './util/initializeProviders' @@ -43,9 +43,9 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { // Helpers: // - async function getRewardCards(): Promise { + async function getRewardCards(): Promise<{ activeCards: RewardsCardItem[]; archivedCards: RewardsCardItem[] }> { const giftCards = await provider.otherMethods.getGiftCards() - const rewardCards: RewardsCardItem[] = giftCards.cards.map(card => { + const convert = (card: GiftCard) => { // Expires 6 calendar months from the creation date const expirationDate = new Date(card.CreatedDate.valueOf()) expirationDate.setMonth(card.CreatedDate.getMonth() + 6) @@ -55,15 +55,16 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { expiration: expirationDate, url: card.CardNumber } - }) - // Reverse order to show latest first - return rewardCards + } + const activeCards: RewardsCardItem[] = giftCards.cards.map(convert) + const archivedCards: RewardsCardItem[] = giftCards.archivedCards.map(convert) + return { activeCards, archivedCards } } async function refreshRewardsCards(retries: number) { if (retries > 15) return await getRewardCards() - .then(async cards => { + .then(async ({ activeCards: cards }) => { if (cards.length === rewardCards.length) { console.log(`Retrying rewards card refresh`) await snooze(retries * 1000) @@ -304,10 +305,11 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { const isAuthenticated = await provider.otherMethods.authenticate().catch(e => { throw new Error(lstrings.rewards_card_error_authenticate) }) + let hasCards = false if (isAuthenticated) { // Get/refresh rewards cards: - rewardCards = await showUi.showToastSpinner( + const { activeCards, archivedCards } = await showUi.showToastSpinner( lstrings.loading, runWithTimeout( getRewardCards().catch(e => { @@ -317,6 +319,8 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { new Error(lstrings.rewards_card_error_timeout_loading) ) ) + rewardCards = activeCards + hasCards = activeCards.length + archivedCards.length > 0 } redundantQuoteParams = { @@ -325,7 +329,7 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { regionCode: startParams.regionCode } - if (isAuthenticated) { + if (isAuthenticated && hasCards) { await showDashboard({ showLoading: false }) } else { await showWelcome() From a9a0cedff71b552500676c91902567fc2a10c38d Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Wed, 31 May 2023 16:03:21 -0700 Subject: [PATCH 054/104] Move RewardsCardItem data model to ioniaProvider IO layer The ioniaProvider concerns itself with returning RewardsCardItem objects to be consumed by the RewardsCardPlugin. We add the expiration/creation fields to the data type as well. --- src/plugins/gui/RewardsCardPlugin.tsx | 28 ++------ src/plugins/gui/providers/ioniaProvider.ts | 66 ++++++++++++++----- .../gui/scenes/RewardsCardDashboardScene.tsx | 2 +- 3 files changed, 58 insertions(+), 38 deletions(-) diff --git a/src/plugins/gui/RewardsCardPlugin.tsx b/src/plugins/gui/RewardsCardPlugin.tsx index 33ba31e4bf5..c178e9b1a25 100644 --- a/src/plugins/gui/RewardsCardPlugin.tsx +++ b/src/plugins/gui/RewardsCardPlugin.tsx @@ -13,7 +13,7 @@ import { openBrowserUri } from '../../util/WebUtils' import { FiatPlugin, FiatPluginFactory, FiatPluginStartParams, FiatPluginWalletPickerResult } from './fiatPluginTypes' import { FiatProviderGetQuoteParams } from './fiatProviderTypes' import { getRateFromQuote } from './pluginUtils' -import { GiftCard, IoniaMethods, makeIoniaProvider } from './providers/ioniaProvider' +import { IoniaMethods, makeIoniaProvider } from './providers/ioniaProvider' import { RewardCard } from './scenes/RewardsCardDashboardScene' import { initializeProviders } from './util/initializeProviders' @@ -21,7 +21,8 @@ const SUPPORT_URL = 'https://edge.app/visa-card-how-to' export interface RewardsCardItem { id: number - expiration: Date + creationDate: Date + expirationDate: Date url: string } @@ -43,27 +44,10 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { // Helpers: // - async function getRewardCards(): Promise<{ activeCards: RewardsCardItem[]; archivedCards: RewardsCardItem[] }> { - const giftCards = await provider.otherMethods.getGiftCards() - const convert = (card: GiftCard) => { - // Expires 6 calendar months from the creation date - const expirationDate = new Date(card.CreatedDate.valueOf()) - expirationDate.setMonth(card.CreatedDate.getMonth() + 6) - - return { - id: card.Id, - expiration: expirationDate, - url: card.CardNumber - } - } - const activeCards: RewardsCardItem[] = giftCards.cards.map(convert) - const archivedCards: RewardsCardItem[] = giftCards.archivedCards.map(convert) - return { activeCards, archivedCards } - } - async function refreshRewardsCards(retries: number) { if (retries > 15) return - await getRewardCards() + await await provider.otherMethods + .getRewardsCards() .then(async ({ activeCards: cards }) => { if (cards.length === rewardCards.length) { console.log(`Retrying rewards card refresh`) @@ -312,7 +296,7 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { const { activeCards, archivedCards } = await showUi.showToastSpinner( lstrings.loading, runWithTimeout( - getRewardCards().catch(e => { + provider.otherMethods.getRewardsCards().catch(e => { throw new Error(lstrings.rewards_card_error_retrieving_cards) }), 11000, diff --git a/src/plugins/gui/providers/ioniaProvider.ts b/src/plugins/gui/providers/ioniaProvider.ts index 55443ac6c99..7233dad3aa6 100644 --- a/src/plugins/gui/providers/ioniaProvider.ts +++ b/src/plugins/gui/providers/ioniaProvider.ts @@ -1,5 +1,21 @@ import { div, mul } from 'biggystring' -import { asArray, asBoolean, asDate, asEither, asJSON, asMaybe, asNull, asNumber, asObject, asOptional, asString, asValue, Cleaner, uncleaner } from 'cleaners' +import { + asArray, + asBoolean, + asCodec, + asDate, + asEither, + asJSON, + asMaybe, + asNull, + asNumber, + asObject, + asOptional, + asString, + asValue, + Cleaner, + uncleaner +} from 'cleaners' import { sprintf } from 'sprintf-js' import URL from 'url-parse' @@ -9,6 +25,7 @@ import { cleanFetch, fetcherWithOptions } from '../../../util/cleanFetch' import { toBigNumberString } from '../../../util/toBigNumberString' import { makeUuid } from '../../../util/utils' import { FiatProvider, FiatProviderAssetMap, FiatProviderFactory, FiatProviderGetQuoteParams, FiatProviderQuote } from '../fiatProviderTypes' +import { RewardsCardItem } from '../RewardsCardPlugin' // JWT 24 hour access token for Edge let ACCESS_TOKEN: string @@ -34,12 +51,31 @@ const asIoniaPluginApiKeys = asObject({ scope: asString }) -export type GiftCard = ReturnType -export const asGiftCard = asObject({ - Id: asNumber, - CardNumber: asString, - CreatedDate: asDate -}) +export const asRewardsCard = asCodec( + raw => { + const ioniaCard = asObject({ + Id: asNumber, + CardNumber: asString, + CreatedDate: asDate + })(raw) + + // Expires 6 calendar months from the creation date + const expirationDate = new Date(ioniaCard.CreatedDate.valueOf()) + expirationDate.setMonth(ioniaCard.CreatedDate.getMonth() + 6) + + return { + id: ioniaCard.Id, + creationDate: ioniaCard.CreatedDate, + expirationDate, + url: ioniaCard.CardNumber + } + }, + rewardCard => ({ + Id: rewardCard.id, + CreatedDate: rewardCard.creationDate, + CardNumber: rewardCard.url + }) +) export type IoniaPurchaseCard = ReturnType export const asIoniaPurchaseCard = asObject({ @@ -65,7 +101,7 @@ const wasStoreHiddenCards = uncleaner(asStoreHiddenCards) export interface IoniaMethods { authenticate: (shouldCreate?: boolean) => Promise - getGiftCards: () => Promise<{ cards: GiftCard[]; archivedCards: GiftCard[] }> + getRewardsCards: () => Promise<{ activeCards: RewardsCardItem[]; archivedCards: RewardsCardItem[] }> hideCard: (cardId: number) => Promise queryPurchaseCard: (currencyCode: string, cardAmount: number) => Promise } @@ -143,7 +179,7 @@ export const makeIoniaProvider: FiatProviderFactory = { {} ) ), - asResponse: asJSON(asIoniaResponse(asArray(asGiftCard))) + asResponse: asJSON(asIoniaResponse(asArray(asRewardsCard))) }) // Ionia Purchase Card Request: @@ -403,17 +439,17 @@ export const makeIoniaProvider: FiatProviderFactory = { hiddenCardIds = Array.from(set) await store.setItem(STORE_HIDDEN_CARDS_KEY, wasStoreHiddenCards(hiddenCardIds)) }, - async getGiftCards() { + async getRewardsCards() { const giftCardsResponse = await fetchGetGiftCards({ headers: userAuthenticatedFetchOptions.headers }) - const { Data: giftCards } = giftCardsResponse + const { Data: cards } = giftCardsResponse - const out: { cards: GiftCard[]; archivedCards: GiftCard[] } = { cards: [], archivedCards: [] } + const out: { activeCards: RewardsCardItem[]; archivedCards: RewardsCardItem[] } = { activeCards: [], archivedCards: [] } // Filter all deleted cards: - for (const card of giftCards) { - if (hiddenCardIds.includes(card.Id)) out.archivedCards.push(card) - else out.cards.push(card) + for (const card of cards) { + if (hiddenCardIds.includes(card.id)) out.archivedCards.push(card) + else out.activeCards.push(card) } return out }, diff --git a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx index 22c73d4cbe2..8cab7d44d07 100644 --- a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx +++ b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx @@ -101,7 +101,7 @@ export const RewardCard = ({ item, onPress, onRemovePress }: { item: RewardsCard {lstrings.rewards_card_dashboard_expires_label} - {item.expiration.toLocaleString()} + {item.expirationDate.toLocaleString()} {onRemovePress == null ? null : ( From 842a58412db2f2f49a97369d3012eb9ce34e34f2 Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Wed, 31 May 2023 16:07:45 -0700 Subject: [PATCH 055/104] Require user to have purchased a card before skipping welcome screen --- src/plugins/gui/RewardsCardPlugin.tsx | 26 ++++++++++++---------- src/plugins/gui/providers/ioniaProvider.ts | 6 ++--- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/plugins/gui/RewardsCardPlugin.tsx b/src/plugins/gui/RewardsCardPlugin.tsx index c178e9b1a25..7cef15da722 100644 --- a/src/plugins/gui/RewardsCardPlugin.tsx +++ b/src/plugins/gui/RewardsCardPlugin.tsx @@ -26,6 +26,11 @@ export interface RewardsCardItem { url: string } +export interface UserRewardsCards { + activeCards: RewardsCardItem[] + archivedCards: RewardsCardItem[] +} + const PROVIDER_FACTORIES = [makeIoniaProvider] export const makeRewardsCardPlugin: FiatPluginFactory = async params => { @@ -48,13 +53,13 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { if (retries > 15) return await await provider.otherMethods .getRewardsCards() - .then(async ({ activeCards: cards }) => { - if (cards.length === rewardCards.length) { + .then(async ({ activeCards, archivedCards }) => { + if (activeCards.length === rewardsCards.activeCards.length) { console.log(`Retrying rewards card refresh`) await snooze(retries * 1000) return await refreshRewardsCards(retries + 1) } - rewardCards = cards + rewardsCards = { activeCards, archivedCards } showDashboard({ showLoading: false }) }) .catch(async error => { @@ -68,16 +73,14 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { // let redundantQuoteParams: Pick - // Get the reward cards: - let rewardCards: RewardsCardItem[] = [] - + let rewardsCards: UserRewardsCards = { activeCards: [], archivedCards: [] } // // State Machine: // const showDashboard = async ({ showLoading }: { showLoading: boolean }) => { showUi.rewardsCardDashboard({ - items: rewardCards, + items: rewardsCards.activeCards, showLoading, onCardPress({ url }) { showUi.openWebView({ url }) @@ -113,7 +116,7 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { // Hide the card provider.otherMethods.hideCard(card.id) // Remove card from plugin state - rewardCards = rewardCards.filter(c => c.id !== card.id) + rewardsCards.activeCards = rewardsCards.activeCards.filter(c => c.id !== card.id) // Reset state for dashboard showDashboard({ showLoading: false }) @@ -289,11 +292,10 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { const isAuthenticated = await provider.otherMethods.authenticate().catch(e => { throw new Error(lstrings.rewards_card_error_authenticate) }) - let hasCards = false if (isAuthenticated) { // Get/refresh rewards cards: - const { activeCards, archivedCards } = await showUi.showToastSpinner( + rewardsCards = await showUi.showToastSpinner( lstrings.loading, runWithTimeout( provider.otherMethods.getRewardsCards().catch(e => { @@ -303,10 +305,10 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { new Error(lstrings.rewards_card_error_timeout_loading) ) ) - rewardCards = activeCards - hasCards = activeCards.length + archivedCards.length > 0 } + const hasCards = rewardsCards.activeCards.length + rewardsCards.activeCards.length > 0 + redundantQuoteParams = { direction: startParams.direction, paymentTypes: startParams.paymentTypes, diff --git a/src/plugins/gui/providers/ioniaProvider.ts b/src/plugins/gui/providers/ioniaProvider.ts index 7233dad3aa6..71f2785d718 100644 --- a/src/plugins/gui/providers/ioniaProvider.ts +++ b/src/plugins/gui/providers/ioniaProvider.ts @@ -25,7 +25,7 @@ import { cleanFetch, fetcherWithOptions } from '../../../util/cleanFetch' import { toBigNumberString } from '../../../util/toBigNumberString' import { makeUuid } from '../../../util/utils' import { FiatProvider, FiatProviderAssetMap, FiatProviderFactory, FiatProviderGetQuoteParams, FiatProviderQuote } from '../fiatProviderTypes' -import { RewardsCardItem } from '../RewardsCardPlugin' +import { RewardsCardItem, UserRewardsCards } from '../RewardsCardPlugin' // JWT 24 hour access token for Edge let ACCESS_TOKEN: string @@ -101,7 +101,7 @@ const wasStoreHiddenCards = uncleaner(asStoreHiddenCards) export interface IoniaMethods { authenticate: (shouldCreate?: boolean) => Promise - getRewardsCards: () => Promise<{ activeCards: RewardsCardItem[]; archivedCards: RewardsCardItem[] }> + getRewardsCards: () => Promise hideCard: (cardId: number) => Promise queryPurchaseCard: (currencyCode: string, cardAmount: number) => Promise } @@ -445,7 +445,7 @@ export const makeIoniaProvider: FiatProviderFactory = { }) const { Data: cards } = giftCardsResponse - const out: { activeCards: RewardsCardItem[]; archivedCards: RewardsCardItem[] } = { activeCards: [], archivedCards: [] } + const out: UserRewardsCards = { activeCards: [], archivedCards: [] } // Filter all deleted cards: for (const card of cards) { if (hiddenCardIds.includes(card.id)) out.archivedCards.push(card) From a78811bb2524ba64e0311cc6dbdc7d94827abf3e Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Mon, 29 May 2023 15:02:56 -0700 Subject: [PATCH 056/104] Rename rewards cards state in RewardsCardsPlugin --- src/plugins/gui/RewardsCardPlugin.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/plugins/gui/RewardsCardPlugin.tsx b/src/plugins/gui/RewardsCardPlugin.tsx index 7cef15da722..311521d8dc7 100644 --- a/src/plugins/gui/RewardsCardPlugin.tsx +++ b/src/plugins/gui/RewardsCardPlugin.tsx @@ -54,12 +54,12 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { await await provider.otherMethods .getRewardsCards() .then(async ({ activeCards, archivedCards }) => { - if (activeCards.length === rewardsCards.activeCards.length) { + if (activeCards.length === userRewardsCards.activeCards.length) { console.log(`Retrying rewards card refresh`) await snooze(retries * 1000) return await refreshRewardsCards(retries + 1) } - rewardsCards = { activeCards, archivedCards } + userRewardsCards = { activeCards, archivedCards } showDashboard({ showLoading: false }) }) .catch(async error => { @@ -73,14 +73,14 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { // let redundantQuoteParams: Pick - let rewardsCards: UserRewardsCards = { activeCards: [], archivedCards: [] } + let userRewardsCards: UserRewardsCards = { activeCards: [], archivedCards: [] } // // State Machine: // const showDashboard = async ({ showLoading }: { showLoading: boolean }) => { showUi.rewardsCardDashboard({ - items: rewardsCards.activeCards, + items: userRewardsCards.activeCards, showLoading, onCardPress({ url }) { showUi.openWebView({ url }) @@ -116,7 +116,7 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { // Hide the card provider.otherMethods.hideCard(card.id) // Remove card from plugin state - rewardsCards.activeCards = rewardsCards.activeCards.filter(c => c.id !== card.id) + userRewardsCards.activeCards = userRewardsCards.activeCards.filter(c => c.id !== card.id) // Reset state for dashboard showDashboard({ showLoading: false }) @@ -295,7 +295,7 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { if (isAuthenticated) { // Get/refresh rewards cards: - rewardsCards = await showUi.showToastSpinner( + userRewardsCards = await showUi.showToastSpinner( lstrings.loading, runWithTimeout( provider.otherMethods.getRewardsCards().catch(e => { @@ -307,7 +307,7 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { ) } - const hasCards = rewardsCards.activeCards.length + rewardsCards.activeCards.length > 0 + const hasCards = userRewardsCards.activeCards.length + userRewardsCards.activeCards.length > 0 redundantQuoteParams = { direction: startParams.direction, From 593cfd49d37d58aa4c57cce786a889fb4e81be3e Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Fri, 2 Jun 2023 14:15:02 -0700 Subject: [PATCH 057/104] Rework RewardCard component design This consolidates all display logic for the RewardCard into the component and allows for variable height should it be presented in a stacked visual mode. --- src/plugins/gui/RewardsCardPlugin.tsx | 4 +- .../gui/scenes/RewardsCardDashboardScene.tsx | 79 +++++++++++-------- 2 files changed, 49 insertions(+), 34 deletions(-) diff --git a/src/plugins/gui/RewardsCardPlugin.tsx b/src/plugins/gui/RewardsCardPlugin.tsx index 311521d8dc7..d13d7b38b09 100644 --- a/src/plugins/gui/RewardsCardPlugin.tsx +++ b/src/plugins/gui/RewardsCardPlugin.tsx @@ -14,7 +14,7 @@ import { FiatPlugin, FiatPluginFactory, FiatPluginStartParams, FiatPluginWalletP import { FiatProviderGetQuoteParams } from './fiatProviderTypes' import { getRateFromQuote } from './pluginUtils' import { IoniaMethods, makeIoniaProvider } from './providers/ioniaProvider' -import { RewardCard } from './scenes/RewardsCardDashboardScene' +import { RewardsCard } from './scenes/RewardsCardDashboardScene' import { initializeProviders } from './util/initializeProviders' const SUPPORT_URL = 'https://edge.app/visa-card-how-to' @@ -107,7 +107,7 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { message: lstrings.rewards_card_delete_modal_message, children: ( - + ) }) diff --git a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx index 8cab7d44d07..913f780d0fd 100644 --- a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx +++ b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx @@ -57,18 +57,15 @@ export const RewardsCardDashboardScene = (props: Props) => { withTopMargin /> - + {items.map(item => { - return ( - - onCardPress(item)} onRemovePress={() => handleRemovePress(item)} /> - - ) + return onCardPress(item)} onRemovePress={() => handleRemovePress(item)} shouldStack /> })} {items.length === 0 && !showLoading ? {lstrings.rewards_card_no_cards} : null} {showLoading ? ( - - + + + {lstrings.rewards_card_loading} @@ -76,10 +73,10 @@ export const RewardsCardDashboardScene = (props: Props) => { {lstrings.rewards_card_purchase_disclaimer} - - + + ) : null} - + setBottomFloatHeight(event.nativeEvent.layout.height)}> @@ -90,13 +87,26 @@ export const RewardsCardDashboardScene = (props: Props) => { ) } -export const RewardCard = ({ item, onPress, onRemovePress }: { item: RewardsCardItem; onPress?: () => void; onRemovePress?: () => void }) => { +export interface RewardsCardProps { + item: RewardsCardItem + onPress?: () => void + onRemovePress?: () => void + shouldStack?: boolean +} + +export const RewardsCard = (props: RewardsCardProps) => { + const { item, onPress, onRemovePress, shouldStack = false } = props const theme = useTheme() return ( - - - + + + +
@@ -109,9 +119,9 @@ export const RewardCard = ({ item, onPress, onRemovePress }: { item: RewardsCard )} - + - + ) } @@ -121,28 +131,34 @@ const MessageText = styled(EdgeText)(props => ({ textAlign: 'center' })) -const CardListContainer = styled(View)<{ bottomSpace: number }>(props => ({ +const CardList = styled(View)<{ bottomSpace: number }>(props => ({ justifyContent: 'space-around', marginBottom: props.bottomSpace, padding: props.theme.rem(1.5) })) -const CardListItemWrapper = styled(View)(props => ({ - height: props.theme.rem(7) -})) -const CardListItem = styled(View)(props => ({ +const CardContainer = View + +const CardBackground = styled(View)(props => ({ + // This is the aspect ratio of a standard US credit card + aspectRatio: 1.5882352941, backgroundColor: props.theme.modal, - // Math for figuring out 1/8th inches border radius ((1/8)/3.375 * 314)/16: - borderRadius: props.theme.rem(0.7268518519), + // 0.75 rem is roughly proportional to a 1/8th inches border radius of a standard US credit card + borderRadius: props.theme.rem(0.75), borderWidth: 1, borderTopColor: 'rgba(255,255,255,.2)', borderColor: 'rgba(255,255,255,.1)', + flexDirection: 'row', + justifyContent: 'space-between', + padding: props.theme.rem(1.25), + position: 'absolute', shadowOpacity: 0.5, - shadowRadius: props.theme.rem(0.5) + shadowRadius: props.theme.rem(0.5), + width: '100%' })) -const CardListItemContainer = styled(View)(props => ({ - aspectRatio: 1.5882352941, +const CardInner = styled(View)<{ shouldStack?: boolean }>(props => ({ + aspectRatio: props.shouldStack === false ? 1.5882352941 : undefined, flexDirection: 'row', justifyContent: 'space-between', padding: props.theme.rem(1.25), @@ -158,8 +174,7 @@ const BottomFloat = styled(View)(props => ({ const LoadingContainer = styled(View)(props => ({ alignItems: 'center', flex: 1, - justifyContent: 'center', - paddingVertical: props.theme.rem(1) + justifyContent: 'center' })) const LoadingText = styled(Text)(props => ({ @@ -180,11 +195,11 @@ const LoadingTextDisclaimer = styled(Text)(props => ({ textAlign: 'left' })) -const Icon = styled(Ionicon)(props => ({})) +const Icon = Ionicon -const Details = styled(View)(props => ({})) +const Details = View -const DetailItem = styled(View)(prop => ({})) +const DetailItem = View const VisaBrandImage = styled(Image)(props => ({ resizeMode: 'contain', From c19f39339e10bd7528321bd00a8ab0c17caf490d Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Tue, 30 May 2023 14:45:53 -0700 Subject: [PATCH 058/104] Adjust spacing around card in delete modal --- src/plugins/gui/RewardsCardPlugin.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/gui/RewardsCardPlugin.tsx b/src/plugins/gui/RewardsCardPlugin.tsx index d13d7b38b09..78a44a0882b 100644 --- a/src/plugins/gui/RewardsCardPlugin.tsx +++ b/src/plugins/gui/RewardsCardPlugin.tsx @@ -106,7 +106,7 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { title: lstrings.rewards_card_delete_modal_title, message: lstrings.rewards_card_delete_modal_message, children: ( - + ) From 6f2ba894f4e5db30780472ea87da358a49894ceb Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Tue, 30 May 2023 14:49:42 -0700 Subject: [PATCH 059/104] Log errors caught to throw user-friendly errors --- src/plugins/gui/RewardsCardPlugin.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/gui/RewardsCardPlugin.tsx b/src/plugins/gui/RewardsCardPlugin.tsx index 78a44a0882b..5e78f43ca24 100644 --- a/src/plugins/gui/RewardsCardPlugin.tsx +++ b/src/plugins/gui/RewardsCardPlugin.tsx @@ -289,7 +289,8 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { pluginId, startPlugin: async (startParams: FiatPluginStartParams) => { // Auth User: - const isAuthenticated = await provider.otherMethods.authenticate().catch(e => { + const isAuthenticated = await provider.otherMethods.authenticate().catch(error => { + console.error(error) throw new Error(lstrings.rewards_card_error_authenticate) }) @@ -298,7 +299,8 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { userRewardsCards = await showUi.showToastSpinner( lstrings.loading, runWithTimeout( - provider.otherMethods.getRewardsCards().catch(e => { + provider.otherMethods.getRewardsCards().catch(error => { + console.error(error) throw new Error(lstrings.rewards_card_error_retrieving_cards) }), 11000, From cece145972cf77a0584e0ab3ff10fac69372c8b1 Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Tue, 30 May 2023 15:34:30 -0700 Subject: [PATCH 060/104] Fix expanded and sideways state for Space component --- src/hooks/useSpaceStyle.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useSpaceStyle.ts b/src/hooks/useSpaceStyle.ts index 72128ab9f77..fdbfe44f3df 100644 --- a/src/hooks/useSpaceStyle.ts +++ b/src/hooks/useSpaceStyle.ts @@ -84,7 +84,7 @@ export const useSpaceStyle = (props: SpaceProps): ViewStyle => { const horizontalAlignment = leftFill && rightFill ? 'center' : rightFill ? 'flex-start' : leftFill ? 'flex-end' : undefined const verticalAlignment = topFill && bottomFill ? 'center' : bottomFill ? 'flex-start' : topFill ? 'flex-end' : undefined const alignItems = sideways ? verticalAlignment : horizontalAlignment - const justifyContent = sideways ? horizontalAlignment : verticalAlignment + const justifyContent = sideways ? horizontalAlignment ?? (fill ? 'space-between' : undefined) : verticalAlignment // Flex: const flex = fill ? 1 : undefined From 95165974bfbc5087ba0bde5e54b30a4ac125772c Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Tue, 30 May 2023 16:09:25 -0700 Subject: [PATCH 061/104] Fix loading card disclaimer text alignment --- src/plugins/gui/scenes/RewardsCardDashboardScene.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx index 913f780d0fd..83f926bf313 100644 --- a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx +++ b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx @@ -192,7 +192,7 @@ const LoadingTextDisclaimer = styled(Text)(props => ({ color: props.theme.secondaryText, fontFamily: props.theme.fontFaceDefault, includeFontPadding: false, - textAlign: 'left' + textAlign: 'justify' })) const Icon = Ionicon From 45b8c6f7cc575267b09f0e259917b9f65797b45a Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Fri, 2 Jun 2023 14:52:52 -0700 Subject: [PATCH 062/104] Redesign and include more card details in RewardsCard --- src/locales/en_US.ts | 5 +- src/locales/strings/enUS.json | 5 +- src/plugins/gui/RewardsCardPlugin.tsx | 3 + src/plugins/gui/providers/ioniaProvider.ts | 14 +++- .../gui/scenes/RewardsCardDashboardScene.tsx | 72 ++++++++++++------- 5 files changed, 68 insertions(+), 31 deletions(-) diff --git a/src/locales/en_US.ts b/src/locales/en_US.ts index 4725bcfe3fd..1cf285411d4 100644 --- a/src/locales/en_US.ts +++ b/src/locales/en_US.ts @@ -465,6 +465,7 @@ const strings = { staking_no_fio_address_error: 'Unable to stake without a FIO addresses', staking_no_bundled_txs_error: 'Not enough bundled transactions for FIO address %1$s', string_i_agree: 'I Agree', + string_expires: `Expires`, string_decline: 'Decline', string_cancel_cap: 'Cancel', string_cancel: 'CANCEL', @@ -1531,7 +1532,9 @@ const strings = { rewards_card_welcome_more_info: `Learn More`, rewards_card_new_card_button_label: `Buy New Card`, rewards_card_call_to_action: `Buy Prepaid Visa® Cards`, - rewards_card_dashboard_expires_label: `Expires`, + rewards_card_dashboard_field_purchase_asset_label: `Purchase Asset`, + rewards_card_dashboard_field_purchase_date_label: `Purchase Date`, + rewards_card_dashboard_field_purchase_price_label: `Purchase Price`, rewards_card_dashboard_title: `Visa® Card Program`, rewards_card_delete_modal_title: 'Delete Card?', rewards_card_delete_modal_message: `Are you sure you want to delete this Visa® Card?`, diff --git a/src/locales/strings/enUS.json b/src/locales/strings/enUS.json index dc69696c65e..bc44281caf4 100644 --- a/src/locales/strings/enUS.json +++ b/src/locales/strings/enUS.json @@ -402,6 +402,7 @@ "staking_no_fio_address_error": "Unable to stake without a FIO addresses", "staking_no_bundled_txs_error": "Not enough bundled transactions for FIO address %1$s", "string_i_agree": "I Agree", + "string_expires": "Expires", "string_decline": "Decline", "string_cancel_cap": "Cancel", "string_cancel": "CANCEL", @@ -1350,7 +1351,9 @@ "rewards_card_welcome_more_info": "Learn More", "rewards_card_new_card_button_label": "Buy New Card", "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", - "rewards_card_dashboard_expires_label": "Expires", + "rewards_card_dashboard_field_purchase_asset_label": "Purchase Asset", + "rewards_card_dashboard_field_purchase_date_label": "Purchase Date", + "rewards_card_dashboard_field_purchase_price_label": "Purchase Price", "rewards_card_dashboard_title": "Visa® Card Program", "rewards_card_delete_modal_title": "Delete Card?", "rewards_card_delete_modal_message": "Are you sure you want to delete this Visa® Card?", diff --git a/src/plugins/gui/RewardsCardPlugin.tsx b/src/plugins/gui/RewardsCardPlugin.tsx index 5e78f43ca24..8e7938cc210 100644 --- a/src/plugins/gui/RewardsCardPlugin.tsx +++ b/src/plugins/gui/RewardsCardPlugin.tsx @@ -23,6 +23,9 @@ export interface RewardsCardItem { id: number creationDate: Date expirationDate: Date + amount: number + purchaseAsset: string + purchaseDate: Date url: string } diff --git a/src/plugins/gui/providers/ioniaProvider.ts b/src/plugins/gui/providers/ioniaProvider.ts index 71f2785d718..48c595a0df9 100644 --- a/src/plugins/gui/providers/ioniaProvider.ts +++ b/src/plugins/gui/providers/ioniaProvider.ts @@ -55,10 +55,15 @@ export const asRewardsCard = asCodec( raw => { const ioniaCard = asObject({ Id: asNumber, + ActualAmount: asNumber, CardNumber: asString, - CreatedDate: asDate + CreatedDate: asDate, + Currency: asString })(raw) + const purchaseAsset = ioniaCard.Currency + const amount = ioniaCard.ActualAmount + const purchaseDate = ioniaCard.CreatedDate // Expires 6 calendar months from the creation date const expirationDate = new Date(ioniaCard.CreatedDate.valueOf()) expirationDate.setMonth(ioniaCard.CreatedDate.getMonth() + 6) @@ -67,13 +72,18 @@ export const asRewardsCard = asCodec( id: ioniaCard.Id, creationDate: ioniaCard.CreatedDate, expirationDate, + amount, + purchaseAsset, + purchaseDate, url: ioniaCard.CardNumber } }, rewardCard => ({ Id: rewardCard.id, + ActualAmount: rewardCard.amount, + CardNumber: rewardCard.url, CreatedDate: rewardCard.creationDate, - CardNumber: rewardCard.url + Currency: rewardCard.purchaseAsset }) ) diff --git a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx index 83f926bf313..955291b37d8 100644 --- a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx +++ b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx @@ -12,6 +12,7 @@ import { EdgeText } from '../../../components/themed/EdgeText' import { MainButton } from '../../../components/themed/MainButton' import { SceneHeader } from '../../../components/themed/SceneHeader' import { useHandler } from '../../../hooks/useHandler' +import { toLocaleDate } from '../../../locales/intl' import { lstrings } from '../../../locales/strings' import { useState } from '../../../types/reactHooks' import { RouteProp } from '../../../types/routerTypes' @@ -97,6 +98,7 @@ export interface RewardsCardProps { export const RewardsCard = (props: RewardsCardProps) => { const { item, onPress, onRemovePress, shouldStack = false } = props const theme = useTheme() + const purchaseAmount = `$${item.amount.toString()}` return ( @@ -107,18 +109,36 @@ export const RewardsCard = (props: RewardsCardProps) => { activeOpacity={onPress == null ? 1 : undefined} > -
+ - - {lstrings.rewards_card_dashboard_expires_label} - {item.expirationDate.toLocaleString()} - -
- {onRemovePress == null ? null : ( - - - - )} + {onRemovePress == null ? null : ( + + + + )} + + + + + {lstrings.rewards_card_dashboard_field_purchase_date_label} + {toLocaleDate(item.purchaseDate)} + + + {lstrings.rewards_card_dashboard_field_purchase_price_label} + {purchaseAmount} + + + + + {lstrings.string_expires} + {toLocaleDate(item.expirationDate)} + + + {lstrings.rewards_card_dashboard_field_purchase_asset_label} + {item.purchaseAsset} + + +
@@ -159,10 +179,7 @@ const CardBackground = styled(View)(props => ({ const CardInner = styled(View)<{ shouldStack?: boolean }>(props => ({ aspectRatio: props.shouldStack === false ? 1.5882352941 : undefined, - flexDirection: 'row', - justifyContent: 'space-between', - padding: props.theme.rem(1.25), - width: '100%' + padding: props.theme.rem(1.25) })) const BottomFloat = styled(View)(props => ({ @@ -171,7 +188,7 @@ const BottomFloat = styled(View)(props => ({ position: 'absolute' })) -const LoadingContainer = styled(View)(props => ({ +const LoadingContainer = styled(View)(_props => ({ alignItems: 'center', flex: 1, justifyContent: 'center' @@ -195,11 +212,10 @@ const LoadingTextDisclaimer = styled(Text)(props => ({ textAlign: 'justify' })) -const Icon = Ionicon - -const Details = View - -const DetailItem = View +const CardHeader = styled(View)(_props => ({ + flexDirection: 'row', + justifyContent: 'space-between' +})) const VisaBrandImage = styled(Image)(props => ({ resizeMode: 'contain', @@ -208,16 +224,18 @@ const VisaBrandImage = styled(Image)(props => ({ marginBottom: props.theme.rem(1.25) })) -const ExpiryLabel = styled(Text)(props => ({ +const CardFieldLabel = styled(Text)<{ textAlign?: 'left' | 'right' }>(props => ({ color: props.theme.secondaryText, fontFamily: props.theme.fontFaceDefault, - fontSize: props.theme.rem(0.75), - includeFontPadding: false + fontSize: props.theme.rem(0.7), + includeFontPadding: false, + textAlign: props.textAlign ?? 'left' })) -const DateLabel = styled(Text)(props => ({ +const CardFieldValue = styled(Text)<{ textAlign?: 'left' | 'right' }>(props => ({ color: props.theme.primaryText, fontFamily: props.theme.fontFaceDefault, - fontSize: props.theme.rem(0.75), - includeFontPadding: false + fontSize: props.theme.rem(0.8), + includeFontPadding: false, + textAlign: props.textAlign ?? 'left' })) From 95d1c0a8a72345deb6556f23130009ccb35523db Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Tue, 30 May 2023 16:27:03 -0700 Subject: [PATCH 063/104] Add chevron icon to RewardsCard --- src/plugins/gui/scenes/RewardsCardDashboardScene.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx index 955291b37d8..6c488043edb 100644 --- a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx +++ b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx @@ -110,7 +110,10 @@ export const RewardsCard = (props: RewardsCardProps) => { > - + + + {onPress == null ? null : } + {onRemovePress == null ? null : ( @@ -221,7 +224,8 @@ const VisaBrandImage = styled(Image)(props => ({ resizeMode: 'contain', height: props.theme.rem(1.75), width: props.theme.rem(4), - marginBottom: props.theme.rem(1.25) + marginBottom: props.theme.rem(1.25), + marginRight: props.theme.rem(0.5) })) const CardFieldLabel = styled(Text)<{ textAlign?: 'left' | 'right' }>(props => ({ From 9246f8b0f82c44b76084b7c69ab452b1d7b0ffce Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Tue, 30 May 2023 17:05:04 -0700 Subject: [PATCH 064/104] Add maxWidth to RewardCards design for larger displays --- src/plugins/gui/scenes/RewardsCardDashboardScene.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx index 6c488043edb..2d858055b8f 100644 --- a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx +++ b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx @@ -155,12 +155,15 @@ const MessageText = styled(EdgeText)(props => ({ })) const CardList = styled(View)<{ bottomSpace: number }>(props => ({ - justifyContent: 'space-around', marginBottom: props.bottomSpace, padding: props.theme.rem(1.5) })) -const CardContainer = View +const CardContainer = styled(View)(props => ({ + maxWidth: props.theme.rem(20), + width: '100%', + alignSelf: 'center' +})) const CardBackground = styled(View)(props => ({ // This is the aspect ratio of a standard US credit card @@ -171,9 +174,6 @@ const CardBackground = styled(View)(props => ({ borderWidth: 1, borderTopColor: 'rgba(255,255,255,.2)', borderColor: 'rgba(255,255,255,.1)', - flexDirection: 'row', - justifyContent: 'space-between', - padding: props.theme.rem(1.25), position: 'absolute', shadowOpacity: 0.5, shadowRadius: props.theme.rem(0.5), From 2908b778f9d93596c849db4a593c72939a704004 Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Tue, 30 May 2023 18:19:11 -0700 Subject: [PATCH 065/104] Redesign loading card state for RewardsCardsDashboardScene --- src/locales/en_US.ts | 2 +- src/locales/strings/enUS.json | 2 +- .../gui/scenes/RewardsCardDashboardScene.tsx | 81 ++++++++----------- 3 files changed, 37 insertions(+), 48 deletions(-) diff --git a/src/locales/en_US.ts b/src/locales/en_US.ts index 1cf285411d4..373ecbe3a26 100644 --- a/src/locales/en_US.ts +++ b/src/locales/en_US.ts @@ -1525,7 +1525,7 @@ const strings = { rewards_card_error_authenticate: 'Error authenticating with Visa Card program. Please try again later.', rewards_card_error_timeout_loading: 'Timeout error loading Visa Card program. Please try again later.', rewards_card_purchase_disclaimer: - 'Newly purchased cards take a few seconds to become available. Cards purchased with BTC require 1 confirmation and could take 10-30 minutes to become available.', + 'Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.', rewards_card_loading: 'Loading your Visa® Cards...', rewards_card_add_new_input_amount_title: `Buy Visa® Card`, rewards_card_welcome_intro: `Purchase Visa® prepaid cards that can be used at millions of merchants in the U.S. Cards can be purchased up to $1,000 in value, with a daily limit of $10,000.`, diff --git a/src/locales/strings/enUS.json b/src/locales/strings/enUS.json index bc44281caf4..df9e9b91094 100644 --- a/src/locales/strings/enUS.json +++ b/src/locales/strings/enUS.json @@ -1344,7 +1344,7 @@ "rewards_card_error_retrieving_cards": "Error retrieving Visa cards. Please try again later.", "rewards_card_error_authenticate": "Error authenticating with Visa Card program. Please try again later.", "rewards_card_error_timeout_loading": "Timeout error loading Visa Card program. Please try again later.", - "rewards_card_purchase_disclaimer": "Newly purchased cards take a few seconds to become available. Cards purchased with BTC require 1 confirmation and could take 10-30 minutes to become available.", + "rewards_card_purchase_disclaimer": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", "rewards_card_loading": "Loading your Visa® Cards...", "rewards_card_add_new_input_amount_title": "Buy Visa® Card", "rewards_card_welcome_intro": "Purchase Visa® prepaid cards that can be used at millions of merchants in the U.S. Cards can be purchased up to $1,000 in value, with a daily limit of $10,000.", diff --git a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx index 2d858055b8f..0f40f2434d5 100644 --- a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx +++ b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx @@ -1,11 +1,14 @@ import * as React from 'react' -import { ActivityIndicator, Image, Text, TouchableOpacity, View } from 'react-native' +import { Image, Text, TouchableOpacity, View } from 'react-native' import Ionicon from 'react-native-vector-icons/Ionicons' import visaBrandImage from '../../../assets/images/guiPlugins/visaBrand.png' import { SceneWrapper } from '../../../components/common/SceneWrapper' import { styled } from '../../../components/hoc/styled' import { Space } from '../../../components/layout/Space' +import { ButtonsModal } from '../../../components/modals/ButtonsModal' +import { Shimmer } from '../../../components/progress-indicators/Shimmer' +import { Airship, showError } from '../../../components/services/AirshipInstance' import { useTheme } from '../../../components/services/ThemeContext' import { DividerLine } from '../../../components/themed/DividerLine' import { EdgeText } from '../../../components/themed/EdgeText' @@ -43,6 +46,11 @@ export const RewardsCardDashboardScene = (props: Props) => { const handleRemovePress = useHandler((item: RewardsCardItem) => { onRemovePress(item) }) + const handleQuestionPress = useHandler(() => { + Airship.show(bridge => ( + + )).catch(showError) + }) return ( <> @@ -63,20 +71,7 @@ export const RewardsCardDashboardScene = (props: Props) => { return onCardPress(item)} onRemovePress={() => handleRemovePress(item)} shouldStack /> })} {items.length === 0 && !showLoading ? {lstrings.rewards_card_no_cards} : null} - {showLoading ? ( - - - - - - {lstrings.rewards_card_loading} - - {lstrings.rewards_card_purchase_disclaimer} - - - - - ) : null} + {showLoading ? : null} setBottomFloatHeight(event.nativeEvent.layout.height)}> @@ -89,16 +84,17 @@ export const RewardsCardDashboardScene = (props: Props) => { } export interface RewardsCardProps { - item: RewardsCardItem + item?: RewardsCardItem onPress?: () => void + onQuestionPress?: () => void onRemovePress?: () => void shouldStack?: boolean } export const RewardsCard = (props: RewardsCardProps) => { - const { item, onPress, onRemovePress, shouldStack = false } = props + const { item, onPress, onQuestionPress, onRemovePress, shouldStack = false } = props const theme = useTheme() - const purchaseAmount = `$${item.amount.toString()}` + const purchaseAmount = item == null ? undefined : `$${item.amount.toString()}` return ( @@ -119,26 +115,43 @@ export const RewardsCard = (props: RewardsCardProps) => { )} + {onQuestionPress == null ? null : ( + + + + )} {lstrings.rewards_card_dashboard_field_purchase_date_label} - {toLocaleDate(item.purchaseDate)} + + + {item == null ? ' ' : toLocaleDate(item.purchaseDate)} + {lstrings.rewards_card_dashboard_field_purchase_price_label} - {purchaseAmount} + + + {purchaseAmount ?? ' '} + {lstrings.string_expires} - {toLocaleDate(item.expirationDate)} + + + {item == null ? ' ' : toLocaleDate(item.expirationDate)} + {lstrings.rewards_card_dashboard_field_purchase_asset_label} - {item.purchaseAsset} + + + {item?.purchaseAsset ?? ' '} + @@ -191,30 +204,6 @@ const BottomFloat = styled(View)(props => ({ position: 'absolute' })) -const LoadingContainer = styled(View)(_props => ({ - alignItems: 'center', - flex: 1, - justifyContent: 'center' -})) - -const LoadingText = styled(Text)(props => ({ - alignSelf: 'stretch', - color: props.theme.primaryText, - fontFamily: props.theme.fontFaceDefault, - fontSize: props.theme.rem(1), - includeFontPadding: false, - marginBottom: props.theme.rem(0.5), - textAlign: 'left' -})) - -const LoadingTextDisclaimer = styled(Text)(props => ({ - alignSelf: 'stretch', - color: props.theme.secondaryText, - fontFamily: props.theme.fontFaceDefault, - includeFontPadding: false, - textAlign: 'justify' -})) - const CardHeader = styled(View)(_props => ({ flexDirection: 'row', justifyContent: 'space-between' From 795acd4b53b0b641651c9e3ac48b3beff4beb1fa Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Mon, 5 Jun 2023 16:36:37 -0700 Subject: [PATCH 066/104] Update some `rewards_card_*` strings to be more generic --- src/locales/en_US.ts | 33 ++++++++++--------- src/locales/strings/enUS.json | 32 +++++++++--------- src/plugins/gui/RewardsCardPlugin.tsx | 8 ++--- src/plugins/gui/providers/ioniaProvider.ts | 4 +-- .../gui/scenes/RewardsCardDashboardScene.tsx | 10 +++--- .../gui/scenes/RewardsCardWelcomeScene.tsx | 4 +-- 6 files changed, 46 insertions(+), 45 deletions(-) diff --git a/src/locales/en_US.ts b/src/locales/en_US.ts index 373ecbe3a26..586aa05b344 100644 --- a/src/locales/en_US.ts +++ b/src/locales/en_US.ts @@ -1520,30 +1520,31 @@ const strings = { wallet_settings_label: 'Wallet settings', // Reward Card - rewards_card_getting_invoice: 'Getting payment invoice', rewards_card_error_retrieving_cards: 'Error retrieving Visa cards. Please try again later.', - rewards_card_error_authenticate: 'Error authenticating with Visa Card program. Please try again later.', - rewards_card_error_timeout_loading: 'Timeout error loading Visa Card program. Please try again later.', + rewards_card_error_authenticate: 'Error authenticating with Visa® Card program. Please try again later.', + rewards_card_error_timeout_loading: 'Timeout error loading Visa® Card program. Please try again later.', + rewards_card_call_to_action: `Buy Prepaid Visa® Cards`, rewards_card_purchase_disclaimer: 'Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.', rewards_card_loading: 'Loading your Visa® Cards...', rewards_card_add_new_input_amount_title: `Buy Visa® Card`, rewards_card_welcome_intro: `Purchase Visa® prepaid cards that can be used at millions of merchants in the U.S. Cards can be purchased up to $1,000 in value, with a daily limit of $10,000.`, - rewards_card_welcome_more_info: `Learn More`, - rewards_card_new_card_button_label: `Buy New Card`, - rewards_card_call_to_action: `Buy Prepaid Visa® Cards`, - rewards_card_dashboard_field_purchase_asset_label: `Purchase Asset`, - rewards_card_dashboard_field_purchase_date_label: `Purchase Date`, - rewards_card_dashboard_field_purchase_price_label: `Purchase Price`, rewards_card_dashboard_title: `Visa® Card Program`, - rewards_card_delete_modal_title: 'Delete Card?', rewards_card_delete_modal_message: `Are you sure you want to delete this Visa® Card?`, - rewards_card_error_missing_payment_address: `Missing payment address from provider`, - rewards_card_error_amount_max_s: `Maximum card purchase amount is $%s`, - rewards_card_error_amount_min_s: `Minimum card purchase amount is $%s`, - rewards_card_no_cards: 'You have no active cards.', - rewards_card_select_wallet: `Select wallet to use to purchase card`, - rewards_card_terms_of_use_message: `Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds.` + rewards_card_terms_of_use_message: `Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds.`, + + buy_new_card_button: `Buy New Card`, + card_amount_max_error_message_s: `Maximum card purchase amount is $%s`, + card_amount_min_error_message_s: `Minimum card purchase amount is $%s`, + delete_card_confirmation_title: 'Delete Card?', + getting_payment_invoice_message: 'Getting payment invoice', + learn_more_button: `Learn More`, + missing_provider_payment_address_message: `Missing payment address from provider`, + no_active_cards_message: 'You have no active cards.', + purchase_asset_label: `Purchase Asset`, + purchase_date_label: `Purchase Date`, + purchase_price_label: `Purchase Price`, + select_wallet_to_purchase_card_title: `Select wallet to use to purchase card` } // eslint-disable-next-line import/no-default-export diff --git a/src/locales/strings/enUS.json b/src/locales/strings/enUS.json index df9e9b91094..6917bed962f 100644 --- a/src/locales/strings/enUS.json +++ b/src/locales/strings/enUS.json @@ -1340,27 +1340,27 @@ "spinner_hint": "Loading", "toggle_button_hint": "Toggle", "wallet_settings_label": "Wallet settings", - "rewards_card_getting_invoice": "Getting payment invoice", "rewards_card_error_retrieving_cards": "Error retrieving Visa cards. Please try again later.", - "rewards_card_error_authenticate": "Error authenticating with Visa Card program. Please try again later.", - "rewards_card_error_timeout_loading": "Timeout error loading Visa Card program. Please try again later.", + "rewards_card_error_authenticate": "Error authenticating with Visa® Card program. Please try again later.", + "rewards_card_error_timeout_loading": "Timeout error loading Visa® Card program. Please try again later.", + "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", "rewards_card_purchase_disclaimer": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", "rewards_card_loading": "Loading your Visa® Cards...", "rewards_card_add_new_input_amount_title": "Buy Visa® Card", "rewards_card_welcome_intro": "Purchase Visa® prepaid cards that can be used at millions of merchants in the U.S. Cards can be purchased up to $1,000 in value, with a daily limit of $10,000.", - "rewards_card_welcome_more_info": "Learn More", - "rewards_card_new_card_button_label": "Buy New Card", - "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", - "rewards_card_dashboard_field_purchase_asset_label": "Purchase Asset", - "rewards_card_dashboard_field_purchase_date_label": "Purchase Date", - "rewards_card_dashboard_field_purchase_price_label": "Purchase Price", "rewards_card_dashboard_title": "Visa® Card Program", - "rewards_card_delete_modal_title": "Delete Card?", "rewards_card_delete_modal_message": "Are you sure you want to delete this Visa® Card?", - "rewards_card_error_missing_payment_address": "Missing payment address from provider", - "rewards_card_error_amount_max_s": "Maximum card purchase amount is $%s", - "rewards_card_error_amount_min_s": "Minimum card purchase amount is $%s", - "rewards_card_no_cards": "You have no active cards.", - "rewards_card_select_wallet": "Select wallet to use to purchase card", - "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds." + "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds.", + "buy_new_card_button": "Buy New Card", + "card_amount_max_error_message_s": "Maximum card purchase amount is $%s", + "card_amount_min_error_message_s": "Minimum card purchase amount is $%s", + "delete_card_confirmation_title": "Delete Card?", + "getting_payment_invoice_message": "Getting payment invoice", + "learn_more_button": "Learn More", + "missing_provider_payment_address_message": "Missing payment address from provider", + "no_active_cards_message": "You have no active cards.", + "purchase_asset_label": "Purchase Asset", + "purchase_date_label": "Purchase Date", + "purchase_price_label": "Purchase Price", + "select_wallet_to_purchase_card_title": "Select wallet to use to purchase card" } \ No newline at end of file diff --git a/src/plugins/gui/RewardsCardPlugin.tsx b/src/plugins/gui/RewardsCardPlugin.tsx index 8e7938cc210..ad43422d872 100644 --- a/src/plugins/gui/RewardsCardPlugin.tsx +++ b/src/plugins/gui/RewardsCardPlugin.tsx @@ -106,7 +106,7 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { delete: { label: lstrings.string_delete, type: 'secondary' }, keep: { label: lstrings.string_keep, type: 'escape' } }, - title: lstrings.rewards_card_delete_modal_title, + title: lstrings.delete_card_confirmation_title, message: lstrings.rewards_card_delete_modal_message, children: ( @@ -216,7 +216,7 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { if (!approved) return if (!parsedUri.paymentProtocolUrl) { - return showError(lstrings.rewards_card_error_missing_payment_address) + return showError(lstrings.missing_provider_payment_address_message) } const onDone = () => { @@ -231,7 +231,7 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { category: 'expense:Visa® Prepaid Card' } showUi.showToastSpinner( - lstrings.rewards_card_getting_invoice, + lstrings.getting_payment_invoice_message, showUi.sendPaymentProto({ uri: parsedUri.paymentProtocolUrl, params: { wallet, currencyCode, metadata, onDone } }) ) } @@ -240,7 +240,7 @@ export const makeRewardsCardPlugin: FiatPluginFactory = async params => { const showNewCardWalletListModal = async () => { const walletListResult: FiatPluginWalletPickerResult = await showUi.walletPicker({ - headerTitle: lstrings.rewards_card_select_wallet, + headerTitle: lstrings.select_wallet_to_purchase_card_title, allowedAssets, showCreateWallet: false }) diff --git a/src/plugins/gui/providers/ioniaProvider.ts b/src/plugins/gui/providers/ioniaProvider.ts index 48c595a0df9..904736abac7 100644 --- a/src/plugins/gui/providers/ioniaProvider.ts +++ b/src/plugins/gui/providers/ioniaProvider.ts @@ -303,10 +303,10 @@ export const makeIoniaProvider: FiatProviderFactory = { function checkAmountMinMax(fiatAmount: number) { if (fiatAmount > MAX_FIAT_CARD_PURCHASE_AMOUNT) { - throw new Error(sprintf(lstrings.rewards_card_error_amount_max_s, MAX_FIAT_CARD_PURCHASE_AMOUNT)) + throw new Error(sprintf(lstrings.card_amount_max_error_message_s, MAX_FIAT_CARD_PURCHASE_AMOUNT)) } if (fiatAmount < MIN_FIAT_CARD_PURCHASE_AMOUNT) { - throw new Error(sprintf(lstrings.rewards_card_error_amount_min_s, MIN_FIAT_CARD_PURCHASE_AMOUNT)) + throw new Error(sprintf(lstrings.card_amount_min_error_message_s, MIN_FIAT_CARD_PURCHASE_AMOUNT)) } } diff --git a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx index 0f40f2434d5..d6ca26c7c45 100644 --- a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx +++ b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx @@ -70,13 +70,13 @@ export const RewardsCardDashboardScene = (props: Props) => { {items.map(item => { return onCardPress(item)} onRemovePress={() => handleRemovePress(item)} shouldStack /> })} - {items.length === 0 && !showLoading ? {lstrings.rewards_card_no_cards} : null} + {items.length === 0 && !showLoading ? {lstrings.no_active_cards_message} : null} {showLoading ? : null} setBottomFloatHeight(event.nativeEvent.layout.height)}> - + @@ -124,14 +124,14 @@ export const RewardsCard = (props: RewardsCardProps) => { - {lstrings.rewards_card_dashboard_field_purchase_date_label} + {lstrings.purchase_date_label} {item == null ? ' ' : toLocaleDate(item.purchaseDate)} - {lstrings.rewards_card_dashboard_field_purchase_price_label} + {lstrings.purchase_price_label} {purchaseAmount ?? ' '} @@ -147,7 +147,7 @@ export const RewardsCard = (props: RewardsCardProps) => { - {lstrings.rewards_card_dashboard_field_purchase_asset_label} + {lstrings.purchase_asset_label} {item?.purchaseAsset ?? ' '} diff --git a/src/plugins/gui/scenes/RewardsCardWelcomeScene.tsx b/src/plugins/gui/scenes/RewardsCardWelcomeScene.tsx index dba6833feb5..3e5b81349aa 100644 --- a/src/plugins/gui/scenes/RewardsCardWelcomeScene.tsx +++ b/src/plugins/gui/scenes/RewardsCardWelcomeScene.tsx @@ -32,9 +32,9 @@ export const RewardsCardWelcomeScene = (props: Props) => { {lstrings.rewards_card_welcome_intro} - + - + From 8fc944ad98741c80731157ab7cdbf5b9502c8773 Mon Sep 17 00:00:00 2001 From: Jon Tzeng Date: Fri, 26 May 2023 13:58:04 -0700 Subject: [PATCH 067/104] Add providerId to FiatProviderQuoteErrors, log errors This will make identification of which providers failed a lot easier. --- src/__tests__/amountQuotePlugin.test.ts | 32 ++++++++++---------- src/plugins/gui/amountQuotePlugin.ts | 1 + src/plugins/gui/fiatProviderTypes.ts | 8 ++--- src/plugins/gui/providers/banxaProvider.ts | 12 ++++---- src/plugins/gui/providers/bityProvider.ts | 5 +-- src/plugins/gui/providers/dummyProvider.ts | 4 +-- src/plugins/gui/providers/dummyProvider2.ts | 4 +-- src/plugins/gui/providers/moonpayProvider.ts | 12 ++++---- src/plugins/gui/providers/simplexProvider.ts | 8 ++--- 9 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/__tests__/amountQuotePlugin.test.ts b/src/__tests__/amountQuotePlugin.test.ts index 6874fc99850..8ecc9d103eb 100644 --- a/src/__tests__/amountQuotePlugin.test.ts +++ b/src/__tests__/amountQuotePlugin.test.ts @@ -26,57 +26,57 @@ describe('creditCardPlugin', function () { }) describe('getBestError', function () { test('overLimit', function () { - const errors: FiatProviderError[] = [new FiatProviderError({ errorType: 'overLimit', errorAmount: 50 })] + const errors: FiatProviderError[] = [new FiatProviderError({ providerId: '', errorType: 'overLimit', errorAmount: 50 })] const result = getBestError(errors, 'USD') expect(result).toBe(sprintf(lstrings.fiat_plugin_buy_amount_over_limit, '50 USD')) }) test('underLimit', function () { - const errors: FiatProviderError[] = [new FiatProviderError({ errorType: 'underLimit', errorAmount: 50 })] + const errors: FiatProviderError[] = [new FiatProviderError({ providerId: '', errorType: 'underLimit', errorAmount: 50 })] const result = getBestError(errors, 'USD') expect(result).toBe(sprintf(lstrings.fiat_plugin_buy_amount_under_limit, '50 USD')) }) test('regionRestricted', function () { - const errors: FiatProviderError[] = [new FiatProviderError({ errorType: 'regionRestricted', displayCurrencyCode: FAKE_CODE })] + const errors: FiatProviderError[] = [new FiatProviderError({ providerId: '', errorType: 'regionRestricted', displayCurrencyCode: FAKE_CODE })] const result = getBestError(errors, 'USD') expect(result).toBe(sprintf(lstrings.fiat_plugin_buy_region_restricted, FAKE_CODE)) }) test('assetUnsupported', function () { - const errors: FiatProviderError[] = [new FiatProviderError({ errorType: 'assetUnsupported' })] + const errors: FiatProviderError[] = [new FiatProviderError({ providerId: '', errorType: 'assetUnsupported' })] const result = getBestError(errors, 'USD') expect(result).toBe(lstrings.fiat_plugin_asset_unsupported) }) test('underLimit 1 2 3', function () { const errors: FiatProviderError[] = [ - new FiatProviderError({ errorType: 'underLimit', errorAmount: 1 }), - new FiatProviderError({ errorType: 'underLimit', errorAmount: 2 }), - new FiatProviderError({ errorType: 'underLimit', errorAmount: 3 }) + new FiatProviderError({ providerId: '', errorType: 'underLimit', errorAmount: 1 }), + new FiatProviderError({ providerId: '', errorType: 'underLimit', errorAmount: 2 }), + new FiatProviderError({ providerId: '', errorType: 'underLimit', errorAmount: 3 }) ] const result = getBestError(errors, 'USD') expect(result).toBe(sprintf(lstrings.fiat_plugin_buy_amount_under_limit, '1 USD')) }) test('overLimit 1 2 3', function () { const errors: FiatProviderError[] = [ - new FiatProviderError({ errorType: 'overLimit', errorAmount: 1 }), - new FiatProviderError({ errorType: 'overLimit', errorAmount: 2 }), - new FiatProviderError({ errorType: 'overLimit', errorAmount: 3 }) + new FiatProviderError({ providerId: '', errorType: 'overLimit', errorAmount: 1 }), + new FiatProviderError({ providerId: '', errorType: 'overLimit', errorAmount: 2 }), + new FiatProviderError({ providerId: '', errorType: 'overLimit', errorAmount: 3 }) ] const result = getBestError(errors, 'USD') expect(result).toBe(sprintf(lstrings.fiat_plugin_buy_amount_over_limit, '3 USD')) }) test('overLimit underLimit regionRestricted assetUnsupported', function () { const errors: FiatProviderError[] = [ - new FiatProviderError({ errorType: 'overLimit', errorAmount: 1 }), - new FiatProviderError({ errorType: 'underLimit', errorAmount: 2 }), - new FiatProviderError({ errorType: 'regionRestricted', displayCurrencyCode: FAKE_CODE }), - new FiatProviderError({ errorType: 'assetUnsupported' }) + new FiatProviderError({ providerId: '', errorType: 'overLimit', errorAmount: 1 }), + new FiatProviderError({ providerId: '', errorType: 'underLimit', errorAmount: 2 }), + new FiatProviderError({ providerId: '', errorType: 'regionRestricted', displayCurrencyCode: FAKE_CODE }), + new FiatProviderError({ providerId: '', errorType: 'assetUnsupported' }) ] const result = getBestError(errors, 'USD') expect(result).toBe(sprintf(lstrings.fiat_plugin_buy_amount_under_limit, '2 USD')) }) test('regionRestricted assetUnsupported', function () { const errors: FiatProviderError[] = [ - new FiatProviderError({ errorType: 'regionRestricted', displayCurrencyCode: FAKE_CODE }), - new FiatProviderError({ errorType: 'assetUnsupported' }) + new FiatProviderError({ providerId: '', errorType: 'regionRestricted', displayCurrencyCode: FAKE_CODE }), + new FiatProviderError({ providerId: '', errorType: 'assetUnsupported' }) ] const result = getBestError(errors, 'USD') expect(result).toBe(sprintf(lstrings.fiat_plugin_buy_region_restricted, FAKE_CODE)) diff --git a/src/plugins/gui/amountQuotePlugin.ts b/src/plugins/gui/amountQuotePlugin.ts index 4a97309822e..db77b8dca38 100644 --- a/src/plugins/gui/amountQuotePlugin.ts +++ b/src/plugins/gui/amountQuotePlugin.ts @@ -200,6 +200,7 @@ export const amountQuoteFiatPlugin: FiatPluginFactory = async (params: FiatPlugi let errors: unknown[] = [] const quotes = await fuzzyTimeout(quotePromises, 5000).catch(e => { errors = e + console.error(errors) return [] }) diff --git a/src/plugins/gui/fiatProviderTypes.ts b/src/plugins/gui/fiatProviderTypes.ts index fb1ac5e334b..d435bd387d1 100644 --- a/src/plugins/gui/fiatProviderTypes.ts +++ b/src/plugins/gui/fiatProviderTypes.ts @@ -36,11 +36,9 @@ export type FiatProviderQuoteErrorTypes = FiatProviderQuoteErrorTypesLimit | Fia // errorAmount must be in units of the provided FiatProviderGetQuoteParams.exchangeAmount as determined by // amountType export type FiatProviderQuoteError = - | { - errorType: FiatProviderQuoteErrorTypesOther - } - | { errorType: FiatProviderQuoteErrorTypesLimit; errorAmount: number } - | { errorType: FiatProviderQuoteErrorTypesRegion; displayCurrencyCode: string } + | { providerId: string; errorType: FiatProviderQuoteErrorTypesOther } + | { providerId: string; errorType: FiatProviderQuoteErrorTypesLimit; errorAmount: number } + | { providerId: string; errorType: FiatProviderQuoteErrorTypesRegion; displayCurrencyCode: string } export class FiatProviderError extends Error { // @ts-expect-error diff --git a/src/plugins/gui/providers/banxaProvider.ts b/src/plugins/gui/providers/banxaProvider.ts index a50f66e0c69..4e236062b14 100644 --- a/src/plugins/gui/providers/banxaProvider.ts +++ b/src/plugins/gui/providers/banxaProvider.ts @@ -229,7 +229,7 @@ export const banxaProvider: FiatProviderFactory = { try { banxaCrypto = edgeToBanxaCrypto(pluginId, displayCurrencyCode) } catch (e: any) { - throw new FiatProviderError({ errorType: 'assetUnsupported' }) + throw new FiatProviderError({ providerId, errorType: 'assetUnsupported' }) } const { banxaChain, banxaCoin } = banxaCrypto @@ -241,21 +241,21 @@ export const banxaProvider: FiatProviderFactory = { try { paymentType = paymentTypes.find(t => banxaPaymentsMap[fiat][banxaCoin][t] != null) } catch (e: any) { - throw new FiatProviderError({ errorType: 'assetUnsupported' }) + throw new FiatProviderError({ providerId, errorType: 'assetUnsupported' }) } if (paymentType == null) { - throw new FiatProviderError({ errorType: 'paymentUnsupported' }) + throw new FiatProviderError({ providerId, errorType: 'paymentUnsupported' }) } const paymentObj = banxaPaymentsMap[fiat][banxaCoin][paymentType ?? ''] ?? {} - if (paymentObj == null) throw new FiatProviderError({ errorType: 'paymentUnsupported' }) + if (paymentObj == null) throw new FiatProviderError({ providerId, errorType: 'paymentUnsupported' }) let queryParams if (amountType === 'fiat') { if (gt(exchangeAmount, paymentObj.max)) { - throw new FiatProviderError({ errorType: 'overLimit', errorAmount: parseFloat(paymentObj.max) }) + throw new FiatProviderError({ providerId, errorType: 'overLimit', errorAmount: parseFloat(paymentObj.max) }) } else if (lt(exchangeAmount, paymentObj.min)) { - throw new FiatProviderError({ errorType: 'underLimit', errorAmount: parseFloat(paymentObj.min) }) + throw new FiatProviderError({ providerId, errorType: 'underLimit', errorAmount: parseFloat(paymentObj.min) }) } queryParams = { account_reference: banxaUsername, diff --git a/src/plugins/gui/providers/bityProvider.ts b/src/plugins/gui/providers/bityProvider.ts index a18073fabdb..0f16351856d 100644 --- a/src/plugins/gui/providers/bityProvider.ts +++ b/src/plugins/gui/providers/bityProvider.ts @@ -336,8 +336,8 @@ export const bityProvider: FiatProviderFactory = { displayCurrencyCode } = params const isBuy = direction === 'buy' - if (!allowedCountryCodes[regionCode.countryCode]) throw new FiatProviderError({ errorType: 'regionRestricted', displayCurrencyCode }) - if (!paymentTypes.includes(supportedPaymentType)) throw new FiatProviderError({ errorType: 'paymentUnsupported' }) + if (!allowedCountryCodes[regionCode.countryCode]) throw new FiatProviderError({ providerId, errorType: 'regionRestricted', displayCurrencyCode }) + if (!paymentTypes.includes(supportedPaymentType)) throw new FiatProviderError({ providerId, errorType: 'paymentUnsupported' }) const cryptoCurrencyObj = asBityCurrency(allowedCurrencyCodes.crypto[pluginId][displayCurrencyCode]) const fiatCurrencyObj = asBityCurrency(allowedCurrencyCodes.fiat[fiatCurrencyCode]) @@ -370,6 +370,7 @@ export const bityProvider: FiatProviderFactory = { if (lt(amount, minimumAmount)) { throw new FiatProviderError({ // TODO: direction, + providerId, errorType: 'underLimit', errorAmount: parseFloat(minimumAmount) }) diff --git a/src/plugins/gui/providers/dummyProvider.ts b/src/plugins/gui/providers/dummyProvider.ts index d66bc63c293..d071d6904f9 100644 --- a/src/plugins/gui/providers/dummyProvider.ts +++ b/src/plugins/gui/providers/dummyProvider.ts @@ -173,10 +173,10 @@ export const dummyProvider: FiatProviderFactory = { minLimit = parseFloat(toFixed(mul(MIN_USD, div(cryptoAmount, fiatAmount, 16)), 0, 6)) } if (gt(fiatAmount, MAX_USD)) { - throw new FiatProviderError({ errorType: 'overLimit', errorAmount: maxLimit }) + throw new FiatProviderError({ providerId, errorType: 'overLimit', errorAmount: maxLimit }) } if (lt(fiatAmount, MIN_USD)) { - throw new FiatProviderError({ errorType: 'underLimit', errorAmount: minLimit }) + throw new FiatProviderError({ providerId, errorType: 'underLimit', errorAmount: minLimit }) } const paymentQuote: FiatProviderQuote = { diff --git a/src/plugins/gui/providers/dummyProvider2.ts b/src/plugins/gui/providers/dummyProvider2.ts index 346e56929cd..130092a1e8f 100644 --- a/src/plugins/gui/providers/dummyProvider2.ts +++ b/src/plugins/gui/providers/dummyProvider2.ts @@ -173,10 +173,10 @@ export const dummyProvider2: FiatProviderFactory = { minLimit = parseFloat(toFixed(mul(MIN_USD, div(cryptoAmount, fiatAmount, 16)), 0, 6)) } if (gt(fiatAmount, MAX_USD)) { - throw new FiatProviderError({ errorType: 'overLimit', errorAmount: maxLimit }) + throw new FiatProviderError({ providerId, errorType: 'overLimit', errorAmount: maxLimit }) } if (lt(fiatAmount, MIN_USD)) { - throw new FiatProviderError({ errorType: 'underLimit', errorAmount: minLimit }) + throw new FiatProviderError({ providerId, errorType: 'underLimit', errorAmount: minLimit }) } const paymentQuote: FiatProviderQuote = { diff --git a/src/plugins/gui/providers/moonpayProvider.ts b/src/plugins/gui/providers/moonpayProvider.ts index 9ce2b7c8a28..ef352d9b9c1 100644 --- a/src/plugins/gui/providers/moonpayProvider.ts +++ b/src/plugins/gui/providers/moonpayProvider.ts @@ -169,7 +169,7 @@ export const moonpayProvider: FiatProviderFactory = { }, getQuote: async (params: FiatProviderGetQuoteParams): Promise => { const { regionCode, paymentTypes, displayCurrencyCode } = params - if (!allowedCountryCodes[regionCode.countryCode]) throw new FiatProviderError({ errorType: 'regionRestricted', displayCurrencyCode }) + if (!allowedCountryCodes[regionCode.countryCode]) throw new FiatProviderError({ providerId, errorType: 'regionRestricted', displayCurrencyCode }) let foundPaymentType = false let useIAch = false for (const type of paymentTypes) { @@ -181,7 +181,7 @@ export const moonpayProvider: FiatProviderFactory = { useIAch = true } } - if (!foundPaymentType) throw new FiatProviderError({ errorType: 'paymentUnsupported' }) + if (!foundPaymentType) throw new FiatProviderError({ providerId, errorType: 'paymentUnsupported' }) let amountParam = '' const cryptoCurrencyObj = asMoonpayCurrency(allowedCurrencyCodes.crypto[params.pluginId][params.displayCurrencyCode]) @@ -194,13 +194,13 @@ export const moonpayProvider: FiatProviderFactory = { const minCrypto = Math.min(cryptoCurrencyObj.minAmount ?? Infinity, cryptoCurrencyObj.minBuyAmount ?? Infinity) const exchangeAmount = parseFloat(params.exchangeAmount) if (params.amountType === 'fiat') { - if (exchangeAmount > maxFiat) throw new FiatProviderError({ errorType: 'overLimit', errorAmount: maxFiat }) - if (exchangeAmount < minFiat) throw new FiatProviderError({ errorType: 'underLimit', errorAmount: minFiat }) + if (exchangeAmount > maxFiat) throw new FiatProviderError({ providerId, errorType: 'overLimit', errorAmount: maxFiat }) + if (exchangeAmount < minFiat) throw new FiatProviderError({ providerId, errorType: 'underLimit', errorAmount: minFiat }) // User typed a fiat amount. Need a crypto value amountParam = `baseCurrencyAmount=${params.exchangeAmount}` } else { - if (exchangeAmount > maxCrypto) throw new FiatProviderError({ errorType: 'overLimit', errorAmount: maxCrypto }) - if (exchangeAmount < minCrypto) throw new FiatProviderError({ errorType: 'underLimit', errorAmount: minCrypto }) + if (exchangeAmount > maxCrypto) throw new FiatProviderError({ providerId, errorType: 'overLimit', errorAmount: maxCrypto }) + if (exchangeAmount < minCrypto) throw new FiatProviderError({ providerId, errorType: 'underLimit', errorAmount: minCrypto }) amountParam = `quoteCurrencyAmount=${params.exchangeAmount}` } diff --git a/src/plugins/gui/providers/simplexProvider.ts b/src/plugins/gui/providers/simplexProvider.ts index 050e2068013..7cae6b73be6 100644 --- a/src/plugins/gui/providers/simplexProvider.ts +++ b/src/plugins/gui/providers/simplexProvider.ts @@ -217,7 +217,7 @@ export const simplexProvider: FiatProviderFactory = { }, getQuote: async (params: FiatProviderGetQuoteParams): Promise => { const { regionCode, exchangeAmount, amountType, paymentTypes, displayCurrencyCode } = params - if (!allowedCountryCodes[regionCode.countryCode]) throw new FiatProviderError({ errorType: 'regionRestricted', displayCurrencyCode }) + if (!allowedCountryCodes[regionCode.countryCode]) throw new FiatProviderError({ providerId, errorType: 'regionRestricted', displayCurrencyCode }) let foundPaymentType = false for (const type of paymentTypes) { const t = asFiatPaymentType(type) @@ -226,7 +226,7 @@ export const simplexProvider: FiatProviderFactory = { break } } - if (!foundPaymentType) throw new FiatProviderError({ errorType: 'paymentUnsupported' }) + if (!foundPaymentType) throw new FiatProviderError({ providerId, errorType: 'paymentUnsupported' }) const ts = Math.floor(Date.now() / 1000) const simplexCryptoCode = SIMPLEX_ID_MAP[params.pluginId][params.displayCurrencyCode] @@ -276,10 +276,10 @@ export const simplexProvider: FiatProviderFactory = { const [minLimit, maxLimit] = result3.slice(2, 4) if (gt(params.exchangeAmount, maxLimit)) { - throw new FiatProviderError({ errorType: 'overLimit', errorAmount: parseFloat(maxLimit) }) + throw new FiatProviderError({ providerId, errorType: 'overLimit', errorAmount: parseFloat(maxLimit) }) } if (lt(params.exchangeAmount, minLimit)) { - throw new FiatProviderError({ errorType: 'underLimit', errorAmount: parseFloat(minLimit) }) + throw new FiatProviderError({ providerId, errorType: 'underLimit', errorAmount: parseFloat(minLimit) }) } } throw new Error('Simplex unknown error') From a0fe5c06e39defb88feafcbf9afd7363b0452536 Mon Sep 17 00:00:00 2001 From: Jon Tzeng Date: Fri, 26 May 2023 14:06:41 -0700 Subject: [PATCH 068/104] Support under/over errors without known limits --- src/locales/en_US.ts | 2 + src/locales/strings/enUS.json | 2 + src/plugins/gui/fiatProviderTypes.ts | 4 +- src/plugins/gui/pluginUtils.ts | 54 ++++++++++++++--------- src/plugins/gui/providers/bityProvider.ts | 14 +++++- 5 files changed, 52 insertions(+), 24 deletions(-) diff --git a/src/locales/en_US.ts b/src/locales/en_US.ts index 586aa05b344..76362be3843 100644 --- a/src/locales/en_US.ts +++ b/src/locales/en_US.ts @@ -1246,7 +1246,9 @@ const strings = { fiat_plugin_sell_currencycode_s: 'Sell %s', fiat_plugin_amount_currencycode: 'Amount %s', fiat_plugin_buy_amount_over_limit: 'Max purchase amount is %s', + fiat_plugin_buy_amount_over_undef_limit: 'Purchase amount is over maximum', fiat_plugin_buy_amount_under_limit: 'Minimum purchase amount is %s', + fiat_plugin_buy_amount_under_undef_limit: 'Purchase amount is under minimum', fiat_plugin_asset_unsupported: 'Asset Unsupported', fiat_plugin_payment_unsupported: 'Payment Method Unsupported', fiat_plugin_buy_region_restricted: 'Region restricted from purchasing %s', diff --git a/src/locales/strings/enUS.json b/src/locales/strings/enUS.json index 6917bed962f..cdb25b22749 100644 --- a/src/locales/strings/enUS.json +++ b/src/locales/strings/enUS.json @@ -1090,7 +1090,9 @@ "fiat_plugin_sell_currencycode_s": "Sell %s", "fiat_plugin_amount_currencycode": "Amount %s", "fiat_plugin_buy_amount_over_limit": "Max purchase amount is %s", + "fiat_plugin_buy_amount_over_undef_limit": "Purchase amount is over maximum", "fiat_plugin_buy_amount_under_limit": "Minimum purchase amount is %s", + "fiat_plugin_buy_amount_under_undef_limit": "Purchase amount is under minimum", "fiat_plugin_asset_unsupported": "Asset Unsupported", "fiat_plugin_payment_unsupported": "Payment Method Unsupported", "fiat_plugin_buy_region_restricted": "Region restricted from purchasing %s", diff --git a/src/plugins/gui/fiatProviderTypes.ts b/src/plugins/gui/fiatProviderTypes.ts index d435bd387d1..83410ecd570 100644 --- a/src/plugins/gui/fiatProviderTypes.ts +++ b/src/plugins/gui/fiatProviderTypes.ts @@ -37,12 +37,10 @@ export type FiatProviderQuoteErrorTypes = FiatProviderQuoteErrorTypesLimit | Fia // amountType export type FiatProviderQuoteError = | { providerId: string; errorType: FiatProviderQuoteErrorTypesOther } - | { providerId: string; errorType: FiatProviderQuoteErrorTypesLimit; errorAmount: number } + | { providerId: string; errorType: FiatProviderQuoteErrorTypesLimit; errorAmount?: number } | { providerId: string; errorType: FiatProviderQuoteErrorTypesRegion; displayCurrencyCode: string } export class FiatProviderError extends Error { - // @ts-expect-error - name: string readonly quoteError: FiatProviderQuoteError constructor(info: FiatProviderQuoteError) { diff --git a/src/plugins/gui/pluginUtils.ts b/src/plugins/gui/pluginUtils.ts index fb203e8a282..6d134c04b1c 100644 --- a/src/plugins/gui/pluginUtils.ts +++ b/src/plugins/gui/pluginUtils.ts @@ -15,8 +15,7 @@ export const createStore = (storeId: string, store: EdgeDataStore): FiatProvider } } -// @ts-expect-error -const ERROR_PRIORITIES: { [errorType: FiatProviderQuoteErrorTypes]: number } = { +const ERROR_PRIORITIES: { [errorType in FiatProviderQuoteErrorTypes]: number } = { underLimit: 1, overLimit: 2, paymentUnsupported: 3, @@ -24,14 +23,6 @@ const ERROR_PRIORITIES: { [errorType: FiatProviderQuoteErrorTypes]: number } = { assetUnsupported: 5 } -const ERROR_TEXT = { - underLimit: lstrings.fiat_plugin_buy_amount_under_limit, - overLimit: lstrings.fiat_plugin_buy_amount_over_limit, - paymentUnsupported: lstrings.fiat_plugin_payment_unsupported, - regionRestricted: lstrings.fiat_plugin_buy_region_restricted, - assetUnsupported: lstrings.fiat_plugin_asset_unsupported -} - export const getRateFromQuote = (quote: FiatProviderQuote, fiatCode: string): string => { const bestRate = div(quote.fiatAmount, quote.cryptoAmount, 16) const localeRate = formatNumber(toFixed(bestRate, 0, 2)) @@ -48,32 +39,55 @@ export const getBestError = (errorQuotes: FiatProviderError[], currencyCode: str bestError = errorQuote continue } - // @ts-expect-error if (ERROR_PRIORITIES[errorQuote.errorType] < ERROR_PRIORITIES[bestError.errorType]) { bestError = errorQuote continue } - // @ts-expect-error if (ERROR_PRIORITIES[errorQuote.errorType] === ERROR_PRIORITIES[bestError.errorType]) { if (errorQuote.errorType === 'overLimit' && bestError.errorType === 'overLimit') { - if (errorQuote.errorAmount > bestError.errorAmount) { + if ((errorQuote.errorAmount ?? 0) > (bestError.errorAmount ?? 0)) { bestError = errorQuote } } else if (errorQuote.errorType === 'underLimit' && bestError.errorType === 'underLimit') { - if (errorQuote.errorAmount < bestError.errorAmount) { + if ((errorQuote.errorAmount ?? Infinity) < (bestError.errorAmount ?? Infinity)) { bestError = errorQuote } } } } if (bestError == null) return - let errorText = ERROR_TEXT[bestError.errorType] - if (bestError.errorType === 'underLimit' || bestError.errorType === 'overLimit') { - const localeAmount = formatNumber(bestError.errorAmount.toString()) - errorText = sprintf(errorText, localeAmount + ' ' + currencyCode) - } else if (bestError.errorType === 'regionRestricted') { - errorText = sprintf(errorText, bestError.displayCurrencyCode) + return getErrorText(bestError, currencyCode) +} + +const getErrorText = (error: FiatProviderQuoteError, currencyCode: string): string => { + let errorText = '' + + switch (error.errorType) { + case 'underLimit': + errorText = + error.errorAmount == null + ? lstrings.fiat_plugin_buy_amount_under_undef_limit + : sprintf(lstrings.fiat_plugin_buy_amount_under_limit, `${formatNumber(error.errorAmount.toString())} ${currencyCode}`) + break + case 'overLimit': + errorText = + error.errorAmount == null + ? lstrings.fiat_plugin_buy_amount_over_undef_limit + : sprintf(lstrings.fiat_plugin_buy_amount_over_limit, `${formatNumber(error.errorAmount.toString())} ${currencyCode}`) + break + case 'paymentUnsupported': + errorText = lstrings.fiat_plugin_payment_unsupported + break + case 'regionRestricted': + errorText = sprintf(lstrings.fiat_plugin_buy_region_restricted, error.displayCurrencyCode) + break + case 'assetUnsupported': + errorText = lstrings.fiat_plugin_asset_unsupported + break + default: + errorText = 'Unknown error type' } + return errorText } diff --git a/src/plugins/gui/providers/bityProvider.ts b/src/plugins/gui/providers/bityProvider.ts index 0f16351856d..c9313ad2b45 100644 --- a/src/plugins/gui/providers/bityProvider.ts +++ b/src/plugins/gui/providers/bityProvider.ts @@ -78,6 +78,8 @@ const asBityCurrency = asObject({ }) const asBityCurrencyResponse = asObject({ currencies: asArray(asBityCurrency) }) +const asBityErrorResponse = asObject({ errors: asArray(asObject({ code: asString, message: asString })) }) + export type BityCurrency = ReturnType export type BityCurrencyTag = ReturnType @@ -191,7 +193,17 @@ const fetchBityQuote = async (bodyData: BityQuoteRequest) => { const newData = await result.json() return newData } else { - throw new Error('Bity: Unable to fetch quote: ' + (await result.text())) + let bityErrorRes + try { + bityErrorRes = asBityErrorResponse(await result.json()) + } catch (e) { + // TODO: Implement typed generic provider error handling now that providerId + // is a required FiatProviderQuoteError param. + throw new Error('Bity: Unable to fetch quote: ' + (await result.text())) + } + if (bityErrorRes.errors.some((bityError: { code: string; message: string }) => bityError.code === 'amount_too_large')) { + throw new FiatProviderError({ providerId, errorType: 'overLimit' }) + } } } From 59b69ad76394e23b85f33aedb8e7d8408df11772 Mon Sep 17 00:00:00 2001 From: William Swanson Date: Tue, 6 Jun 2023 13:47:44 -0700 Subject: [PATCH 069/104] Upgrade to edge-login-ui-rn v2.1.0 --- ios/Podfile.lock | 4 ++-- package.json | 3 +-- yarn.lock | 22 ++++++++++++++-------- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 1fd67af3792..42bda168366 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -22,7 +22,7 @@ PODS: - React-Core - edge-currency-accountbased (1.2.13): - React-Core - - edge-login-ui-rn (2.0.0): + - edge-login-ui-rn (2.1.0): - React - FBLazyVector (0.67.5) - FBReactNativeSpec (0.67.5): @@ -1111,7 +1111,7 @@ SPEC CHECKSUMS: DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662 edge-core-js: 655cd63654df00c4e36d387381e7e90bc1b69340 edge-currency-accountbased: b5c9b417420254bcc5a92353eeb96bb82d84b24a - edge-login-ui-rn: 321a5874cf31a25cf52f450af8d0e1d6efc440b5 + edge-login-ui-rn: 1bb5f0054181b0464970180f51a27f70d2f29e45 FBLazyVector: d2db9d00883282819d03bbd401b2ad4360d47580 FBReactNativeSpec: 94da4d84ba3b1acf459103320882daa481a2b62d Firebase: 5f8193dff4b5b7c5d5ef72ae54bb76c08e2b841d diff --git a/package.json b/package.json index a01495d4041..e09f8fd277d 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,6 @@ "@ledgerhq/hw-transport-node-hid": "file:./patches/fake-hw-transport-node-hid", "axios": "0.21.1", "babel-runtime": "6.26.0", - "base-x": "3.0.4", "bip39": "3.0.2", "bn.js": "4.11.8", "bs58": "4.0.1", @@ -124,7 +123,7 @@ "edge-currency-monero": "^1.0.0", "edge-currency-plugins": "^2.0.2", "edge-exchange-plugins": "^0.19.5", - "edge-login-ui-rn": "^2.0.0", + "edge-login-ui-rn": "^2.1.0", "edge-plugin-bity": "https://github.com/EdgeApp/edge-plugin-bity.git#2a52e6cb86512b98f69f8f5dd3105cdf6d0c2d8a", "edge-plugin-simplex": "https://github.com/EdgeApp/edge-plugin-simplex.git#b11def82d84f2735b91f4b8104a9e0d3e8c3600d", "edge-plugin-wyre": "https://github.com/EdgeApp/edge-plugin-wyre.git#28c143cd5828d3444bff62adc224839e33eb0bf9", diff --git a/yarn.lock b/yarn.lock index f9dfe176f0c..44035c8bf37 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4961,13 +4961,18 @@ base-64@^0.1.0: resolved "https://registry.yarnpkg.com/base-64/-/base-64-0.1.0.tgz#780a99c84e7d600260361511c4877613bf24f6bb" integrity sha1-eAqZyE59YAJgNhURxId2E78k9rs= -base-x@3.0.4, base-x@3.0.9, base-x@^1.0.1, base-x@^1.0.4, base-x@^3.0.2, base-x@^3.0.8: - version "3.0.4" - resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.4.tgz#94c1788736da065edb1d68808869e357c977fa77" - integrity sha512-UYOadoSIkEI/VrRGSG6qp93rp2WdokiAiNYDfGW5qURAY8GiAQkvMbwNNSDYiVJopqv4gCna7xqf4rrNGp+5AA== +base-x@3.0.9, base-x@^3.0.2, base-x@^3.0.8: + version "3.0.9" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" + integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== dependencies: safe-buffer "^5.0.1" +base-x@^1.0.1, base-x@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-1.1.0.tgz#42d3d717474f9ea02207f6d1aa1f426913eeb7ac" + integrity sha512-c0WLeG3K5OlL4Skz2/LVdS+MjggByKhowxQpG+JpCLA48s/bGwIDyzA1naFjywtNvp/37fLK0p0FpjTNNLLUXQ== + base-x@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/base-x/-/base-x-4.0.0.tgz#d0e3b7753450c73f8ad2389b5c018a4af7b2224a" @@ -7332,11 +7337,12 @@ edge-exchange-plugins@^0.19.5: iso4217 "^0.2.0" utf8 "^3.0.0" -edge-login-ui-rn@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/edge-login-ui-rn/-/edge-login-ui-rn-2.0.0.tgz#f253c4d3127ab25b754bc76c15e4a30a8cbd9729" - integrity sha512-P1Y+m/8QD7Rx7OW8jqB9TbC9nOvJyeHoI68Mk2/FY2CGr575SlE74ktsamDYY8LBy0YBjiFNsqcrEEJWtuHx/Q== +edge-login-ui-rn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/edge-login-ui-rn/-/edge-login-ui-rn-2.1.0.tgz#44063c8fecd710debfd97a6e6476773358bfe949" + integrity sha512-nY0kZU7CZQo8cGgpsWo09qTB37MZSWu8a7LMc/iZns2si5pzgpHQ4UWluYqc/qyazD/U/fufrdkILdvyUwyl/Q== dependencies: + base-x "^4.0.0" cleaners "^0.3.12" date-fns "^2.23.0" qrcode-generator "^1.4.4" From 6a35444ee807035f82b46ce85e94a40eb393e39d Mon Sep 17 00:00:00 2001 From: Github Action Date: Wed, 7 Jun 2023 00:30:43 +0000 Subject: [PATCH 070/104] File sync from EdgeApp/edge-workflows --- .github/workflows/pr-checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 89e10eaab25..08adff09fc1 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -6,4 +6,4 @@ jobs: steps: - uses: actions/checkout@v2.0.0 - name: Block WIP PR - uses: samholmes/block-wip-pr-action@v1.1.1 + uses: samholmes/block-wip-pr-action@v1.2.0 From e3326527fc5a16130a9d2057902d0ed3b921db9f Mon Sep 17 00:00:00 2001 From: Github Action Date: Wed, 7 Jun 2023 00:30:44 +0000 Subject: [PATCH 071/104] File sync from EdgeApp/edge-workflows --- .github/workflows/asana-attachment.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/workflows/asana-attachment.yml diff --git a/.github/workflows/asana-attachment.yml b/.github/workflows/asana-attachment.yml new file mode 100644 index 00000000000..50aa506deb1 --- /dev/null +++ b/.github/workflows/asana-attachment.yml @@ -0,0 +1 @@ +# removed \ No newline at end of file From 15b2475ae27e84fbce2683b939e708a995ee77dd Mon Sep 17 00:00:00 2001 From: Github Action Date: Wed, 7 Jun 2023 00:30:44 +0000 Subject: [PATCH 072/104] File sync from EdgeApp/edge-workflows --- .github/workflows/asana-comment.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/workflows/asana-comment.yml diff --git a/.github/workflows/asana-comment.yml b/.github/workflows/asana-comment.yml new file mode 100644 index 00000000000..50aa506deb1 --- /dev/null +++ b/.github/workflows/asana-comment.yml @@ -0,0 +1 @@ +# removed \ No newline at end of file From ef08bfb33320c27683475f529d1a73ce80b133b1 Mon Sep 17 00:00:00 2001 From: William Swanson Date: Tue, 6 Jun 2023 16:31:55 -0700 Subject: [PATCH 073/104] Fix viewing raw private keys --- src/actions/WalletListMenuActions.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/actions/WalletListMenuActions.tsx b/src/actions/WalletListMenuActions.tsx index df8036dbf1d..d0ec7d5c89e 100644 --- a/src/actions/WalletListMenuActions.tsx +++ b/src/actions/WalletListMenuActions.tsx @@ -261,9 +261,9 @@ export function walletListMenuAction( const state = getState() const { account } = state.core - const keys = account.allKeys.find(key => key.id === walletId) - const seed = keys ? JSON.stringify(keys.keys, null, 2) : '' - Airship.show(bridge => ) + const rawKeys = await account.getRawPrivateKey(walletId) + const keys = JSON.stringify(rawKeys, null, 2) + Airship.show(bridge => ) } } } From 68f3728f964abba25a434881212b4483eaa5a4b0 Mon Sep 17 00:00:00 2001 From: William Swanson Date: Tue, 16 May 2023 15:30:07 -0700 Subject: [PATCH 074/104] Rename the ControlPanel to SideMenu --- src/components/Main.tsx | 6 +++--- src/components/themed/{ControlPanel.tsx => SideMenu.tsx} | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename src/components/themed/{ControlPanel.tsx => SideMenu.tsx} (99%) diff --git a/src/components/Main.tsx b/src/components/Main.tsx index a018af1eba8..7399ad1ded9 100644 --- a/src/components/Main.tsx +++ b/src/components/Main.tsx @@ -116,8 +116,8 @@ import { WcConnectScene as WcConnectSceneComponent } from './scenes/WcConnectSce import { WcDisconnectScene as WcDisconnectSceneComponent } from './scenes/WcDisconnectScene' import { Airship } from './services/AirshipInstance' import { useTheme } from './services/ThemeContext' -import { ControlPanel as ControlPanelComponent } from './themed/ControlPanel' import { MenuTabs } from './themed/MenuTabs' +import { SideMenu as SideMenuComponent } from './themed/SideMenu' const ChangeMiningFeeScene = ifLoggedIn(ChangeMiningFeeSceneComponent) const ChangeMiningFeeScene2 = ifLoggedIn(ChangeMiningFeeScene2Component) @@ -127,7 +127,7 @@ const ChangeRecoveryScene = ifLoggedIn(ChangeRecoverySceneComponent) const CoinRankingDetailsScene = ifLoggedIn(CoinRankingDetailsSceneComponent) const CoinRankingScene = ifLoggedIn(CoinRankingSceneComponent) const ConfirmScene = ifLoggedIn(ConfirmSceneComponent) -const ControlPanel = ifLoggedIn(ControlPanelComponent) +const SideMenu = ifLoggedIn(SideMenuComponent) const CreateWalletAccountSelectScene = ifLoggedIn(CreateWalletAccountSelectSceneComponent) const CreateWalletAccountSetupScene = ifLoggedIn(CreateWalletAccountSetupSceneComponent) const CreateWalletCompletionScene = ifLoggedIn(CreateWalletCompletionSceneComponent) @@ -284,7 +284,7 @@ const EdgeApp = () => { return ( ControlPanel(props)} + drawerContent={props => SideMenu(props)} initialRouteName="edgeAppStack" screenOptions={{ drawerPosition: 'right', diff --git a/src/components/themed/ControlPanel.tsx b/src/components/themed/SideMenu.tsx similarity index 99% rename from src/components/themed/ControlPanel.tsx rename to src/components/themed/SideMenu.tsx index 87a038eaea0..45624653636 100644 --- a/src/components/themed/ControlPanel.tsx +++ b/src/components/themed/SideMenu.tsx @@ -20,7 +20,6 @@ import { launchDeepLink } from '../../actions/DeepLinkingActions' import { logoutRequest } from '../../actions/LoginActions' import { executePluginAction } from '../../actions/PluginActions' import { Fontello } from '../../assets/vector' -import { CryptoIcon } from '../../components/icons/CryptoIcon' import { EDGE_URL } from '../../constants/constantSettings' import { ENV } from '../../env' import { useSelectedWallet } from '../../hooks/useSelectedWallet' @@ -34,6 +33,7 @@ import { NavigationBase } from '../../types/routerTypes' import { parseDeepLink } from '../../util/DeepLinkParser' import { IONIA_SUPPORTED_FIATS } from '../cards/VisaCardCard' import { SceneWrapper } from '../common/SceneWrapper' +import { CryptoIcon } from '../icons/CryptoIcon' import { ButtonsModal } from '../modals/ButtonsModal' import { ScanModal } from '../modals/ScanModal' import { Airship, showError } from '../services/AirshipInstance' @@ -46,7 +46,7 @@ import { ModalMessage, ModalTitle } from './ModalParts' const xButtonGradientStart = { x: 0, y: 0 } const xButtonGradientEnd = { x: 0, y: 0.75 } -export function ControlPanel(props: DrawerContentComponentProps) { +export function SideMenu(props: DrawerContentComponentProps) { // Fix this type assertion (seems like DrawerContentComponentProps works just fine as NavigationBase?) const navigation: NavigationBase = props.navigation as any const isDrawerOpen = useDrawerStatus() === 'open' From e2ef1d7d0a43db2332e7265219330fc5952df83b Mon Sep 17 00:00:00 2001 From: William Swanson Date: Thu, 1 Jun 2023 21:41:25 -0700 Subject: [PATCH 075/104] Avoid deprecated `pinLoginEnabled` method --- src/actions/LoginActions.tsx | 6 +++++- src/actions/SettingsActions.tsx | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/actions/LoginActions.tsx b/src/actions/LoginActions.tsx index d40c7e9940c..c5c7f7a2302 100644 --- a/src/actions/LoginActions.tsx +++ b/src/actions/LoginActions.tsx @@ -200,7 +200,11 @@ export function initializeAccount(navigation: NavigationBase, account: EdgeAccou } accountInitObject = { ...accountInitObject, ...mergedLocalSettings.finalSettings } - accountInitObject.pinLoginEnabled = await context.pinLoginEnabled(account.username) + for (const userInfo of context.localUsers) { + if (userInfo.loginId === account.rootLoginId && userInfo.pinLoginEnabled) { + accountInitObject.pinLoginEnabled = true + } + } const defaultDenominationSettings = state.ui.settings.denominationSettings const syncedDenominationSettings = syncedSettings?.denominationSettings ?? {} diff --git a/src/actions/SettingsActions.tsx b/src/actions/SettingsActions.tsx index 6ae35231493..8f9975679f5 100644 --- a/src/actions/SettingsActions.tsx +++ b/src/actions/SettingsActions.tsx @@ -187,7 +187,13 @@ export function togglePinLoginEnabled(pinLoginEnabled: boolean): ThunkAction { showError(error) - const pinLoginEnabled = await context.pinLoginEnabled(account.username) + let pinLoginEnabled = false + for (const userInfo of context.localUsers) { + if (userInfo.loginId === account.rootLoginId && userInfo.pinLoginEnabled) { + pinLoginEnabled = true + } + } + dispatch({ type: 'UI/SETTINGS/TOGGLE_PIN_LOGIN_ENABLED', data: { pinLoginEnabled } From 8b167d0cda4259e07aba28eda3f34b764f9dcff6 Mon Sep 17 00:00:00 2001 From: William Swanson Date: Thu, 1 Jun 2023 22:20:14 -0700 Subject: [PATCH 076/104] Fix FIO name creation to work without usernames --- src/components/scenes/Fio/FioCreateHandleScene.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/scenes/Fio/FioCreateHandleScene.tsx b/src/components/scenes/Fio/FioCreateHandleScene.tsx index 8d88e7df625..ff9d2aa78ce 100644 --- a/src/components/scenes/Fio/FioCreateHandleScene.tsx +++ b/src/components/scenes/Fio/FioCreateHandleScene.tsx @@ -54,7 +54,6 @@ export const FioCreateHandleScene = ({ navigation, route }: Props) => { const styles = getStyles(theme) const dispatch = useDispatch() const account = useSelector(state => state.core.account) - const accountUserName = useSelector(state => state.core.account.username) const fioPlugin = useSelector(state => state.core.account.currencyConfig.fio) if (fioPlugin.otherMethods == null) { showError(lstrings.fio_register_handle_error) @@ -158,7 +157,7 @@ export const FioCreateHandleScene = ({ navigation, route }: Props) => { return } } - handleChangeFioHandle(accountUserName) + handleChangeFioHandle(account.username ?? '') const wallet = await dispatch(createFioWallet()) From 9299f15b2b77d60d577995fd96dba8672e3ed879 Mon Sep 17 00:00:00 2001 From: William Swanson Date: Thu, 1 Jun 2023 22:29:04 -0700 Subject: [PATCH 077/104] Fix the control panel to work without usernames --- src/actions/AccountActions.tsx | 9 +----- src/components/themed/SideMenu.tsx | 46 ++++++++++++++---------------- src/locales/en_US.ts | 1 + src/locales/strings/enUS.json | 1 + 4 files changed, 25 insertions(+), 32 deletions(-) diff --git a/src/actions/AccountActions.tsx b/src/actions/AccountActions.tsx index d1cb8fbcc43..491f8226726 100644 --- a/src/actions/AccountActions.tsx +++ b/src/actions/AccountActions.tsx @@ -2,7 +2,7 @@ import { OtpError } from 'edge-core-js' import * as React from 'react' import { TextInputModal } from '../components/modals/TextInputModal' -import { Airship, showError } from '../components/services/AirshipInstance' +import { Airship } from '../components/services/AirshipInstance' import { lstrings } from '../locales/strings' import { ThunkAction } from '../types/reduxTypes' import { NavigationBase } from '../types/routerTypes' @@ -57,10 +57,3 @@ export function validatePassword(opts: ValidatePasswordOptions = {}): ThunkActio return password != null } } - -export function deleteLocalAccount(username: string): ThunkAction> { - return async (dispatch, getState) => { - const state = getState() - return await state.core.context.deleteLocalAccount(username).catch(showError) - } -} diff --git a/src/components/themed/SideMenu.tsx b/src/components/themed/SideMenu.tsx index 45624653636..9934c3e667c 100644 --- a/src/components/themed/SideMenu.tsx +++ b/src/components/themed/SideMenu.tsx @@ -2,7 +2,7 @@ import { DrawerContentComponentProps, useDrawerStatus } from '@react-navigation/drawer' import { DrawerActions } from '@react-navigation/native' -import { EdgeUserInfo } from 'edge-core-js' +import { EdgeAccount, EdgeUserInfo } from 'edge-core-js' import * as React from 'react' import { Image, Platform, Pressable, ScrollView, TouchableOpacity, View } from 'react-native' import LinearGradient from 'react-native-linear-gradient' @@ -15,7 +15,6 @@ import FontAwesome5Icon from 'react-native-vector-icons/FontAwesome5' import MaterialIcon from 'react-native-vector-icons/MaterialIcons' import { sprintf } from 'sprintf-js' -import { deleteLocalAccount } from '../../actions/AccountActions' import { launchDeepLink } from '../../actions/DeepLinkingActions' import { logoutRequest } from '../../actions/LoginActions' import { executePluginAction } from '../../actions/PluginActions' @@ -59,7 +58,7 @@ export function SideMenu(props: DrawerContentComponentProps) { // ---- Redux State ---- const defaultFiat = useSelector(state => getDefaultFiat(state)) - const activeUsername = useSelector(state => state.core.account.username) + const account = useSelector(state => state.core.account) const context = useSelector(state => state.core.context) const selectedWallet = useSelectedWallet() const selectedDenomination = useSelector(state => { @@ -71,7 +70,7 @@ export function SideMenu(props: DrawerContentComponentProps) { // Maintain the list of usernames: const localUsers = useWatch(context, 'localUsers') - const usernames = React.useMemo(() => arrangeUsers(localUsers, activeUsername), [localUsers, activeUsername]) + const sortedUsers = React.useMemo(() => arrangeUsers(localUsers, account), [account, localUsers]) const closeButtonContainerStyle = React.useMemo(() => { return [styles.closeButtonContainer, { paddingBottom: insets.bottom }] @@ -79,7 +78,7 @@ export function SideMenu(props: DrawerContentComponentProps) { // User List dropdown/open state: const [isDropped, setIsDropped] = React.useState(false) - const isMultiUsers = usernames.length > 0 + const isMultiUsers = sortedUsers.length > 0 const handleToggleDropdown = () => { if (isMultiUsers) setIsDropped(!isDropped) } @@ -91,17 +90,18 @@ export function SideMenu(props: DrawerContentComponentProps) { /// ---- Callbacks ---- - const handleDeleteAccount = (username: string) => () => { + const handleDeleteAccount = (userInfo: EdgeUserInfo) => () => { Airship.show<'ok' | 'cancel' | undefined>(bridge => ( { - await dispatch(deleteLocalAccount(username)) + // TODO: Add a way to make this work for accounts without usernames: + await context.deleteLocalAccount(userInfo.username ?? '') return true }, type: 'primary' @@ -112,8 +112,8 @@ export function SideMenu(props: DrawerContentComponentProps) { )) } - const handleSwitchAccount = (username: string) => () => { - dispatch(logoutRequest(navigation, username)) + const handleSwitchAccount = (userInfo: EdgeUserInfo) => () => { + dispatch(logoutRequest(navigation, userInfo.username)) } const handleBorrow = () => { @@ -163,7 +163,7 @@ export function SideMenu(props: DrawerContentComponentProps) { /// ---- Animation ---- // Track the destination height of the dropdown - const userListDesiredHeight = styles.rowContainer.height * usernames.length + theme.rem(1) + const userListDesiredHeight = styles.rowContainer.height * sortedUsers.length + theme.rem(1) const userListHeight = Math.min(userListDesiredHeight, bottomPanelHeight) const isUserListHeightOverflowing = userListDesiredHeight >= bottomPanelHeight @@ -321,7 +321,7 @@ export function SideMenu(props: DrawerContentComponentProps) { - {activeUsername} + {account.username ?? lstrings.missing_username} {isMultiUsers ? ( @@ -339,14 +339,14 @@ export function SideMenu(props: DrawerContentComponentProps) { {/* === Dropdown Start === */} - {usernames.map((username: string) => ( - + {sortedUsers.map(userInfo => ( + {/* This empty container is required to align the row contents properly */} - - {username} + + {userInfo.username ?? lstrings.missing_username} - + @@ -393,25 +393,23 @@ export function SideMenu(props: DrawerContentComponentProps) { * remove the given user, then organize the 3 most recent users, * followed by the rest in alphabetical order. */ -function arrangeUsers(localUsers: EdgeUserInfo[], activeUsername: string): string[] { +function arrangeUsers(localUsers: EdgeUserInfo[], activeAccount: EdgeAccount): EdgeUserInfo[] { // Sort the users according to their last login date (excluding active logged in user): const inactiveUsers = localUsers - .filter(info => info.username !== activeUsername) + .filter(info => info.loginId !== activeAccount.rootLoginId) .sort((a, b) => { const { lastLogin: aDate = new Date(0) } = a const { lastLogin: bDate = new Date(0) } = b return bDate.valueOf() - aDate.valueOf() }) - .map(info => info.username) - .filter((username): username is string => username != null) // Get the most recent 3 users that were logged in const recentUsers = inactiveUsers.slice(0, 3) // Sort everything after the last 3 entries alphabetically: - const oldUsers = inactiveUsers.slice(3).sort((a: string, b: string) => { - const stringA = a.toUpperCase() - const stringB = b.toUpperCase() + const oldUsers = inactiveUsers.slice(3).sort((a, b) => { + const stringA = a.username?.toLowerCase() ?? '' + const stringB = b.username?.toLowerCase() ?? '' if (stringA < stringB) return -1 if (stringA > stringB) return 1 return 0 diff --git a/src/locales/en_US.ts b/src/locales/en_US.ts index 76362be3843..1b735bbb8be 100644 --- a/src/locales/en_US.ts +++ b/src/locales/en_US.ts @@ -372,6 +372,7 @@ const strings = { incorrect_pin: 'Incorrect PIN', invalid_spend_request: 'Invalid Spend Request', invalid_custom_fee: 'Minimum custom fee is', + missing_username: '', settings_account_title_cap: 'Account', settings_button_change_password: 'Change Password', settings_developer_mode: 'Developer Mode', diff --git a/src/locales/strings/enUS.json b/src/locales/strings/enUS.json index cdb25b22749..1fffacf3d5a 100644 --- a/src/locales/strings/enUS.json +++ b/src/locales/strings/enUS.json @@ -310,6 +310,7 @@ "incorrect_pin": "Incorrect PIN", "invalid_spend_request": "Invalid Spend Request", "invalid_custom_fee": "Minimum custom fee is", + "missing_username": "", "settings_account_title_cap": "Account", "settings_button_change_password": "Change Password", "settings_developer_mode": "Developer Mode", From fa136c2394ea7b4d964dd4c6488527cc308cf7b8 Mon Sep 17 00:00:00 2001 From: William Swanson Date: Thu, 1 Jun 2023 21:39:38 -0700 Subject: [PATCH 078/104] Fix log upload to work without usernames --- src/actions/LogActions.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/actions/LogActions.tsx b/src/actions/LogActions.tsx index 271778f6f59..3d946480872 100644 --- a/src/actions/LogActions.tsx +++ b/src/actions/LogActions.tsx @@ -147,7 +147,7 @@ export function getLogOutput(): ThunkAction> { logOutput.loggedInUser = { userId: rootLoginId, - userName: username, + userName: username ?? '', wallets: [], actions: [] } From cf463fe09a72eb3ec85b100d4ca36af34d315b5e Mon Sep 17 00:00:00 2001 From: William Swanson Date: Thu, 1 Jun 2023 21:32:13 -0700 Subject: [PATCH 079/104] Upgrade to edge-core-js v1.0.1 --- ios/Podfile.lock | 4 ++-- package.json | 2 +- yarn.lock | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 42bda168366..7fe2f9181f8 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -18,7 +18,7 @@ PODS: - disklet (0.5.2): - React - DoubleConversion (1.1.6) - - edge-core-js (1.0.0): + - edge-core-js (1.0.1): - React-Core - edge-currency-accountbased (1.2.13): - React-Core @@ -1109,7 +1109,7 @@ SPEC CHECKSUMS: CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 disklet: e7ed3e673ccad9d175a1675f9f3589ffbf69a5fd DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662 - edge-core-js: 655cd63654df00c4e36d387381e7e90bc1b69340 + edge-core-js: faaac18a528eee7093d722a8d36a71c51512a2a3 edge-currency-accountbased: b5c9b417420254bcc5a92353eeb96bb82d84b24a edge-login-ui-rn: 1bb5f0054181b0464970180f51a27f70d2f29e45 FBLazyVector: d2db9d00883282819d03bbd401b2ad4360d47580 diff --git a/package.json b/package.json index e09f8fd277d..7076012427f 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,7 @@ "deepmerge": "^4.3.1", "detect-bundler": "^1.1.0", "disklet": "^0.5.2", - "edge-core-js": "^1.0.0", + "edge-core-js": "^1.0.1", "edge-currency-accountbased": "^1.2.13", "edge-currency-monero": "^1.0.0", "edge-currency-plugins": "^2.0.2", diff --git a/yarn.lock b/yarn.lock index 44035c8bf37..fe330950449 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7219,10 +7219,10 @@ edge-core-js@^0.19.48: yaob "^0.3.9" yavent "^0.1.3" -edge-core-js@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/edge-core-js/-/edge-core-js-1.0.0.tgz#8ec013b6c59940582120b72a64290d09460718a7" - integrity sha512-r6UHDdzSO7vjfB+aOhDSfHjlm3aF53fhqQYASmy7vWAjcL46dJlSd7Vp+MLp/5Yn3HMPSLDP+q+dVsjY2/fIDg== +edge-core-js@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/edge-core-js/-/edge-core-js-1.0.1.tgz#e9316a6e9a3f0d7ffc539bd6c66d9c5acb7587bc" + integrity sha512-CCvMS3vg+NMtElzS/yf8vkk8rmFdWwSq9JEsY/BQmDbdVhDpgn4Q3eC9AijufcN2Xg3n+FFO41tVr7+uuW3JhQ== dependencies: aes-js "^3.1.0" base-x "^1.0.4" From 171a9eacf40864587c0f38cc8f2e2cb605bad0af Mon Sep 17 00:00:00 2001 From: Paul V Puey Date: Wed, 7 Jun 2023 11:23:20 -0700 Subject: [PATCH 080/104] New translations enUS.json (Spanish) --- src/locales/strings/es.json | 431 +++++++++++++++++++----------------- 1 file changed, 225 insertions(+), 206 deletions(-) diff --git a/src/locales/strings/es.json b/src/locales/strings/es.json index aac6b2c1e16..230743485dd 100644 --- a/src/locales/strings/es.json +++ b/src/locales/strings/es.json @@ -1,121 +1,121 @@ { - "action_queue_display_unknown_title": "Acción desconocida", - "action_queue_display_unknown_message": "Edge no puede identificar el tipo de acción que se está completando.", - "aciton_queue_display_close_title": "Cerrando préstamo", + "action_queue_display_unknown_title": "Unknown action", + "action_queue_display_unknown_message": "Edge is unable to identify the type of action being completed.", + "aciton_queue_display_close_title": "Closing Loan", "action_queue_display_close_message": "Edge is paying principal in full and withdrawing the remaining collateral.", - "action_queue_display_seq_title": "Pasos de acción", - "action_queue_display_seq_message": "Hacer una secuencia de acciones.", - "action_queue_display_par_title": "Grupo de acción", - "action_queue_display_par_message": "Realizando múltiples acciones a la vez.", - "action_queue_display_fiat_buy_title": "Compra %s", - "action_queue_display_fiat_buy_message": "Compra %1$s de %3$s.", - "action_queue_display_fiat_sell_title": "Depositar fondos a banco", + "action_queue_display_seq_title": "Action steps", + "action_queue_display_seq_message": "Doing a sequence of actions.", + "action_queue_display_par_title": "Action group", + "action_queue_display_par_message": "Doing multiple actions at once.", + "action_queue_display_fiat_buy_title": "Purchase %s", + "action_queue_display_fiat_buy_message": "Purchase %1$s from %3$s.", + "action_queue_display_fiat_sell_title": "Deposit funds to bank", "action_queue_display_fiat_sell_message": "Your %1$s is being sold by our partners and deposited into your bank account through %2$s.", - "action_queue_display_loan_borrow_title": "Obtener préstamo", - "action_queue_display_loan_borrow_message_1s": "Un préstamo de %1$s ha sido solicitado y está en camino a tu billetera.", - "action_queue_display_loan_deposit_title": "Depositando %1$s como colateral", + "action_queue_display_loan_borrow_title": "Take out loan", + "action_queue_display_loan_borrow_message_1s": "A %1$s loan has been requested and is on its way to your wallet.", + "action_queue_display_loan_deposit_title": "Depositing %1$s as collateral", "action_queue_display_loan_deposit_message": "Edge has sent your %1$s tokens to %2$s and is awaiting confirmation of the transfer.", - "action_queue_display_loan_repay_title": "Pagar préstamo principal", - "action_queue_display_loan_repay_message": "Hacer un pago a su préstamo principal.", - "action_queue_display_loan_repay_with_collateral_title": "Pagar el principal del préstamo con el colateral", + "action_queue_display_loan_repay_title": "Repay loan principal", + "action_queue_display_loan_repay_message": "Make a payment towards your loan principal.", + "action_queue_display_loan_repay_with_collateral_title": "Repay loan principal with collateral", "action_queue_display_loan_repay_with_collateral_message": "Make a payment towards your loan principal using your collateral on AAVE.", - "action_queue_display_loan_withdraw_title": "Retirar el colateral del préstamo", - "action_queue_display_loan_withdraw_message": "Retirar %1$s del préstamo.", - "action_queue_display_swap_title": "Intercambiar %1$s a %2$s", + "action_queue_display_loan_withdraw_title": "Withdraw collateral from loan", + "action_queue_display_loan_withdraw_message": "Withdraw %1$s from loan.", + "action_queue_display_swap_title": "Swap %1$s into %2$s", "action_queue_display_swap_message": "To use %1$s as collateral, %2$s must swap %1$s into %3$s to put it on the same network as %4$s (%5$s).", - "action_queue_push_notification_title": "Acción completada", - "action_queue_push_notification_body": "Edge ha completado el procesamiento de su operación de préstamo.", - "action_display_title_create": "Creando préstamo", - "action_display_title_swap": "Intercambiando fondos", - "action_display_message_create_3s": "%1$s está creando su préstamo en %2$s usando su %3$s como colateral", + "action_queue_push_notification_title": "Action Complete", + "action_queue_push_notification_body": "Edge has completed processing your loan operation.", + "action_display_title_create": "Creating Loan", + "action_display_title_swap": "Swapping Funds", + "action_display_message_create_3s": "%1$s is creating your loan on %2$s using your %3$s as collateral", "action_display_message_swap_4s": "%1$s is swapping your %2$s into %3$s for deposit into %4$s. This may take a few mins to several hours…", "action_display_message_swap_fees_5s": "%1$s is swapping your %2$s into %3$s and %4$s (to pay fees) for deposit into %5$s. This may take a few mins to several hours…", - "action_display_title_complete_default": "Felicitaciones!", + "action_display_title_complete_default": "Congratulations!", "action_display_message_complete_default": "Your transactions completed successfully!\nPlease allow time for your accounts to update.", "action_display_message_complete_wallet_2s": "Your loan is complete! \nYou should see %1$s in your %2$s account", "action_display_message_complete_bank": "Your loan is complete! \nYou should see funds in your bank account in 1-4 days", - "bitpay_metadata_name": "Factura #: %s", + "bitpay_metadata_name": "Invoice ID: %s", "bitcoin_received": "Has recibido %1$s", - "dialog_title": "Auto cierre de sesión", + "dialog_title": "Fijar tiempo para desconexión automática", "share_subject": "Hola, creo que deberías probar %s", - "share_message": "Puedes comprar, guardar y intercambiar con decenas de criptomonedas en una sola aplicación.", - "drawer_borrow_dollars": "Pedir prestado dolares", - "drawer_exchange_rate_loading": "Cargando Tipo de Cambio", - "drawer_exchange": "Intercambio", - "drawer_scan_qr_send": "Escanear Código QR", - "drawer_sweep_private_key": "Retirar clave privada (Sweep Pk)", + "share_message": "Puedes comprar, almacenar y operar con decenas de criptomonedas en una sola aplicación.", + "drawer_borrow_dollars": "Borrow Dollars", + "drawer_exchange_rate_loading": "Cargando tipo de cambio", + "drawer_exchange": "Exchange", + "drawer_scan_qr_send": "Scan QR", + "drawer_sweep_private_key": "Barrer clave privada (Sweep Pk)", "drawer_fio_names": "Nombres FIO", "drawer_fio_requests": "Solicitudes FIO", "network_alert_title": "Sin conexión a Internet", "fio_network_alert_text": "La funcionalidad FIO requiere conexión a Internet.", - "fio_address_choose_label": "Elige un ususario para FIO", + "fio_address_choose_label": "Choose a FIO Crypto Handle", "fio_domain_choose_label": "Elegir un dominio FIO", - "fio_address_choose_domain_label": "Elige un dominio FIO para tu ususario", + "fio_address_choose_domain_label": "Choose FIO Domain for Your Crypto Handle", "scan_qr_label": "Escanear código QR", - "error_paymentprotocol_empty_output_invoice": "No se ha recibido respuesta en la solicitud de pago", - "error_paymentprotocol_empty_verification_hex_req": "Generado hex(s) de transacción vacía", + "error_paymentprotocol_empty_output_invoice": "Received no output in payment request", + "error_paymentprotocol_empty_verification_hex_req": "Generated empty transaction hex(es)", "error_paymentprotocol_currency_not_supported": "Payment Protocol invoice payments in %s not currently supported. Please choose another payment currency.", "error_paymentprotocol_invalid_payment_option": "Payment Protocol invoice does not accept this currency. Accepted currencies: %s", - "error_paymentprotocol_fetch": "Error de búsqueda (%s)%s del protocolo de pago %s", - "error_paymentprotocol_multi_output_invoice": "Múltiples resultados encontradas en la solicitud de pago", - "error_paymentprotocol_multi_tx_invoice": "Múltiples transacciones encontradas en la solicitud de pago", + "error_paymentprotocol_fetch": "Payment Protocol %s fetch error (%s)%s", + "error_paymentprotocol_multi_output_invoice": "Multiple outputs found in payment request", + "error_paymentprotocol_multi_tx_invoice": "Multiple transactions found in payment request", "error_paymentprotocol_no_payment_option": "No currencies available for this Payment Protocol invoice. Accepted currencies: %s", - "error_paymentprotocol_tx_verification_failed": "La verificación de la transacción del protocolo de pago no coincide", + "error_paymentprotocol_tx_verification_failed": "Payment Protocol transaction verification mismatch", "error_spend_amount_less_then_min_s": "Spend amount is less than minimum of %s", "warning_low_fee_selected": "Tarifa baja seleccionada", "warning_custom_fee_selected": "Tarifa personalizada seleccionada", "warning_low_or_custom_fee": "Usar una comisión baja puede aumentar la cantidad de tiempo que tarda en confirmar tu transacción. En raras ocasiones tu transacción puede fallar.", "warning_alphanumeric": "Sólo se permiten letras y números", - "warning_please_wait_title": "Por favor espere", - "warning_scam_title": "Advertencia de Estafa", - "warning_scam_message_financial_advice": "Edge no te dará asesoramiento financiero.", - "warning_scam_message_irreversibility": "Las transacciones con criptomonedas son irreversibles.", - "warning_scam_message_unknown_recipients": "No envíes dinero a personas u organizaciones que no concoces.", - "warning_scam_footer": "Si tienes alguna pregunta o duda relacionada con este envío, por favor contacta a support@edge.app", + "warning_please_wait_title": "Please Wait", + "warning_scam_title": "Scam Warning", + "warning_scam_message_financial_advice": "Edge will not give financial advice.", + "warning_scam_message_irreversibility": "Cryptocurrency transactions are irreversible.", + "warning_scam_message_unknown_recipients": "Do not send money to people or organizations you do not know.", + "warning_scam_footer": "If you have any questions or concerns regarding this send please contact support@edge.app", "alert_dropdown_alert": "¡Alerta! ", "alert_dropdown_warning": "¡Advertencia! ", "azteco_success": "Has canjeado una tarjeta de bitcoin Azteco. Los fondos deberían llegar pronto.", - "azteco_invalid_code": "Código Azteco inválido.", - "azteco_service_unavailable": "Error contactando con el servidor Azteco. Por favor, inténtalo de nuevo más tarde.", + "azteco_invalid_code": "Código Azteco incorrecto.", + "azteco_service_unavailable": "Error contactando con el servidor de Azteco. Por favor, inténtalo de nuevo más tarde.", "reqaddr_error_unsupported_chains": "%1$s does not support the following chains listed in the request: %2$s", - "reqaddr_error_invalid_redir": "Consulta 'redir' inválida en la solicitud de dirección de pago", - "reqaddr_error_no_currencies_found": "No se encontraron divisas en la solicitud de dirección de pago", - "reqaddr_error_no_wallets_selected": "No hay monederos seleccionados para la solicitud de dirección de pago", - "reqaddr_error_post_redir": "Dirección de publicación y redirección no encontrada en la solicitud de dirección de pago", - "reqaddr_application_fragment": "Una solicitud", - "reqaddr_confirm_modal_title": "Confirmar solicitud?", + "reqaddr_error_invalid_redir": "Invalid 'redir' query in request for payment address", + "reqaddr_error_no_currencies_found": "No currencies found in request for payment address", + "reqaddr_error_no_wallets_selected": "No wallets selected for request for payment address", + "reqaddr_error_post_redir": "Post and redir address not found in request for payment address", + "reqaddr_application_fragment": "An application", + "reqaddr_confirm_modal_title": "Confirm request?", "reqaddr_confirm_modal_message": "%1$s is requesting a payment address for %2$s. Choose wallets for request?", - "max_spend_unavailable_modal_title": "Gasto Máximo No Disponible", + "max_spend_unavailable_modal_title": "Gasto máximo no disponible", "max_spend_unavailable_modal_message": "No podemos calcular la cantidad máxima disponible para la moneda %s. Por favor introduce una cantidad.", "access_wallet_description": "This application would like to create or access its wallet in your %1$s account.\n\n It will not have access to any other wallets.", "edge_description_warning": "The \"%1$s\" application is requesting full access to your account and all wallets. \n\nOnly accept this login request if you trust this application and where it was downloaded from.", - "exchange_failed": "No se pudo completar el intercambio", + "exchange_failed": "No se pudo completar el cambio", "exchange_congratulations": "¡ Felicidades!", "exchange_congratulations_msg": "¡Tu intercambio se ha completado con éxito!", "exchange_congratulations_msg_info": "Los intercambios pueden tardar entre unos minutos y hasta 24 horas en procesarse.", "no_exchange_amount": "Ninguna cantidad seleccionada", "exchange_asset_unsupported": "%s unsupported at this time. Please try again later.", - "select_exchange_amount": "Ingresa una cantidad para intercambiar", - "select_exchange_amount_short": "Ingresa Monto", + "select_exchange_amount": "Introduce una cantidad para cambiar", + "select_exchange_amount_short": "Introduce una cantidad", "fragment_wallets_addwallet_fiat_hint": "Elije una moneda fiat", "managetokens_top_instructions": "Seleccionar tokens para mostrar en la cartera:", "accept_button_text": "Aceptar", - "addtoken_contract_address_input_text": "Dirección del contrato", + "addtoken_contract_address_input_text": "Dirección del smart contract", "addtoken_currency_code_input_text": "Código del token", - "addtoken_invalid_information": "Por favor ingresa la información del token correcta e inténtelo de nuevo", + "addtoken_invalid_information": "Por favor introduzca la información del token correcta e inténtelo de nuevo", "addtoken_denomination_input_text": "Número de decimales", "addtoken_name_input_text": "Nombre del token", "addtoken_add": "Añadir token personalizado", "edittoken_delete_token": "Borrar token", "edittoken_delete_prompt": "¿Seguro que quieres eliminar este token?", - "edittoken_invalid_decimal_places": "Ingresa un número de decimales válido por favor.", + "edittoken_invalid_decimal_places": "Introduce un número de decimales válido por favor.", "fragment_create_wallet_create_wallet": "Crear cartera", - "fragment_create_wallet_instructions": "Pulse en el monedero para editar el nombre", + "fragment_create_wallet_instructions": "Tap on wallet to edit name", "fragment_create_wallet_select_valid": "Seleccione datos válidos por favor", "fragment_request_copy_title": "Copiar", - "fragment_request_subtitle": "Recibir", + "fragment_request_subtitle": "Receive", "fragment_request_address_uri_copied": "Request address URI copied to clipboard", - "fragment_copied": "Copiado correctamente en el portapapeles", + "fragment_copied": "¡Copiado correctamente en el portapapeles", "request_minimum_notification_title": "Saldo mínimo requerido", "request_xrp_minimum_notification_body": "Ripple (XRP) wallets require a 10 XRP minimum balance. You must deposit at least 10 XRP to this address before this wallet will show a balance or transactions. 10 XRP will be unspendable for the lifetime of this wallet address.", "request_xrp_minimum_notification_alert_body": "This wallet will always require a 10 XRP minimum", @@ -130,32 +130,32 @@ "scan_invalid_address_error_title": "Dirección Inválida", "scan_invalid_address_error_description": "No es una dirección pública válida", "fragment_send_subtitle": "Enviar", - "fragment_send_myself": "A mí", + "fragment_send_myself": "Myself", "fragment_send_from_label": "De", - "fragment_stake_label": "Bloqueo (Stake)", - "fragment_transaction_exchange": "Intercambiar", + "fragment_stake_label": "Stake", + "fragment_transaction_exchange": "Exchange", "fragment_transaction_expense": "Gasto", "fragment_transaction_income": "Ingreso", "fragment_transaction_list_receive_prefix": "Recibido ", "fragment_transaction_list_sent_prefix": "Enviado ", "fragment_transaction_transfer": "Transferir", "fragment_wallet_unconfirmed": "Pendiente", - "fragment_transaction_list_tx_dropped": "Descartado", + "fragment_transaction_list_tx_dropped": "Cancelada", "fragment_transaction_list_tx_synchronizing": "Sincronizando", "fragment_transaction_list_confirmation_progress": "%s de %s confirmaciones", - "fragment_transaction_list_unconfirmed_rbf": "Esperando confirmación, puede ser cancelado", + "fragment_transaction_list_unconfirmed_rbf": "Awaiting confirmation, may be cancelled", "fragment_transaction_list_transaction": "Transacciones", "transaction_list_buy_crypto_message": "Comprar %s", - "transaction_list_no_tx_yet": "Aún no hay transacciones", - "transaction_list_no_tx_support_yet": "El historial de transacciones aún no está soportado", + "transaction_list_no_tx_yet": "No transactions yet", + "transaction_list_no_tx_support_yet": "Transaction history is not yet supported", "transaction_list_search": "Buscar Transacciones", "transaction_list_search_no_result": "No se han encontrado resultados para tu búsqueda", - "fragment_wallets_balance_text": "Saldo Total", + "fragment_wallets_balance_text": "Balance total", "fragment_wallets_delete_wallet": "Archivar cartera", "fragment_wallets_resync_wallet": "Resincronizar la cartera", "fragment_wallets_split_wallet": "Dividir la cartera", - "fragment_wallets_copy_seed": "Copiar semilla", - "fragment_wallets_copied_seed": "Semilla copiada", + "fragment_wallets_copy_seed": "Copy Seed", + "fragment_wallets_copied_seed": "Copied Seed", "fragment_wallets_get_seed_wallet": "Obtener la semilla", "fragment_wallets_view_private_view_key": "Private View Key", "fragment_wallets_view_private_view_key_warning": "The private view key allows the receiver to see the balance in your Monero wallet. Do not share this key unless necessary, such as for tax purposes, accounting, or similar reasons.", @@ -163,31 +163,31 @@ "fragment_wallets_pubkey_copied_title": "Dirección XPub copiada", "fragment_wallets_export_transactions": "Exportar transacciones", "fragment_wallets_rename_wallet": "Renombrar cartera", - "fragment_wallets_resync_wallet_first_confirm_message_mobile": "¿Estás seguro de que quieres resincronizar?\n", + "fragment_wallets_resync_wallet_first_confirm_message_mobile": "¿Estás seguro de que quieres resincronizar?", "fragment_wallets_split_wallet_bch_to_bsv": "Estás a punto de dividir tu cartera BCH y crear una nueva cartera BSV desde tus claves privadas de BCH. Esto requiere una transacción de BCH para proteger tus fondos de un gasto no intencionado en la cadena incorrecta. Esto generará un pequeño coste de transacción en la cartera BCH. Por favor asegúrate de que esta transacción inicial se confirma antes de hacer más transacciones con BCH. Estás seguro de que quieres dividir\n", - "fragment_wallets_split_wallet_first_confirm_message_mobile": "¿Estás seguro de que quieres partir la cartera? (Wallet split)\n", - "fragment_wallets_get_seed_title": "Mostrar clave privada maestra", + "fragment_wallets_split_wallet_first_confirm_message_mobile": "¿Estás seguro de que quieres partir la cartera? (Wallet split)", + "fragment_wallets_get_seed_title": "Reveal Master Private Key", "fragment_wallets_get_seed_warning_message": "Sharing your master private key may put you at risk of fraudulent tokens and loss of funds.\n\nDo not share your key with anyone.\n\nBy entering your password, you are confirming that you understand the risks.", - "fragment_wallets_get_raw_keys_title": "Revelar llaves de origen", + "fragment_wallets_get_raw_keys_title": "Reveal Raw Keys", "fragment_wallets_get_raw_keys_warning_message": "Sharing your raw keys may put you at risk of fraudulent tokens and loss of funds.\n\nDo not share your keys with anyone.\n\nBy entering your password, you are confirming that you understand the risks.", "fragmet_wallets_delete_wallet_first_confirm_message_mobile": "¿Está seguro de que desea archivar ", "fragmet_wallets_delete_fio_extra_message_mobile": "Eliminar esta cartera FIO eliminará el acceso a cualquier dirección FIO que hayas vinculado a esta cartera.", "fragmet_wallets_delete_eth_extra_message": "Archivar esta cartera también archivará cualquier token habilitado para esta cartera.", - "wallet_list_add_wallet": "Añadir cartera", + "wallet_list_add_wallet": "Crear cartera", "wallet_list_add_token": "Añadir token", "wallet_list_referral_link_currency_invalid": "La moneda a crear no es válida", "wallet_list_referral_link_currency_loading": "Un momento. Creando la cartera necesaria para esta promoción", "wallet_list_referral_link_ask_wallet_creation": "Necesitas una cartera de %s para esta promoción. ¿Quieres crear una?", "wallet_list_referral_link_cancelled_wallet_creation": "El usuario no aprobó la creación de una cartera para la promoción", "wallet_list_wallet_search": "Buscar carteras", - "compromised_key_label": "Lave comprometida", + "compromised_key_label": "Compromised Key", "create_wallet_choice_new_button": "Crear nueva cartera", - "create_wallet_choice_new_button_fragment": "Nuevo monedero", + "create_wallet_choice_new_button_fragment": "New Wallet", "create_wallet_select_wallet_for_assets": "Please select the wallet you would like to add the following assets: %s", "create_wallet_import_title": "Importar cartera", "create_wallet_import_options_title": "Import Options", "create_wallet_import_options_birthday_height": "Wallet Birthday Height", - "create_wallet_imports_title": "Importar monedero", + "create_wallet_imports_title": "Import Wallets", "create_wallet_import_all_instructions": "Enter your private seed, private key, or active key to verify and restore the associated wallet", "create_wallet_import_instructions": "Introduce tu semilla privada para verificar y restaurar la cartera asociada", "create_wallet_import_input_prompt": "Semilla privada", @@ -197,33 +197,33 @@ "create_wallet_import_input_key_or_seed_prompt": "Clave privada o semilla privada", "create_wallet_import_polkadot_input_key_or_seed_instructions": "Enter your private seed or private key to verify and restore the associated ed25519 wallet", "create_wallet_import_active_key_input_prompt": "Clave Privada Activa", - "create_wallet_import_active_key_instructions": "Ingresa tu semilla privada para verificar y restaurar la cartera asociada:", - "create_wallet_edit": "Editar", + "create_wallet_import_active_key_instructions": "Introduce tu semilla privada para verificar y restaurar la cartera asociada:", + "create_wallet_edit": "Edit", "create_wallet_tokens": "Tokens", - "create_wallet_select_valid_crypto": "Seleccione un tipo de cartera válido", + "create_wallet_select_valid_crypto": "Seleccione un tipo de cartera válido por favor", "create_wallet_invalid_input": "Entrada inválida", "create_wallet_name_label": "Nombre de la cartera:", "create_wallet_crypto_type_label": "Tipo de cartera:", "create_wallet_fiat_type_label": "Moneda fiat de la cartera:", "create_wallet_failed_import_header": "Fallo en la importación de la clave", - "create_wallet_all_failed": "Por favor edite la clave y vuelva a intentarlo.", + "create_wallet_all_failed": "Please edit the key and try again.", "create_wallet_some_failed": "The following assets cannot be imported with the provided seed: %s. Would you like to continue importing all other assets?", "create_wallet_all_disabled_import": "No selected assets can be imported. You can create new wallets or go back and select different assets.", "create_wallet_some_disabled_import": "The following assets cannot be imported: %s. \nWould you like to continue importing all other assets?", - "create_wallet_no_assets_selected": "No hay activos seleccionados", - "create_wallet_failed_message": "La creación de la cartera falló por exceder el tiempo de espera. Por favor comprueba tu conexión a internet e vuevla a inténtarlo más tarde.", - "create_wallet_create_account": "Crear Cuenta", - "create_wallet_account_activate": "Activar Cuenta", - "create_wallet_account_handle": "Alias de Cuenta", + "create_wallet_no_assets_selected": "No assets selected", + "create_wallet_failed_message": "La creación de la cartera falló por exceder el tiempo de espera. Por favor comprueba tu conexión a internet e inténtalo de nuevo más tarde.", + "create_wallet_create_account": "Crear cuenta", + "create_wallet_account_activate": "Activar cuenta", + "create_wallet_account_handle": "Alias de la cuenta", "create_wallet_account_select_instructions_with_cost": "Todas las nuevas carteras de %1$s requieren un pago inicial para activar la cuenta y nombre. Este pago es un requisito de la red %2$s y no de %3$s. El coste actual equivale a %4$s pero puede fluctuar en el futuro. Selecciona una cartera desde la que pagar:", "create_wallet_account_make_payment": "Estás a punto de realizar el siguiente pago para activar tu cuenta de %s:", - "create_wallet_account_select_wallet": "Seleccionar Cartera", - "create_wallet_account_review_instructions": "Crear un alias de cuenta único, éste también será el nombre de tu cartera de %s:", + "create_wallet_account_select_wallet": "Seleccionar cartera", + "create_wallet_account_review_instructions": "Crear un alias de cuenta único, éste será también el nombre de tu cartera de %s:", "create_wallet_account_requirements_eos": "• Debe tener exactamente 12 caracteres\n• Debe incluir sólo letras minúsculas a-z o números 1-5\n", "create_wallet_account_invalid_account_name": "Nombre de cuenta inválido. No cumple los requisitos", "create_wallet_account_account_name_unavailable": "Nombre de cuenta no disponible. Por favor elige otro", "create_wallet_account_unknown_error": "Error desconocido comprobando el nombre de la cuenta. Por favor inténtalo más tarde", - "create_wallet_account_confirm": "Verifique la cartera y el información del pago antes de enviar.", + "create_wallet_account_confirm": "Comprueba doblemente la información de la cartera y el pago antes de enviar.", "create_wallet_account_amount_due": "Importe:", "create_wallet_account_error_sending_transaction": "Error enviando la transacción", "create_wallet_account_payment_sent_title": "Pago Enviado", @@ -235,14 +235,14 @@ "create_wallet_account_metadata_notes": "Esta transacción pagó la activación de tu cartera %s. Por favor espera a tener una confirmación de esta transacción antes de utilizar tu nueva cartera %s. Para problemas relacionados con la activación de la cartera por favor escribe %s", "create_wallet_account_unfinished_activation_title": "Cartera no activada", "create_wallet_account_unfinished_activation_message": "Para completar la activación de esta cartera %s, por favor elige un nombre de cuenta único y completa el pago de activación. Si ya has hecho un pago de activación, por favor espera a que ese pago se haya confirmado antes de intentar utilizar esta cartera.", - "activate_wallet_token_transaction_name_category_generic": "Activación del token", - "activate_wallet_token_transaction_notes_generic": "Activar transacción de token", - "activate_wallet_token_transaction_name_xrp": "Libro contable de XRP", - "activate_wallet_token_transaction_notes_xrp": "Activar el token XRP habilitando la Línea de Confianza al emisor", - "activate_wallet_token_scene_title": "Activar token", - "activate_wallet_tokens_scene_title": "Activar tokens", - "activate_wallet_token_scene_tile_title": "Token para activar", - "activate_wallet_tokens_scene_tile_title": "Tokens para activar", + "activate_wallet_token_transaction_name_category_generic": "Token Activation", + "activate_wallet_token_transaction_notes_generic": "Activate token transaction", + "activate_wallet_token_transaction_name_xrp": "XRP Ledger", + "activate_wallet_token_transaction_notes_xrp": "Activate XRP token by enabling Trust Line to issuer", + "activate_wallet_token_scene_title": "Activate Token", + "activate_wallet_tokens_scene_title": "Activate Tokens", + "activate_wallet_token_scene_tile_title": "Token to Activate", + "activate_wallet_tokens_scene_tile_title": "Tokens to Activate", "activate_wallet_token_scene_body": "To send and receive the selected token you will first need to activate it with a blockchain transaction. This transaction will cost the following fee.\n\nPlease confirm using the slider below.", "activate_wallet_token_scene_body_xrp_extra": "Token activation will increase the XRP reserve requirement by 2 XRP per token activated.", "activate_wallet_token_scene_body_algo_extra": "Token activation will increase the ALGO reserve requirement by 0.1 ALGO per token activated.", @@ -257,8 +257,8 @@ "fio_src_wallet": "Pagar desde cartera", "submit": "Enviar", "login": "Entrar", - "help_build": "Versión", - "help_modal_title_thanks": "Gracias por utilizar %1$s!", + "help_build": "Build", + "help_modal_title_thanks": "Thanks for using %1$s!", "help_version": "Versión", "help_knowledge_base": "Centro de conocimientos", "help_knowledge_base_text": "Preguntas frecuentes", @@ -266,35 +266,35 @@ "help_support_text": "Solución de problemas y soporte técnico", "help_call": "Llamar a asistencia", "help_call_text": "Póngase en contacto por teléfono", - "help_visit_site": "Visita el sitio %1$s", - "help_site_more_info_text": "Más información en %1$s", + "help_visit_site": "Visit the %1$s site", + "help_site_more_info_text": "More info on %1$s", "loading": "Cargando…", "validating": "Validando…", - "high_fee_warning_confirm_send": "Confirma el envío", + "high_fee_warning_confirm_send": "Confirm Send", "mining_fee_custom_label_choice": "Personalizar", "mining_fee_high_label_choice": "Alta", "mining_fee_low_label_choice": "Baja", "mining_fee_standard_label_choice": "Óptimo", - "request_deprecated_header": "Soporte para %1$s ha sido removido.", + "request_deprecated_header": "Support for %1$s has been deprecated.", "request_deprecated_currency_code": "Please extract the private keys and import into a %1$s supporting wallet. If you need assistance please submit a support ticket below.", "request_qr_email_title": "Pagar con %1$s:", - "request_email_subject": "Solicitud %1$s %2$s", - "request_qr_your_wallet_address": "Su dirección de monedero", - "request_qr_your_wrapped_segwit_address": "Tu dirección Wrapped-Segwit", - "request_qr_your_legacy_address": "Tu dirección Legacy", - "request_qr_your_segwit_address": "Tu dirección Segwit", + "request_email_subject": "%1$s %2$s Request", + "request_qr_your_wallet_address": "Your Wallet Address", + "request_qr_your_wrapped_segwit_address": "Your Wrapped-Segwit Address", + "request_qr_your_legacy_address": "Your Legacy Address", + "request_qr_your_segwit_address": "Your Segwit Address", "request_review_question_title": "¿Disfrutando %1$s?", "request_review_question_subtitle": "Por favor, danos una reseña", "request_review_answer_no": "No, gracias", "request_review_answer_yes": "Calificar ahora", - "request_review_android_page_link": "https://play.google.com/store/apps/details?id=co.edgesecure.app&hl=es_US", + "request_review_android_page_link": "https://play.google.com/store/apps/details?id=co.edgesecure.app&hl=en_US", "search_wallets": "Buscar carteras", "search_tokens": "Buscar tokens", - "search_assets": "Buscar Activos", + "search_assets": "Search Assets", "select_wallet": "Seleccionar cartera", - "send_confirmation_calculating_fee": "Calculando comisión", + "send_confirmation_calculating_fee": "Calculating Fee", "send_confirmation_slide_to_confirm": "Deslizar para confirmar", - "send_confirmation_balance": "Saldo", + "send_confirmation_balance": "Balance", "send_confirmation_eos_error_cpu": "CPU disponible insuficiente para enviar transacciones de EOS. Por favor espere 1-3 días para que la CPU recargue.", "send_confirmation_eos_error_net": "Red disponible insuficiente para enviar una transacción EOS. Por favor espera 1-3 días a que la red se recargue.", "send_confirmation_eos_error_ram": "RAM disponible insuficiente para enviar la transacción de EOS. Consulte edge.app/eos para obtener más información sobre la resolución.", @@ -305,10 +305,10 @@ "send_confirmation_fee_modal_alert_message_fragment_eth": "El uso de una tarifa demasiado baja puede resultar en una transacción fallida y pérdida de la comisión gastada.", "transaction_failure": "Fallo en la transacción", "transaction_failure_message": "%s.", - "transaction_success": "Transacción Exitosa", + "transaction_success": "Transacción correcta", "transaction_success_message": "Tu transacción ha sido enviada correctamente.", - "incorrect_pin": "NIP incorrecto", - "invalid_spend_request": "Solicitud de gasto inválida", + "incorrect_pin": "PIN incorrecto", + "invalid_spend_request": "Petición de gasto inválida", "invalid_custom_fee": "Tarifa mínima es", "settings_account_title_cap": "Cuenta", "settings_button_change_password": "Cambiar contraseña", @@ -317,24 +317,24 @@ "settings_dark_theme": "Tema Oscuro", "settings_button_lock_settings": "Pulsar para bloquear la configuración de la cuenta", "settings_button_password_recovery": "Configurar recuperación de contraseña", - "settings_button_logout": "Cerrar sesión", - "settings_button_pin": "Cambiar NIP", - "settings_exchange_settings": "Configuración de Intercambio", + "settings_button_logout": "Salir", + "settings_button_pin": "Cambiar el PIN", + "settings_exchange_settings": "Ajustes de cambio", "settings_exchange_instruction": "Activar o desactivar las casas de cambio disponibles para ti", - "settings_marketing_notifications_switch": "Habilitar alertas de mercadeo", - "settings_price_notifications_switch": "Habilitar alertas de precios", - "settings_hide_spam_transactions": "Ocultar transacciones spam", + "settings_marketing_notifications_switch": "Enable Marketing Alerts", + "settings_price_notifications_switch": "Enable Price Alerts", + "settings_hide_spam_transactions": "Hide spam transactions", "swap_preferred_header": "Casa de cambio preferida", "swap_preferred_cheapest": "Elegir mejor precio", - "swap_preferred_dex": "Preferir modo descentralizado", - "swap_preferred_cex": "Preferir modo centralizado", - "swap_options_header_decentralized": "Descentralizado\nNo se requiere información personal", - "swap_options_header_centralized": "Centralizado\nPuede requerir información personal", + "swap_preferred_dex": "Prefer Decentralized", + "swap_preferred_cex": "Prefer Centralized", + "swap_options_header_decentralized": "Decentralized\nNo personal info required", + "swap_options_header_centralized": "Centralized\nMay require personal info", "swap_preferred_instructions": "Cuando varias casas de cambio pueden ejecutar una orden, preferir:", - "swap_preferred_promo_instructions": "Cuando varias casas de cambio pueden completar un pedido, la promoción actual prefiere:", - "settings_button_clear_logs": "Eliminar registros", - "settings_button_send_logs": "Enviar registros a Edge", - "settings_button_export_logs": "Exportar registros", + "swap_preferred_promo_instructions": "Cuando múltiples intercambios pueden llenar un pedido, la promoción actual siempre prefiere:", + "settings_button_clear_logs": "Clear Logs", + "settings_button_send_logs": "Send Logs to Edge", + "settings_button_export_logs": "Export Logs", "settings_button_setup_two_factor": "Configurar seguridad de 2 factores", "settings_button_unlock_settings": "Pulsa para desbloquear la configuración de la cuenta", "settings_button_use_touchID": "Usar TouchID", @@ -342,25 +342,25 @@ "settings_button_use_biometric": "Usar huella", "settings_days": "Día(s)", "settings_denominations_title": "Denominaciones", - "settings_custom_nodes_title": "Servidores Personalizados", - "settings_custom_servers_title": "Servidores %s Personalizados", + "settings_custom_nodes_title": "Custom Servers", + "settings_custom_servers_title": "Custom %s Servers", "settings_blockbook": "Blockbook", "settings_electrum": "Electrum", "settings_hours": "Hora(s)", "settings_minutes": "Minuto(s)", "settings_modal_export_logs_message": "You may add any additional notes here, and select whether to share logs with Edge, or export logs to your device.", - "settings_modal_clear_logs_message": "Está seguro que desea borrar todos los registros de este dispositivo?", - "settings_modal_clear_logs_success": "Los registros han sido borrados", + "settings_modal_clear_logs_message": "Are you sure you want to clear all logs on this device?", + "settings_modal_clear_logs_success": "Logs have been cleared", "settings_modal_send_logs_success": "Los registros han sido enviados", "settings_modal_send_logs_failure": "El envío de registros ha fallado", - "settings_modal_share_logs_failure": "Fallo al compartir registros", + "settings_modal_share_logs_failure": "Sharing logs has failed", "settings_modal_send_unsafe": "These logs appear to contain sensitive information, such as private keys and addresses, that could result in the loss of funds. Therefore, it is not safe to send these logs to Edge servers.", "settings_modal_send_logs_label": "Escribe notas aquí", "settings_options_title_cap": "Opciones", "settings_seconds": "Segundo(s)", "settings_title_auto_logoff": "Desconexión automática después de", - "settings_title_currency": "Moneda Predeterminada", - "settings_title_pin_login": "NIP Re-login", + "settings_title_currency": "Moneda por defecto", + "settings_title_pin_login": "PIN Re-login", "settings_title": "Configuración", "settings_enable_custom_nodes": "Enable Custom Servers", "settings_add_custom_node": "Add Custom Server", @@ -368,7 +368,7 @@ "settings_custom_node_url": "URL del nodo", "settings_promotion_affiliation_header": "Programa de afiliación", "settings_promotion_header": "Códigos de promoción", - "settings_promotion_add": "Ingresar código de promoción", + "settings_promotion_add": "Introduce el código de promoción", "settings_promotion_device_normal": "Esta aplicación fue instalada normalmente.", "settings_promotion_device_installer": "Esta aplicación fue instalada a través de %s.", "settings_promotion_device_currencies": "Las nuevas cuentas tendrán carteras para: %s", @@ -383,44 +383,45 @@ "staking_change_explaner1": "Stake your coins to earn passive income on your funds", "staking_change_explaner2": "Staked coins are unusable for the duration of the stake", "staking_change_remove_header": "Unstake %s", - "staking_change_remove_amount_title": "Cantidad a desbloquear", - "staking_change_remove_unlock_date": "Fecha de desbloqueo", - "staking_change_unlock_explainer_title": "Fondos desbloqueados", - "staking_change_unlock_explainer1": "Los fondos desbloqueados no están disponibles inmediatamente. ", + "staking_change_remove_amount_title": "Amount to unstake", + "staking_change_remove_unlock_date": "Unlock date", + "staking_change_unlock_explainer_title": "Unstaked Funds", + "staking_change_unlock_explainer1": "Unstaked funds are not immediately available. ", "staking_change_unlock_explainer2": "These continue to be locked and unusable for 7 days after you unstake the funds.", - "staking_overview_header": "Bloquear %s", - "staking_overview_explainer": "Tienes los siguientes fondos bloqueados:", + "staking_overview_header": "Stake %s", + "staking_overview_explainer": "You have the following funds staked:", "staking_locked_title": "Unstaked and locked until %1$s", - "staking_stake_funds_button": "Bloquear más fondos", + "staking_stake_funds_button": "Stake More Funds", "staking_unstake_funds_button": "Unstake", - "staking_status": "%1$s bloqueado (%2$s)", - "staking_success": "Bloqueado exitosamente", - "staking_unstake_success": "Desbloqueado exitosamente", - "staking_estimated_rewards": "Recompensas estimadas", - "staking_estimated_return": "Rendimiento estimado: %1$s APY", - "staking_estimated_return_up_to": "Rendimiento estimado: hasta %1$s APY", - "staking_no_fio_address_error": "No se puede hacer el bloqueo sin una direccion FIO", + "staking_status": "%1$s locked (%2$s)", + "staking_success": "Successfully staked", + "staking_unstake_success": "Successfully unstaked", + "staking_estimated_rewards": "Estimated Rewards", + "staking_estimated_return": "Estimated Return: %1$s APY", + "staking_estimated_return_up_to": "Estimated Return: up to %1$s APY", + "staking_no_fio_address_error": "Unable to stake without a FIO addresses", "staking_no_bundled_txs_error": "Not enough bundled transactions for FIO address %1$s", "string_i_agree": "I Agree", + "string_expires": "Expires", "string_decline": "Decline", "string_cancel_cap": "Cancelar", "string_cancel": "CANCELAR", "string_ok_cap": "Ok", - "string_forget": "Olvidar", + "string_forget": "Forget", "string_delete": "Borrar", "string_keep": "Keep", "string_archive": "Archivar", "string_archive_wallet": "Archivar cartera", - "satPerByte": "Satoshi por Byte", + "satPerByte": "Satoshi Per Byte", "gasLimit": "Límite de gas", "gasPrice": "Precio Gas (Gwei)", "string_disable": "Deshabilitado", "string_done_cap": "Hecho", "string_first_ethereum_wallet_name": "Mi Ether", - "string_first_ethereum_classic_wallet_name": "Mi Ethereum Classic", - "string_first_ethereum_pow_wallet_name": "Mi Ethereum POW", + "string_first_ethereum_classic_wallet_name": "My Ethereum Classic", + "string_first_ethereum_pow_wallet_name": "My Ethereum POW", "string_first_bitcoin_wallet_name": "Mi Bitcoin", - "string_first_bitcoin_testnet_wallet_name": "Mi Bitcoin Testnet", + "string_first_bitcoin_testnet_wallet_name": "My Bitcoin Testnet", "string_first_bitcoincash_wallet_name": "Mi Bitcoin Cash", "string_first_bitcoin_sv_wallet_name": "Mi Bitcoin SV", "string_first_bitcoin_gold_wallet_name": "Mi Bitcoin Gold", @@ -435,7 +436,7 @@ "string_first_litecoin_wallet_name": "Mi Litecoin", "string_first_monero_wallet_name": "Mi Monero", "string_first_qtum_wallet_name": "Mi Qtum", - "string_first_ripple_wallet_name": "Mi XRP", + "string_first_ripple_wallet_name": "My XRP", "string_first_smartcash_wallet_name": "Mi Smartcash", "string_first_ufo_wallet_name": "Mi UFO", "string_first_vertcoin_wallet_name": "Mi Vertcoin", @@ -443,22 +444,22 @@ "string_first_zcoin_wallet_name": "Mis Firo", "string_first_stellar_wallet_name": "Mi Stellar", "string_first_tezos_wallet_name": "Mi Tezos", - "string_first_rsk_wallet_name": "Mi Rootstock", + "string_first_rsk_wallet_name": "My Rootstock", "string_first_bnb_wallet_name": "Mi BNB", - "string_first_binance_smart_chain_wallet_name": "Mi Binance Smart Chain", + "string_first_binance_smart_chain_wallet_name": "My Binance Smart Chain", "string_first_eboost_wallet_name": "Mi eBoost", - "string_first_celo_wallet_name": "Mi Celo", - "string_first_solana_wallet_name": "Mi Solana", - "string_first_piratechain_wallet_name": "Mi Pirate", - "string_first_zcash_wallet_name": "Mi Zcash", - "string_first_tron_wallet_name": "Mi Tron", + "string_first_celo_wallet_name": "My Celo", + "string_first_solana_wallet_name": "My Solana", + "string_first_piratechain_wallet_name": "My Pirate", + "string_first_zcash_wallet_name": "My Zcash", + "string_first_tron_wallet_name": "My Tron", "string_first_doge_wallet_name": "Mi Doge", "string_first_fantom_wallet_name": "Mis Fantom", "string_first_hedera_wallet_name": "Mis Hedera", - "string_first_polkadot_wallet_name": "Mi Polkadot", - "string_first_polygon_wallet_name": "Mi Polygon", - "string_first_avalanche_wallet_name": "Mi Avalanche", - "string_first_optimism_wallet_name": "Mi Optimism", + "string_first_polkadot_wallet_name": "My Polkadot", + "string_first_polygon_wallet_name": "My Polygon", + "string_first_avalanche_wallet_name": "My Avalanche", + "string_first_optimism_wallet_name": "My Optimism", "string_first_algorand_wallet_name": "My Algorand", "string_first_zksync_wallet_name": "My zkSync", "my_crypto_wallet_name": "Mi %s", @@ -477,26 +478,26 @@ "string_to_capitalize": "A", "string_show_balance": "Mostrar saldo", "string_amount": "Cantidad", - "string_tap_to_edit": "Toca para editar", - "string_rate": "Calificar", - "string_got_it": "Entendido!", + "string_tap_to_edit": "Tap to edit", + "string_rate": "Rate", + "string_got_it": "Got it!", "exchange_rates_loading": "Cargando tipo de cambio...", "exchange_rate_loading_singular": "Cargando tipo de cambio...", "string_master_private_key": "Clave privada maestra", "string_split_wallet": "Dividir %s", "string_add_edit_tokens": "Añadir /Editar Tokens", - "string_get_raw_keys": "Obtener llaves crudas", - "string_raw_keys": "Llaves Crudas", - "title_create_wallet_select_crypto": "Elegir monederos a añadir", + "string_get_raw_keys": "Obtener llaves en bruto", + "string_raw_keys": "Llaves en bruto (raw keys)", + "title_create_wallet_select_crypto": "Choose Wallets to Add", "title_create_wallet_select_fiat": "Seleccionar Fiat", "title_change_mining_fee": "Cambiar comisión de minado", "title_change_password": "Cambiar contraseña", - "title_change_pin": "Cambiar NIP", - "title_create_wallet": "Crear Cartera", - "title_create_wallets": "Crear monederos", - "title_export_transactions": "Exportar Transacciones", + "title_change_pin": "Cambiar PIN", + "title_create_wallet": "Crear cartera", + "title_create_wallets": "Create Wallets", + "title_export_transactions": "Exportar transacciones", "title_edge_login": "Edge Login", - "title_exchange": "Intercambio", + "title_exchange": "Casa de cambio", "title_fio_sent_request_details": "Detalles de la solicitud enviados", "title_fio_address_settings": "Ajustes de dirección", "title_fio_domain_settings": "Ajustes de dominio", @@ -505,7 +506,7 @@ "title_fio_renew": "Renovar", "title_fio_make_public_domain": "Hacer público el dominio", "title_fio_make_private_domain": "Hacer Dominio Privado", - "title_fio_transfer_domain": "Transfer FIO Domain", + "title_fio_transfer_domain": "Transferir dominio FIO", "title_fio_transfer_address": "Transferir dirección FIO", "title_fio_address": "FIO Crypto Handles", "title_fio_names": "Nombres FIO", @@ -525,11 +526,11 @@ "title_settings": "Configuración", "title_promotion_settings": "Ajustes de la promoción", "title_terms_of_service": "Términos del Servicio", - "title_markets": "Mercados", + "title_markets": "Markets", "title_wallets": "Carteras", "title_buy": "Comprar", "title_sell": "Vender", - "title_map": "Mapa", + "title_map": "Map", "no_exchanges_available": "No hay casas de cambio activadas", "check_exchange_settings": "Por favor actívalas en los ajustes de casa de cambio.", "amount_above_limit": "La cantidad está por encima del límite máximo de %1$s %2$s. Este límite máximo está sujeto a cambios basados en las condiciones del mercado", @@ -552,7 +553,7 @@ "transaction_details_choose_a_sub_category": "Elegir sub-categoría", "transaction_details_recipient_addresses": "Dirección del destinatario", "transaction_details_advance_details_header": "Parámetros avanzados", - "transaction_details_advance_details_fee_setting": "Ajuste de comisión", + "transaction_details_advance_details_fee_setting": "Fee Setting", "transaction_details_advance_details_device": "Dispositivo", "transaction_details_advance_details_fee_used": "Tarifa utilizada", "transaction_details_advance_details_show_explorer": "Mostrar en el explorador", @@ -570,7 +571,7 @@ "transaction_details_accelerate_transaction_new_fee_title": "Nueva comisión", "transaction_details_accelerate_transaction_slider_disabled": "No se puede acelerar la transacción", "transaction_details_accelerate_transaction_fee_too_low": "Accelerated transaction fee is too low. Fee has been updated. Please try again.", - "transaction_details_accelerate_transaction_sent": "Tu transacción ha sido acelerada.", + "transaction_details_accelerate_transaction_sent": "Your transaction has been accelerated.", "transaction_details_exchange_details": "Detalles de la casa de cambio", "transaction_details_exchange_service": "Servicios de casa de cambio", "transaction_details_exchange_order_id": "Número de pedido", @@ -583,7 +584,7 @@ "transaction_details_exchange_status_page": "Página de estado de la casa de cambio", "transaction_details_exchange_support": "Soporte de la casa de cambio", "transaction_details_exchange_support_request": "Petición de soporte %s", - "transaction_details_fee_warning": "Tarifas de red altas", + "transaction_details_fee_warning": "High Network Fees", "my_receive_addresses_title": "My Receive Addresses", "tx_detail_picker_title": "Elige una categoría:", "transaction_details_notes_title": "Notas", @@ -1089,7 +1090,9 @@ "fiat_plugin_sell_currencycode_s": "Sell %s", "fiat_plugin_amount_currencycode": "Amount %s", "fiat_plugin_buy_amount_over_limit": "Max purchase amount is %s", + "fiat_plugin_buy_amount_over_undef_limit": "Purchase amount is over maximum", "fiat_plugin_buy_amount_under_limit": "Minimum purchase amount is %s", + "fiat_plugin_buy_amount_under_undef_limit": "Purchase amount is under minimum", "fiat_plugin_asset_unsupported": "Asset Unsupported", "fiat_plugin_payment_unsupported": "Payment Method Unsupported", "fiat_plugin_buy_region_restricted": "Region restricted from purchasing %s", @@ -1326,24 +1329,40 @@ "getting_started_welcome_prompt": "Swipe to Learn More", "getting_started_welcome_title": "Welcome to\nFinancial *Freedom*", "app_logo_hint": "App logo", - "rewards_card_getting_invoice": "Getting payment invoice", + "check_icon_hint": "Confirmed", + "close_control_panel_hint": "Close control panel", + "close_hint": "Close", + "create_wallet_hint": "Create Wallet %s", + "edit_icon_hint": "Edit", + "import_key_icon_hint": "Import Key", + "modal_close_hint": "Close modal", + "off_hint": "Off", + "on_hint": "On", + "sort_wallets_hint": "Sort Wallets", + "spinner_hint": "Loading", + "toggle_button_hint": "Toggle", + "wallet_settings_label": "Wallet settings", "rewards_card_error_retrieving_cards": "Error retrieving Visa cards. Please try again later.", - "rewards_card_error_authenticate": "Error authenticating with Visa Card program. Please try again later.", - "rewards_card_error_timeout_loading": "Timeout error loading Visa Card program. Please try again later.", - "rewards_card_purchase_successful": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", + "rewards_card_error_authenticate": "Error authenticating with Visa® Card program. Please try again later.", + "rewards_card_error_timeout_loading": "Timeout error loading Visa® Card program. Please try again later.", + "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", + "rewards_card_purchase_disclaimer": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", "rewards_card_loading": "Loading your Visa® Cards...", "rewards_card_add_new_input_amount_title": "Buy Visa® Card", "rewards_card_welcome_intro": "Purchase Visa® prepaid cards that can be used at millions of merchants in the U.S. Cards can be purchased up to $1,000 in value, with a daily limit of $10,000.", - "rewards_card_welcome_more_info": "Learn More", - "rewards_card_new_card_button_label": "Buy New Card", - "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", - "rewards_card_dashboard_expires_label": "Expires", "rewards_card_dashboard_title": "Visa® Card Program", - "rewards_card_delete_modal_title": "Delete Card?", - "rewards_card_delete_modal_message_s": "Are you sure you want to delete the Visa® Card with expiration?\n\n%s", - "rewards_card_error_missing_payment_address": "Missing payment address from provider", - "rewards_card_error_amount_max_s": "Maximum card purchase amount is $%s", - "rewards_card_error_amount_min_s": "Minimum card purchase amount is $%s", - "rewards_card_select_wallet": "Select wallet to use to purchase card", - "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds." + "rewards_card_delete_modal_message": "Are you sure you want to delete this Visa® Card?", + "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds.", + "buy_new_card_button": "Buy New Card", + "card_amount_max_error_message_s": "Maximum card purchase amount is $%s", + "card_amount_min_error_message_s": "Minimum card purchase amount is $%s", + "delete_card_confirmation_title": "Delete Card?", + "getting_payment_invoice_message": "Getting payment invoice", + "learn_more_button": "Learn More", + "missing_provider_payment_address_message": "Missing payment address from provider", + "no_active_cards_message": "You have no active cards.", + "purchase_asset_label": "Purchase Asset", + "purchase_date_label": "Purchase Date", + "purchase_price_label": "Purchase Price", + "select_wallet_to_purchase_card_title": "Select wallet to use to purchase card" } \ No newline at end of file From 0bfe87c5ea26a8eb571016e145f80f41daf736a7 Mon Sep 17 00:00:00 2001 From: Paul V Puey Date: Wed, 7 Jun 2023 11:23:22 -0700 Subject: [PATCH 081/104] New translations enUS.json (German) --- src/locales/strings/de.json | 49 +++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/src/locales/strings/de.json b/src/locales/strings/de.json index ff3062b4816..9626789d5ff 100644 --- a/src/locales/strings/de.json +++ b/src/locales/strings/de.json @@ -402,6 +402,7 @@ "staking_no_fio_address_error": "Nicht möglich ohne FIO-Adressen zu staken", "staking_no_bundled_txs_error": "Not enough bundled transactions for FIO address %1$s", "string_i_agree": "I Agree", + "string_expires": "Expires", "string_decline": "Decline", "string_cancel_cap": "Abbrechen", "string_cancel": "ABBRECHEN", @@ -1089,7 +1090,9 @@ "fiat_plugin_sell_currencycode_s": "Sell %s", "fiat_plugin_amount_currencycode": "Amount %s", "fiat_plugin_buy_amount_over_limit": "Max purchase amount is %s", + "fiat_plugin_buy_amount_over_undef_limit": "Purchase amount is over maximum", "fiat_plugin_buy_amount_under_limit": "Minimum purchase amount is %s", + "fiat_plugin_buy_amount_under_undef_limit": "Purchase amount is under minimum", "fiat_plugin_asset_unsupported": "Asset Unsupported", "fiat_plugin_payment_unsupported": "Payment Method Unsupported", "fiat_plugin_buy_region_restricted": "Region restricted from purchasing %s", @@ -1326,24 +1329,40 @@ "getting_started_welcome_prompt": "Swipe to Learn More", "getting_started_welcome_title": "Welcome to\nFinancial *Freedom*", "app_logo_hint": "App logo", - "rewards_card_getting_invoice": "Getting payment invoice", + "check_icon_hint": "Confirmed", + "close_control_panel_hint": "Close control panel", + "close_hint": "Close", + "create_wallet_hint": "Create Wallet %s", + "edit_icon_hint": "Edit", + "import_key_icon_hint": "Import Key", + "modal_close_hint": "Close modal", + "off_hint": "Off", + "on_hint": "On", + "sort_wallets_hint": "Sort Wallets", + "spinner_hint": "Loading", + "toggle_button_hint": "Toggle", + "wallet_settings_label": "Wallet settings", "rewards_card_error_retrieving_cards": "Error retrieving Visa cards. Please try again later.", - "rewards_card_error_authenticate": "Error authenticating with Visa Card program. Please try again later.", - "rewards_card_error_timeout_loading": "Timeout error loading Visa Card program. Please try again later.", - "rewards_card_purchase_successful": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", + "rewards_card_error_authenticate": "Error authenticating with Visa® Card program. Please try again later.", + "rewards_card_error_timeout_loading": "Timeout error loading Visa® Card program. Please try again later.", + "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", + "rewards_card_purchase_disclaimer": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", "rewards_card_loading": "Loading your Visa® Cards...", "rewards_card_add_new_input_amount_title": "Buy Visa® Card", "rewards_card_welcome_intro": "Purchase Visa® prepaid cards that can be used at millions of merchants in the U.S. Cards can be purchased up to $1,000 in value, with a daily limit of $10,000.", - "rewards_card_welcome_more_info": "Learn More", - "rewards_card_new_card_button_label": "Buy New Card", - "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", - "rewards_card_dashboard_expires_label": "Expires", "rewards_card_dashboard_title": "Visa® Card Program", - "rewards_card_delete_modal_title": "Delete Card?", - "rewards_card_delete_modal_message_s": "Are you sure you want to delete the Visa® Card with expiration?\n\n%s", - "rewards_card_error_missing_payment_address": "Missing payment address from provider", - "rewards_card_error_amount_max_s": "Maximum card purchase amount is $%s", - "rewards_card_error_amount_min_s": "Minimum card purchase amount is $%s", - "rewards_card_select_wallet": "Select wallet to use to purchase card", - "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds." + "rewards_card_delete_modal_message": "Are you sure you want to delete this Visa® Card?", + "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds.", + "buy_new_card_button": "Buy New Card", + "card_amount_max_error_message_s": "Maximum card purchase amount is $%s", + "card_amount_min_error_message_s": "Minimum card purchase amount is $%s", + "delete_card_confirmation_title": "Delete Card?", + "getting_payment_invoice_message": "Getting payment invoice", + "learn_more_button": "Learn More", + "missing_provider_payment_address_message": "Missing payment address from provider", + "no_active_cards_message": "You have no active cards.", + "purchase_asset_label": "Purchase Asset", + "purchase_date_label": "Purchase Date", + "purchase_price_label": "Purchase Price", + "select_wallet_to_purchase_card_title": "Select wallet to use to purchase card" } \ No newline at end of file From 058a2519d331ef6836a4c49af6a15fadad168287 Mon Sep 17 00:00:00 2001 From: Paul V Puey Date: Wed, 7 Jun 2023 11:23:23 -0700 Subject: [PATCH 082/104] New translations enUS.json (Italian) --- src/locales/strings/it.json | 49 +++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/src/locales/strings/it.json b/src/locales/strings/it.json index 356b594e69b..d2e996c50ca 100644 --- a/src/locales/strings/it.json +++ b/src/locales/strings/it.json @@ -402,6 +402,7 @@ "staking_no_fio_address_error": "Impossibile fare stake senza un indirizzo FIO", "staking_no_bundled_txs_error": "Transazioni in bundle non sufficienti per l'indirizzo FIO %1$s", "string_i_agree": "Accetto", + "string_expires": "Scadenza", "string_decline": "Rifiuto", "string_cancel_cap": "Annulla", "string_cancel": "ANNULLA", @@ -1089,7 +1090,9 @@ "fiat_plugin_sell_currencycode_s": "Vendi %s", "fiat_plugin_amount_currencycode": "Importo: %s", "fiat_plugin_buy_amount_over_limit": "La quantità massima di acquisto è %s", + "fiat_plugin_buy_amount_over_undef_limit": "L'importo inserito è superiore al massimo", "fiat_plugin_buy_amount_under_limit": "L'importo minimo d'acquisto è %s", + "fiat_plugin_buy_amount_under_undef_limit": "L'importo inserito è inferiore al minimo", "fiat_plugin_asset_unsupported": "Asset non supportato", "fiat_plugin_payment_unsupported": "Metodo di pagamento non supportato", "fiat_plugin_buy_region_restricted": "Località limitata per l'acquisto di %s", @@ -1326,24 +1329,40 @@ "getting_started_welcome_prompt": "Scorri per saperne di più", "getting_started_welcome_title": "Benvenuti nella\n*libertà* finanziaria", "app_logo_hint": "App logo", - "rewards_card_getting_invoice": "Ottengo la fattura di pagamento", + "check_icon_hint": "Confirmed", + "close_control_panel_hint": "Close control panel", + "close_hint": "Close", + "create_wallet_hint": "Create Wallet %s", + "edit_icon_hint": "Edit", + "import_key_icon_hint": "Import Key", + "modal_close_hint": "Close modal", + "off_hint": "Off", + "on_hint": "On", + "sort_wallets_hint": "Ordina Portafogli", + "spinner_hint": "Caricamento", + "toggle_button_hint": "Toggle", + "wallet_settings_label": "Impostazioni portafoglio", "rewards_card_error_retrieving_cards": "Errore nel recupero delle carte Visa. Riprova più tardi.", - "rewards_card_error_authenticate": "Errore nell'autenticazione con il programma Visa Card. Riprova più tardi.", - "rewards_card_error_timeout_loading": "Errore nel caricamento del programma Visa Card. Riprova più tardi.", - "rewards_card_purchase_successful": "Acquisto carta riuscito!\n\nNota che le nuove carte acquistate impiegano alcuni secondi per diventare disponibili. \n\nLe carte acquistate con Bitcoin richiedono 1 conferma e potrebbero richiedere 10-30 minuti per diventare disponibili.", + "rewards_card_error_authenticate": "Errore di autenticazione con il programma Visa®️ card. Riprova più tardi.", + "rewards_card_error_timeout_loading": "Errore nel caricamento del programma Visa® Card. Riprova più tardi.", + "rewards_card_call_to_action": "Acquista Carte Prepagate Visa®️", + "rewards_card_purchase_disclaimer": "Acquisto carta riuscito!\n\nLe nuove carte acquistate impiegano alcuni secondi per diventare disponibili. \n\nLe carte acquistate con Bitcoin richiedono 1 conferma e potrebbero richiedere 10-30 minuti per diventare disponibili.", "rewards_card_loading": "Caricamento delle tue carte Visa®...", "rewards_card_add_new_input_amount_title": "Acquista Carta Visa®️", "rewards_card_welcome_intro": "Acquista carte prepagate Visa®️ che possono essere utilizzate presso milioni di commercianti in Usa. Puoi acquistare carte per un valore massimo di $1.000 ciascuna, con un limite giornaliero di $10.000.", - "rewards_card_welcome_more_info": "Maggiori informazioni", - "rewards_card_new_card_button_label": "Acquista una nuova carta", - "rewards_card_call_to_action": "Acquista Carte Prepagate Visa®️", - "rewards_card_dashboard_expires_label": "Scadenza", "rewards_card_dashboard_title": "Programma Visa® Card", - "rewards_card_delete_modal_title": "Eliminare la carta?", - "rewards_card_delete_modal_message_s": "Sei sicuro di voler eliminare la scheda Visa®️ con scadenza?\n\n%s", - "rewards_card_error_missing_payment_address": "Indirizzo di pagamento mancante dal provider", - "rewards_card_error_amount_max_s": "L'importo massimo di acquisto della carta è $%s", - "rewards_card_error_amount_min_s": "L'importo minimo d'acquisto è %s", - "rewards_card_select_wallet": "Seleziona il portafoglio da usare per acquistare la carta", - "rewards_card_terms_of_use_message": "Rivedi i Termini d'Uso:\n\nComprendo che le carte virtuali tramite questo programma possono essere acquistate solo dagli utenti statunitensi.\n\nComprendo che le carte acquistate non sono soggette a rimborso." + "rewards_card_delete_modal_message": "Sei sicuro di voler eliminare questa carta Visa®️?", + "rewards_card_terms_of_use_message": "Rivedi i Termini d'Uso:\n\nComprendo che le carte virtuali tramite questo programma possono essere acquistate solo dagli utenti statunitensi.\n\nComprendo che le carte acquistate non sono soggette a rimborso.", + "buy_new_card_button": "Acquista una nuova carta", + "card_amount_max_error_message_s": "L'importo massimo di acquisto della carta è $%s", + "card_amount_min_error_message_s": "L'importo minimo d'acquisto è %s", + "delete_card_confirmation_title": "Eliminare la carta?", + "getting_payment_invoice_message": "Ottengo la fattura di pagamento", + "learn_more_button": "Maggiori informazioni", + "missing_provider_payment_address_message": "Indirizzo di pagamento mancante dal provider", + "no_active_cards_message": "Non hai carte attive.", + "purchase_asset_label": "Asset di acquisto", + "purchase_date_label": "Data di acquisto", + "purchase_price_label": "Prezzo di acquisto", + "select_wallet_to_purchase_card_title": "Seleziona il portafoglio da usare per acquistare la carta" } \ No newline at end of file From 95d6bbb33fb34d480d0d53049753e9074636b9c7 Mon Sep 17 00:00:00 2001 From: Paul V Puey Date: Wed, 7 Jun 2023 11:23:24 -0700 Subject: [PATCH 083/104] New translations enUS.json (Japanese) --- src/locales/strings/ja.json | 49 +++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/src/locales/strings/ja.json b/src/locales/strings/ja.json index 39985d93906..3648433a294 100644 --- a/src/locales/strings/ja.json +++ b/src/locales/strings/ja.json @@ -402,6 +402,7 @@ "staking_no_fio_address_error": "Unable to stake without a FIO addresses", "staking_no_bundled_txs_error": "Not enough bundled transactions for FIO address %1$s", "string_i_agree": "I Agree", + "string_expires": "Expires", "string_decline": "Decline", "string_cancel_cap": "キャンセル", "string_cancel": "キャンセル", @@ -1089,7 +1090,9 @@ "fiat_plugin_sell_currencycode_s": "Sell %s", "fiat_plugin_amount_currencycode": "Amount %s", "fiat_plugin_buy_amount_over_limit": "Max purchase amount is %s", + "fiat_plugin_buy_amount_over_undef_limit": "Purchase amount is over maximum", "fiat_plugin_buy_amount_under_limit": "Minimum purchase amount is %s", + "fiat_plugin_buy_amount_under_undef_limit": "Purchase amount is under minimum", "fiat_plugin_asset_unsupported": "Asset Unsupported", "fiat_plugin_payment_unsupported": "Payment Method Unsupported", "fiat_plugin_buy_region_restricted": "Region restricted from purchasing %s", @@ -1326,24 +1329,40 @@ "getting_started_welcome_prompt": "Swipe to Learn More", "getting_started_welcome_title": "Welcome to\nFinancial *Freedom*", "app_logo_hint": "App logo", - "rewards_card_getting_invoice": "Getting payment invoice", + "check_icon_hint": "Confirmed", + "close_control_panel_hint": "Close control panel", + "close_hint": "Close", + "create_wallet_hint": "Create Wallet %s", + "edit_icon_hint": "Edit", + "import_key_icon_hint": "Import Key", + "modal_close_hint": "Close modal", + "off_hint": "Off", + "on_hint": "On", + "sort_wallets_hint": "Sort Wallets", + "spinner_hint": "Loading", + "toggle_button_hint": "Toggle", + "wallet_settings_label": "Wallet settings", "rewards_card_error_retrieving_cards": "Error retrieving Visa cards. Please try again later.", - "rewards_card_error_authenticate": "Error authenticating with Visa Card program. Please try again later.", - "rewards_card_error_timeout_loading": "Timeout error loading Visa Card program. Please try again later.", - "rewards_card_purchase_successful": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", + "rewards_card_error_authenticate": "Error authenticating with Visa® Card program. Please try again later.", + "rewards_card_error_timeout_loading": "Timeout error loading Visa® Card program. Please try again later.", + "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", + "rewards_card_purchase_disclaimer": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", "rewards_card_loading": "Loading your Visa® Cards...", "rewards_card_add_new_input_amount_title": "Buy Visa® Card", "rewards_card_welcome_intro": "Purchase Visa® prepaid cards that can be used at millions of merchants in the U.S. Cards can be purchased up to $1,000 in value, with a daily limit of $10,000.", - "rewards_card_welcome_more_info": "Learn More", - "rewards_card_new_card_button_label": "Buy New Card", - "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", - "rewards_card_dashboard_expires_label": "Expires", "rewards_card_dashboard_title": "Visa® Card Program", - "rewards_card_delete_modal_title": "Delete Card?", - "rewards_card_delete_modal_message_s": "Are you sure you want to delete the Visa® Card with expiration?\n\n%s", - "rewards_card_error_missing_payment_address": "Missing payment address from provider", - "rewards_card_error_amount_max_s": "Maximum card purchase amount is $%s", - "rewards_card_error_amount_min_s": "Minimum card purchase amount is $%s", - "rewards_card_select_wallet": "Select wallet to use to purchase card", - "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds." + "rewards_card_delete_modal_message": "Are you sure you want to delete this Visa® Card?", + "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds.", + "buy_new_card_button": "Buy New Card", + "card_amount_max_error_message_s": "Maximum card purchase amount is $%s", + "card_amount_min_error_message_s": "Minimum card purchase amount is $%s", + "delete_card_confirmation_title": "Delete Card?", + "getting_payment_invoice_message": "Getting payment invoice", + "learn_more_button": "Learn More", + "missing_provider_payment_address_message": "Missing payment address from provider", + "no_active_cards_message": "You have no active cards.", + "purchase_asset_label": "Purchase Asset", + "purchase_date_label": "Purchase Date", + "purchase_price_label": "Purchase Price", + "select_wallet_to_purchase_card_title": "Select wallet to use to purchase card" } \ No newline at end of file From 2088c4df7c7e7415096cee27191bbcd520e13bf1 Mon Sep 17 00:00:00 2001 From: Paul V Puey Date: Wed, 7 Jun 2023 11:23:25 -0700 Subject: [PATCH 084/104] New translations enUS.json (Korean) --- src/locales/strings/ko.json | 49 +++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/src/locales/strings/ko.json b/src/locales/strings/ko.json index d62ab90f8be..19b1c70436a 100644 --- a/src/locales/strings/ko.json +++ b/src/locales/strings/ko.json @@ -402,6 +402,7 @@ "staking_no_fio_address_error": "Unable to stake without a FIO addresses", "staking_no_bundled_txs_error": "Not enough bundled transactions for FIO address %1$s", "string_i_agree": "I Agree", + "string_expires": "Expires", "string_decline": "Decline", "string_cancel_cap": "취소", "string_cancel": "취소", @@ -1089,7 +1090,9 @@ "fiat_plugin_sell_currencycode_s": "Sell %s", "fiat_plugin_amount_currencycode": "Amount %s", "fiat_plugin_buy_amount_over_limit": "Max purchase amount is %s", + "fiat_plugin_buy_amount_over_undef_limit": "Purchase amount is over maximum", "fiat_plugin_buy_amount_under_limit": "Minimum purchase amount is %s", + "fiat_plugin_buy_amount_under_undef_limit": "Purchase amount is under minimum", "fiat_plugin_asset_unsupported": "Asset Unsupported", "fiat_plugin_payment_unsupported": "Payment Method Unsupported", "fiat_plugin_buy_region_restricted": "Region restricted from purchasing %s", @@ -1326,24 +1329,40 @@ "getting_started_welcome_prompt": "Swipe to Learn More", "getting_started_welcome_title": "Welcome to\nFinancial *Freedom*", "app_logo_hint": "App logo", - "rewards_card_getting_invoice": "Getting payment invoice", + "check_icon_hint": "Confirmed", + "close_control_panel_hint": "Close control panel", + "close_hint": "Close", + "create_wallet_hint": "Create Wallet %s", + "edit_icon_hint": "Edit", + "import_key_icon_hint": "Import Key", + "modal_close_hint": "Close modal", + "off_hint": "Off", + "on_hint": "On", + "sort_wallets_hint": "Sort Wallets", + "spinner_hint": "Loading", + "toggle_button_hint": "Toggle", + "wallet_settings_label": "Wallet settings", "rewards_card_error_retrieving_cards": "Error retrieving Visa cards. Please try again later.", - "rewards_card_error_authenticate": "Error authenticating with Visa Card program. Please try again later.", - "rewards_card_error_timeout_loading": "Timeout error loading Visa Card program. Please try again later.", - "rewards_card_purchase_successful": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", + "rewards_card_error_authenticate": "Error authenticating with Visa® Card program. Please try again later.", + "rewards_card_error_timeout_loading": "Timeout error loading Visa® Card program. Please try again later.", + "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", + "rewards_card_purchase_disclaimer": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", "rewards_card_loading": "Loading your Visa® Cards...", "rewards_card_add_new_input_amount_title": "Buy Visa® Card", "rewards_card_welcome_intro": "Purchase Visa® prepaid cards that can be used at millions of merchants in the U.S. Cards can be purchased up to $1,000 in value, with a daily limit of $10,000.", - "rewards_card_welcome_more_info": "Learn More", - "rewards_card_new_card_button_label": "Buy New Card", - "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", - "rewards_card_dashboard_expires_label": "Expires", "rewards_card_dashboard_title": "Visa® Card Program", - "rewards_card_delete_modal_title": "Delete Card?", - "rewards_card_delete_modal_message_s": "Are you sure you want to delete the Visa® Card with expiration?\n\n%s", - "rewards_card_error_missing_payment_address": "Missing payment address from provider", - "rewards_card_error_amount_max_s": "Maximum card purchase amount is $%s", - "rewards_card_error_amount_min_s": "Minimum card purchase amount is $%s", - "rewards_card_select_wallet": "Select wallet to use to purchase card", - "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds." + "rewards_card_delete_modal_message": "Are you sure you want to delete this Visa® Card?", + "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds.", + "buy_new_card_button": "Buy New Card", + "card_amount_max_error_message_s": "Maximum card purchase amount is $%s", + "card_amount_min_error_message_s": "Minimum card purchase amount is $%s", + "delete_card_confirmation_title": "Delete Card?", + "getting_payment_invoice_message": "Getting payment invoice", + "learn_more_button": "Learn More", + "missing_provider_payment_address_message": "Missing payment address from provider", + "no_active_cards_message": "You have no active cards.", + "purchase_asset_label": "Purchase Asset", + "purchase_date_label": "Purchase Date", + "purchase_price_label": "Purchase Price", + "select_wallet_to_purchase_card_title": "Select wallet to use to purchase card" } \ No newline at end of file From 3dbe8506fb8d02003687f89a2f96907f261d2077 Mon Sep 17 00:00:00 2001 From: Paul V Puey Date: Wed, 7 Jun 2023 11:23:26 -0700 Subject: [PATCH 085/104] New translations enUS.json (Portuguese) --- src/locales/strings/pt.json | 49 +++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/src/locales/strings/pt.json b/src/locales/strings/pt.json index 0d95caf11fc..b25d530485f 100644 --- a/src/locales/strings/pt.json +++ b/src/locales/strings/pt.json @@ -402,6 +402,7 @@ "staking_no_fio_address_error": "Unable to stake without a FIO addresses", "staking_no_bundled_txs_error": "Not enough bundled transactions for FIO address %1$s", "string_i_agree": "I Agree", + "string_expires": "Expires", "string_decline": "Decline", "string_cancel_cap": "Cancelar", "string_cancel": "CANCELAR", @@ -1089,7 +1090,9 @@ "fiat_plugin_sell_currencycode_s": "Sell %s", "fiat_plugin_amount_currencycode": "Amount %s", "fiat_plugin_buy_amount_over_limit": "Max purchase amount is %s", + "fiat_plugin_buy_amount_over_undef_limit": "Purchase amount is over maximum", "fiat_plugin_buy_amount_under_limit": "Minimum purchase amount is %s", + "fiat_plugin_buy_amount_under_undef_limit": "Purchase amount is under minimum", "fiat_plugin_asset_unsupported": "Asset Unsupported", "fiat_plugin_payment_unsupported": "Payment Method Unsupported", "fiat_plugin_buy_region_restricted": "Region restricted from purchasing %s", @@ -1326,24 +1329,40 @@ "getting_started_welcome_prompt": "Swipe to Learn More", "getting_started_welcome_title": "Welcome to\nFinancial *Freedom*", "app_logo_hint": "App logo", - "rewards_card_getting_invoice": "Getting payment invoice", + "check_icon_hint": "Confirmed", + "close_control_panel_hint": "Close control panel", + "close_hint": "Close", + "create_wallet_hint": "Create Wallet %s", + "edit_icon_hint": "Edit", + "import_key_icon_hint": "Import Key", + "modal_close_hint": "Close modal", + "off_hint": "Off", + "on_hint": "On", + "sort_wallets_hint": "Sort Wallets", + "spinner_hint": "Loading", + "toggle_button_hint": "Toggle", + "wallet_settings_label": "Wallet settings", "rewards_card_error_retrieving_cards": "Error retrieving Visa cards. Please try again later.", - "rewards_card_error_authenticate": "Error authenticating with Visa Card program. Please try again later.", - "rewards_card_error_timeout_loading": "Timeout error loading Visa Card program. Please try again later.", - "rewards_card_purchase_successful": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", + "rewards_card_error_authenticate": "Error authenticating with Visa® Card program. Please try again later.", + "rewards_card_error_timeout_loading": "Timeout error loading Visa® Card program. Please try again later.", + "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", + "rewards_card_purchase_disclaimer": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", "rewards_card_loading": "Loading your Visa® Cards...", "rewards_card_add_new_input_amount_title": "Buy Visa® Card", "rewards_card_welcome_intro": "Purchase Visa® prepaid cards that can be used at millions of merchants in the U.S. Cards can be purchased up to $1,000 in value, with a daily limit of $10,000.", - "rewards_card_welcome_more_info": "Learn More", - "rewards_card_new_card_button_label": "Buy New Card", - "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", - "rewards_card_dashboard_expires_label": "Expires", "rewards_card_dashboard_title": "Visa® Card Program", - "rewards_card_delete_modal_title": "Delete Card?", - "rewards_card_delete_modal_message_s": "Are you sure you want to delete the Visa® Card with expiration?\n\n%s", - "rewards_card_error_missing_payment_address": "Missing payment address from provider", - "rewards_card_error_amount_max_s": "Maximum card purchase amount is $%s", - "rewards_card_error_amount_min_s": "Minimum card purchase amount is $%s", - "rewards_card_select_wallet": "Select wallet to use to purchase card", - "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds." + "rewards_card_delete_modal_message": "Are you sure you want to delete this Visa® Card?", + "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds.", + "buy_new_card_button": "Buy New Card", + "card_amount_max_error_message_s": "Maximum card purchase amount is $%s", + "card_amount_min_error_message_s": "Minimum card purchase amount is $%s", + "delete_card_confirmation_title": "Delete Card?", + "getting_payment_invoice_message": "Getting payment invoice", + "learn_more_button": "Learn More", + "missing_provider_payment_address_message": "Missing payment address from provider", + "no_active_cards_message": "You have no active cards.", + "purchase_asset_label": "Purchase Asset", + "purchase_date_label": "Purchase Date", + "purchase_price_label": "Purchase Price", + "select_wallet_to_purchase_card_title": "Select wallet to use to purchase card" } \ No newline at end of file From 0876c5054737781151b9e8617aa0395f0aed9c54 Mon Sep 17 00:00:00 2001 From: Paul V Puey Date: Wed, 7 Jun 2023 11:23:27 -0700 Subject: [PATCH 086/104] New translations enUS.json (Russian) --- src/locales/strings/ru.json | 49 +++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/src/locales/strings/ru.json b/src/locales/strings/ru.json index 38be56f1bc4..4f9c27f11af 100644 --- a/src/locales/strings/ru.json +++ b/src/locales/strings/ru.json @@ -402,6 +402,7 @@ "staking_no_fio_address_error": "Unable to stake without a FIO addresses", "staking_no_bundled_txs_error": "Not enough bundled transactions for FIO address %1$s", "string_i_agree": "I Agree", + "string_expires": "Expires", "string_decline": "Decline", "string_cancel_cap": "Отмена", "string_cancel": "ОТМЕНА", @@ -1089,7 +1090,9 @@ "fiat_plugin_sell_currencycode_s": "Sell %s", "fiat_plugin_amount_currencycode": "Amount %s", "fiat_plugin_buy_amount_over_limit": "Max purchase amount is %s", + "fiat_plugin_buy_amount_over_undef_limit": "Purchase amount is over maximum", "fiat_plugin_buy_amount_under_limit": "Minimum purchase amount is %s", + "fiat_plugin_buy_amount_under_undef_limit": "Purchase amount is under minimum", "fiat_plugin_asset_unsupported": "Asset Unsupported", "fiat_plugin_payment_unsupported": "Payment Method Unsupported", "fiat_plugin_buy_region_restricted": "Region restricted from purchasing %s", @@ -1326,24 +1329,40 @@ "getting_started_welcome_prompt": "Swipe to Learn More", "getting_started_welcome_title": "Welcome to\nFinancial *Freedom*", "app_logo_hint": "App logo", - "rewards_card_getting_invoice": "Getting payment invoice", + "check_icon_hint": "Confirmed", + "close_control_panel_hint": "Close control panel", + "close_hint": "Close", + "create_wallet_hint": "Create Wallet %s", + "edit_icon_hint": "Edit", + "import_key_icon_hint": "Import Key", + "modal_close_hint": "Close modal", + "off_hint": "Off", + "on_hint": "On", + "sort_wallets_hint": "Sort Wallets", + "spinner_hint": "Loading", + "toggle_button_hint": "Toggle", + "wallet_settings_label": "Wallet settings", "rewards_card_error_retrieving_cards": "Error retrieving Visa cards. Please try again later.", - "rewards_card_error_authenticate": "Error authenticating with Visa Card program. Please try again later.", - "rewards_card_error_timeout_loading": "Timeout error loading Visa Card program. Please try again later.", - "rewards_card_purchase_successful": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", + "rewards_card_error_authenticate": "Error authenticating with Visa® Card program. Please try again later.", + "rewards_card_error_timeout_loading": "Timeout error loading Visa® Card program. Please try again later.", + "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", + "rewards_card_purchase_disclaimer": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", "rewards_card_loading": "Loading your Visa® Cards...", "rewards_card_add_new_input_amount_title": "Buy Visa® Card", "rewards_card_welcome_intro": "Purchase Visa® prepaid cards that can be used at millions of merchants in the U.S. Cards can be purchased up to $1,000 in value, with a daily limit of $10,000.", - "rewards_card_welcome_more_info": "Learn More", - "rewards_card_new_card_button_label": "Buy New Card", - "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", - "rewards_card_dashboard_expires_label": "Expires", "rewards_card_dashboard_title": "Visa® Card Program", - "rewards_card_delete_modal_title": "Delete Card?", - "rewards_card_delete_modal_message_s": "Are you sure you want to delete the Visa® Card with expiration?\n\n%s", - "rewards_card_error_missing_payment_address": "Missing payment address from provider", - "rewards_card_error_amount_max_s": "Maximum card purchase amount is $%s", - "rewards_card_error_amount_min_s": "Minimum card purchase amount is $%s", - "rewards_card_select_wallet": "Select wallet to use to purchase card", - "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds." + "rewards_card_delete_modal_message": "Are you sure you want to delete this Visa® Card?", + "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds.", + "buy_new_card_button": "Buy New Card", + "card_amount_max_error_message_s": "Maximum card purchase amount is $%s", + "card_amount_min_error_message_s": "Minimum card purchase amount is $%s", + "delete_card_confirmation_title": "Delete Card?", + "getting_payment_invoice_message": "Getting payment invoice", + "learn_more_button": "Learn More", + "missing_provider_payment_address_message": "Missing payment address from provider", + "no_active_cards_message": "You have no active cards.", + "purchase_asset_label": "Purchase Asset", + "purchase_date_label": "Purchase Date", + "purchase_price_label": "Purchase Price", + "select_wallet_to_purchase_card_title": "Select wallet to use to purchase card" } \ No newline at end of file From 418a3ba386c9757d36bbf54a94b5708d3110b313 Mon Sep 17 00:00:00 2001 From: Paul V Puey Date: Wed, 7 Jun 2023 11:23:28 -0700 Subject: [PATCH 087/104] New translations enUS.json (Chinese Simplified) --- src/locales/strings/zh.json | 49 +++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/src/locales/strings/zh.json b/src/locales/strings/zh.json index 9feeef2260a..88792b5edb9 100644 --- a/src/locales/strings/zh.json +++ b/src/locales/strings/zh.json @@ -402,6 +402,7 @@ "staking_no_fio_address_error": "Unable to stake without a FIO addresses", "staking_no_bundled_txs_error": "Not enough bundled transactions for FIO address %1$s", "string_i_agree": "I Agree", + "string_expires": "Expires", "string_decline": "Decline", "string_cancel_cap": "取消", "string_cancel": "取消", @@ -1089,7 +1090,9 @@ "fiat_plugin_sell_currencycode_s": "Sell %s", "fiat_plugin_amount_currencycode": "Amount %s", "fiat_plugin_buy_amount_over_limit": "Max purchase amount is %s", + "fiat_plugin_buy_amount_over_undef_limit": "Purchase amount is over maximum", "fiat_plugin_buy_amount_under_limit": "Minimum purchase amount is %s", + "fiat_plugin_buy_amount_under_undef_limit": "Purchase amount is under minimum", "fiat_plugin_asset_unsupported": "Asset Unsupported", "fiat_plugin_payment_unsupported": "Payment Method Unsupported", "fiat_plugin_buy_region_restricted": "Region restricted from purchasing %s", @@ -1326,24 +1329,40 @@ "getting_started_welcome_prompt": "Swipe to Learn More", "getting_started_welcome_title": "Welcome to\nFinancial *Freedom*", "app_logo_hint": "App logo", - "rewards_card_getting_invoice": "Getting payment invoice", + "check_icon_hint": "Confirmed", + "close_control_panel_hint": "Close control panel", + "close_hint": "Close", + "create_wallet_hint": "Create Wallet %s", + "edit_icon_hint": "Edit", + "import_key_icon_hint": "Import Key", + "modal_close_hint": "Close modal", + "off_hint": "Off", + "on_hint": "On", + "sort_wallets_hint": "Sort Wallets", + "spinner_hint": "Loading", + "toggle_button_hint": "Toggle", + "wallet_settings_label": "Wallet settings", "rewards_card_error_retrieving_cards": "Error retrieving Visa cards. Please try again later.", - "rewards_card_error_authenticate": "Error authenticating with Visa Card program. Please try again later.", - "rewards_card_error_timeout_loading": "Timeout error loading Visa Card program. Please try again later.", - "rewards_card_purchase_successful": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", + "rewards_card_error_authenticate": "Error authenticating with Visa® Card program. Please try again later.", + "rewards_card_error_timeout_loading": "Timeout error loading Visa® Card program. Please try again later.", + "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", + "rewards_card_purchase_disclaimer": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", "rewards_card_loading": "Loading your Visa® Cards...", "rewards_card_add_new_input_amount_title": "Buy Visa® Card", "rewards_card_welcome_intro": "Purchase Visa® prepaid cards that can be used at millions of merchants in the U.S. Cards can be purchased up to $1,000 in value, with a daily limit of $10,000.", - "rewards_card_welcome_more_info": "Learn More", - "rewards_card_new_card_button_label": "Buy New Card", - "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", - "rewards_card_dashboard_expires_label": "Expires", "rewards_card_dashboard_title": "Visa® Card Program", - "rewards_card_delete_modal_title": "Delete Card?", - "rewards_card_delete_modal_message_s": "Are you sure you want to delete the Visa® Card with expiration?\n\n%s", - "rewards_card_error_missing_payment_address": "Missing payment address from provider", - "rewards_card_error_amount_max_s": "Maximum card purchase amount is $%s", - "rewards_card_error_amount_min_s": "Minimum card purchase amount is $%s", - "rewards_card_select_wallet": "Select wallet to use to purchase card", - "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds." + "rewards_card_delete_modal_message": "Are you sure you want to delete this Visa® Card?", + "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds.", + "buy_new_card_button": "Buy New Card", + "card_amount_max_error_message_s": "Maximum card purchase amount is $%s", + "card_amount_min_error_message_s": "Minimum card purchase amount is $%s", + "delete_card_confirmation_title": "Delete Card?", + "getting_payment_invoice_message": "Getting payment invoice", + "learn_more_button": "Learn More", + "missing_provider_payment_address_message": "Missing payment address from provider", + "no_active_cards_message": "You have no active cards.", + "purchase_asset_label": "Purchase Asset", + "purchase_date_label": "Purchase Date", + "purchase_price_label": "Purchase Price", + "select_wallet_to_purchase_card_title": "Select wallet to use to purchase card" } \ No newline at end of file From c44cb8c79caeec9c41888a5e8ba81a87c74d7627 Mon Sep 17 00:00:00 2001 From: Paul V Puey Date: Wed, 7 Jun 2023 11:23:30 -0700 Subject: [PATCH 088/104] New translations enUS.json (Vietnamese) --- src/locales/strings/vi.json | 49 +++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/src/locales/strings/vi.json b/src/locales/strings/vi.json index 003ac848c11..74a4d0b47d6 100644 --- a/src/locales/strings/vi.json +++ b/src/locales/strings/vi.json @@ -402,6 +402,7 @@ "staking_no_fio_address_error": "Unable to stake without a FIO addresses", "staking_no_bundled_txs_error": "Not enough bundled transactions for FIO address %1$s", "string_i_agree": "I Agree", + "string_expires": "Expires", "string_decline": "Decline", "string_cancel_cap": "Huỷ", "string_cancel": "HUỶ", @@ -1089,7 +1090,9 @@ "fiat_plugin_sell_currencycode_s": "Sell %s", "fiat_plugin_amount_currencycode": "Amount %s", "fiat_plugin_buy_amount_over_limit": "Max purchase amount is %s", + "fiat_plugin_buy_amount_over_undef_limit": "Purchase amount is over maximum", "fiat_plugin_buy_amount_under_limit": "Minimum purchase amount is %s", + "fiat_plugin_buy_amount_under_undef_limit": "Purchase amount is under minimum", "fiat_plugin_asset_unsupported": "Asset Unsupported", "fiat_plugin_payment_unsupported": "Payment Method Unsupported", "fiat_plugin_buy_region_restricted": "Region restricted from purchasing %s", @@ -1326,24 +1329,40 @@ "getting_started_welcome_prompt": "Swipe to Learn More", "getting_started_welcome_title": "Welcome to\nFinancial *Freedom*", "app_logo_hint": "App logo", - "rewards_card_getting_invoice": "Getting payment invoice", + "check_icon_hint": "Confirmed", + "close_control_panel_hint": "Close control panel", + "close_hint": "Close", + "create_wallet_hint": "Create Wallet %s", + "edit_icon_hint": "Edit", + "import_key_icon_hint": "Import Key", + "modal_close_hint": "Close modal", + "off_hint": "Off", + "on_hint": "On", + "sort_wallets_hint": "Sort Wallets", + "spinner_hint": "Loading", + "toggle_button_hint": "Toggle", + "wallet_settings_label": "Wallet settings", "rewards_card_error_retrieving_cards": "Error retrieving Visa cards. Please try again later.", - "rewards_card_error_authenticate": "Error authenticating with Visa Card program. Please try again later.", - "rewards_card_error_timeout_loading": "Timeout error loading Visa Card program. Please try again later.", - "rewards_card_purchase_successful": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", + "rewards_card_error_authenticate": "Error authenticating with Visa® Card program. Please try again later.", + "rewards_card_error_timeout_loading": "Timeout error loading Visa® Card program. Please try again later.", + "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", + "rewards_card_purchase_disclaimer": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", "rewards_card_loading": "Loading your Visa® Cards...", "rewards_card_add_new_input_amount_title": "Buy Visa® Card", "rewards_card_welcome_intro": "Purchase Visa® prepaid cards that can be used at millions of merchants in the U.S. Cards can be purchased up to $1,000 in value, with a daily limit of $10,000.", - "rewards_card_welcome_more_info": "Learn More", - "rewards_card_new_card_button_label": "Buy New Card", - "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", - "rewards_card_dashboard_expires_label": "Expires", "rewards_card_dashboard_title": "Visa® Card Program", - "rewards_card_delete_modal_title": "Delete Card?", - "rewards_card_delete_modal_message_s": "Are you sure you want to delete the Visa® Card with expiration?\n\n%s", - "rewards_card_error_missing_payment_address": "Missing payment address from provider", - "rewards_card_error_amount_max_s": "Maximum card purchase amount is $%s", - "rewards_card_error_amount_min_s": "Minimum card purchase amount is $%s", - "rewards_card_select_wallet": "Select wallet to use to purchase card", - "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds." + "rewards_card_delete_modal_message": "Are you sure you want to delete this Visa® Card?", + "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds.", + "buy_new_card_button": "Buy New Card", + "card_amount_max_error_message_s": "Maximum card purchase amount is $%s", + "card_amount_min_error_message_s": "Minimum card purchase amount is $%s", + "delete_card_confirmation_title": "Delete Card?", + "getting_payment_invoice_message": "Getting payment invoice", + "learn_more_button": "Learn More", + "missing_provider_payment_address_message": "Missing payment address from provider", + "no_active_cards_message": "You have no active cards.", + "purchase_asset_label": "Purchase Asset", + "purchase_date_label": "Purchase Date", + "purchase_price_label": "Purchase Price", + "select_wallet_to_purchase_card_title": "Select wallet to use to purchase card" } \ No newline at end of file From fff4f14a598b3bb1773b46a6e555c77590589cb4 Mon Sep 17 00:00:00 2001 From: Paul V Puey Date: Wed, 7 Jun 2023 11:23:31 -0700 Subject: [PATCH 089/104] New translations enUS.json (Spanish, Mexico) --- src/locales/strings/es.json | 382 ++++++++++++++++++------------------ 1 file changed, 191 insertions(+), 191 deletions(-) diff --git a/src/locales/strings/es.json b/src/locales/strings/es.json index 230743485dd..c27c61413f3 100644 --- a/src/locales/strings/es.json +++ b/src/locales/strings/es.json @@ -1,121 +1,121 @@ { - "action_queue_display_unknown_title": "Unknown action", - "action_queue_display_unknown_message": "Edge is unable to identify the type of action being completed.", - "aciton_queue_display_close_title": "Closing Loan", + "action_queue_display_unknown_title": "Acción desconocida", + "action_queue_display_unknown_message": "Edge no puede identificar el tipo de acción que se está completando.", + "aciton_queue_display_close_title": "Cerrando préstamo", "action_queue_display_close_message": "Edge is paying principal in full and withdrawing the remaining collateral.", - "action_queue_display_seq_title": "Action steps", - "action_queue_display_seq_message": "Doing a sequence of actions.", - "action_queue_display_par_title": "Action group", - "action_queue_display_par_message": "Doing multiple actions at once.", - "action_queue_display_fiat_buy_title": "Purchase %s", - "action_queue_display_fiat_buy_message": "Purchase %1$s from %3$s.", - "action_queue_display_fiat_sell_title": "Deposit funds to bank", + "action_queue_display_seq_title": "Pasos de acción", + "action_queue_display_seq_message": "Hacer una secuencia de acciones.", + "action_queue_display_par_title": "Grupo de acción", + "action_queue_display_par_message": "Realizando múltiples acciones a la vez.", + "action_queue_display_fiat_buy_title": "Compra %s", + "action_queue_display_fiat_buy_message": "Compra %1$s de %3$s.", + "action_queue_display_fiat_sell_title": "Depositar fondos a banco", "action_queue_display_fiat_sell_message": "Your %1$s is being sold by our partners and deposited into your bank account through %2$s.", - "action_queue_display_loan_borrow_title": "Take out loan", - "action_queue_display_loan_borrow_message_1s": "A %1$s loan has been requested and is on its way to your wallet.", - "action_queue_display_loan_deposit_title": "Depositing %1$s as collateral", + "action_queue_display_loan_borrow_title": "Obtener préstamo", + "action_queue_display_loan_borrow_message_1s": "Un préstamo de %1$s ha sido solicitado y está en camino a tu billetera.", + "action_queue_display_loan_deposit_title": "Depositando %1$s como colateral", "action_queue_display_loan_deposit_message": "Edge has sent your %1$s tokens to %2$s and is awaiting confirmation of the transfer.", - "action_queue_display_loan_repay_title": "Repay loan principal", - "action_queue_display_loan_repay_message": "Make a payment towards your loan principal.", - "action_queue_display_loan_repay_with_collateral_title": "Repay loan principal with collateral", + "action_queue_display_loan_repay_title": "Pagar préstamo principal", + "action_queue_display_loan_repay_message": "Hacer un pago a su préstamo principal.", + "action_queue_display_loan_repay_with_collateral_title": "Pagar el principal del préstamo con el colateral", "action_queue_display_loan_repay_with_collateral_message": "Make a payment towards your loan principal using your collateral on AAVE.", - "action_queue_display_loan_withdraw_title": "Withdraw collateral from loan", - "action_queue_display_loan_withdraw_message": "Withdraw %1$s from loan.", - "action_queue_display_swap_title": "Swap %1$s into %2$s", + "action_queue_display_loan_withdraw_title": "Retirar el colateral del préstamo", + "action_queue_display_loan_withdraw_message": "Retirar %1$s del préstamo.", + "action_queue_display_swap_title": "Intercambiar %1$s a %2$s", "action_queue_display_swap_message": "To use %1$s as collateral, %2$s must swap %1$s into %3$s to put it on the same network as %4$s (%5$s).", - "action_queue_push_notification_title": "Action Complete", - "action_queue_push_notification_body": "Edge has completed processing your loan operation.", - "action_display_title_create": "Creating Loan", - "action_display_title_swap": "Swapping Funds", - "action_display_message_create_3s": "%1$s is creating your loan on %2$s using your %3$s as collateral", + "action_queue_push_notification_title": "Acción completada", + "action_queue_push_notification_body": "Edge ha completado el procesamiento de su operación de préstamo.", + "action_display_title_create": "Creando préstamo", + "action_display_title_swap": "Intercambiando fondos", + "action_display_message_create_3s": "%1$s está creando su préstamo en %2$s usando su %3$s como colateral", "action_display_message_swap_4s": "%1$s is swapping your %2$s into %3$s for deposit into %4$s. This may take a few mins to several hours…", "action_display_message_swap_fees_5s": "%1$s is swapping your %2$s into %3$s and %4$s (to pay fees) for deposit into %5$s. This may take a few mins to several hours…", - "action_display_title_complete_default": "Congratulations!", + "action_display_title_complete_default": "Felicitaciones!", "action_display_message_complete_default": "Your transactions completed successfully!\nPlease allow time for your accounts to update.", "action_display_message_complete_wallet_2s": "Your loan is complete! \nYou should see %1$s in your %2$s account", "action_display_message_complete_bank": "Your loan is complete! \nYou should see funds in your bank account in 1-4 days", - "bitpay_metadata_name": "Invoice ID: %s", + "bitpay_metadata_name": "Factura #: %s", "bitcoin_received": "Has recibido %1$s", - "dialog_title": "Fijar tiempo para desconexión automática", + "dialog_title": "Auto cierre de sesión", "share_subject": "Hola, creo que deberías probar %s", - "share_message": "Puedes comprar, almacenar y operar con decenas de criptomonedas en una sola aplicación.", - "drawer_borrow_dollars": "Borrow Dollars", - "drawer_exchange_rate_loading": "Cargando tipo de cambio", - "drawer_exchange": "Exchange", - "drawer_scan_qr_send": "Scan QR", - "drawer_sweep_private_key": "Barrer clave privada (Sweep Pk)", + "share_message": "Puedes comprar, guardar y intercambiar con decenas de criptomonedas en una sola aplicación.", + "drawer_borrow_dollars": "Pedir prestado dolares", + "drawer_exchange_rate_loading": "Cargando Tipo de Cambio", + "drawer_exchange": "Intercambio", + "drawer_scan_qr_send": "Escanear Código QR", + "drawer_sweep_private_key": "Retirar clave privada (Sweep Pk)", "drawer_fio_names": "Nombres FIO", "drawer_fio_requests": "Solicitudes FIO", "network_alert_title": "Sin conexión a Internet", "fio_network_alert_text": "La funcionalidad FIO requiere conexión a Internet.", - "fio_address_choose_label": "Choose a FIO Crypto Handle", + "fio_address_choose_label": "Elige un ususario para FIO", "fio_domain_choose_label": "Elegir un dominio FIO", - "fio_address_choose_domain_label": "Choose FIO Domain for Your Crypto Handle", + "fio_address_choose_domain_label": "Elige un dominio FIO para tu ususario", "scan_qr_label": "Escanear código QR", - "error_paymentprotocol_empty_output_invoice": "Received no output in payment request", - "error_paymentprotocol_empty_verification_hex_req": "Generated empty transaction hex(es)", + "error_paymentprotocol_empty_output_invoice": "No se ha recibido respuesta en la solicitud de pago", + "error_paymentprotocol_empty_verification_hex_req": "Generado hex(s) de transacción vacía", "error_paymentprotocol_currency_not_supported": "Payment Protocol invoice payments in %s not currently supported. Please choose another payment currency.", "error_paymentprotocol_invalid_payment_option": "Payment Protocol invoice does not accept this currency. Accepted currencies: %s", - "error_paymentprotocol_fetch": "Payment Protocol %s fetch error (%s)%s", - "error_paymentprotocol_multi_output_invoice": "Multiple outputs found in payment request", - "error_paymentprotocol_multi_tx_invoice": "Multiple transactions found in payment request", + "error_paymentprotocol_fetch": "Error de búsqueda (%s)%s del protocolo de pago %s", + "error_paymentprotocol_multi_output_invoice": "Múltiples resultados encontradas en la solicitud de pago", + "error_paymentprotocol_multi_tx_invoice": "Múltiples transacciones encontradas en la solicitud de pago", "error_paymentprotocol_no_payment_option": "No currencies available for this Payment Protocol invoice. Accepted currencies: %s", - "error_paymentprotocol_tx_verification_failed": "Payment Protocol transaction verification mismatch", + "error_paymentprotocol_tx_verification_failed": "La verificación de la transacción del protocolo de pago no coincide", "error_spend_amount_less_then_min_s": "Spend amount is less than minimum of %s", "warning_low_fee_selected": "Tarifa baja seleccionada", "warning_custom_fee_selected": "Tarifa personalizada seleccionada", "warning_low_or_custom_fee": "Usar una comisión baja puede aumentar la cantidad de tiempo que tarda en confirmar tu transacción. En raras ocasiones tu transacción puede fallar.", "warning_alphanumeric": "Sólo se permiten letras y números", - "warning_please_wait_title": "Please Wait", - "warning_scam_title": "Scam Warning", - "warning_scam_message_financial_advice": "Edge will not give financial advice.", - "warning_scam_message_irreversibility": "Cryptocurrency transactions are irreversible.", - "warning_scam_message_unknown_recipients": "Do not send money to people or organizations you do not know.", - "warning_scam_footer": "If you have any questions or concerns regarding this send please contact support@edge.app", + "warning_please_wait_title": "Por favor espere", + "warning_scam_title": "Advertencia de Estafa", + "warning_scam_message_financial_advice": "Edge no te dará asesoramiento financiero.", + "warning_scam_message_irreversibility": "Las transacciones con criptomonedas son irreversibles.", + "warning_scam_message_unknown_recipients": "No envíes dinero a personas u organizaciones que no concoces.", + "warning_scam_footer": "Si tienes alguna pregunta o duda relacionada con este envío, por favor contacta a support@edge.app", "alert_dropdown_alert": "¡Alerta! ", "alert_dropdown_warning": "¡Advertencia! ", "azteco_success": "Has canjeado una tarjeta de bitcoin Azteco. Los fondos deberían llegar pronto.", - "azteco_invalid_code": "Código Azteco incorrecto.", - "azteco_service_unavailable": "Error contactando con el servidor de Azteco. Por favor, inténtalo de nuevo más tarde.", + "azteco_invalid_code": "Código Azteco inválido.", + "azteco_service_unavailable": "Error contactando con el servidor Azteco. Por favor, inténtalo de nuevo más tarde.", "reqaddr_error_unsupported_chains": "%1$s does not support the following chains listed in the request: %2$s", - "reqaddr_error_invalid_redir": "Invalid 'redir' query in request for payment address", - "reqaddr_error_no_currencies_found": "No currencies found in request for payment address", - "reqaddr_error_no_wallets_selected": "No wallets selected for request for payment address", - "reqaddr_error_post_redir": "Post and redir address not found in request for payment address", - "reqaddr_application_fragment": "An application", - "reqaddr_confirm_modal_title": "Confirm request?", + "reqaddr_error_invalid_redir": "Consulta 'redir' inválida en la solicitud de dirección de pago", + "reqaddr_error_no_currencies_found": "No se encontraron divisas en la solicitud de dirección de pago", + "reqaddr_error_no_wallets_selected": "No hay monederos seleccionados para la solicitud de dirección de pago", + "reqaddr_error_post_redir": "Dirección de publicación y redirección no encontrada en la solicitud de dirección de pago", + "reqaddr_application_fragment": "Una solicitud", + "reqaddr_confirm_modal_title": "Confirmar solicitud?", "reqaddr_confirm_modal_message": "%1$s is requesting a payment address for %2$s. Choose wallets for request?", - "max_spend_unavailable_modal_title": "Gasto máximo no disponible", + "max_spend_unavailable_modal_title": "Gasto Máximo No Disponible", "max_spend_unavailable_modal_message": "No podemos calcular la cantidad máxima disponible para la moneda %s. Por favor introduce una cantidad.", "access_wallet_description": "This application would like to create or access its wallet in your %1$s account.\n\n It will not have access to any other wallets.", "edge_description_warning": "The \"%1$s\" application is requesting full access to your account and all wallets. \n\nOnly accept this login request if you trust this application and where it was downloaded from.", - "exchange_failed": "No se pudo completar el cambio", + "exchange_failed": "No se pudo completar el intercambio", "exchange_congratulations": "¡ Felicidades!", "exchange_congratulations_msg": "¡Tu intercambio se ha completado con éxito!", "exchange_congratulations_msg_info": "Los intercambios pueden tardar entre unos minutos y hasta 24 horas en procesarse.", "no_exchange_amount": "Ninguna cantidad seleccionada", "exchange_asset_unsupported": "%s unsupported at this time. Please try again later.", - "select_exchange_amount": "Introduce una cantidad para cambiar", - "select_exchange_amount_short": "Introduce una cantidad", + "select_exchange_amount": "Ingresa una cantidad para intercambiar", + "select_exchange_amount_short": "Ingresa Monto", "fragment_wallets_addwallet_fiat_hint": "Elije una moneda fiat", "managetokens_top_instructions": "Seleccionar tokens para mostrar en la cartera:", "accept_button_text": "Aceptar", - "addtoken_contract_address_input_text": "Dirección del smart contract", + "addtoken_contract_address_input_text": "Dirección del contrato", "addtoken_currency_code_input_text": "Código del token", - "addtoken_invalid_information": "Por favor introduzca la información del token correcta e inténtelo de nuevo", + "addtoken_invalid_information": "Por favor ingresa la información del token correcta e inténtelo de nuevo", "addtoken_denomination_input_text": "Número de decimales", "addtoken_name_input_text": "Nombre del token", "addtoken_add": "Añadir token personalizado", "edittoken_delete_token": "Borrar token", "edittoken_delete_prompt": "¿Seguro que quieres eliminar este token?", - "edittoken_invalid_decimal_places": "Introduce un número de decimales válido por favor.", + "edittoken_invalid_decimal_places": "Ingresa un número de decimales válido por favor.", "fragment_create_wallet_create_wallet": "Crear cartera", - "fragment_create_wallet_instructions": "Tap on wallet to edit name", + "fragment_create_wallet_instructions": "Pulse en el monedero para editar el nombre", "fragment_create_wallet_select_valid": "Seleccione datos válidos por favor", "fragment_request_copy_title": "Copiar", - "fragment_request_subtitle": "Receive", + "fragment_request_subtitle": "Recibir", "fragment_request_address_uri_copied": "Request address URI copied to clipboard", - "fragment_copied": "¡Copiado correctamente en el portapapeles", + "fragment_copied": "Copiado correctamente en el portapapeles", "request_minimum_notification_title": "Saldo mínimo requerido", "request_xrp_minimum_notification_body": "Ripple (XRP) wallets require a 10 XRP minimum balance. You must deposit at least 10 XRP to this address before this wallet will show a balance or transactions. 10 XRP will be unspendable for the lifetime of this wallet address.", "request_xrp_minimum_notification_alert_body": "This wallet will always require a 10 XRP minimum", @@ -130,32 +130,32 @@ "scan_invalid_address_error_title": "Dirección Inválida", "scan_invalid_address_error_description": "No es una dirección pública válida", "fragment_send_subtitle": "Enviar", - "fragment_send_myself": "Myself", + "fragment_send_myself": "A mí", "fragment_send_from_label": "De", - "fragment_stake_label": "Stake", - "fragment_transaction_exchange": "Exchange", + "fragment_stake_label": "Bloqueo (Stake)", + "fragment_transaction_exchange": "Intercambiar", "fragment_transaction_expense": "Gasto", "fragment_transaction_income": "Ingreso", "fragment_transaction_list_receive_prefix": "Recibido ", "fragment_transaction_list_sent_prefix": "Enviado ", "fragment_transaction_transfer": "Transferir", "fragment_wallet_unconfirmed": "Pendiente", - "fragment_transaction_list_tx_dropped": "Cancelada", + "fragment_transaction_list_tx_dropped": "Descartado", "fragment_transaction_list_tx_synchronizing": "Sincronizando", "fragment_transaction_list_confirmation_progress": "%s de %s confirmaciones", - "fragment_transaction_list_unconfirmed_rbf": "Awaiting confirmation, may be cancelled", + "fragment_transaction_list_unconfirmed_rbf": "Esperando confirmación, puede ser cancelado", "fragment_transaction_list_transaction": "Transacciones", "transaction_list_buy_crypto_message": "Comprar %s", - "transaction_list_no_tx_yet": "No transactions yet", - "transaction_list_no_tx_support_yet": "Transaction history is not yet supported", + "transaction_list_no_tx_yet": "Aún no hay transacciones", + "transaction_list_no_tx_support_yet": "El historial de transacciones aún no está soportado", "transaction_list_search": "Buscar Transacciones", "transaction_list_search_no_result": "No se han encontrado resultados para tu búsqueda", - "fragment_wallets_balance_text": "Balance total", + "fragment_wallets_balance_text": "Saldo Total", "fragment_wallets_delete_wallet": "Archivar cartera", "fragment_wallets_resync_wallet": "Resincronizar la cartera", "fragment_wallets_split_wallet": "Dividir la cartera", - "fragment_wallets_copy_seed": "Copy Seed", - "fragment_wallets_copied_seed": "Copied Seed", + "fragment_wallets_copy_seed": "Copiar semilla", + "fragment_wallets_copied_seed": "Semilla copiada", "fragment_wallets_get_seed_wallet": "Obtener la semilla", "fragment_wallets_view_private_view_key": "Private View Key", "fragment_wallets_view_private_view_key_warning": "The private view key allows the receiver to see the balance in your Monero wallet. Do not share this key unless necessary, such as for tax purposes, accounting, or similar reasons.", @@ -163,31 +163,31 @@ "fragment_wallets_pubkey_copied_title": "Dirección XPub copiada", "fragment_wallets_export_transactions": "Exportar transacciones", "fragment_wallets_rename_wallet": "Renombrar cartera", - "fragment_wallets_resync_wallet_first_confirm_message_mobile": "¿Estás seguro de que quieres resincronizar?", + "fragment_wallets_resync_wallet_first_confirm_message_mobile": "¿Estás seguro de que quieres resincronizar?\n", "fragment_wallets_split_wallet_bch_to_bsv": "Estás a punto de dividir tu cartera BCH y crear una nueva cartera BSV desde tus claves privadas de BCH. Esto requiere una transacción de BCH para proteger tus fondos de un gasto no intencionado en la cadena incorrecta. Esto generará un pequeño coste de transacción en la cartera BCH. Por favor asegúrate de que esta transacción inicial se confirma antes de hacer más transacciones con BCH. Estás seguro de que quieres dividir\n", - "fragment_wallets_split_wallet_first_confirm_message_mobile": "¿Estás seguro de que quieres partir la cartera? (Wallet split)", - "fragment_wallets_get_seed_title": "Reveal Master Private Key", + "fragment_wallets_split_wallet_first_confirm_message_mobile": "¿Estás seguro de que quieres partir la cartera? (Wallet split)\n", + "fragment_wallets_get_seed_title": "Mostrar clave privada maestra", "fragment_wallets_get_seed_warning_message": "Sharing your master private key may put you at risk of fraudulent tokens and loss of funds.\n\nDo not share your key with anyone.\n\nBy entering your password, you are confirming that you understand the risks.", - "fragment_wallets_get_raw_keys_title": "Reveal Raw Keys", + "fragment_wallets_get_raw_keys_title": "Revelar llaves de origen", "fragment_wallets_get_raw_keys_warning_message": "Sharing your raw keys may put you at risk of fraudulent tokens and loss of funds.\n\nDo not share your keys with anyone.\n\nBy entering your password, you are confirming that you understand the risks.", "fragmet_wallets_delete_wallet_first_confirm_message_mobile": "¿Está seguro de que desea archivar ", "fragmet_wallets_delete_fio_extra_message_mobile": "Eliminar esta cartera FIO eliminará el acceso a cualquier dirección FIO que hayas vinculado a esta cartera.", "fragmet_wallets_delete_eth_extra_message": "Archivar esta cartera también archivará cualquier token habilitado para esta cartera.", - "wallet_list_add_wallet": "Crear cartera", + "wallet_list_add_wallet": "Añadir cartera", "wallet_list_add_token": "Añadir token", "wallet_list_referral_link_currency_invalid": "La moneda a crear no es válida", "wallet_list_referral_link_currency_loading": "Un momento. Creando la cartera necesaria para esta promoción", "wallet_list_referral_link_ask_wallet_creation": "Necesitas una cartera de %s para esta promoción. ¿Quieres crear una?", "wallet_list_referral_link_cancelled_wallet_creation": "El usuario no aprobó la creación de una cartera para la promoción", "wallet_list_wallet_search": "Buscar carteras", - "compromised_key_label": "Compromised Key", + "compromised_key_label": "Lave comprometida", "create_wallet_choice_new_button": "Crear nueva cartera", - "create_wallet_choice_new_button_fragment": "New Wallet", + "create_wallet_choice_new_button_fragment": "Nuevo monedero", "create_wallet_select_wallet_for_assets": "Please select the wallet you would like to add the following assets: %s", "create_wallet_import_title": "Importar cartera", "create_wallet_import_options_title": "Import Options", "create_wallet_import_options_birthday_height": "Wallet Birthday Height", - "create_wallet_imports_title": "Import Wallets", + "create_wallet_imports_title": "Importar monedero", "create_wallet_import_all_instructions": "Enter your private seed, private key, or active key to verify and restore the associated wallet", "create_wallet_import_instructions": "Introduce tu semilla privada para verificar y restaurar la cartera asociada", "create_wallet_import_input_prompt": "Semilla privada", @@ -197,33 +197,33 @@ "create_wallet_import_input_key_or_seed_prompt": "Clave privada o semilla privada", "create_wallet_import_polkadot_input_key_or_seed_instructions": "Enter your private seed or private key to verify and restore the associated ed25519 wallet", "create_wallet_import_active_key_input_prompt": "Clave Privada Activa", - "create_wallet_import_active_key_instructions": "Introduce tu semilla privada para verificar y restaurar la cartera asociada:", - "create_wallet_edit": "Edit", + "create_wallet_import_active_key_instructions": "Ingresa tu semilla privada para verificar y restaurar la cartera asociada:", + "create_wallet_edit": "Editar", "create_wallet_tokens": "Tokens", - "create_wallet_select_valid_crypto": "Seleccione un tipo de cartera válido por favor", + "create_wallet_select_valid_crypto": "Seleccione un tipo de cartera válido", "create_wallet_invalid_input": "Entrada inválida", "create_wallet_name_label": "Nombre de la cartera:", "create_wallet_crypto_type_label": "Tipo de cartera:", "create_wallet_fiat_type_label": "Moneda fiat de la cartera:", "create_wallet_failed_import_header": "Fallo en la importación de la clave", - "create_wallet_all_failed": "Please edit the key and try again.", + "create_wallet_all_failed": "Por favor edite la clave y vuelva a intentarlo.", "create_wallet_some_failed": "The following assets cannot be imported with the provided seed: %s. Would you like to continue importing all other assets?", "create_wallet_all_disabled_import": "No selected assets can be imported. You can create new wallets or go back and select different assets.", "create_wallet_some_disabled_import": "The following assets cannot be imported: %s. \nWould you like to continue importing all other assets?", - "create_wallet_no_assets_selected": "No assets selected", - "create_wallet_failed_message": "La creación de la cartera falló por exceder el tiempo de espera. Por favor comprueba tu conexión a internet e inténtalo de nuevo más tarde.", - "create_wallet_create_account": "Crear cuenta", - "create_wallet_account_activate": "Activar cuenta", - "create_wallet_account_handle": "Alias de la cuenta", + "create_wallet_no_assets_selected": "No hay activos seleccionados", + "create_wallet_failed_message": "La creación de la cartera falló por exceder el tiempo de espera. Por favor comprueba tu conexión a internet e vuevla a inténtarlo más tarde.", + "create_wallet_create_account": "Crear Cuenta", + "create_wallet_account_activate": "Activar Cuenta", + "create_wallet_account_handle": "Alias de Cuenta", "create_wallet_account_select_instructions_with_cost": "Todas las nuevas carteras de %1$s requieren un pago inicial para activar la cuenta y nombre. Este pago es un requisito de la red %2$s y no de %3$s. El coste actual equivale a %4$s pero puede fluctuar en el futuro. Selecciona una cartera desde la que pagar:", "create_wallet_account_make_payment": "Estás a punto de realizar el siguiente pago para activar tu cuenta de %s:", - "create_wallet_account_select_wallet": "Seleccionar cartera", - "create_wallet_account_review_instructions": "Crear un alias de cuenta único, éste será también el nombre de tu cartera de %s:", + "create_wallet_account_select_wallet": "Seleccionar Cartera", + "create_wallet_account_review_instructions": "Crear un alias de cuenta único, éste también será el nombre de tu cartera de %s:", "create_wallet_account_requirements_eos": "• Debe tener exactamente 12 caracteres\n• Debe incluir sólo letras minúsculas a-z o números 1-5\n", "create_wallet_account_invalid_account_name": "Nombre de cuenta inválido. No cumple los requisitos", "create_wallet_account_account_name_unavailable": "Nombre de cuenta no disponible. Por favor elige otro", "create_wallet_account_unknown_error": "Error desconocido comprobando el nombre de la cuenta. Por favor inténtalo más tarde", - "create_wallet_account_confirm": "Comprueba doblemente la información de la cartera y el pago antes de enviar.", + "create_wallet_account_confirm": "Verifique la cartera y el información del pago antes de enviar.", "create_wallet_account_amount_due": "Importe:", "create_wallet_account_error_sending_transaction": "Error enviando la transacción", "create_wallet_account_payment_sent_title": "Pago Enviado", @@ -235,14 +235,14 @@ "create_wallet_account_metadata_notes": "Esta transacción pagó la activación de tu cartera %s. Por favor espera a tener una confirmación de esta transacción antes de utilizar tu nueva cartera %s. Para problemas relacionados con la activación de la cartera por favor escribe %s", "create_wallet_account_unfinished_activation_title": "Cartera no activada", "create_wallet_account_unfinished_activation_message": "Para completar la activación de esta cartera %s, por favor elige un nombre de cuenta único y completa el pago de activación. Si ya has hecho un pago de activación, por favor espera a que ese pago se haya confirmado antes de intentar utilizar esta cartera.", - "activate_wallet_token_transaction_name_category_generic": "Token Activation", - "activate_wallet_token_transaction_notes_generic": "Activate token transaction", - "activate_wallet_token_transaction_name_xrp": "XRP Ledger", - "activate_wallet_token_transaction_notes_xrp": "Activate XRP token by enabling Trust Line to issuer", - "activate_wallet_token_scene_title": "Activate Token", - "activate_wallet_tokens_scene_title": "Activate Tokens", - "activate_wallet_token_scene_tile_title": "Token to Activate", - "activate_wallet_tokens_scene_tile_title": "Tokens to Activate", + "activate_wallet_token_transaction_name_category_generic": "Activación del token", + "activate_wallet_token_transaction_notes_generic": "Activar transacción de token", + "activate_wallet_token_transaction_name_xrp": "Libro contable de XRP", + "activate_wallet_token_transaction_notes_xrp": "Activar el token XRP habilitando la Línea de Confianza al emisor", + "activate_wallet_token_scene_title": "Activar token", + "activate_wallet_tokens_scene_title": "Activar tokens", + "activate_wallet_token_scene_tile_title": "Token para activar", + "activate_wallet_tokens_scene_tile_title": "Tokens para activar", "activate_wallet_token_scene_body": "To send and receive the selected token you will first need to activate it with a blockchain transaction. This transaction will cost the following fee.\n\nPlease confirm using the slider below.", "activate_wallet_token_scene_body_xrp_extra": "Token activation will increase the XRP reserve requirement by 2 XRP per token activated.", "activate_wallet_token_scene_body_algo_extra": "Token activation will increase the ALGO reserve requirement by 0.1 ALGO per token activated.", @@ -257,8 +257,8 @@ "fio_src_wallet": "Pagar desde cartera", "submit": "Enviar", "login": "Entrar", - "help_build": "Build", - "help_modal_title_thanks": "Thanks for using %1$s!", + "help_build": "Versión", + "help_modal_title_thanks": "Gracias por utilizar %1$s!", "help_version": "Versión", "help_knowledge_base": "Centro de conocimientos", "help_knowledge_base_text": "Preguntas frecuentes", @@ -266,35 +266,35 @@ "help_support_text": "Solución de problemas y soporte técnico", "help_call": "Llamar a asistencia", "help_call_text": "Póngase en contacto por teléfono", - "help_visit_site": "Visit the %1$s site", - "help_site_more_info_text": "More info on %1$s", + "help_visit_site": "Visita el sitio %1$s", + "help_site_more_info_text": "Más información en %1$s", "loading": "Cargando…", "validating": "Validando…", - "high_fee_warning_confirm_send": "Confirm Send", + "high_fee_warning_confirm_send": "Confirma el envío", "mining_fee_custom_label_choice": "Personalizar", "mining_fee_high_label_choice": "Alta", "mining_fee_low_label_choice": "Baja", "mining_fee_standard_label_choice": "Óptimo", - "request_deprecated_header": "Support for %1$s has been deprecated.", + "request_deprecated_header": "Soporte para %1$s ha sido removido.", "request_deprecated_currency_code": "Please extract the private keys and import into a %1$s supporting wallet. If you need assistance please submit a support ticket below.", "request_qr_email_title": "Pagar con %1$s:", - "request_email_subject": "%1$s %2$s Request", - "request_qr_your_wallet_address": "Your Wallet Address", - "request_qr_your_wrapped_segwit_address": "Your Wrapped-Segwit Address", - "request_qr_your_legacy_address": "Your Legacy Address", - "request_qr_your_segwit_address": "Your Segwit Address", + "request_email_subject": "Solicitud %1$s %2$s", + "request_qr_your_wallet_address": "Su dirección de monedero", + "request_qr_your_wrapped_segwit_address": "Tu dirección Wrapped-Segwit", + "request_qr_your_legacy_address": "Tu dirección Legacy", + "request_qr_your_segwit_address": "Tu dirección Segwit", "request_review_question_title": "¿Disfrutando %1$s?", "request_review_question_subtitle": "Por favor, danos una reseña", "request_review_answer_no": "No, gracias", "request_review_answer_yes": "Calificar ahora", - "request_review_android_page_link": "https://play.google.com/store/apps/details?id=co.edgesecure.app&hl=en_US", + "request_review_android_page_link": "https://play.google.com/store/apps/details?id=co.edgesecure.app&hl=es_US", "search_wallets": "Buscar carteras", "search_tokens": "Buscar tokens", - "search_assets": "Search Assets", + "search_assets": "Buscar Activos", "select_wallet": "Seleccionar cartera", - "send_confirmation_calculating_fee": "Calculating Fee", + "send_confirmation_calculating_fee": "Calculando comisión", "send_confirmation_slide_to_confirm": "Deslizar para confirmar", - "send_confirmation_balance": "Balance", + "send_confirmation_balance": "Saldo", "send_confirmation_eos_error_cpu": "CPU disponible insuficiente para enviar transacciones de EOS. Por favor espere 1-3 días para que la CPU recargue.", "send_confirmation_eos_error_net": "Red disponible insuficiente para enviar una transacción EOS. Por favor espera 1-3 días a que la red se recargue.", "send_confirmation_eos_error_ram": "RAM disponible insuficiente para enviar la transacción de EOS. Consulte edge.app/eos para obtener más información sobre la resolución.", @@ -305,10 +305,10 @@ "send_confirmation_fee_modal_alert_message_fragment_eth": "El uso de una tarifa demasiado baja puede resultar en una transacción fallida y pérdida de la comisión gastada.", "transaction_failure": "Fallo en la transacción", "transaction_failure_message": "%s.", - "transaction_success": "Transacción correcta", + "transaction_success": "Transacción Exitosa", "transaction_success_message": "Tu transacción ha sido enviada correctamente.", - "incorrect_pin": "PIN incorrecto", - "invalid_spend_request": "Petición de gasto inválida", + "incorrect_pin": "NIP incorrecto", + "invalid_spend_request": "Solicitud de gasto inválida", "invalid_custom_fee": "Tarifa mínima es", "settings_account_title_cap": "Cuenta", "settings_button_change_password": "Cambiar contraseña", @@ -317,24 +317,24 @@ "settings_dark_theme": "Tema Oscuro", "settings_button_lock_settings": "Pulsar para bloquear la configuración de la cuenta", "settings_button_password_recovery": "Configurar recuperación de contraseña", - "settings_button_logout": "Salir", - "settings_button_pin": "Cambiar el PIN", - "settings_exchange_settings": "Ajustes de cambio", + "settings_button_logout": "Cerrar sesión", + "settings_button_pin": "Cambiar NIP", + "settings_exchange_settings": "Configuración de Intercambio", "settings_exchange_instruction": "Activar o desactivar las casas de cambio disponibles para ti", - "settings_marketing_notifications_switch": "Enable Marketing Alerts", - "settings_price_notifications_switch": "Enable Price Alerts", - "settings_hide_spam_transactions": "Hide spam transactions", + "settings_marketing_notifications_switch": "Habilitar alertas de mercadeo", + "settings_price_notifications_switch": "Habilitar alertas de precios", + "settings_hide_spam_transactions": "Ocultar transacciones spam", "swap_preferred_header": "Casa de cambio preferida", "swap_preferred_cheapest": "Elegir mejor precio", - "swap_preferred_dex": "Prefer Decentralized", - "swap_preferred_cex": "Prefer Centralized", - "swap_options_header_decentralized": "Decentralized\nNo personal info required", - "swap_options_header_centralized": "Centralized\nMay require personal info", + "swap_preferred_dex": "Preferir modo descentralizado", + "swap_preferred_cex": "Preferir modo centralizado", + "swap_options_header_decentralized": "Descentralizado\nNo se requiere información personal", + "swap_options_header_centralized": "Centralizado\nPuede requerir información personal", "swap_preferred_instructions": "Cuando varias casas de cambio pueden ejecutar una orden, preferir:", - "swap_preferred_promo_instructions": "Cuando múltiples intercambios pueden llenar un pedido, la promoción actual siempre prefiere:", - "settings_button_clear_logs": "Clear Logs", - "settings_button_send_logs": "Send Logs to Edge", - "settings_button_export_logs": "Export Logs", + "swap_preferred_promo_instructions": "Cuando varias casas de cambio pueden completar un pedido, la promoción actual prefiere:", + "settings_button_clear_logs": "Eliminar registros", + "settings_button_send_logs": "Enviar registros a Edge", + "settings_button_export_logs": "Exportar registros", "settings_button_setup_two_factor": "Configurar seguridad de 2 factores", "settings_button_unlock_settings": "Pulsa para desbloquear la configuración de la cuenta", "settings_button_use_touchID": "Usar TouchID", @@ -342,25 +342,25 @@ "settings_button_use_biometric": "Usar huella", "settings_days": "Día(s)", "settings_denominations_title": "Denominaciones", - "settings_custom_nodes_title": "Custom Servers", - "settings_custom_servers_title": "Custom %s Servers", + "settings_custom_nodes_title": "Servidores Personalizados", + "settings_custom_servers_title": "Servidores %s Personalizados", "settings_blockbook": "Blockbook", "settings_electrum": "Electrum", "settings_hours": "Hora(s)", "settings_minutes": "Minuto(s)", "settings_modal_export_logs_message": "You may add any additional notes here, and select whether to share logs with Edge, or export logs to your device.", - "settings_modal_clear_logs_message": "Are you sure you want to clear all logs on this device?", - "settings_modal_clear_logs_success": "Logs have been cleared", + "settings_modal_clear_logs_message": "Está seguro que desea borrar todos los registros de este dispositivo?", + "settings_modal_clear_logs_success": "Los registros han sido borrados", "settings_modal_send_logs_success": "Los registros han sido enviados", "settings_modal_send_logs_failure": "El envío de registros ha fallado", - "settings_modal_share_logs_failure": "Sharing logs has failed", + "settings_modal_share_logs_failure": "Fallo al compartir registros", "settings_modal_send_unsafe": "These logs appear to contain sensitive information, such as private keys and addresses, that could result in the loss of funds. Therefore, it is not safe to send these logs to Edge servers.", "settings_modal_send_logs_label": "Escribe notas aquí", "settings_options_title_cap": "Opciones", "settings_seconds": "Segundo(s)", "settings_title_auto_logoff": "Desconexión automática después de", - "settings_title_currency": "Moneda por defecto", - "settings_title_pin_login": "PIN Re-login", + "settings_title_currency": "Moneda Predeterminada", + "settings_title_pin_login": "NIP Re-login", "settings_title": "Configuración", "settings_enable_custom_nodes": "Enable Custom Servers", "settings_add_custom_node": "Add Custom Server", @@ -368,7 +368,7 @@ "settings_custom_node_url": "URL del nodo", "settings_promotion_affiliation_header": "Programa de afiliación", "settings_promotion_header": "Códigos de promoción", - "settings_promotion_add": "Introduce el código de promoción", + "settings_promotion_add": "Ingresar código de promoción", "settings_promotion_device_normal": "Esta aplicación fue instalada normalmente.", "settings_promotion_device_installer": "Esta aplicación fue instalada a través de %s.", "settings_promotion_device_currencies": "Las nuevas cuentas tendrán carteras para: %s", @@ -383,23 +383,23 @@ "staking_change_explaner1": "Stake your coins to earn passive income on your funds", "staking_change_explaner2": "Staked coins are unusable for the duration of the stake", "staking_change_remove_header": "Unstake %s", - "staking_change_remove_amount_title": "Amount to unstake", - "staking_change_remove_unlock_date": "Unlock date", - "staking_change_unlock_explainer_title": "Unstaked Funds", - "staking_change_unlock_explainer1": "Unstaked funds are not immediately available. ", + "staking_change_remove_amount_title": "Cantidad a desbloquear", + "staking_change_remove_unlock_date": "Fecha de desbloqueo", + "staking_change_unlock_explainer_title": "Fondos desbloqueados", + "staking_change_unlock_explainer1": "Los fondos desbloqueados no están disponibles inmediatamente. ", "staking_change_unlock_explainer2": "These continue to be locked and unusable for 7 days after you unstake the funds.", - "staking_overview_header": "Stake %s", - "staking_overview_explainer": "You have the following funds staked:", + "staking_overview_header": "Bloquear %s", + "staking_overview_explainer": "Tienes los siguientes fondos bloqueados:", "staking_locked_title": "Unstaked and locked until %1$s", - "staking_stake_funds_button": "Stake More Funds", + "staking_stake_funds_button": "Bloquear más fondos", "staking_unstake_funds_button": "Unstake", - "staking_status": "%1$s locked (%2$s)", - "staking_success": "Successfully staked", - "staking_unstake_success": "Successfully unstaked", - "staking_estimated_rewards": "Estimated Rewards", - "staking_estimated_return": "Estimated Return: %1$s APY", - "staking_estimated_return_up_to": "Estimated Return: up to %1$s APY", - "staking_no_fio_address_error": "Unable to stake without a FIO addresses", + "staking_status": "%1$s bloqueado (%2$s)", + "staking_success": "Bloqueado exitosamente", + "staking_unstake_success": "Desbloqueado exitosamente", + "staking_estimated_rewards": "Recompensas estimadas", + "staking_estimated_return": "Rendimiento estimado: %1$s APY", + "staking_estimated_return_up_to": "Rendimiento estimado: hasta %1$s APY", + "staking_no_fio_address_error": "No se puede hacer el bloqueo sin una direccion FIO", "staking_no_bundled_txs_error": "Not enough bundled transactions for FIO address %1$s", "string_i_agree": "I Agree", "string_expires": "Expires", @@ -407,21 +407,21 @@ "string_cancel_cap": "Cancelar", "string_cancel": "CANCELAR", "string_ok_cap": "Ok", - "string_forget": "Forget", + "string_forget": "Olvidar", "string_delete": "Borrar", "string_keep": "Keep", "string_archive": "Archivar", "string_archive_wallet": "Archivar cartera", - "satPerByte": "Satoshi Per Byte", + "satPerByte": "Satoshi por Byte", "gasLimit": "Límite de gas", "gasPrice": "Precio Gas (Gwei)", "string_disable": "Deshabilitado", "string_done_cap": "Hecho", "string_first_ethereum_wallet_name": "Mi Ether", - "string_first_ethereum_classic_wallet_name": "My Ethereum Classic", - "string_first_ethereum_pow_wallet_name": "My Ethereum POW", + "string_first_ethereum_classic_wallet_name": "Mi Ethereum Classic", + "string_first_ethereum_pow_wallet_name": "Mi Ethereum POW", "string_first_bitcoin_wallet_name": "Mi Bitcoin", - "string_first_bitcoin_testnet_wallet_name": "My Bitcoin Testnet", + "string_first_bitcoin_testnet_wallet_name": "Mi Bitcoin Testnet", "string_first_bitcoincash_wallet_name": "Mi Bitcoin Cash", "string_first_bitcoin_sv_wallet_name": "Mi Bitcoin SV", "string_first_bitcoin_gold_wallet_name": "Mi Bitcoin Gold", @@ -436,7 +436,7 @@ "string_first_litecoin_wallet_name": "Mi Litecoin", "string_first_monero_wallet_name": "Mi Monero", "string_first_qtum_wallet_name": "Mi Qtum", - "string_first_ripple_wallet_name": "My XRP", + "string_first_ripple_wallet_name": "Mi XRP", "string_first_smartcash_wallet_name": "Mi Smartcash", "string_first_ufo_wallet_name": "Mi UFO", "string_first_vertcoin_wallet_name": "Mi Vertcoin", @@ -444,22 +444,22 @@ "string_first_zcoin_wallet_name": "Mis Firo", "string_first_stellar_wallet_name": "Mi Stellar", "string_first_tezos_wallet_name": "Mi Tezos", - "string_first_rsk_wallet_name": "My Rootstock", + "string_first_rsk_wallet_name": "Mi Rootstock", "string_first_bnb_wallet_name": "Mi BNB", - "string_first_binance_smart_chain_wallet_name": "My Binance Smart Chain", + "string_first_binance_smart_chain_wallet_name": "Mi Binance Smart Chain", "string_first_eboost_wallet_name": "Mi eBoost", - "string_first_celo_wallet_name": "My Celo", - "string_first_solana_wallet_name": "My Solana", - "string_first_piratechain_wallet_name": "My Pirate", - "string_first_zcash_wallet_name": "My Zcash", - "string_first_tron_wallet_name": "My Tron", + "string_first_celo_wallet_name": "Mi Celo", + "string_first_solana_wallet_name": "Mi Solana", + "string_first_piratechain_wallet_name": "Mi Pirate", + "string_first_zcash_wallet_name": "Mi Zcash", + "string_first_tron_wallet_name": "Mi Tron", "string_first_doge_wallet_name": "Mi Doge", "string_first_fantom_wallet_name": "Mis Fantom", "string_first_hedera_wallet_name": "Mis Hedera", - "string_first_polkadot_wallet_name": "My Polkadot", - "string_first_polygon_wallet_name": "My Polygon", - "string_first_avalanche_wallet_name": "My Avalanche", - "string_first_optimism_wallet_name": "My Optimism", + "string_first_polkadot_wallet_name": "Mi Polkadot", + "string_first_polygon_wallet_name": "Mi Polygon", + "string_first_avalanche_wallet_name": "Mi Avalanche", + "string_first_optimism_wallet_name": "Mi Optimism", "string_first_algorand_wallet_name": "My Algorand", "string_first_zksync_wallet_name": "My zkSync", "my_crypto_wallet_name": "Mi %s", @@ -478,26 +478,26 @@ "string_to_capitalize": "A", "string_show_balance": "Mostrar saldo", "string_amount": "Cantidad", - "string_tap_to_edit": "Tap to edit", - "string_rate": "Rate", - "string_got_it": "Got it!", + "string_tap_to_edit": "Toca para editar", + "string_rate": "Calificar", + "string_got_it": "Entendido!", "exchange_rates_loading": "Cargando tipo de cambio...", "exchange_rate_loading_singular": "Cargando tipo de cambio...", "string_master_private_key": "Clave privada maestra", "string_split_wallet": "Dividir %s", "string_add_edit_tokens": "Añadir /Editar Tokens", - "string_get_raw_keys": "Obtener llaves en bruto", - "string_raw_keys": "Llaves en bruto (raw keys)", - "title_create_wallet_select_crypto": "Choose Wallets to Add", + "string_get_raw_keys": "Obtener llaves crudas", + "string_raw_keys": "Llaves Crudas", + "title_create_wallet_select_crypto": "Elegir monederos a añadir", "title_create_wallet_select_fiat": "Seleccionar Fiat", "title_change_mining_fee": "Cambiar comisión de minado", "title_change_password": "Cambiar contraseña", - "title_change_pin": "Cambiar PIN", - "title_create_wallet": "Crear cartera", - "title_create_wallets": "Create Wallets", - "title_export_transactions": "Exportar transacciones", + "title_change_pin": "Cambiar NIP", + "title_create_wallet": "Crear Cartera", + "title_create_wallets": "Crear monederos", + "title_export_transactions": "Exportar Transacciones", "title_edge_login": "Edge Login", - "title_exchange": "Casa de cambio", + "title_exchange": "Intercambio", "title_fio_sent_request_details": "Detalles de la solicitud enviados", "title_fio_address_settings": "Ajustes de dirección", "title_fio_domain_settings": "Ajustes de dominio", @@ -506,7 +506,7 @@ "title_fio_renew": "Renovar", "title_fio_make_public_domain": "Hacer público el dominio", "title_fio_make_private_domain": "Hacer Dominio Privado", - "title_fio_transfer_domain": "Transferir dominio FIO", + "title_fio_transfer_domain": "Transfer FIO Domain", "title_fio_transfer_address": "Transferir dirección FIO", "title_fio_address": "FIO Crypto Handles", "title_fio_names": "Nombres FIO", @@ -526,11 +526,11 @@ "title_settings": "Configuración", "title_promotion_settings": "Ajustes de la promoción", "title_terms_of_service": "Términos del Servicio", - "title_markets": "Markets", + "title_markets": "Mercados", "title_wallets": "Carteras", "title_buy": "Comprar", "title_sell": "Vender", - "title_map": "Map", + "title_map": "Mapa", "no_exchanges_available": "No hay casas de cambio activadas", "check_exchange_settings": "Por favor actívalas en los ajustes de casa de cambio.", "amount_above_limit": "La cantidad está por encima del límite máximo de %1$s %2$s. Este límite máximo está sujeto a cambios basados en las condiciones del mercado", @@ -553,7 +553,7 @@ "transaction_details_choose_a_sub_category": "Elegir sub-categoría", "transaction_details_recipient_addresses": "Dirección del destinatario", "transaction_details_advance_details_header": "Parámetros avanzados", - "transaction_details_advance_details_fee_setting": "Fee Setting", + "transaction_details_advance_details_fee_setting": "Ajuste de comisión", "transaction_details_advance_details_device": "Dispositivo", "transaction_details_advance_details_fee_used": "Tarifa utilizada", "transaction_details_advance_details_show_explorer": "Mostrar en el explorador", @@ -571,7 +571,7 @@ "transaction_details_accelerate_transaction_new_fee_title": "Nueva comisión", "transaction_details_accelerate_transaction_slider_disabled": "No se puede acelerar la transacción", "transaction_details_accelerate_transaction_fee_too_low": "Accelerated transaction fee is too low. Fee has been updated. Please try again.", - "transaction_details_accelerate_transaction_sent": "Your transaction has been accelerated.", + "transaction_details_accelerate_transaction_sent": "Tu transacción ha sido acelerada.", "transaction_details_exchange_details": "Detalles de la casa de cambio", "transaction_details_exchange_service": "Servicios de casa de cambio", "transaction_details_exchange_order_id": "Número de pedido", @@ -584,7 +584,7 @@ "transaction_details_exchange_status_page": "Página de estado de la casa de cambio", "transaction_details_exchange_support": "Soporte de la casa de cambio", "transaction_details_exchange_support_request": "Petición de soporte %s", - "transaction_details_fee_warning": "High Network Fees", + "transaction_details_fee_warning": "Tarifas de red altas", "my_receive_addresses_title": "My Receive Addresses", "tx_detail_picker_title": "Elige una categoría:", "transaction_details_notes_title": "Notas", From 2a5d054bd8270cbb03666fc155de45743a6ac6fb Mon Sep 17 00:00:00 2001 From: Paul V Puey Date: Wed, 7 Jun 2023 11:23:32 -0700 Subject: [PATCH 090/104] New translations enUS.json (Karakalpak) --- src/locales/strings/kaa.json | 49 +++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/src/locales/strings/kaa.json b/src/locales/strings/kaa.json index 5577d5b4638..9f8f5109cf4 100644 --- a/src/locales/strings/kaa.json +++ b/src/locales/strings/kaa.json @@ -402,6 +402,7 @@ "staking_no_fio_address_error": "Unable to stake without a FIO addresses", "staking_no_bundled_txs_error": "Not enough bundled transactions for FIO address %1$s", "string_i_agree": "I Agree", + "string_expires": "Expires", "string_decline": "Decline", "string_cancel_cap": "Biykarlaw", "string_cancel": "BIYKARLAW", @@ -1089,7 +1090,9 @@ "fiat_plugin_sell_currencycode_s": "Sell %s", "fiat_plugin_amount_currencycode": "Amount %s", "fiat_plugin_buy_amount_over_limit": "Max purchase amount is %s", + "fiat_plugin_buy_amount_over_undef_limit": "Purchase amount is over maximum", "fiat_plugin_buy_amount_under_limit": "Minimum purchase amount is %s", + "fiat_plugin_buy_amount_under_undef_limit": "Purchase amount is under minimum", "fiat_plugin_asset_unsupported": "Asset Unsupported", "fiat_plugin_payment_unsupported": "Payment Method Unsupported", "fiat_plugin_buy_region_restricted": "Region restricted from purchasing %s", @@ -1326,24 +1329,40 @@ "getting_started_welcome_prompt": "Swipe to Learn More", "getting_started_welcome_title": "Welcome to\nFinancial *Freedom*", "app_logo_hint": "App logo", - "rewards_card_getting_invoice": "Getting payment invoice", + "check_icon_hint": "Confirmed", + "close_control_panel_hint": "Close control panel", + "close_hint": "Close", + "create_wallet_hint": "Create Wallet %s", + "edit_icon_hint": "Edit", + "import_key_icon_hint": "Import Key", + "modal_close_hint": "Close modal", + "off_hint": "Off", + "on_hint": "On", + "sort_wallets_hint": "Sort Wallets", + "spinner_hint": "Loading", + "toggle_button_hint": "Toggle", + "wallet_settings_label": "Wallet settings", "rewards_card_error_retrieving_cards": "Error retrieving Visa cards. Please try again later.", - "rewards_card_error_authenticate": "Error authenticating with Visa Card program. Please try again later.", - "rewards_card_error_timeout_loading": "Timeout error loading Visa Card program. Please try again later.", - "rewards_card_purchase_successful": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", + "rewards_card_error_authenticate": "Error authenticating with Visa® Card program. Please try again later.", + "rewards_card_error_timeout_loading": "Timeout error loading Visa® Card program. Please try again later.", + "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", + "rewards_card_purchase_disclaimer": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", "rewards_card_loading": "Loading your Visa® Cards...", "rewards_card_add_new_input_amount_title": "Buy Visa® Card", "rewards_card_welcome_intro": "Purchase Visa® prepaid cards that can be used at millions of merchants in the U.S. Cards can be purchased up to $1,000 in value, with a daily limit of $10,000.", - "rewards_card_welcome_more_info": "Learn More", - "rewards_card_new_card_button_label": "Buy New Card", - "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", - "rewards_card_dashboard_expires_label": "Expires", "rewards_card_dashboard_title": "Visa® Card Program", - "rewards_card_delete_modal_title": "Delete Card?", - "rewards_card_delete_modal_message_s": "Are you sure you want to delete the Visa® Card with expiration?\n\n%s", - "rewards_card_error_missing_payment_address": "Missing payment address from provider", - "rewards_card_error_amount_max_s": "Maximum card purchase amount is $%s", - "rewards_card_error_amount_min_s": "Minimum card purchase amount is $%s", - "rewards_card_select_wallet": "Select wallet to use to purchase card", - "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds." + "rewards_card_delete_modal_message": "Are you sure you want to delete this Visa® Card?", + "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds.", + "buy_new_card_button": "Buy New Card", + "card_amount_max_error_message_s": "Maximum card purchase amount is $%s", + "card_amount_min_error_message_s": "Minimum card purchase amount is $%s", + "delete_card_confirmation_title": "Delete Card?", + "getting_payment_invoice_message": "Getting payment invoice", + "learn_more_button": "Learn More", + "missing_provider_payment_address_message": "Missing payment address from provider", + "no_active_cards_message": "You have no active cards.", + "purchase_asset_label": "Purchase Asset", + "purchase_date_label": "Purchase Date", + "purchase_price_label": "Purchase Price", + "select_wallet_to_purchase_card_title": "Select wallet to use to purchase card" } \ No newline at end of file From ab3e935dde7dcc99b6dedff2c0d133565940c6a4 Mon Sep 17 00:00:00 2001 From: Paul V Puey Date: Wed, 7 Jun 2023 11:23:33 -0700 Subject: [PATCH 091/104] New translations enUS.json (French) --- src/locales/strings/fr.json | 49 +++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/src/locales/strings/fr.json b/src/locales/strings/fr.json index 2c63939d913..8bb15d59021 100644 --- a/src/locales/strings/fr.json +++ b/src/locales/strings/fr.json @@ -402,6 +402,7 @@ "staking_no_fio_address_error": "Unable to stake without a FIO addresses", "staking_no_bundled_txs_error": "Not enough bundled transactions for FIO address %1$s", "string_i_agree": "I Agree", + "string_expires": "Expires", "string_decline": "Decline", "string_cancel_cap": "Annuler", "string_cancel": "ANNULER", @@ -1089,7 +1090,9 @@ "fiat_plugin_sell_currencycode_s": "Sell %s", "fiat_plugin_amount_currencycode": "Amount %s", "fiat_plugin_buy_amount_over_limit": "Max purchase amount is %s", + "fiat_plugin_buy_amount_over_undef_limit": "Purchase amount is over maximum", "fiat_plugin_buy_amount_under_limit": "Minimum purchase amount is %s", + "fiat_plugin_buy_amount_under_undef_limit": "Purchase amount is under minimum", "fiat_plugin_asset_unsupported": "Asset Unsupported", "fiat_plugin_payment_unsupported": "Payment Method Unsupported", "fiat_plugin_buy_region_restricted": "Region restricted from purchasing %s", @@ -1326,24 +1329,40 @@ "getting_started_welcome_prompt": "Swipe to Learn More", "getting_started_welcome_title": "Welcome to\nFinancial *Freedom*", "app_logo_hint": "App logo", - "rewards_card_getting_invoice": "Getting payment invoice", + "check_icon_hint": "Confirmed", + "close_control_panel_hint": "Close control panel", + "close_hint": "Close", + "create_wallet_hint": "Create Wallet %s", + "edit_icon_hint": "Edit", + "import_key_icon_hint": "Import Key", + "modal_close_hint": "Close modal", + "off_hint": "Off", + "on_hint": "On", + "sort_wallets_hint": "Sort Wallets", + "spinner_hint": "Loading", + "toggle_button_hint": "Toggle", + "wallet_settings_label": "Wallet settings", "rewards_card_error_retrieving_cards": "Error retrieving Visa cards. Please try again later.", - "rewards_card_error_authenticate": "Error authenticating with Visa Card program. Please try again later.", - "rewards_card_error_timeout_loading": "Timeout error loading Visa Card program. Please try again later.", - "rewards_card_purchase_successful": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", + "rewards_card_error_authenticate": "Error authenticating with Visa® Card program. Please try again later.", + "rewards_card_error_timeout_loading": "Timeout error loading Visa® Card program. Please try again later.", + "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", + "rewards_card_purchase_disclaimer": "Card purchase successful!\n\nNote that newly purchased cards take a few seconds to become available. \n\nCards purchased with Bitcoin require 1 confirmation and could take 10-30 minutes to become available.", "rewards_card_loading": "Loading your Visa® Cards...", "rewards_card_add_new_input_amount_title": "Buy Visa® Card", "rewards_card_welcome_intro": "Purchase Visa® prepaid cards that can be used at millions of merchants in the U.S. Cards can be purchased up to $1,000 in value, with a daily limit of $10,000.", - "rewards_card_welcome_more_info": "Learn More", - "rewards_card_new_card_button_label": "Buy New Card", - "rewards_card_call_to_action": "Buy Prepaid Visa® Cards", - "rewards_card_dashboard_expires_label": "Expires", "rewards_card_dashboard_title": "Visa® Card Program", - "rewards_card_delete_modal_title": "Delete Card?", - "rewards_card_delete_modal_message_s": "Are you sure you want to delete the Visa® Card with expiration?\n\n%s", - "rewards_card_error_missing_payment_address": "Missing payment address from provider", - "rewards_card_error_amount_max_s": "Maximum card purchase amount is $%s", - "rewards_card_error_amount_min_s": "Minimum card purchase amount is $%s", - "rewards_card_select_wallet": "Select wallet to use to purchase card", - "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds." + "rewards_card_delete_modal_message": "Are you sure you want to delete this Visa® Card?", + "rewards_card_terms_of_use_message": "Review Terms of Use:\n\nI understand that virtual cards via this program can only be purchased by United States based users.\n\nI understand that purchased cards are not eligible for refunds.", + "buy_new_card_button": "Buy New Card", + "card_amount_max_error_message_s": "Maximum card purchase amount is $%s", + "card_amount_min_error_message_s": "Minimum card purchase amount is $%s", + "delete_card_confirmation_title": "Delete Card?", + "getting_payment_invoice_message": "Getting payment invoice", + "learn_more_button": "Learn More", + "missing_provider_payment_address_message": "Missing payment address from provider", + "no_active_cards_message": "You have no active cards.", + "purchase_asset_label": "Purchase Asset", + "purchase_date_label": "Purchase Date", + "purchase_price_label": "Purchase Price", + "select_wallet_to_purchase_card_title": "Select wallet to use to purchase card" } \ No newline at end of file From 02794d2a8c7ed30f1db0c7f666a91fd5c8ce5e75 Mon Sep 17 00:00:00 2001 From: William Swanson Date: Wed, 7 Jun 2023 11:29:46 -0700 Subject: [PATCH 092/104] v3.12.0 --- CHANGELOG.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db114567ac7..746b4b59dcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # edge-react-gui +## 3.12.0 + +## 3.11.0 + ## 3.10.0 (2023-05-25) - Add Pepe (PEPE) diff --git a/package.json b/package.json index 7076012427f..108be0e202b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "edge-react-gui", - "version": "3.11.0", + "version": "3.12.0", "private": true, "description": "Edge Wallet React GUI", "homepage": "https://edge.app", From 851d41bc7e9ca61e44bfcd18aa13ca72db0e2b99 Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Thu, 8 Jun 2023 13:33:17 -0700 Subject: [PATCH 093/104] Fix logging of Error objects in production --- src/util/logger.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/util/logger.ts b/src/util/logger.ts index 0ce6d3b1602..59638423c77 100644 --- a/src/util/logger.ts +++ b/src/util/logger.ts @@ -28,8 +28,10 @@ const logMap = { const getTime = () => new Date().toISOString() const isObject = (item: any) => typeof item === 'object' && item !== null +const isError = (item: any): item is Error => item instanceof Error -const normalize = (...info: any[]) => `${getTime()} | ${info.map(item => (isObject(item) ? JSON.stringify(item) : item)).join(' ')}` +const normalize = (...info: any[]) => + `${getTime()} | ${info.map(item => (isError(item) ? item.stack ?? item.message : isObject(item) ? JSON.stringify(item) : item)).join(' ')}` const lock = new AsyncLock({ maxPending: 100000 }) From aa261efc6a8dad19bd2907d6dd5fed89a1d33f0e Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Wed, 7 Jun 2023 14:13:15 -0700 Subject: [PATCH 094/104] Limit numberOfLines for WelcomeHeroTitle --- src/components/scenes/GettingStartedScene.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/scenes/GettingStartedScene.tsx b/src/components/scenes/GettingStartedScene.tsx index 5d51bf517fa..677826e44f0 100644 --- a/src/components/scenes/GettingStartedScene.tsx +++ b/src/components/scenes/GettingStartedScene.tsx @@ -173,7 +173,9 @@ export const GettingStartedScene = (props: Props) => { - {parseMarkedText(lstrings.getting_started_welcome_title)} + + {parseMarkedText(lstrings.getting_started_welcome_title)} + {lstrings.getting_started_welcome_message} {lstrings.getting_started_welcome_prompt} @@ -265,6 +267,7 @@ const WelcomeHeroTitle = styled(Text)(props => ({ fontFamily: props.theme.fontFaceDefault, fontSize: props.theme.rem(2.25), includeFontPadding: false, + lineHeight: props.theme.rem(2.8), paddingVertical: props.theme.rem(1), textAlign: 'center' })) From b7771f99e1251645c9e76aa7eef2e673d3c36501 Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Wed, 7 Jun 2023 14:13:27 -0700 Subject: [PATCH 095/104] Give more room to the Pagination and WelcomeHero components --- src/components/scenes/GettingStartedScene.tsx | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/src/components/scenes/GettingStartedScene.tsx b/src/components/scenes/GettingStartedScene.tsx index 677826e44f0..cdc45a3f792 100644 --- a/src/components/scenes/GettingStartedScene.tsx +++ b/src/components/scenes/GettingStartedScene.tsx @@ -33,6 +33,7 @@ import { SceneWrapper } from '../common/SceneWrapper' import { styled } from '../hoc/styled' import { SwipeOffsetDetector } from '../interactions/SwipeOffsetDetector' import { Space } from '../layout/Space' +import { useTheme } from '../services/ThemeContext' import { EdgeText } from '../themed/EdgeText' import { MainButton } from '../themed/MainButton' @@ -355,30 +356,37 @@ const PageIndicator = styled(Animated.View)<{ swipeOffset: SharedValue; // Sections // -const SectionCoverAnimated = styled(Animated.View)<{ swipeOffset: SharedValue }>(props => [ - { - alignItems: 'stretch', - backgroundColor: '#0F1D26', - paddingVertical: props.theme.rem(1) - }, - useAnimatedStyle(() => { - const backgroundColor = interpolateColor(props.swipeOffset.value, [0, 1], [`${props.theme.modal}00`, `${props.theme.modal}ff`]) - const flex = interpolate(props.swipeOffset.value, [0, 1], [0.5, 1.5], Extrapolation.CLAMP) - return { - backgroundColor, - flex - } - }) -]) +const SectionCoverAnimated = styled(Animated.View)<{ swipeOffset: SharedValue }>(props => { + const theme = useTheme() + const themeRem = theme.rem(1) + return [ + { + alignItems: 'stretch', + justifyContent: 'space-between', + backgroundColor: '#0F1D26', + paddingVertical: props.theme.rem(1) + }, + useAnimatedStyle(() => { + const backgroundColor = interpolateColor(props.swipeOffset.value, [0, 1], [`${props.theme.modal}00`, `${props.theme.modal}ff`]) + const paddingVertical = interpolate(props.swipeOffset.value, [0, 1], [0, themeRem], Extrapolation.CLAMP) + const flexGrow = interpolate(props.swipeOffset.value, [0, 1], [0, 1.2], Extrapolation.CLAMP) + return { + backgroundColor, + paddingVertical, + flexGrow + } + }) + ] +}) const Sections = styled(Animated.View)<{ swipeOffset: SharedValue }>(props => [ { paddingBottom: props.theme.rem(1) }, useAnimatedStyle(() => { - const flex = interpolate(props.swipeOffset.value, [0, 1], [0.00000001, 1.5]) + const flexGrow = interpolate(props.swipeOffset.value, [0, 1], [0, 1.5]) return { - flex + flexGrow } }) ]) From d491abc6d2bd85a11cf3413abc50f6bb411f6cf7 Mon Sep 17 00:00:00 2001 From: Samuel Holmes Date: Wed, 7 Jun 2023 14:14:51 -0700 Subject: [PATCH 096/104] Remove bottom gap on iOS devices by overflowing SectionCoverAnimated --- src/components/scenes/GettingStartedScene.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/scenes/GettingStartedScene.tsx b/src/components/scenes/GettingStartedScene.tsx index cdc45a3f792..8a3f688a4d8 100644 --- a/src/components/scenes/GettingStartedScene.tsx +++ b/src/components/scenes/GettingStartedScene.tsx @@ -14,7 +14,7 @@ import Animated, { useSharedValue, withTiming } from 'react-native-reanimated' -import { useSafeAreaFrame } from 'react-native-safe-area-context' +import { useSafeAreaFrame, useSafeAreaInsets } from 'react-native-safe-area-context' import edgeLogoIcon from '../../assets/images/edgeLogo/Edge_logo_Icon_L.png' import slide1HeroImage from '../../assets/images/gettingStarted/slide1HeroImage.png' @@ -359,12 +359,16 @@ const PageIndicator = styled(Animated.View)<{ swipeOffset: SharedValue; const SectionCoverAnimated = styled(Animated.View)<{ swipeOffset: SharedValue }>(props => { const theme = useTheme() const themeRem = theme.rem(1) + const insets = useSafeAreaInsets() + return [ { alignItems: 'stretch', justifyContent: 'space-between', backgroundColor: '#0F1D26', - paddingVertical: props.theme.rem(1) + paddingVertical: props.theme.rem(1), + paddingBottom: insets.bottom, + marginBottom: -insets.bottom }, useAnimatedStyle(() => { const backgroundColor = interpolateColor(props.swipeOffset.value, [0, 1], [`${props.theme.modal}00`, `${props.theme.modal}ff`]) From 475e7ac23291713d16b0866675cfd2b1572e0aa2 Mon Sep 17 00:00:00 2001 From: Paul Puey Date: Fri, 9 Jun 2023 14:25:53 -0700 Subject: [PATCH 097/104] Add ENV.ENABLE_VISA_PROGRAM Disable all buttons to enter Visa Program if ENABLE_VISA_PROGRAM is false --- src/components/cards/VisaCardCard.tsx | 3 +++ src/components/scenes/GuiPluginListScene.tsx | 4 ++++ src/components/themed/SideMenu.tsx | 2 +- src/envConfig.ts | 1 + 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/cards/VisaCardCard.tsx b/src/components/cards/VisaCardCard.tsx index 7f6eb9f3903..e533c767fea 100644 --- a/src/components/cards/VisaCardCard.tsx +++ b/src/components/cards/VisaCardCard.tsx @@ -5,6 +5,7 @@ import FastImage from 'react-native-fast-image' import { executePluginAction } from '../../actions/PluginActions' import { SPECIAL_CURRENCY_INFO } from '../../constants/WalletAndCurrencyConstants' +import { ENV } from '../../env' import { useHandler } from '../../hooks/useHandler' import { lstrings } from '../../locales/strings' import { getDefaultFiat } from '../../selectors/SettingsSelectors' @@ -42,6 +43,8 @@ export const VisaCardCard = (props: Props) => { return null } + if (!ENV.ENABLE_VISA_PROGRAM) return null + const { pluginId } = wallet.currencyInfo const icon = getCurrencyIconUris(pluginId, tokenId) diff --git a/src/components/scenes/GuiPluginListScene.tsx b/src/components/scenes/GuiPluginListScene.tsx index 2d08803ea48..b02eb61207d 100644 --- a/src/components/scenes/GuiPluginListScene.tsx +++ b/src/components/scenes/GuiPluginListScene.tsx @@ -331,6 +331,10 @@ class GuiPluginList extends React.PureComponent { const activePlugins = bestOfPlugins(accountPlugins, accountReferral, undefined) plugins = plugins.filter(plugin => !activePlugins.disabled[plugin.pluginId]) + if (!ENV.ENABLE_VISA_PROGRAM) { + plugins = plugins.filter(plugin => plugin.pluginId !== 'rewardscard') + } + if (!this.state.hasWyreAccountHack) { plugins = plugins.filter(plugin => plugin.pluginId !== 'wyre') } diff --git a/src/components/themed/SideMenu.tsx b/src/components/themed/SideMenu.tsx index 9934c3e667c..f9183f37f21 100644 --- a/src/components/themed/SideMenu.tsx +++ b/src/components/themed/SideMenu.tsx @@ -267,7 +267,7 @@ export function SideMenu(props: DrawerContentComponentProps) { } ] - if (IONIA_SUPPORTED_FIATS.includes(defaultFiat)) { + if (ENV.ENABLE_VISA_PROGRAM && IONIA_SUPPORTED_FIATS.includes(defaultFiat)) { rowDatas.unshift({ pressHandler: () => { dispatch(executePluginAction(navigation, 'rewardscard', 'sell')) diff --git a/src/envConfig.ts b/src/envConfig.ts index 5de16ed821a..a4261d5a919 100644 --- a/src/envConfig.ts +++ b/src/envConfig.ts @@ -221,6 +221,7 @@ export const asEnvConfig = asObject({ // App options: APP_CONFIG: asOptional(asString, 'edge'), + ENABLE_VISA_PROGRAM: asOptional(asBoolean, true), BETA_FEATURES: asOptional(asBoolean, false), USE_FAKE_CORE: asOptional(asBoolean, false), USE_FIREBASE: asOptional(asBoolean, true), From 65b040dd642e960a756011ea99ce81f88ee14b06 Mon Sep 17 00:00:00 2001 From: Paul V Puey Date: Fri, 9 Jun 2023 14:42:30 -0700 Subject: [PATCH 098/104] Update snapshot from disabled Visa program --- .../TransactionListTop.test.tsx.snap | 107 ------------------ 1 file changed, 107 deletions(-) diff --git a/src/__tests__/components/__snapshots__/TransactionListTop.test.tsx.snap b/src/__tests__/components/__snapshots__/TransactionListTop.test.tsx.snap index 83660b213b0..5afae59bed4 100644 --- a/src/__tests__/components/__snapshots__/TransactionListTop.test.tsx.snap +++ b/src/__tests__/components/__snapshots__/TransactionListTop.test.tsx.snap @@ -764,113 +764,6 @@ Array [ } /> - - - - - - - - Buy Prepaid Visa® Cards - - - - , Date: Fri, 9 Jun 2023 14:42:30 -0700 Subject: [PATCH 099/104] Revert "Update snapshot from disabled Visa program" This reverts commit 65b040dd642e960a756011ea99ce81f88ee14b06. --- .../TransactionListTop.test.tsx.snap | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/src/__tests__/components/__snapshots__/TransactionListTop.test.tsx.snap b/src/__tests__/components/__snapshots__/TransactionListTop.test.tsx.snap index 5afae59bed4..83660b213b0 100644 --- a/src/__tests__/components/__snapshots__/TransactionListTop.test.tsx.snap +++ b/src/__tests__/components/__snapshots__/TransactionListTop.test.tsx.snap @@ -764,6 +764,113 @@ Array [ } /> + + + + + + + + Buy Prepaid Visa® Cards + + + + , Date: Tue, 13 Jun 2023 13:23:57 -0700 Subject: [PATCH 100/104] Support new Ionia API fields as optional (Currency and ActualAmount) --- src/plugins/gui/RewardsCardPlugin.tsx | 5 ++-- src/plugins/gui/providers/ioniaProvider.ts | 6 ++-- .../gui/scenes/RewardsCardDashboardScene.tsx | 28 +++++++++++-------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/plugins/gui/RewardsCardPlugin.tsx b/src/plugins/gui/RewardsCardPlugin.tsx index ad43422d872..e0c9d433f26 100644 --- a/src/plugins/gui/RewardsCardPlugin.tsx +++ b/src/plugins/gui/RewardsCardPlugin.tsx @@ -23,9 +23,8 @@ export interface RewardsCardItem { id: number creationDate: Date expirationDate: Date - amount: number - purchaseAsset: string - purchaseDate: Date + amount?: number + purchaseAsset?: string url: string } diff --git a/src/plugins/gui/providers/ioniaProvider.ts b/src/plugins/gui/providers/ioniaProvider.ts index 904736abac7..979fa564ed7 100644 --- a/src/plugins/gui/providers/ioniaProvider.ts +++ b/src/plugins/gui/providers/ioniaProvider.ts @@ -55,15 +55,14 @@ export const asRewardsCard = asCodec( raw => { const ioniaCard = asObject({ Id: asNumber, - ActualAmount: asNumber, + ActualAmount: asOptional(asNumber), CardNumber: asString, CreatedDate: asDate, - Currency: asString + Currency: asOptional(asString) })(raw) const purchaseAsset = ioniaCard.Currency const amount = ioniaCard.ActualAmount - const purchaseDate = ioniaCard.CreatedDate // Expires 6 calendar months from the creation date const expirationDate = new Date(ioniaCard.CreatedDate.valueOf()) expirationDate.setMonth(ioniaCard.CreatedDate.getMonth() + 6) @@ -74,7 +73,6 @@ export const asRewardsCard = asCodec( expirationDate, amount, purchaseAsset, - purchaseDate, url: ioniaCard.CardNumber } }, diff --git a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx index d6ca26c7c45..1dc01f95b22 100644 --- a/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx +++ b/src/plugins/gui/scenes/RewardsCardDashboardScene.tsx @@ -94,7 +94,7 @@ export interface RewardsCardProps { export const RewardsCard = (props: RewardsCardProps) => { const { item, onPress, onQuestionPress, onRemovePress, shouldStack = false } = props const theme = useTheme() - const purchaseAmount = item == null ? undefined : `$${item.amount.toString()}` + const purchaseAmount = item?.amount == null ? undefined : `$${item.amount.toString()}` return ( @@ -127,16 +127,18 @@ export const RewardsCard = (props: RewardsCardProps) => { {lstrings.purchase_date_label} - {item == null ? ' ' : toLocaleDate(item.purchaseDate)} + {item == null ? ' ' : toLocaleDate(item.creationDate)} - - {lstrings.purchase_price_label} + {purchaseAmount == null ? null : ( - - {purchaseAmount ?? ' '} + {lstrings.purchase_price_label} + + + {purchaseAmount} + - + )} @@ -146,13 +148,15 @@ export const RewardsCard = (props: RewardsCardProps) => { {item == null ? ' ' : toLocaleDate(item.expirationDate)} - - {lstrings.purchase_asset_label} + {item?.purchaseAsset == null ? null : ( - - {item?.purchaseAsset ?? ' '} + {lstrings.purchase_asset_label} + + + {item.purchaseAsset} + - + )} From db148859627a0c54136934ddd6e896a61cf32ee9 Mon Sep 17 00:00:00 2001 From: Paul Puey Date: Tue, 13 Jun 2023 15:34:35 -0700 Subject: [PATCH 101/104] Enable Bitrefill with stablecoins --- src/constants/plugins/GuiPlugins.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/constants/plugins/GuiPlugins.ts b/src/constants/plugins/GuiPlugins.ts index 11593b07d9f..0b4553906de 100644 --- a/src/constants/plugins/GuiPlugins.ts +++ b/src/constants/plugins/GuiPlugins.ts @@ -107,7 +107,8 @@ export const guiPlugins: { [pluginId: string]: GuiPlugin } = { bitrefill: { pluginId: 'bitrefill', storeId: 'co.edgesecure.bitrefill', - baseUri: 'https://embed.bitrefill.com/?ref=nUqaI7Qe&theme=dark&paymentMethods=bitcoin,ethereum,dogecoin,litecoin,dash', + baseUri: + 'https://embed.bitrefill.com/?ref=nUqaI7Qe&theme=dark&paymentMethods=bitcoin,ethereum,usdt_trc20,usdt_erc20,usdt_polygon,usdc_erc20,usdc_polygon,litecoin,dogecoin,dash', lockUriPath: true, displayName: 'Bitrefill' }, From 4d3c31c7d0b6500fdabfdc1cb20f2a653e6a297d Mon Sep 17 00:00:00 2001 From: Paul Puey Date: Tue, 13 Jun 2023 16:49:33 -0700 Subject: [PATCH 102/104] Properly validate paymentTypes Without validating paymentTypes, getQuote may try to process a quote that was hard disabled in the constant above. --- src/plugins/gui/providers/banxaProvider.ts | 2 ++ src/plugins/gui/providers/moonpayProvider.ts | 2 ++ src/plugins/gui/providers/simplexProvider.ts | 3 +++ 3 files changed, 7 insertions(+) diff --git a/src/plugins/gui/providers/banxaProvider.ts b/src/plugins/gui/providers/banxaProvider.ts index 4e236062b14..c069db6ca49 100644 --- a/src/plugins/gui/providers/banxaProvider.ts +++ b/src/plugins/gui/providers/banxaProvider.ts @@ -219,6 +219,8 @@ export const banxaProvider: FiatProviderFactory = { }, getQuote: async (params: FiatProviderGetQuoteParams): Promise => { const { pluginId, regionCode, exchangeAmount, amountType, paymentTypes, fiatCurrencyCode, displayCurrencyCode, direction } = params + if (!paymentTypes.some(paymentType => allowedPaymentTypes[paymentType] === true)) + throw new FiatProviderError({ providerId, errorType: 'paymentUnsupported' }) if (direction !== 'buy') throw new Error('Only buy supported by Banxa') diff --git a/src/plugins/gui/providers/moonpayProvider.ts b/src/plugins/gui/providers/moonpayProvider.ts index ef352d9b9c1..b02ca0b933b 100644 --- a/src/plugins/gui/providers/moonpayProvider.ts +++ b/src/plugins/gui/providers/moonpayProvider.ts @@ -170,6 +170,8 @@ export const moonpayProvider: FiatProviderFactory = { getQuote: async (params: FiatProviderGetQuoteParams): Promise => { const { regionCode, paymentTypes, displayCurrencyCode } = params if (!allowedCountryCodes[regionCode.countryCode]) throw new FiatProviderError({ providerId, errorType: 'regionRestricted', displayCurrencyCode }) + if (!paymentTypes.some(paymentType => allowedPaymentTypes[paymentType] === true)) + throw new FiatProviderError({ providerId, errorType: 'paymentUnsupported' }) let foundPaymentType = false let useIAch = false for (const type of paymentTypes) { diff --git a/src/plugins/gui/providers/simplexProvider.ts b/src/plugins/gui/providers/simplexProvider.ts index 7cae6b73be6..99c635095bd 100644 --- a/src/plugins/gui/providers/simplexProvider.ts +++ b/src/plugins/gui/providers/simplexProvider.ts @@ -218,6 +218,9 @@ export const simplexProvider: FiatProviderFactory = { getQuote: async (params: FiatProviderGetQuoteParams): Promise => { const { regionCode, exchangeAmount, amountType, paymentTypes, displayCurrencyCode } = params if (!allowedCountryCodes[regionCode.countryCode]) throw new FiatProviderError({ providerId, errorType: 'regionRestricted', displayCurrencyCode }) + if (!paymentTypes.some(paymentType => allowedPaymentTypes[paymentType] === true)) + throw new FiatProviderError({ providerId, errorType: 'paymentUnsupported' }) + let foundPaymentType = false for (const type of paymentTypes) { const t = asFiatPaymentType(type) From f8fb419ac66638c76fe7d8867d4b772d48bb8fd9 Mon Sep 17 00:00:00 2001 From: Paul Puey Date: Tue, 13 Jun 2023 17:00:43 -0700 Subject: [PATCH 103/104] Enable googlepay with banxa --- src/plugins/gui/providers/banxaProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/gui/providers/banxaProvider.ts b/src/plugins/gui/providers/banxaProvider.ts index c069db6ca49..fb3f83fd83f 100644 --- a/src/plugins/gui/providers/banxaProvider.ts +++ b/src/plugins/gui/providers/banxaProvider.ts @@ -21,7 +21,7 @@ const storeId = 'banxa' const partnerIcon = 'banxa.png' const pluginDisplayName = 'Banxa' -const allowedPaymentTypes: { [Payment in FiatPaymentType]?: boolean } = { applepay: true, credit: true, googlepay: false } +const allowedPaymentTypes: { [Payment in FiatPaymentType]?: boolean } = { applepay: true, credit: true, googlepay: true } const asBanxaApiKeys = asObject({ partnerUrl: asString, From 7fc2f90094d53cc15bd692919601a4f7017c3a85 Mon Sep 17 00:00:00 2001 From: Paul V Puey Date: Fri, 9 Jun 2023 14:42:30 -0700 Subject: [PATCH 104/104] Revert "Revert "Update snapshot from disabled Visa program"" This reverts commit f98961f0df6bbe10d3f57e4e4975d5835e6ef4b3. --- .../TransactionListTop.test.tsx.snap | 107 ------------------ 1 file changed, 107 deletions(-) diff --git a/src/__tests__/components/__snapshots__/TransactionListTop.test.tsx.snap b/src/__tests__/components/__snapshots__/TransactionListTop.test.tsx.snap index 83660b213b0..5afae59bed4 100644 --- a/src/__tests__/components/__snapshots__/TransactionListTop.test.tsx.snap +++ b/src/__tests__/components/__snapshots__/TransactionListTop.test.tsx.snap @@ -764,113 +764,6 @@ Array [ } /> - - - - - - - - Buy Prepaid Visa® Cards - - - - ,