diff --git a/index.js b/index.js
index 163ecdd4..d3d27b9f 100644
--- a/index.js
+++ b/index.js
@@ -2,6 +2,7 @@ import { AppRegistry } from 'react-native'
import 'node-libs-react-native/globals'
import './shim.js'
import 'react-native-get-random-values'
+import './polyfill'
import App from './src/App'
import { name as appName } from './app.json'
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index cd66925d..0d826695 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -104,6 +104,7 @@ PODS:
- libwebp/mux (1.2.1):
- libwebp/demux
- libwebp/webp (1.2.1)
+ - MultiplatformBleAdapter (0.1.9)
- OpenSSL-Universal (1.1.180)
- Permission-Camera (3.1.0):
- RNPermissions
@@ -324,6 +325,9 @@ PODS:
- React-jsinspector (0.66.0)
- React-logger (0.66.0):
- glog
+ - react-native-ble-plx (2.0.3):
+ - MultiplatformBleAdapter (= 0.1.9)
+ - React-Core
- react-native-camera (3.44.3):
- React-Core
- react-native-camera/RCT (= 3.44.3)
@@ -334,7 +338,7 @@ PODS:
- React-Core
- react-native-get-random-values (1.7.0):
- React-Core
- - react-native-netinfo (6.1.0):
+ - react-native-netinfo (6.2.0):
- React-Core
- react-native-randombytes (3.6.1):
- React-Core
@@ -544,6 +548,7 @@ DEPENDENCIES:
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
+ - react-native-ble-plx (from `../node_modules/react-native-ble-plx`)
- react-native-camera (from `../node_modules/react-native-camera`)
- react-native-get-random-values (from `../node_modules/react-native-get-random-values`)
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
@@ -603,6 +608,7 @@ SPEC REPOS:
- IOSSecuritySuite
- libevent
- libwebp
+ - MultiplatformBleAdapter
- OpenSSL-Universal
- SDWebImage
- SDWebImageWebPCoder
@@ -661,6 +667,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/jsinspector"
React-logger:
:path: "../node_modules/react-native/ReactCommon/logger"
+ react-native-ble-plx:
+ :path: "../node_modules/react-native-ble-plx"
react-native-camera:
:path: "../node_modules/react-native-camera"
react-native-get-random-values:
@@ -767,6 +775,7 @@ SPEC CHECKSUMS:
IOSSecuritySuite: 0dbc01c68ce296c390ccf0443bf68cb40077abe8
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
libwebp: 98a37e597e40bfdb4c911fc98f2c53d0b12d05fc
+ MultiplatformBleAdapter: 5a6a897b006764392f9cef785e4360f54fb9477d
OpenSSL-Universal: 1aa4f6a6ee7256b83db99ec1ccdaa80d10f9af9b
Permission-Camera: 0db4fd6e1c556c1cf47f38b989a8084cea3ec3dd
Permission-FaceID: 34794093f5de6410b373f9245b29632630beab6e
@@ -783,9 +792,10 @@ SPEC CHECKSUMS:
React-jsiexecutor: 6a05173dc0142abc582bd4edd2d23146b8cc218a
React-jsinspector: be95ad424ba9f7b817aff22732eb9b1b810a000a
React-logger: 9a9cd87d4ea681ae929b32ef580638ff1b50fb24
+ react-native-ble-plx: f10240444452dfb2d2a13a0e4f58d7783e92d76e
react-native-camera: b8cc03e2feec0c04403d0998e37cf519d8fd4c6f
react-native-get-random-values: 237bffb1c7e05fb142092681531810a29ba53015
- react-native-netinfo: 5a001e406317eaaf1e4846906650e107dadcaa72
+ react-native-netinfo: de0d4343f8d5ec9b92653b17a0ef47091317986a
react-native-randombytes: 421f1c7d48c0af8dbcd471b0324393ebf8fe7846
react-native-safe-area-context: 584dc04881deb49474363f3be89e4ca0e854c057
react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865
diff --git a/ios/TerraStation.xcodeproj/project.pbxproj b/ios/TerraStation.xcodeproj/project.pbxproj
index 36124b6e..6333ab2f 100644
--- a/ios/TerraStation.xcodeproj/project.pbxproj
+++ b/ios/TerraStation.xcodeproj/project.pbxproj
@@ -320,7 +320,8 @@
isa = PBXNativeTarget;
buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "TerraStationTests" */;
buildPhases = (
- 1094904C30E0599A88A31232 /* [CP] Check Pods Manifest.lock */,
+ 1FBF24C91EF2F5CC0F3EEBFA /* [CP] Check Pods Manifest.lock */,
+ 1094904C30E0599A88A31232 /* ShellScript */,
00E356EA1AD99517003FC87E /* Sources */,
00E356EB1AD99517003FC87E /* Frameworks */,
00E356EC1AD99517003FC87E /* Resources */,
@@ -348,7 +349,7 @@
13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
82CB3A3E8AE96C14458A723E /* [CP] Embed Pods Frameworks */,
- 208C9CA467347E583F98EA0C /* [CP] Copy Pods Resources */,
+ 37E4AC43A832A3B137421FB0 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -369,11 +370,14 @@
TargetAttributes = {
00E356ED1AD99517003FC87E = {
CreatedOnToolsVersion = 6.2;
+ DevelopmentTeam = UYTGWV77XZ;
+ ProvisioningStyle = Manual;
TestTargetID = 13B07F861A680F5B00A75B9A;
};
13B07F861A680F5B00A75B9A = {
- DevelopmentTeam = U5D98K4YPD;
+ DevelopmentTeam = UYTGWV77XZ;
LastSwiftMigration = 1150;
+ ProvisioningStyle = Automatic;
};
};
};
@@ -434,7 +438,7 @@
shellPath = /bin/sh;
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh\n";
};
- 1094904C30E0599A88A31232 /* [CP] Check Pods Manifest.lock */ = {
+ 1094904C30E0599A88A31232 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -457,20 +461,29 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- 0F16806F7C8894FE78ACCAEB /* [CP-User] [RNFB] Core Configuration */ = {
+ 1FBF24C91EF2F5CC0F3EEBFA /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
+ inputFileListPaths = (
+ );
inputPaths = (
- "$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)",
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-TerraStation-TerraStationTests-checkManifestLockResult.txt",
);
- 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 | 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.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 = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
};
- 2E9E1F52522551D5600B71AD /* [CP] Copy Pods Resources */ = {
+ 37E4AC43A832A3B137421FB0 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -527,11 +540,15 @@
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-TerraStation-TerraStationTests/Pods-TerraStation-TerraStationTests-frameworks.sh",
- "${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL/OpenSSL.framework/OpenSSL",
+ "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-DoubleConversion/double-conversion.framework/double-conversion",
+ "${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL-Universal/OpenSSL.framework/OpenSSL",
+ "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/hermes.framework/hermes",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/double-conversion.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@@ -717,6 +734,8 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Manual;
+ DEVELOPMENT_TEAM = UYTGWV77XZ;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
@@ -731,6 +750,8 @@
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TerraStation.app/TerraStation";
};
name = Debug;
@@ -741,7 +762,9 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
+ DEVELOPMENT_TEAM = UYTGWV77XZ;
INFOPLIST_FILE = TerraStationTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
@@ -752,6 +775,8 @@
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TerraStation.app/TerraStation";
};
name = Release;
@@ -763,8 +788,10 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = TerraStation/TerraStation.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 10503003;
- DEVELOPMENT_TEAM = U5D98K4YPD;
+ DEVELOPMENT_TEAM = UYTGWV77XZ;
ENABLE_BITCODE = NO;
EXCLUDED_ARCHS = "";
GCC_PREPROCESSOR_DEFINITIONS = (
@@ -780,8 +807,9 @@
"-ObjC",
"-lc++",
);
- PRODUCT_BUNDLE_IDENTIFIER = money.terra.station;
+ PRODUCT_BUNDLE_IDENTIFIER = money.terra.station.test;
PRODUCT_NAME = TerraStation;
+ PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "./TerraStation/TerraWalletLib/TerraStation-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
@@ -796,8 +824,10 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = TerraStation/TerraStation.entitlements;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 10503003;
- DEVELOPMENT_TEAM = U5D98K4YPD;
+ DEVELOPMENT_TEAM = UYTGWV77XZ;
EXCLUDED_ARCHS = "";
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
INFOPLIST_FILE = TerraStation/Info.plist;
@@ -809,8 +839,9 @@
"-ObjC",
"-lc++",
);
- PRODUCT_BUNDLE_IDENTIFIER = money.terra.station;
+ PRODUCT_BUNDLE_IDENTIFIER = money.terra.station.test;
PRODUCT_NAME = TerraStation;
+ PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "./TerraStation/TerraWalletLib/TerraStation-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
diff --git a/ios/TerraStation/Info.plist b/ios/TerraStation/Info.plist
index a4d6b1ed..d8bdfa08 100644
--- a/ios/TerraStation/Info.plist
+++ b/ios/TerraStation/Info.plist
@@ -67,6 +67,10 @@
+ NSBluetoothAlwaysUsageDescription
+ Connect with Ledger
+ NSBluetoothPeripheralUsageDescription
+ Connect with Ledger
NSCameraUsageDescription
QR Scan
NSFaceIDUsageDescription
diff --git a/package-lock.json b/package-lock.json
index 1353b630..2faaa956 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,6 +10,7 @@
"license": "Apache-2.0",
"dependencies": {
"@apollo/client": "^3.3.10",
+ "@ledgerhq/react-native-hw-transport-ble": "^6.25.1",
"@react-native-community/art": "^1.2.0",
"@react-native-community/checkbox": "^0.5.6",
"@react-native-community/clipboard": "^1.5.1",
@@ -20,6 +21,7 @@
"@react-navigation/native": "^6.0.6",
"@react-navigation/stack": "^6.0.11",
"@sentry/react-native": "^2.2.0",
+ "@terra-money/ledger-terra-js": "^1.2.1",
"@terra-money/log-finder": "^1.1.6",
"@terra-money/log-finder-ruleset": "^1.0.1",
"@terra-money/terra.js": "^3.0.0",
@@ -51,6 +53,7 @@
"react-dom": "^17.0.1",
"react-i18next": "^11.8.6",
"react-native": "^0.66.0",
+ "react-native-ble-plx": "^2.0.3",
"react-native-camera": "^3.42.2",
"react-native-crypto": "^2.2.0",
"react-native-device-info": "^7.3.1",
@@ -3381,6 +3384,132 @@
"node": ">=8"
}
},
+ "node_modules/@ledgerhq/devices": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/@ledgerhq/devices/-/devices-6.24.1.tgz",
+ "integrity": "sha512-6SNXWXxojUF6WKXMVIbRs15Mveg+9k0RKJK/PKlwZh929Lnr/NcbONWdwPjWKZAp1g82eEPT4jIkG6qc4QXlcA==",
+ "dependencies": {
+ "@ledgerhq/errors": "^6.10.0",
+ "@ledgerhq/logs": "^6.10.0",
+ "rxjs": "6",
+ "semver": "^7.3.5"
+ }
+ },
+ "node_modules/@ledgerhq/devices/node_modules/semver": {
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+ "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@ledgerhq/errors": {
+ "version": "6.10.0",
+ "resolved": "https://registry.npmjs.org/@ledgerhq/errors/-/errors-6.10.0.tgz",
+ "integrity": "sha512-fQFnl2VIXh9Yd41lGjReCeK+Q2hwxQJvLZfqHnKqWapTz68NHOv5QcI0OHuZVNEbv0xhgdLhi5b65kgYeQSUVg=="
+ },
+ "node_modules/@ledgerhq/hw-transport": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport/-/hw-transport-6.24.1.tgz",
+ "integrity": "sha512-cOhxkQJrN7DvPFLLXAS2nqAZ7NIDaFqnbgu9ugTccgbJm2/z7ClRZX/uQoI4FscswZ47MuJQdXqz4nK48phteQ==",
+ "dependencies": {
+ "@ledgerhq/devices": "^6.24.1",
+ "@ledgerhq/errors": "^6.10.0",
+ "events": "^3.3.0"
+ }
+ },
+ "node_modules/@ledgerhq/hw-transport-node-hid": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-node-hid/-/hw-transport-node-hid-6.24.1.tgz",
+ "integrity": "sha512-onbxunq8FsiY2sVRR+jRCjC1nx376ANuAtnQsmoHsgxONOVTb5asXWWOV4Cjm8y7RZTCtDw3d1fbziEGRhwiqA==",
+ "dependencies": {
+ "@ledgerhq/devices": "^6.24.1",
+ "@ledgerhq/errors": "^6.10.0",
+ "@ledgerhq/hw-transport": "^6.24.1",
+ "@ledgerhq/hw-transport-node-hid-noevents": "^6.24.1",
+ "@ledgerhq/logs": "^6.10.0",
+ "lodash": "^4.17.21",
+ "node-hid": "2.1.1",
+ "usb": "^1.7.0"
+ }
+ },
+ "node_modules/@ledgerhq/hw-transport-node-hid-noevents": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-node-hid-noevents/-/hw-transport-node-hid-noevents-6.24.1.tgz",
+ "integrity": "sha512-z3uXCU13oayRX51MOaTREdrn83ujrBkccdXn3ljdMy4H3pmAvG6QGn4m30gursEUUJkogA6dkcXs3G8IRfOdxA==",
+ "dependencies": {
+ "@ledgerhq/devices": "^6.24.1",
+ "@ledgerhq/errors": "^6.10.0",
+ "@ledgerhq/hw-transport": "^6.24.1",
+ "@ledgerhq/logs": "^6.10.0",
+ "node-hid": "2.1.1"
+ }
+ },
+ "node_modules/@ledgerhq/hw-transport-webhid": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-webhid/-/hw-transport-webhid-6.24.1.tgz",
+ "integrity": "sha512-jeOB4oSQyytJD99FU+xNUkEflgSB6hWUbzhEqnz7fExnGJhMrRT39035dEmSdwshsOFBhzR/IwTUzlwNZzhNxQ==",
+ "dependencies": {
+ "@ledgerhq/devices": "^6.24.1",
+ "@ledgerhq/errors": "^6.10.0",
+ "@ledgerhq/hw-transport": "^6.24.1",
+ "@ledgerhq/logs": "^6.10.0"
+ }
+ },
+ "node_modules/@ledgerhq/hw-transport-webusb": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-webusb/-/hw-transport-webusb-6.24.1.tgz",
+ "integrity": "sha512-+bAkVF/5MbbGIXobtmc5st/gFEjSRqACk+UPJGSxT21Z2SVm+FgG0Bui5wy24H+Ts/tC4IA3Mff8cz4PGbZhPA==",
+ "dependencies": {
+ "@ledgerhq/devices": "^6.24.1",
+ "@ledgerhq/errors": "^6.10.0",
+ "@ledgerhq/hw-transport": "^6.24.1",
+ "@ledgerhq/logs": "^6.10.0"
+ }
+ },
+ "node_modules/@ledgerhq/hw-transport/node_modules/events": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+ "engines": {
+ "node": ">=0.8.x"
+ }
+ },
+ "node_modules/@ledgerhq/logs": {
+ "version": "6.10.0",
+ "resolved": "https://registry.npmjs.org/@ledgerhq/logs/-/logs-6.10.0.tgz",
+ "integrity": "sha512-lLseUPEhSFUXYTKj6q7s2O3s2vW2ebgA11vMAlKodXGf5AFw4zUoEbTz9CoFOC9jS6xY4Qr8BmRnxP/odT4Uuw=="
+ },
+ "node_modules/@ledgerhq/react-native-hw-transport-ble": {
+ "version": "6.25.1",
+ "resolved": "https://registry.npmjs.org/@ledgerhq/react-native-hw-transport-ble/-/react-native-hw-transport-ble-6.25.1.tgz",
+ "integrity": "sha512-7SZtIciiX44T5rLJSdJ011tT8Fnlx2PHVktzrM5fVEdF1IGDbN4g9S25ppd8nLCsNtoNgwq2TPOWWfmvtEXwIw==",
+ "dependencies": {
+ "@ledgerhq/devices": "^6.24.1",
+ "@ledgerhq/errors": "^6.10.0",
+ "@ledgerhq/hw-transport": "^6.24.1",
+ "@ledgerhq/logs": "^6.10.0",
+ "invariant": "^2.2.4",
+ "react-native-ble-plx": "2.0.3",
+ "rxjs": "6",
+ "uuid": "^3.4.0"
+ }
+ },
+ "node_modules/@ledgerhq/react-native-hw-transport-ble/node_modules/uuid": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
+ "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
+ "bin": {
+ "uuid": "bin/uuid"
+ }
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -5415,6 +5544,23 @@
"node": ">=4"
}
},
+ "node_modules/@terra-money/ledger-terra-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@terra-money/ledger-terra-js/-/ledger-terra-js-1.2.1.tgz",
+ "integrity": "sha512-IdC2Gk1fRrYgU9yLhOiw/4Qci6CRzfxKDMVF5XS8TyTt0r8kz8i8RNqO1DFhYVvb7ngr4ozm14VdOI3gyAXL+Q==",
+ "dependencies": {
+ "@ledgerhq/hw-transport": "^6.20.0",
+ "@ledgerhq/hw-transport-node-hid": "^6.20.0",
+ "@ledgerhq/hw-transport-webhid": "^6.20.0",
+ "@ledgerhq/hw-transport-webusb": "^6.20.0",
+ "bech32": "^2.0.0",
+ "ripemd160": "^2.0.2"
+ },
+ "peerDependencies": {
+ "@terra-money/terra.js": "^3.0.6",
+ "secp256k1": "^4.0.3"
+ }
+ },
"node_modules/@terra-money/log-finder": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/@terra-money/log-finder/-/log-finder-1.1.6.tgz",
@@ -5482,9 +5628,9 @@
}
},
"node_modules/@terra-money/terra.js": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@terra-money/terra.js/-/terra.js-3.0.0.tgz",
- "integrity": "sha512-FVj5gnzx+5YvXFTyoM+i7etpd08XKj9VRAEOwLxldI64tGSaGTyKLr03F0e0xCL3jFFbCPjQhtEBxju5rEEsXw==",
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@terra-money/terra.js/-/terra.js-3.0.7.tgz",
+ "integrity": "sha512-moeVBWqIPZaV0HmCY127Y9H/MsuFtH1VgW0xEvDQWqu1jpKhK5CtPHMLKNje3mKSjU8A7vXZ8hlW3KobqP2poQ==",
"dependencies": {
"@terra-money/terra.proto": "^0.1.7",
"axios": "^0.24.0",
@@ -7849,6 +7995,11 @@
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="
},
+ "node_modules/chownr": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
+ },
"node_modules/ci-info": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
@@ -8798,6 +8949,17 @@
"node": ">=0.10"
}
},
+ "node_modules/decompress-response": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
+ "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
+ "dependencies": {
+ "mimic-response": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/dedent": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
@@ -8832,6 +8994,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/deep-extend": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@@ -8956,6 +9126,17 @@
"resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.2.0.tgz",
"integrity": "sha512-tr7XntDAu50BVENgQfajMLzacmSe34D+qZc4zjnniz0ZVuw/TZcLcyxHQjYpJTM36sGEkZZlYLnIM1hH7alTMA=="
},
+ "node_modules/detect-libc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
+ "bin": {
+ "detect-libc": "bin/detect-libc.js"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
"node_modules/detect-newline": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
@@ -10331,6 +10512,14 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
+ "node_modules/expand-template": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
+ "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/expect": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz",
@@ -11136,6 +11325,11 @@
"node": ">= 0.6"
}
},
+ "node_modules/fs-constants": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
+ },
"node_modules/fs-extra": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz",
@@ -11422,6 +11616,11 @@
"node": ">=6"
}
},
+ "node_modules/github-from-package": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
+ "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4="
+ },
"node_modules/glob": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
@@ -12174,6 +12373,11 @@
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
+ "node_modules/ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
+ },
"node_modules/inline-style-prefixer": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-6.0.1.tgz",
@@ -16861,6 +17065,17 @@
"node": ">=6"
}
},
+ "node_modules/mimic-response": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
+ "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/minimalistic-assert": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
@@ -16938,6 +17153,11 @@
"mkdirp": "bin/cmd.js"
}
},
+ "node_modules/mkdirp-classic": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
+ },
"node_modules/mockdate": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/mockdate/-/mockdate-3.0.5.tgz",
@@ -17007,6 +17227,11 @@
"node": ">=0.10.0"
}
},
+ "node_modules/napi-build-utils": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
+ "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg=="
+ },
"node_modules/natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
@@ -17039,6 +17264,22 @@
"node": ">=4.0.0"
}
},
+ "node_modules/node-abi": {
+ "version": "2.30.1",
+ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz",
+ "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==",
+ "dependencies": {
+ "semver": "^5.4.1"
+ }
+ },
+ "node_modules/node-abi/node_modules/semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "bin": {
+ "semver": "bin/semver"
+ }
+ },
"node_modules/node-addon-api": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz",
@@ -17095,6 +17336,28 @@
"node-gyp-build-test": "build-test.js"
}
},
+ "node_modules/node-hid": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/node-hid/-/node-hid-2.1.1.tgz",
+ "integrity": "sha512-Skzhqow7hyLZU93eIPthM9yjot9lszg9xrKxESleEs05V2NcbUptZc5HFqzjOkSmL0sFlZFr3kmvaYebx06wrw==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "bindings": "^1.5.0",
+ "node-addon-api": "^3.0.2",
+ "prebuild-install": "^6.0.0"
+ },
+ "bin": {
+ "hid-showdevices": "src/show-devices.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/node-hid/node_modules/node-addon-api": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
+ "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A=="
+ },
"node_modules/node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@@ -18256,6 +18519,32 @@
"node": ">=0.10.0"
}
},
+ "node_modules/prebuild-install": {
+ "version": "6.1.4",
+ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz",
+ "integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==",
+ "dependencies": {
+ "detect-libc": "^1.0.3",
+ "expand-template": "^2.0.3",
+ "github-from-package": "0.0.0",
+ "minimist": "^1.2.3",
+ "mkdirp-classic": "^0.5.3",
+ "napi-build-utils": "^1.0.1",
+ "node-abi": "^2.21.0",
+ "npmlog": "^4.0.1",
+ "pump": "^3.0.0",
+ "rc": "^1.2.7",
+ "simple-get": "^3.0.3",
+ "tar-fs": "^2.0.0",
+ "tunnel-agent": "^0.6.0"
+ },
+ "bin": {
+ "prebuild-install": "bin.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -18759,6 +19048,28 @@
"node": ">= 0.6"
}
},
+ "node_modules/rc": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+ "dependencies": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ },
+ "bin": {
+ "rc": "cli.js"
+ }
+ },
+ "node_modules/rc/node_modules/strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/react": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
@@ -18874,6 +19185,11 @@
"react": "17.0.2"
}
},
+ "node_modules/react-native-ble-plx": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/react-native-ble-plx/-/react-native-ble-plx-2.0.3.tgz",
+ "integrity": "sha512-62LRDBPf/03K7sge+qq2ZuF8PWCGB782G+SBrpgNm5fA5Hs3FCY1ExTJZ1G0tB5ZhBPYEXcKRxPLuFegcDFrqA=="
+ },
"node_modules/react-native-camera": {
"version": "3.44.3",
"resolved": "https://registry.npmjs.org/react-native-camera/-/react-native-camera-3.44.3.tgz",
@@ -20448,12 +20764,12 @@
}
},
"node_modules/secp256k1": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz",
- "integrity": "sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==",
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz",
+ "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==",
"hasInstallScript": true,
"dependencies": {
- "elliptic": "^6.5.2",
+ "elliptic": "^6.5.4",
"node-addon-api": "^2.0.0",
"node-gyp-build": "^4.2.0"
},
@@ -20712,6 +21028,35 @@
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz",
"integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ=="
},
+ "node_modules/simple-concat": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
+ "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/simple-get": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
+ "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
+ "dependencies": {
+ "decompress-response": "^4.2.0",
+ "once": "^1.3.1",
+ "simple-concat": "^1.0.0"
+ }
+ },
"node_modules/simple-plist": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.3.0.tgz",
@@ -21768,6 +22113,86 @@
"node": ">=8"
}
},
+ "node_modules/tar-fs": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
+ "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
+ "dependencies": {
+ "chownr": "^1.1.1",
+ "mkdirp-classic": "^0.5.2",
+ "pump": "^3.0.0",
+ "tar-stream": "^2.1.4"
+ }
+ },
+ "node_modules/tar-stream": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+ "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+ "dependencies": {
+ "bl": "^4.0.3",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tar-stream/node_modules/bl": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+ "dependencies": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ }
+ },
+ "node_modules/tar-stream/node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "node_modules/tar-stream/node_modules/readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/tar-stream/node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
"node_modules/temp": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz",
@@ -22148,6 +22573,17 @@
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
"integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY="
},
+ "node_modules/tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -22473,6 +22909,24 @@
"node": ">=0.4.x"
}
},
+ "node_modules/usb": {
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/usb/-/usb-1.9.2.tgz",
+ "integrity": "sha512-dryNz030LWBPAf6gj8vyq0Iev3vPbCLHCT8dBw3gQRXRzVNsIdeuU+VjPp3ksmSPkeMAl1k+kQ14Ij0QHyeiAg==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "node-addon-api": "^4.2.0",
+ "node-gyp-build": "^4.3.0"
+ },
+ "engines": {
+ "node": ">=10.16.0"
+ }
+ },
+ "node_modules/usb/node_modules/node-addon-api": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
+ "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ=="
+ },
"node_modules/use": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
@@ -25624,6 +26078,125 @@
}
}
},
+ "@ledgerhq/devices": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/@ledgerhq/devices/-/devices-6.24.1.tgz",
+ "integrity": "sha512-6SNXWXxojUF6WKXMVIbRs15Mveg+9k0RKJK/PKlwZh929Lnr/NcbONWdwPjWKZAp1g82eEPT4jIkG6qc4QXlcA==",
+ "requires": {
+ "@ledgerhq/errors": "^6.10.0",
+ "@ledgerhq/logs": "^6.10.0",
+ "rxjs": "6",
+ "semver": "^7.3.5"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+ "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ }
+ }
+ },
+ "@ledgerhq/errors": {
+ "version": "6.10.0",
+ "resolved": "https://registry.npmjs.org/@ledgerhq/errors/-/errors-6.10.0.tgz",
+ "integrity": "sha512-fQFnl2VIXh9Yd41lGjReCeK+Q2hwxQJvLZfqHnKqWapTz68NHOv5QcI0OHuZVNEbv0xhgdLhi5b65kgYeQSUVg=="
+ },
+ "@ledgerhq/hw-transport": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport/-/hw-transport-6.24.1.tgz",
+ "integrity": "sha512-cOhxkQJrN7DvPFLLXAS2nqAZ7NIDaFqnbgu9ugTccgbJm2/z7ClRZX/uQoI4FscswZ47MuJQdXqz4nK48phteQ==",
+ "requires": {
+ "@ledgerhq/devices": "^6.24.1",
+ "@ledgerhq/errors": "^6.10.0",
+ "events": "^3.3.0"
+ },
+ "dependencies": {
+ "events": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="
+ }
+ }
+ },
+ "@ledgerhq/hw-transport-node-hid": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-node-hid/-/hw-transport-node-hid-6.24.1.tgz",
+ "integrity": "sha512-onbxunq8FsiY2sVRR+jRCjC1nx376ANuAtnQsmoHsgxONOVTb5asXWWOV4Cjm8y7RZTCtDw3d1fbziEGRhwiqA==",
+ "requires": {
+ "@ledgerhq/devices": "^6.24.1",
+ "@ledgerhq/errors": "^6.10.0",
+ "@ledgerhq/hw-transport": "^6.24.1",
+ "@ledgerhq/hw-transport-node-hid-noevents": "^6.24.1",
+ "@ledgerhq/logs": "^6.10.0",
+ "lodash": "^4.17.21",
+ "node-hid": "2.1.1",
+ "usb": "^1.7.0"
+ }
+ },
+ "@ledgerhq/hw-transport-node-hid-noevents": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-node-hid-noevents/-/hw-transport-node-hid-noevents-6.24.1.tgz",
+ "integrity": "sha512-z3uXCU13oayRX51MOaTREdrn83ujrBkccdXn3ljdMy4H3pmAvG6QGn4m30gursEUUJkogA6dkcXs3G8IRfOdxA==",
+ "requires": {
+ "@ledgerhq/devices": "^6.24.1",
+ "@ledgerhq/errors": "^6.10.0",
+ "@ledgerhq/hw-transport": "^6.24.1",
+ "@ledgerhq/logs": "^6.10.0",
+ "node-hid": "2.1.1"
+ }
+ },
+ "@ledgerhq/hw-transport-webhid": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-webhid/-/hw-transport-webhid-6.24.1.tgz",
+ "integrity": "sha512-jeOB4oSQyytJD99FU+xNUkEflgSB6hWUbzhEqnz7fExnGJhMrRT39035dEmSdwshsOFBhzR/IwTUzlwNZzhNxQ==",
+ "requires": {
+ "@ledgerhq/devices": "^6.24.1",
+ "@ledgerhq/errors": "^6.10.0",
+ "@ledgerhq/hw-transport": "^6.24.1",
+ "@ledgerhq/logs": "^6.10.0"
+ }
+ },
+ "@ledgerhq/hw-transport-webusb": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-webusb/-/hw-transport-webusb-6.24.1.tgz",
+ "integrity": "sha512-+bAkVF/5MbbGIXobtmc5st/gFEjSRqACk+UPJGSxT21Z2SVm+FgG0Bui5wy24H+Ts/tC4IA3Mff8cz4PGbZhPA==",
+ "requires": {
+ "@ledgerhq/devices": "^6.24.1",
+ "@ledgerhq/errors": "^6.10.0",
+ "@ledgerhq/hw-transport": "^6.24.1",
+ "@ledgerhq/logs": "^6.10.0"
+ }
+ },
+ "@ledgerhq/logs": {
+ "version": "6.10.0",
+ "resolved": "https://registry.npmjs.org/@ledgerhq/logs/-/logs-6.10.0.tgz",
+ "integrity": "sha512-lLseUPEhSFUXYTKj6q7s2O3s2vW2ebgA11vMAlKodXGf5AFw4zUoEbTz9CoFOC9jS6xY4Qr8BmRnxP/odT4Uuw=="
+ },
+ "@ledgerhq/react-native-hw-transport-ble": {
+ "version": "6.25.1",
+ "resolved": "https://registry.npmjs.org/@ledgerhq/react-native-hw-transport-ble/-/react-native-hw-transport-ble-6.25.1.tgz",
+ "integrity": "sha512-7SZtIciiX44T5rLJSdJ011tT8Fnlx2PHVktzrM5fVEdF1IGDbN4g9S25ppd8nLCsNtoNgwq2TPOWWfmvtEXwIw==",
+ "requires": {
+ "@ledgerhq/devices": "^6.24.1",
+ "@ledgerhq/errors": "^6.10.0",
+ "@ledgerhq/hw-transport": "^6.24.1",
+ "@ledgerhq/logs": "^6.10.0",
+ "invariant": "^2.2.4",
+ "react-native-ble-plx": "2.0.3",
+ "rxjs": "6",
+ "uuid": "^3.4.0"
+ },
+ "dependencies": {
+ "uuid": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
+ }
+ }
+ },
"@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -27187,6 +27760,19 @@
}
}
},
+ "@terra-money/ledger-terra-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@terra-money/ledger-terra-js/-/ledger-terra-js-1.2.1.tgz",
+ "integrity": "sha512-IdC2Gk1fRrYgU9yLhOiw/4Qci6CRzfxKDMVF5XS8TyTt0r8kz8i8RNqO1DFhYVvb7ngr4ozm14VdOI3gyAXL+Q==",
+ "requires": {
+ "@ledgerhq/hw-transport": "^6.20.0",
+ "@ledgerhq/hw-transport-node-hid": "^6.20.0",
+ "@ledgerhq/hw-transport-webhid": "^6.20.0",
+ "@ledgerhq/hw-transport-webusb": "^6.20.0",
+ "bech32": "^2.0.0",
+ "ripemd160": "^2.0.2"
+ }
+ },
"@terra-money/log-finder": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/@terra-money/log-finder/-/log-finder-1.1.6.tgz",
@@ -27250,9 +27836,9 @@
}
},
"@terra-money/terra.js": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@terra-money/terra.js/-/terra.js-3.0.0.tgz",
- "integrity": "sha512-FVj5gnzx+5YvXFTyoM+i7etpd08XKj9VRAEOwLxldI64tGSaGTyKLr03F0e0xCL3jFFbCPjQhtEBxju5rEEsXw==",
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@terra-money/terra.js/-/terra.js-3.0.7.tgz",
+ "integrity": "sha512-moeVBWqIPZaV0HmCY127Y9H/MsuFtH1VgW0xEvDQWqu1jpKhK5CtPHMLKNje3mKSjU8A7vXZ8hlW3KobqP2poQ==",
"requires": {
"@terra-money/terra.proto": "^0.1.7",
"axios": "^0.24.0",
@@ -29230,6 +29816,11 @@
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="
},
+ "chownr": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
+ },
"ci-info": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
@@ -30047,6 +30638,14 @@
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
},
+ "decompress-response": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
+ "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
+ "requires": {
+ "mimic-response": "^2.0.0"
+ }
+ },
"dedent": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
@@ -30074,6 +30673,11 @@
"regexp.prototype.flags": "^1.2.0"
}
},
+ "deep-extend": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
+ },
"deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@@ -30181,6 +30785,11 @@
"resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.2.0.tgz",
"integrity": "sha512-tr7XntDAu50BVENgQfajMLzacmSe34D+qZc4zjnniz0ZVuw/TZcLcyxHQjYpJTM36sGEkZZlYLnIM1hH7alTMA=="
},
+ "detect-libc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
+ },
"detect-newline": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
@@ -31227,6 +31836,11 @@
}
}
},
+ "expand-template": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
+ "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="
+ },
"expect": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz",
@@ -31859,6 +32473,11 @@
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
+ "fs-constants": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
+ },
"fs-extra": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz",
@@ -32079,6 +32698,11 @@
"resolved": "https://registry.npmjs.org/getenv/-/getenv-1.0.0.tgz",
"integrity": "sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg=="
},
+ "github-from-package": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
+ "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4="
+ },
"glob": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
@@ -32641,6 +33265,11 @@
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
+ "ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
+ },
"inline-style-prefixer": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-6.0.1.tgz",
@@ -36329,6 +36958,11 @@
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
},
+ "mimic-response": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
+ "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA=="
+ },
"minimalistic-assert": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
@@ -36390,6 +37024,11 @@
"minimist": "^1.2.5"
}
},
+ "mkdirp-classic": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
+ },
"mockdate": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/mockdate/-/mockdate-3.0.5.tgz",
@@ -36447,6 +37086,11 @@
"to-regex": "^3.0.1"
}
},
+ "napi-build-utils": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
+ "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg=="
+ },
"natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
@@ -36473,6 +37117,21 @@
"resolved": "https://registry.npmjs.org/nocache/-/nocache-2.1.0.tgz",
"integrity": "sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q=="
},
+ "node-abi": {
+ "version": "2.30.1",
+ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz",
+ "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==",
+ "requires": {
+ "semver": "^5.4.1"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+ }
+ }
+ },
"node-addon-api": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz",
@@ -36520,6 +37179,23 @@
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz",
"integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q=="
},
+ "node-hid": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/node-hid/-/node-hid-2.1.1.tgz",
+ "integrity": "sha512-Skzhqow7hyLZU93eIPthM9yjot9lszg9xrKxESleEs05V2NcbUptZc5HFqzjOkSmL0sFlZFr3kmvaYebx06wrw==",
+ "requires": {
+ "bindings": "^1.5.0",
+ "node-addon-api": "^3.0.2",
+ "prebuild-install": "^6.0.0"
+ },
+ "dependencies": {
+ "node-addon-api": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
+ "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A=="
+ }
+ }
+ },
"node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@@ -37409,6 +38085,26 @@
"resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
"integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs="
},
+ "prebuild-install": {
+ "version": "6.1.4",
+ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz",
+ "integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==",
+ "requires": {
+ "detect-libc": "^1.0.3",
+ "expand-template": "^2.0.3",
+ "github-from-package": "0.0.0",
+ "minimist": "^1.2.3",
+ "mkdirp-classic": "^0.5.3",
+ "napi-build-utils": "^1.0.1",
+ "node-abi": "^2.21.0",
+ "npmlog": "^4.0.1",
+ "pump": "^3.0.0",
+ "rc": "^1.2.7",
+ "simple-get": "^3.0.3",
+ "tar-fs": "^2.0.0",
+ "tunnel-agent": "^0.6.0"
+ }
+ },
"prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -37794,6 +38490,24 @@
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
},
+ "rc": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+ "requires": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ },
+ "dependencies": {
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
+ }
+ }
+ },
"react": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
@@ -37895,6 +38609,11 @@
}
}
},
+ "react-native-ble-plx": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/react-native-ble-plx/-/react-native-ble-plx-2.0.3.tgz",
+ "integrity": "sha512-62LRDBPf/03K7sge+qq2ZuF8PWCGB782G+SBrpgNm5fA5Hs3FCY1ExTJZ1G0tB5ZhBPYEXcKRxPLuFegcDFrqA=="
+ },
"react-native-camera": {
"version": "3.44.3",
"resolved": "https://registry.npmjs.org/react-native-camera/-/react-native-camera-3.44.3.tgz",
@@ -39104,11 +39823,11 @@
}
},
"secp256k1": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz",
- "integrity": "sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==",
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz",
+ "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==",
"requires": {
- "elliptic": "^6.5.2",
+ "elliptic": "^6.5.4",
"node-addon-api": "^2.0.0",
"node-gyp-build": "^4.2.0"
}
@@ -39316,6 +40035,21 @@
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz",
"integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ=="
},
+ "simple-concat": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
+ "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="
+ },
+ "simple-get": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
+ "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
+ "requires": {
+ "decompress-response": "^4.2.0",
+ "once": "^1.3.1",
+ "simple-concat": "^1.0.0"
+ }
+ },
"simple-plist": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.3.0.tgz",
@@ -40171,6 +40905,68 @@
}
}
},
+ "tar-fs": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
+ "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
+ "requires": {
+ "chownr": "^1.1.1",
+ "mkdirp-classic": "^0.5.2",
+ "pump": "^3.0.0",
+ "tar-stream": "^2.1.4"
+ }
+ },
+ "tar-stream": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+ "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+ "requires": {
+ "bl": "^4.0.3",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
+ },
+ "dependencies": {
+ "bl": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+ "requires": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ }
+ },
+ "buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "requires": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "requires": {
+ "safe-buffer": "~5.2.0"
+ }
+ }
+ }
+ },
"temp": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz",
@@ -40482,6 +41278,14 @@
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
"integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY="
},
+ "tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "requires": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
"type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -40733,6 +41537,22 @@
"requires-port": "^1.0.0"
}
},
+ "usb": {
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/usb/-/usb-1.9.2.tgz",
+ "integrity": "sha512-dryNz030LWBPAf6gj8vyq0Iev3vPbCLHCT8dBw3gQRXRzVNsIdeuU+VjPp3ksmSPkeMAl1k+kQ14Ij0QHyeiAg==",
+ "requires": {
+ "node-addon-api": "^4.2.0",
+ "node-gyp-build": "^4.3.0"
+ },
+ "dependencies": {
+ "node-addon-api": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
+ "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ=="
+ }
+ }
+ },
"use": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
diff --git a/package.json b/package.json
index 8138df74..5cffdd23 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
},
"dependencies": {
"@apollo/client": "^3.3.10",
+ "@ledgerhq/react-native-hw-transport-ble": "^6.25.1",
"@react-native-community/art": "^1.2.0",
"@react-native-community/checkbox": "^0.5.6",
"@react-native-community/clipboard": "^1.5.1",
@@ -33,6 +34,7 @@
"@react-navigation/native": "^6.0.6",
"@react-navigation/stack": "^6.0.11",
"@sentry/react-native": "^2.2.0",
+ "@terra-money/ledger-terra-js": "^1.2.1",
"@terra-money/log-finder": "^1.1.6",
"@terra-money/log-finder-ruleset": "^1.0.1",
"@terra-money/terra.js": "^3.0.0",
@@ -64,6 +66,7 @@
"react-dom": "^17.0.1",
"react-i18next": "^11.8.6",
"react-native": "^0.66.0",
+ "react-native-ble-plx": "^2.0.3",
"react-native-camera": "^3.42.2",
"react-native-crypto": "^2.2.0",
"react-native-device-info": "^7.3.1",
diff --git a/polyfill.js b/polyfill.js
new file mode 100644
index 00000000..550d4749
--- /dev/null
+++ b/polyfill.js
@@ -0,0 +1 @@
+global.Buffer = require('buffer').Buffer
\ No newline at end of file
diff --git a/src/App/LoadingView.tsx b/src/App/LoadingView.tsx
index 4bf692ea..cc88b041 100644
--- a/src/App/LoadingView.tsx
+++ b/src/App/LoadingView.tsx
@@ -20,7 +20,8 @@ import { truncate } from 'lib/utils/format'
const LoadingView = (): ReactElement => {
const showLoading = useRecoilValue(AppStore.showLoading)
const txhash = useRecoilValue(AppStore.loadingTxHash)
- const [displayTxhash, setDisplayTxhash] = useState(txhash)
+ const title = useRecoilValue(AppStore.loadingTitle)
+ const [displayTxhash, setDisplayTxhash] = useState(txhash)
const start = useMemo(() => new Date(), [txhash])
const [now, setNow] = useState(new Date())
@@ -32,6 +33,8 @@ const LoadingView = (): ReactElement => {
if (txhash) {
setDisplayTxhash(txhash)
interval = setInterval(() => setNow(new Date()), 1000)
+ } else {
+ setDisplayTxhash(undefined)
}
return (): void => {
interval && clearInterval(interval)
@@ -53,7 +56,7 @@ const LoadingView = (): ReactElement => {
style={{ width: 160, height: 160, marginBottom: 5 }}
/>
- Broadcasting transaction
+ {title || 'Broadcasting transaction'}
{_.some(displayTxhash) && (
@@ -92,7 +95,7 @@ const LoadingView = (): ReactElement => {
style={styles.txhashText}
fontType="medium"
>
- {truncate(displayTxhash, [6, 6])}
+ {truncate(displayTxhash || '', [6, 6])}
{
+ return (
+
+
+
+ {title || 'Oops! Something went wrong'}
+
+
+ {content || 'You have encountered an error'}
+
+
+ )
+}
+
+export default Error
diff --git a/src/components/index.tsx b/src/components/index.tsx
index 49fbbe8c..c41e5ec2 100644
--- a/src/components/index.tsx
+++ b/src/components/index.tsx
@@ -17,6 +17,7 @@ export {
export { default as CopyButton } from './CopyButton'
export { default as QrCodeButton } from './QrCodeButton'
export { default as BiometricButton } from './BiometricButton'
+export { default as Error } from './Error'
export { default as ErrorComponent } from './ErrorComponent'
export { default as Loading } from './Loading'
export { default as WarningBox } from './WarningBox'
diff --git a/src/hooks/useConfirm.ts b/src/hooks/useConfirm.ts
index a879c127..f923094a 100644
--- a/src/hooks/useConfirm.ts
+++ b/src/hooks/useConfirm.ts
@@ -16,11 +16,9 @@ import {
import ConfirmStore from 'stores/ConfirmStore'
import { RootStackParams } from 'types'
-// @ts-ignore
-import getSigner from 'utils/wallet-helper/signer'
-// @ts-ignore
-import signTx from 'utils/wallet-helper/api/signTx'
import { getDecyrptedKey } from 'utils/wallet'
+import { LedgerKey } from '@terra-money/ledger-terra-js'
+import TransportBLE from '@ledgerhq/react-native-hw-transport-ble'
export type NavigateToConfirmProps = {
confirm: ConfirmProps
@@ -65,26 +63,19 @@ export const useConfirm = (): {
return useStationConfirm(confirm, {
user,
password: '',
- sign: async ({ tx, base, password }) => {
- const decyrptedKey = await getDecyrptedKey(
- user.name,
- password
- )
- if (_.isEmpty(decyrptedKey)) {
- throw new Error('Incorrect password')
- }
- const rk = new RawKey(Buffer.from(decyrptedKey, 'hex'))
- const signer = await getSigner(rk.privateKey, rk.publicKey)
- const signedTx = await signTx(tx, signer, base)
- return signedTx
- },
getKey: async (params): Promise => {
- const { name, password } = params!
- const decyrptedKey = await getDecyrptedKey(name, password)
- if (_.isEmpty(decyrptedKey)) {
- throw new Error('Incorrect password')
+ if(user.ledger) {
+ const { password } = params!
+ const transport = await TransportBLE.open(password) /// select device
+ return await LedgerKey.create(transport, user.path)
+ } else {
+ const { name, password } = params!
+ const decyrptedKey = await getDecyrptedKey(name, password)
+ if (_.isEmpty(decyrptedKey)) {
+ throw new Error('Incorrect password')
+ }
+ return new RawKey(Buffer.from(decyrptedKey, 'hex'))
}
- return new RawKey(Buffer.from(decyrptedKey, 'hex'))
},
})
}
diff --git a/src/hooks/useLoading.tsx b/src/hooks/useLoading.tsx
index 71059783..b29de338 100644
--- a/src/hooks/useLoading.tsx
+++ b/src/hooks/useLoading.tsx
@@ -13,20 +13,25 @@ export const useLoading = ({
keyof RootStackParams
>
}): {
- showLoading: ({ txhash }: { txhash?: string }) => void
+ showLoading: ({ txhash, title }: { txhash?: string, title?: string }) => void
hideLoading: () => Promise
} => {
const setShowLoading = useSetRecoilState(AppStore.showLoading)
const [loadingTxHash, setLoadingTxHash] = useRecoilState(
AppStore.loadingTxHash
)
+ const [, setLoadingTitle] = useRecoilState(
+ AppStore.loadingTitle
+ )
- const showLoading = ({ txhash }: { txhash?: string }): void => {
+ const showLoading = ({ txhash, title }: { txhash?: string, title?: string }): void => {
setShowLoading(true)
setLoadingTxHash(txhash || '')
+ setLoadingTitle(title || '')
}
const hideLoading = async (): Promise => {
setLoadingTxHash('')
+ setLoadingTitle('')
return await new Promise((resolve) => {
setTimeout(() => {
setShowLoading(false)
diff --git a/src/hooks/useTx.ts b/src/hooks/useTx.ts
index 8ad86930..66269512 100644
--- a/src/hooks/useTx.ts
+++ b/src/hooks/useTx.ts
@@ -17,6 +17,9 @@ import { useLoading } from './useLoading'
import { RootStackParams } from 'types'
import useLCD from './useLCD'
+import { LedgerKey } from '@terra-money/ledger-terra-js'
+import TransportBLE from '@ledgerhq/react-native-hw-transport-ble'
+
const useTx = ({
user,
navigation,
@@ -26,9 +29,7 @@ const useTx = ({
}): {
broadcastResult?: TxInfo
broadcastSync: (props: {
- address: string
- walletName: string
- password: string
+ password: string // is the device id for ledger
txOptions: CreateTxOptions
}) => Promise
} => {
@@ -56,9 +57,9 @@ const useTx = ({
txOptions: CreateTxOptions
}): Promise => {
const chainID = chain.current.chainID
- const key = await getKey({
- password,
- })
+ const key = user.ledger
+ ? await LedgerKey.create(await TransportBLE.open(password), user.path)
+ : await getKey({ password })
const wallet = new Wallet(lcd, key)
const {
@@ -90,7 +91,9 @@ const useTx = ({
accountNumber: account_number,
sequence,
chainID,
- signMode: SignMode.SIGN_MODE_DIRECT,
+ signMode: user.ledger
+ ? SignMode.SIGN_MODE_LEGACY_AMINO_JSON
+ : SignMode.SIGN_MODE_DIRECT,
})
const result = await lcd.tx.broadcastSync(signed)
if ('code' in result && Number(result.code) !== 0) {
diff --git a/src/hooks/useWalletConnectConfirm.ts b/src/hooks/useWalletConnectConfirm.ts
index ce12efe9..d58e577f 100644
--- a/src/hooks/useWalletConnectConfirm.ts
+++ b/src/hooks/useWalletConnectConfirm.ts
@@ -85,18 +85,13 @@ const useWalletConnectConfirm = ({
const confirmSign = async ({
password,
- address,
- walletName,
txOptions,
}: {
password: string
- address: string
- walletName: string
txOptions: CreateTxOptions
}): Promise => {
+
broadcastSync({
- address,
- walletName,
password,
txOptions,
}).catch((error) => {
diff --git a/src/lib/post/useConfirm.ts b/src/lib/post/useConfirm.ts
index 8a7dda16..8f3d80bb 100644
--- a/src/lib/post/useConfirm.ts
+++ b/src/lib/post/useConfirm.ts
@@ -13,7 +13,6 @@ import { SignMode } from '@terra-money/terra.proto/cosmos/tx/signing/v1beta1/sig
import {
ConfirmProps,
ConfirmPage,
- Sign,
Field,
GetKey,
User,
@@ -32,7 +31,6 @@ interface SignParams {
user: User
password?: string
getKey: GetKey
- sign: Sign
}
export default (
@@ -50,7 +48,7 @@ export default (
const { t } = useTranslation()
const { ERROR } = useInfo()
- const { name, address } = user
+ const { name, address, ledger } = user
const SUCCESS = {
title: t('Post:Confirm:Success!'),
@@ -160,6 +158,7 @@ export default (
const [submitted, setSubmitted] = useState(false)
const [result, setResult] = useState()
const [txhash, setTxHash] = useState()
+ let device = ''
const submit = async (): Promise => {
if (!unsignedTx) return
@@ -189,17 +188,18 @@ export default (
const { gasPrices } = calcFee!
const lcd = new LCDClient({ chainID, URL, gasPrices })
- const key = await getKey(name ? { name, password } : undefined)
+ const key = await getKey(name ? { name, password: ledger ? device : password } : undefined)
const wallet = new Wallet(lcd, key)
const {
account_number,
sequence,
} = await wallet.accountNumberAndSequence()
+
const signed = await key.signTx(unsignedTx, {
accountNumber: account_number,
sequence,
chainID,
- signMode: SignMode.SIGN_MODE_DIRECT,
+ signMode: ledger ? SignMode.SIGN_MODE_LEGACY_AMINO_JSON : SignMode.SIGN_MODE_DIRECT,
})
await broadcast(signed)
} catch (error) {
@@ -321,7 +321,11 @@ export default (
onSubmit: disabled ? undefined : onSubmit,
submitting,
},
-
+ ledger: {
+ onSubmit,
+ setDevice: (d) => { device = d },
+ submitting
+ },
result: simulatedErrorMessage
? { ...ERROR, content: simulatedErrorMessage }
: errorMessage
diff --git a/src/lib/post/useSwapMultiple.ts b/src/lib/post/useSwapMultiple.ts
index c41bda82..49d6fc59 100644
--- a/src/lib/post/useSwapMultiple.ts
+++ b/src/lib/post/useSwapMultiple.ts
@@ -14,7 +14,7 @@ import {
Field,
} from '../types'
import { BankData, Pairs, ConfirmProps } from '../types'
-import { format, gt, minus, sum } from '../utils'
+import { format, gt, sum } from '../utils'
import { toInput } from '../utils/format'
import { useConfig } from '../contexts/ConfigContext'
import { getFeeDenomList, isFeeAvailable } from './validateConfirm'
diff --git a/src/lib/types/auth/auth.ts b/src/lib/types/auth/auth.ts
index a542877a..bc16efa7 100644
--- a/src/lib/types/auth/auth.ts
+++ b/src/lib/types/auth/auth.ts
@@ -1,6 +1,8 @@
export interface User {
address: string
name: string
+ ledger?: boolean
+ path?: number
}
export interface Auth {
diff --git a/src/lib/types/data/confirm.ts b/src/lib/types/data/confirm.ts
index 512ceb01..951aeaa8 100644
--- a/src/lib/types/data/confirm.ts
+++ b/src/lib/types/data/confirm.ts
@@ -38,6 +38,11 @@ export interface ConfirmPage extends Pick {
message?: string
}
form: FormUI
+ ledger: {
+ onSubmit: () => void
+ setDevice: (d: string) => void
+ submitting: boolean,
+ }
result?: Card
txhash?: string
}
diff --git a/src/navigatoin/AuthNavigator.tsx b/src/navigatoin/AuthNavigator.tsx
index 8e138716..e931c7e2 100644
--- a/src/navigatoin/AuthNavigator.tsx
+++ b/src/navigatoin/AuthNavigator.tsx
@@ -5,6 +5,7 @@ import AuthMenu from '../screens/auth/AuthMenu'
import SelectWallet from '../screens/auth/SelectWallet'
import NewWalletStack from './NewWalletStack'
import RecoverWalletStack from './RecoverWalletStack'
+import ConnectLedgerStack from './ConnectLedgerStack'
import WalletConnectDisconnected from '../screens/WalletConnectDisconnected'
const AppNavigator = (): ReactElement => {
@@ -30,6 +31,11 @@ const AppNavigator = (): ReactElement => {
component={RecoverWalletStack}
options={{ headerShown: false }}
/>
+
(
+
+
+
+
+
+)
+
+export default LedgerStack
+
diff --git a/src/navigatoin/MainNavigator.tsx b/src/navigatoin/MainNavigator.tsx
index 7043ba09..ff79686d 100644
--- a/src/navigatoin/MainNavigator.tsx
+++ b/src/navigatoin/MainNavigator.tsx
@@ -13,6 +13,7 @@ import Complete from '../screens/Complete'
import VestingSchedule from '../screens/VestingSchedule'
import Confirm from '../screens/Confirm'
import ConfirmPassword from '../screens/ConfirmPassword'
+import ConfirmLedger from '../screens/ConfirmLedger'
import Delegate from '../screens/Delegate'
import SendTxPasswordView from '../screens/topup/SendTxPasswordView'
@@ -101,6 +102,11 @@ const MainNavigator = (): ReactElement => {
component={ConfirmPassword}
options={ConfirmPassword.navigationOptions}
/>
+
=> {
setPressedNextButton(true)
- if (isUseBioAuth) {
+ if (user.ledger) {
+ navigate('ConfirmLedger', {
+ feeSelectValue: fee.select.attrs.value || '',
+ })
+ } else if (isUseBioAuth) {
const isSuccess = await authenticateBiometric()
if (isSuccess) {
const password = await getBioAuthPassword({
@@ -304,7 +308,7 @@ const Render = ({
_.isEmpty(options) ||
false === initPageComplete
}
- title={'Confirm'}
+ title={'Confirm' + (user.ledger ? ' with Ledger' : '')}
onPress={onPressNextButton}
containerStyle={{ marginTop: 20, marginBottom: 40 }}
/>
diff --git a/src/screens/ConfirmLedger/index.tsx b/src/screens/ConfirmLedger/index.tsx
new file mode 100644
index 00000000..9e5cf5b4
--- /dev/null
+++ b/src/screens/ConfirmLedger/index.tsx
@@ -0,0 +1,116 @@
+import React, { ReactElement, useEffect } from 'react'
+import { StackScreenProps } from '@react-navigation/stack'
+import { useRecoilValue } from 'recoil'
+import _ from 'lodash'
+import {
+ NavigationProp,
+ StackActions,
+ useNavigation,
+} from '@react-navigation/native'
+
+import { ConfirmProps, User } from 'lib'
+
+import Body from 'components/layout/Body'
+import WithAuth from 'components/layout/WithAuth'
+import { navigationHeaderOptions } from 'components/layout/Header'
+import SubHeader from 'components/layout/SubHeader'
+import { Loading } from 'components'
+
+import { RootStackParams } from 'types/navigation'
+
+import ConfirmStore from 'stores/ConfirmStore'
+import { useConfirm } from 'hooks/useConfirm'
+import { useLoading } from 'hooks/useLoading'
+import DeviceSelector from '../../screens/auth/ConnectLedger/DeviceSelector'
+
+type Props = StackScreenProps
+
+const Render = ({
+ confirm,
+ user,
+ route,
+ navigation,
+}: {
+ user: User
+ confirm: ConfirmProps
+} & Props): ReactElement => {
+ const feeSelectValue = route.params.feeSelectValue
+ const { getComfirmData, initConfirm } = useConfirm()
+ const { showLoading, hideLoading } = useLoading({ navigation })
+ const { result, ledger, fee, txhash } = getComfirmData({
+ confirm,
+ user,
+ })
+
+ const { navigate, dispatch } = useNavigation<
+ NavigationProp
+ >()
+
+ // during form is submitting, show loading
+ useEffect(() => {
+ txhash && showLoading({ txhash })
+ }, [txhash])
+
+ // during form is submitting, show loading
+ useEffect(() => {
+ ledger.submitting && showLoading({ txhash, title: 'Confirm in your Ledger' })
+ }, [ledger.submitting])
+
+ // result will set after form.onSubmit or error
+ useEffect(() => {
+ if (result) {
+ hideLoading().then(() => {
+ dispatch(StackActions.popToTop())
+ navigate('Complete', { result })
+ initConfirm()
+ })
+ }
+ }, [result?.title])
+
+ useEffect(() => {
+ if (_.some(fee.select.options)) {
+ fee.select.setValue(feeSelectValue)
+ }
+ }, [fee.select.options])
+
+ return (
+ <>
+
+
+ {_.some(fee.status) ? (
+
+ ) : (
+ { ledger.setDevice(id); ledger.onSubmit() }} />
+ )}
+
+ >
+ )
+}
+
+const ConfirmLedger= (props: Props): ReactElement => {
+ const confirm = useRecoilValue(ConfirmStore.confirm)
+
+ return (
+
+ {(user): ReactElement => (
+ <>
+ {confirm ? (
+
+ ) : null}
+ >
+ )}
+
+ )
+}
+
+ConfirmLedger.navigationOptions = navigationHeaderOptions({
+ theme: 'sapphire',
+})
+
+export default ConfirmLedger
diff --git a/src/screens/Setting/index.tsx b/src/screens/Setting/index.tsx
index 9aa49f3b..456ca812 100644
--- a/src/screens/Setting/index.tsx
+++ b/src/screens/Setting/index.tsx
@@ -228,7 +228,7 @@ const Setting = (): ReactElement => {
containerStyle={{ paddingHorizontal: 0 }}
>
- {user && (
+ {user && !user.ledger && (
{supportBioAuth && (
diff --git a/src/screens/StakingInformation.tsx b/src/screens/StakingInformation.tsx
index 90da71d4..341b5d38 100644
--- a/src/screens/StakingInformation.tsx
+++ b/src/screens/StakingInformation.tsx
@@ -2,12 +2,10 @@ import React, { ReactElement } from 'react'
import { StyleSheet, View } from 'react-native'
import { navigationHeaderOptions } from 'components/layout/Header'
-import { Button, Text } from 'components'
+import { Text } from 'components'
import Body from 'components/layout/Body'
-import useLinking from 'hooks/useLinking'
const StakingInformation = (): ReactElement => {
- const { openURL } = useLinking()
return (
- >()
+ const { dispatch } =
+ useNavigation>()
const { confirmSign, confirmResult } = useWalletConnectConfirm({
connector,
id,
@@ -64,6 +67,7 @@ const Render = ({
const onPressAllow = async (): Promise => {
setErrorMessage('')
setIsListenConfirmRemove(false)
+ showLoading({ title: user.ledger ? 'Confirm in your Ledger' : undefined, txhash: '' })
const result = await testPassword({
name: user.name,
password: inputPassword,
@@ -73,7 +77,7 @@ const Render = ({
address: user.address,
walletName,
txOptions,
- password: inputPassword,
+ password: user.ledger ? deviceId : inputPassword,
})
} else {
setErrorMessage('Incorrect password')
@@ -83,6 +87,7 @@ const Render = ({
useEffect(() => {
if (confirmResult) {
+ hideLoading()
dispatch(StackActions.popToTop())
dispatch(
StackActions.replace('Complete', { result: confirmResult })
@@ -92,7 +97,7 @@ const Render = ({
return (
<>
-
+
-
-
-
-
-
-
-
-
+ {user.ledger ? (
+ { deviceId = id; onPressAllow() }}/>
+ ) : (
+ <>
+
+
+
+
+
+
+
+
+ >
+ )}
>
)
diff --git a/src/screens/auth/AuthMenu.tsx b/src/screens/auth/AuthMenu.tsx
index 85aa2a1c..564cb416 100644
--- a/src/screens/auth/AuthMenu.tsx
+++ b/src/screens/auth/AuthMenu.tsx
@@ -24,9 +24,8 @@ const AuthMenu = (): ReactElement => {
const [initPageComplete, setInitPageComplete] = useState(false)
const [wallets, setWallets] = useState()
const connectAddress = useRecoilValue(TopupStore.connectAddress)
- const { navigate } = useNavigation<
- NavigationProp
- >()
+ const { navigate } =
+ useNavigation>()
const initPage = async (): Promise => {
setWallets(await getWallets())
@@ -99,6 +98,16 @@ const AuthMenu = (): ReactElement => {
OR
+
+
+ }
+ theme={'white'}
+ containerStyle={{
+ marginBottom: 20,
+ borderWidth: 1,
+ borderColor: '#d2d9f0',
+ }}
+ onPress={():void => onPress(id)}
+ />
+ )
+}
+
+interface DeviceInterface {
+ name: string
+ id: string
+}
+
+const DeviceSelector = ({
+ onSubmit,
+ style
+}: {
+ onSubmit: (id: string) => void
+ style?: ViewStyle
+}): ReactElement => {
+ const [isScanning, setScanning] = useState(false)
+ const [error, setError] = useState('')
+ const [devices, setDevices] = useState([])
+
+ useEffect(() => {
+ let stopScan = (): void => {}
+ const subscription = TransportBLE.observeState({
+ next: (e: any) => {
+ if (e.available) {
+ setScanning(true)
+ setError('')
+
+ const scan = TransportBLE.listen({
+ complete: (): void => {
+ setScanning(false)
+ },
+ next: (e: any): void => {
+ if (e.type === 'add') {
+ const device: DeviceInterface = {
+ name: e.descriptor.localName || e.descriptor.name,
+ id: e.descriptor.id,
+ }
+ setDevices([...devices, device])
+ }
+ },
+ error: (error: any): void => {
+ setScanning(false)
+ setError(error)
+ },
+ })
+ stopScan = (): void => {
+ scan.unsubscribe()
+ }
+ } else {
+ setError(e.type)
+ }
+ },
+ complete: (): void => {},
+ error: (error: any): void => {
+ setScanning(false)
+ setError(error)
+ },
+ })
+
+ return (): void => {
+ subscription.unsubscribe()
+ stopScan()
+ }
+ }, [])
+
+ return (
+
+
+ {devices.map((d) => (
+
+ ))}
+ {isScanning ? : <>>}
+
+
+ {error ? (
+
+ ) : (
+ <>>
+ )}
+
+ )
+}
+
+export default DeviceSelector
diff --git a/src/screens/auth/ConnectLedger/LedgerConnected.tsx b/src/screens/auth/ConnectLedger/LedgerConnected.tsx
new file mode 100644
index 00000000..d517cfa8
--- /dev/null
+++ b/src/screens/auth/ConnectLedger/LedgerConnected.tsx
@@ -0,0 +1,77 @@
+import React, { ReactElement } from 'react'
+import { StyleSheet, View } from 'react-native'
+
+import { StackScreenProps } from '@react-navigation/stack'
+
+import { COLOR } from 'consts'
+
+import Body from 'components/layout/Body'
+import { Text, Icon, Button } from 'components'
+import { ConnectLedgerStackParams } from 'types'
+import { useAuth } from 'lib'
+import { settings } from 'utils/storage'
+
+type Props = StackScreenProps<
+ ConnectLedgerStackParams,
+ 'LedgerConnected'
+>
+
+const LedgerConnected = ({ route }: Props): ReactElement => {
+ const wallet = route.params?.wallet
+
+ const { signIn } = useAuth()
+
+ const onPressButton = (): void => {
+ signIn(wallet)
+ settings.set({ walletName: wallet.name })
+ }
+
+ return (
+
+
+
+
+ {'Ledger Connected!'}
+
+
+ {'Welcome aboard to Terra Station'}
+
+
+
+
+ )
+}
+
+export default LedgerConnected
+
+const styles = StyleSheet.create({
+ container: {
+ paddingBottom: 50,
+ paddingTop: 20,
+ justifyContent: 'space-between',
+ },
+ infoSection: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ infoTitle: {
+ fontSize: 24,
+ fontStyle: 'normal',
+ lineHeight: 36,
+ letterSpacing: 0,
+ textAlign: 'center',
+ color: COLOR.primary._02,
+ marginVertical: 5,
+ },
+})
diff --git a/src/screens/auth/ConnectLedger/SelectDevice.tsx b/src/screens/auth/ConnectLedger/SelectDevice.tsx
new file mode 100644
index 00000000..e10a9bb6
--- /dev/null
+++ b/src/screens/auth/ConnectLedger/SelectDevice.tsx
@@ -0,0 +1,40 @@
+import React, { ReactElement } from 'react'
+import { StyleSheet } from 'react-native'
+import {
+ NavigationProp,
+ useNavigation,
+} from '@react-navigation/native'
+
+import Body from 'components/layout/Body'
+import { navigationHeaderOptions } from 'components/layout/Header'
+import SubHeader from 'components/layout/SubHeader'
+
+import { ConnectLedgerStackParams } from 'types'
+import DeviceSelector from './DeviceSelector'
+
+const SelectDevice = (): ReactElement => {
+ const { navigate } =
+ useNavigation>()
+
+ return (
+ <>
+
+
+ navigate('SelectPath', { device: id })} />
+
+ >
+ )
+}
+
+SelectDevice.navigationOptions = navigationHeaderOptions({
+ theme: 'sapphire',
+})
+
+export default SelectDevice
+
+const styles = StyleSheet.create({
+ container: {
+ paddingBottom: 50,
+ paddingTop: 20,
+ },
+})
diff --git a/src/screens/auth/ConnectLedger/SelectPath.tsx b/src/screens/auth/ConnectLedger/SelectPath.tsx
new file mode 100644
index 00000000..d4bd3436
--- /dev/null
+++ b/src/screens/auth/ConnectLedger/SelectPath.tsx
@@ -0,0 +1,153 @@
+import React, { useState, ReactElement } from 'react'
+import { StyleSheet, View, Text } from 'react-native'
+import {
+ NavigationProp,
+ useNavigation,
+} from '@react-navigation/native'
+import { COLOR } from 'consts'
+import Body from 'components/layout/Body'
+import { navigationHeaderOptions } from 'components/layout/Header'
+import SubHeader from 'components/layout/SubHeader'
+import {
+ Button,
+ FormInput,
+ FormLabel,
+ Error,
+ Loading,
+} from 'components'
+
+import { StackScreenProps } from '@react-navigation/stack'
+import { ConnectLedgerStackParams } from 'types'
+import { addWallet } from 'utils/wallet'
+
+import TransportBLE from '@ledgerhq/react-native-hw-transport-ble'
+import { LedgerKey } from '@terra-money/ledger-terra-js'
+
+type Props = StackScreenProps
+
+const SelectPath = ({ route }: Props): ReactElement => {
+ const { navigate } =
+ useNavigation>()
+
+ const [path, setPath] = useState('0')
+ const [loading, setLoading] = useState(false)
+ const [error, setError] = useState('')
+
+ const onChangePath = (p: string): void => {
+ setPath(p.replace(/[^0-9]/g, ''))
+ }
+
+ const onPressNext = async (): Promise => {
+ setLoading(true)
+
+ try {
+ const wallet = await LedgerKey.create(
+ await TransportBLE.open(route.params.device),
+ parseInt(path)
+ )
+
+ await addWallet({
+ wallet: {
+ address: wallet.accAddress,
+ name: 'Ledger',
+ ledger: true,
+ path: parseInt(path),
+ },
+ })
+
+ navigate('LedgerConnected', {
+ wallet: {
+ address: wallet.accAddress,
+ name: 'Ledger',
+ ledger: true,
+ path: parseInt(path),
+ },
+ })
+ } catch (e: any) {
+ setLoading(false)
+ setError(e.toString())
+ }
+ }
+
+ return (
+ <>
+
+
+ {loading ? (
+
+ ) : (
+ <>
+
+
+
+
+
+ {path !== '0' ? (
+
+
+ The default path is 0
+
+
+ ) : (
+ <>>
+ )}
+ {error ? (
+
+ ) : (
+ <>>
+ )}
+
+
+ >
+ )}
+
+ >
+ )
+}
+
+SelectPath.navigationOptions = navigationHeaderOptions({
+ theme: 'sapphire',
+})
+
+export default SelectPath
+
+const styles = StyleSheet.create({
+ container: {
+ paddingBottom: 50,
+ paddingTop: 20,
+ justifyContent: 'space-between',
+ },
+ section: {
+ marginBottom: 20,
+ },
+})
diff --git a/src/screens/auth/RecoverWallet/Step2QR.tsx b/src/screens/auth/RecoverWallet/Step2QR.tsx
index 1ffa1c26..189a47d6 100644
--- a/src/screens/auth/RecoverWallet/Step2QR.tsx
+++ b/src/screens/auth/RecoverWallet/Step2QR.tsx
@@ -81,6 +81,7 @@ const Step2QR = ({ route }: Props): ReactElement => {
const wallet = {
address: qrData.address,
name,
+ ledger: false,
}
await addWallet({
diff --git a/src/stores/AppStore.ts b/src/stores/AppStore.ts
index 5f4423c6..c1e92320 100644
--- a/src/stores/AppStore.ts
+++ b/src/stores/AppStore.ts
@@ -11,7 +11,13 @@ const loadingTxHash = atom({
default: '',
})
+const loadingTitle = atom({
+ key: StoreKeyEnum.loadingTitle,
+ default: '',
+})
+
export default {
showLoading,
loadingTxHash,
+ loadingTitle,
}
diff --git a/src/stores/StoreKeyEnum.ts b/src/stores/StoreKeyEnum.ts
index 646b801b..ccc103fa 100644
--- a/src/stores/StoreKeyEnum.ts
+++ b/src/stores/StoreKeyEnum.ts
@@ -5,6 +5,7 @@ export enum StoreKeyEnum {
isFromAutoLogout = 'isFromAutoLogout',
showLoading = 'showLoading',
loadingTxHash = 'loadingTxHash',
+ loadingTitle = 'loadingTitle',
newWalletName = 'newWalletName',
newWalletPassword = 'newWalletPassword',
newWalletSeed = 'newWalletSeed',
diff --git a/src/types/navigation.ts b/src/types/navigation.ts
index dfce45a6..550a6978 100644
--- a/src/types/navigation.ts
+++ b/src/types/navigation.ts
@@ -1,4 +1,5 @@
import { createStackNavigator } from '@react-navigation/stack'
+import { AccAddress } from '@terra-money/terra.js'
import { BankData, Card, Pairs, VestingItemUI } from 'lib'
import { DelegateType } from 'lib/post/useDelegate'
import { TxParam } from './tx'
@@ -10,6 +11,7 @@ export type AuthStackParams = {
NewWallet: undefined
RecoverWallet: undefined
WalletConnectDisconnected: undefined
+ ConnectLedger: undefined
}
export const AuthStack = createStackNavigator()
@@ -36,6 +38,22 @@ export type RecoverWalletStackParams = {
export const RecoverWalletStack = createStackNavigator()
+type LedgerWallet = {
+ address: AccAddress,
+ name: string,
+ ledger: true,
+ path: number,
+}
+
+/* ConnectLedger */
+export type ConnectLedgerStackParams = {
+ SelectDevice: undefined
+ SelectPath: { device: string }
+ LedgerConnected: { wallet: LedgerWallet }
+}
+
+export const ConnectLedgerStack = createStackNavigator()
+
/* Root */
export type RootStackParams = {
Tabs: undefined
@@ -73,6 +91,7 @@ export type RootStackParams = {
}
Confirm: undefined
ConfirmPassword: { feeSelectValue: string }
+ ConfirmLedger: { feeSelectValue: string }
Delegate: { validatorAddress: string; type: DelegateType }
ChangePassword: { walletName: string }
StakingInformation: undefined
diff --git a/src/types/wallet.d.ts b/src/types/wallet.d.ts
index dc53807b..22bf1fa8 100644
--- a/src/types/wallet.d.ts
+++ b/src/types/wallet.d.ts
@@ -1,4 +1,6 @@
interface LocalWallet {
name: string
address: string
+ ledger: boolean
+ path?: number
}
diff --git a/src/utils/authData.ts b/src/utils/authData.ts
index fdd31285..0180037a 100644
--- a/src/utils/authData.ts
+++ b/src/utils/authData.ts
@@ -2,13 +2,20 @@ import keystore, { KeystoreEnum } from 'nativeModules/keystore'
import _ from 'lodash'
export type AuthDataValueType = {
+ ledger?: false
encryptedKey: string
address: string
password: string
}
+export type LedgerDataValueType = {
+ ledger: true
+ address: string
+ path: number
+}
+
export type AuthDataType =
- | Record
+ | Record
| undefined
export const getAuthData = async (): Promise => {
@@ -25,9 +32,9 @@ export const getAuthData = async (): Promise => {
export const getAuthDataValue = async (
walletName: string
-): Promise => {
+): Promise => {
const authData = await getAuthData()
-
+
return authData && authData[walletName]
}
diff --git a/src/utils/storage.ts b/src/utils/storage.ts
index fa645134..fe5d87e8 100644
--- a/src/utils/storage.ts
+++ b/src/utils/storage.ts
@@ -76,6 +76,5 @@ export const getBioAuthPassword = async ({
walletName: string
}): Promise => {
const authDataValue = await getAuthDataValue(walletName)
-
- return authDataValue ? authDataValue.password : ''
+ return authDataValue && !authDataValue.ledger ? authDataValue.password : ''
}
diff --git a/src/utils/wallet-helper/api/send.js b/src/utils/wallet-helper/api/send.js
deleted file mode 100644
index b139f35a..00000000
--- a/src/utils/wallet-helper/api/send.js
+++ /dev/null
@@ -1,5 +0,0 @@
-export const createBroadcastBody = (signedTx, returnType = 'sync') =>
- JSON.stringify({ tx: signedTx, mode: returnType })
-
-export const createSignedTransactionObject = (tx, signature) =>
- Object.assign({}, tx, { signatures: [signature] })
diff --git a/src/utils/wallet-helper/api/signTx.js b/src/utils/wallet-helper/api/signTx.js
deleted file mode 100644
index fe531f08..00000000
--- a/src/utils/wallet-helper/api/signTx.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import { createSignedTransactionObject } from './send'
-import { createSignMessage, createSignature } from './signature'
-
-const createSignedTransaction = async (tx, signer, request) => {
- let signature, publicKey
- const { sequence, account_number, chain_id } = request
- const _req = { sequence, accountNumber: account_number, chainId: chain_id }
- const signMessage = createSignMessage(tx, _req)
-
- try {
- ;({ signature, publicKey } = await signer(signMessage))
- } catch (err) {
- throw new Error('Signing failed: ' + err.message)
- }
-
- const signatureObject = createSignature(
- signature,
- sequence,
- account_number,
- publicKey
- )
-
- return createSignedTransactionObject(tx, signatureObject)
-}
-
-export default async (tx, signer, request) => {
- const signedTx = await createSignedTransaction(tx, signer, request)
- return JSON.stringify(signedTx)
-}
diff --git a/src/utils/wallet-helper/api/signature.js b/src/utils/wallet-helper/api/signature.js
deleted file mode 100644
index 7daff15e..00000000
--- a/src/utils/wallet-helper/api/signature.js
+++ /dev/null
@@ -1,55 +0,0 @@
-export const createSignMessage = (
- jsonTx,
- { sequence, accountNumber, chainId }
-) => {
- const fee = {
- amount: jsonTx.fee.amount || [],
- gas: jsonTx.fee.gas
- }
-
- return JSON.stringify(
- removeEmptyProperties({
- fee,
- memo: jsonTx.memo,
- msgs: jsonTx.msg,
- sequence,
- account_number: accountNumber,
- chain_id: chainId
- })
- )
-}
-
-export const createSignature = (
- signature,
- sequence,
- accountNumber,
- publicKey
-) => ({
- signature: signature.toString('base64'),
- account_number: accountNumber,
- sequence,
- pub_key: {
- type: 'tendermint/PubKeySecp256k1',
- value: publicKey.toString('base64')
- }
-})
-
-export const removeEmptyProperties = jsonTx => {
- if (Array.isArray(jsonTx)) {
- return jsonTx.map(removeEmptyProperties)
- }
-
- if (typeof jsonTx !== 'object') {
- return jsonTx
- }
-
- const sorted = {}
- Object.keys(jsonTx)
- .sort()
- .forEach(key => {
- if (jsonTx[key] === undefined || jsonTx[key] === null) return
- sorted[key] = removeEmptyProperties(jsonTx[key])
- })
-
- return sorted
-}
diff --git a/src/utils/wallet-helper/keys.js b/src/utils/wallet-helper/keys.js
deleted file mode 100644
index 5b324fde..00000000
--- a/src/utils/wallet-helper/keys.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import * as bech32 from 'bech32'
-import { ecdsaSign } from 'secp256k1'
-import * as CryptoJS from 'crypto-js'
-
-export const getTerraAddress = publicKey => {
- const message = CryptoJS.enc.Hex.parse(publicKey.toString('hex'))
- const address = CryptoJS.RIPEMD160(CryptoJS.SHA256(message)).toString()
- return bech32ify(address, 'terra')
-}
-
-const bech32ify = (address, prefix) => {
- const words = bech32.toWords(Buffer.from(address, 'hex'))
- return bech32.encode(prefix, words)
-}
-
-export const signWithPrivateKey = (signMessage, privateKey) => {
- const signMessageString =
- typeof signMessage === 'string' ? signMessage : JSON.stringify(signMessage)
- const signHash = Buffer.from(
- CryptoJS.SHA256(signMessageString).toString(),
- `hex`
- )
- const { signature } = ecdsaSign(signHash, privateKey)
-
- return Buffer.from(signature)
-}
diff --git a/src/utils/wallet-helper/signer.js b/src/utils/wallet-helper/signer.js
deleted file mode 100644
index a208ca34..00000000
--- a/src/utils/wallet-helper/signer.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { signWithPrivateKey } from './keys'
-
-export default (privateKey, publicKey) => {
- return (signMessage) => {
- const signature = signWithPrivateKey(
- signMessage,
- Buffer.from(privateKey, 'hex')
- )
-
- return { signature, publicKey: Buffer.from(publicKey, 'hex') }
- }
-}
diff --git a/src/utils/wallet.ts b/src/utils/wallet.ts
index 77c14d25..6487e9c5 100644
--- a/src/utils/wallet.ts
+++ b/src/utils/wallet.ts
@@ -67,7 +67,7 @@ export const recoverWalletWithMnemonicKey = async (
if (!key) {
throw new Error('Encryption error occurred')
}
- const wallet = { name, address: mk.accAddress }
+ const wallet = { ledger: false, name, address: mk.accAddress }
await addWallet({ wallet, key, password })
return { success: true, wallet }
} catch {
@@ -88,13 +88,17 @@ export const decryptKey = (
export const getWallets = async (): Promise => {
const authData = await getAuthData()
- return _.map(authData, ({ address }, name) => {
- return { name, address }
+ return _.map(authData, (wallet, name) => {
+ if(wallet?.ledger){
+ return { ...wallet, name }
+ } else {
+ return { ...wallet, name, ledger: false }
+ }
})
}
export const getWallet = async (
- name: string
+ name: string,
): Promise => {
const wallets = await getWallets()
return wallets.find((wallet) => wallet.name === name)
@@ -104,6 +108,7 @@ export const getEncryptedKey = async (
name: string
): Promise => {
const authDataValue = await getAuthDataValue(name)
+ if(authDataValue?.ledger) throw new Error("Can't get the raw key from Ledger")
return authDataValue ? authDataValue.encryptedKey : ''
}
@@ -113,23 +118,36 @@ export const addWallet = async ({
password,
}: {
wallet: LocalWallet
- key: string
- password: string
+ key?: string
+ password?: string
}): Promise => {
const wallets = await getWallets()
- if (wallets.find((w) => w.name === wallet.name))
+ if (wallet.name !== 'Ledger' && wallets.find((w) => w.name === wallet.name))
throw new Error('Wallet with that name already exists')
-
- return await upsertAuthData({
- authData: {
- [wallet.name]: {
- address: wallet.address,
- password,
- encryptedKey: key,
+
+ if(wallet.ledger) {
+ return await upsertAuthData({
+ authData: {
+ [wallet.name]: {
+ ledger: true,
+ address: wallet.address,
+ path: wallet.path || 0,
+ },
},
- },
- })
+ })
+ } else {
+ return await upsertAuthData({
+ authData: {
+ [wallet.name]: {
+ ledger: false,
+ address: wallet.address,
+ password: password || '',
+ encryptedKey: key || '',
+ },
+ },
+ })
+ }
}
export const getDecyrptedKey = async (
@@ -155,9 +173,11 @@ export const changePassword = async (
ondPassword: string,
newPassword: string
): Promise => {
+
const decryptedKey = await getDecyrptedKey(name, ondPassword)
const encryptedKey = encrypt(decryptedKey, newPassword)
const authDataValue = await getAuthDataValue(name)
+ if(authDataValue?.ledger) return false;
if (authDataValue) {
upsertAuthData({
authData: {
@@ -183,6 +203,11 @@ export const testPassword = async ({
{ isSuccess: true } | { isSuccess: false; errorMessage: string }
> => {
const wallet = await getWallet(name)
+ if(wallet?.ledger) {
+ return {
+ isSuccess: true,
+ }
+ }
if (!wallet) {
return {