diff --git a/.env.sample b/.env.sample index 5c8cef78..5ea83baa 100644 --- a/.env.sample +++ b/.env.sample @@ -20,5 +20,8 @@ WALLET_CONNECT_METADATA_URL= HELIUM_VOTE_API_URL= DEVNET_HELIUM_VOTE_API_URL= +PRIVY_APP_ID= +PRIVY_CLIENT_ID= + VIEW_AS= NO_FLIPPER= diff --git a/app.json b/app.json index bf66692a..cac12b29 100644 --- a/app.json +++ b/app.json @@ -20,7 +20,10 @@ ], "bluetoothAlwaysPermission": "Allow $(PRODUCT_NAME) to connect to bluetooth devices" } - ] + ], + "expo-font", + "expo-secure-store", + "expo-web-browser" ], "extra": { "eas": { diff --git a/ios/HeliumWallet.xcodeproj/project.pbxproj b/ios/HeliumWallet.xcodeproj/project.pbxproj index 66767a77..397de3f5 100644 --- a/ios/HeliumWallet.xcodeproj/project.pbxproj +++ b/ios/HeliumWallet.xcodeproj/project.pbxproj @@ -515,7 +515,7 @@ }; }; }; - buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "heliumwallet" */; + buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "HeliumWallet" */; compatibilityVersion = "Xcode 13.0"; developmentRegion = en; hasScannedForEncodings = 0; @@ -1263,7 +1263,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "heliumwallet" */ = { + 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "HeliumWallet" */ = { isa = XCConfigurationList; buildConfigurations = ( 83CBBA201A601CBA00E9B192 /* Debug */, diff --git a/ios/HeliumWallet.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ios/HeliumWallet.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 851c94aa..b0f76351 100644 --- a/ios/HeliumWallet.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ios/HeliumWallet.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,4 +1,5 @@ { + "originHash" : "e70d3525c8e2819a8b34f22909815dab5c700c25a06c32388f3930f7b3627768", "pins" : [ { "identity" : "maplibre-gl-native-distribution", @@ -8,25 +9,7 @@ "revision" : "0f0359865882095c57a555a002bb90b677388874", "version" : "6.11.0" } - }, - { - "identity" : "swiftui-charts", - "kind" : "remoteSourceControl", - "location" : "https://github.com/spacenation/swiftui-charts", - "state" : { - "revision" : "b044e7eb04d0026490eecb115f4fc07197dad942", - "version" : "1.1.0" - } - }, - { - "identity" : "swiftui-shapes", - "kind" : "remoteSourceControl", - "location" : "https://github.com/spacenation/swiftui-shapes.git", - "state" : { - "revision" : "c58b15c37eae9bd20525c6daa93a06a689ca75cb", - "version" : "1.1.0" - } } ], - "version" : 2 + "version" : 3 } diff --git a/ios/HeliumWallet/PrivacyInfo.xcprivacy b/ios/HeliumWallet/PrivacyInfo.xcprivacy index ce0a70e4..42e81eab 100644 --- a/ios/HeliumWallet/PrivacyInfo.xcprivacy +++ b/ios/HeliumWallet/PrivacyInfo.xcprivacy @@ -6,20 +6,20 @@ NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPICategoryFileTimestamp NSPrivacyAccessedAPITypeReasons - CA92.1 + C617.1 + 0A2A.1 + 3B52.1 NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPICategoryUserDefaults NSPrivacyAccessedAPITypeReasons - 0A2A.1 - 3B52.1 - C617.1 + CA92.1 diff --git a/ios/Podfile.lock b/ios/Podfile.lock index d1d24231..251736b5 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -12,6 +12,8 @@ PODS: - Charts/Core (4.1.0): - SwiftAlgorithms (~> 1.0) - DoubleConversion (1.1.6) + - EXApplication (6.1.5): + - ExpoModulesCore - EXConstants (17.1.7): - ExpoModulesCore - Expo (53.0.20): @@ -41,6 +43,8 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga + - ExpoAppleAuthentication (7.2.4): + - ExpoModulesCore - ExpoAsset (11.1.7): - ExpoModulesCore - ExpoBlur (14.1.5): @@ -49,6 +53,10 @@ PODS: - ExpoModulesCore - ZXingObjC/OneD - ZXingObjC/PDF417 + - ExpoClipboard (7.1.5): + - ExpoModulesCore + - ExpoCrypto (14.1.5): + - ExpoModulesCore - ExpoFileSystem (18.1.11): - ExpoModulesCore - ExpoFont (13.3.2): @@ -86,10 +94,14 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga + - ExpoNativeExtensions (0.0.7): + - ExpoModulesCore - ExpoSecureStore (14.2.4): - ExpoModulesCore - ExpoSplashScreen (0.30.10): - ExpoModulesCore + - ExpoWebBrowser (14.2.0): + - ExpoModulesCore - fast_float (6.1.4) - FBLazyVector (0.79.5) - fmt (11.0.2) @@ -2148,6 +2160,8 @@ PODS: - React-logger (= 0.79.5) - React-perflogger (= 0.79.5) - React-utils (= 0.79.5) + - ReactNativePasskeys (0.4.0): + - ExpoModulesCore - RNCAsyncStorage (1.18.1): - React-Core - RNCCheckbox (0.5.20): @@ -2479,11 +2493,15 @@ DEPENDENCIES: - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) - BVLinearGradient (from `../node_modules/react-native-linear-gradient`) - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) + - EXApplication (from `../node_modules/expo-application/ios`) - EXConstants (from `../node_modules/expo-constants/ios`) - Expo (from `../node_modules/expo`) + - ExpoAppleAuthentication (from `../node_modules/expo-apple-authentication/ios`) - ExpoAsset (from `../node_modules/expo-asset/ios`) - ExpoBlur (from `../node_modules/expo-blur/ios`) - ExpoCamera (from `../node_modules/expo-camera/ios`) + - ExpoClipboard (from `../node_modules/expo-clipboard/ios`) + - ExpoCrypto (from `../node_modules/expo-crypto/ios`) - ExpoFileSystem (from `../node_modules/expo-file-system/ios`) - ExpoFont (from `../node_modules/expo-font/ios`) - ExpoHaptics (from `../node_modules/expo-haptics/ios`) @@ -2491,8 +2509,10 @@ DEPENDENCIES: - ExpoLinking (from `../node_modules/expo-linking/ios`) - ExpoLocalAuthentication (from `../node_modules/expo-local-authentication/ios`) - ExpoModulesCore (from `../node_modules/expo-modules-core`) + - "ExpoNativeExtensions (from `../node_modules/@privy-io/expo-native-extensions/ios`)" - ExpoSecureStore (from `../node_modules/expo-secure-store/ios`) - ExpoSplashScreen (from `../node_modules/expo-splash-screen/ios`) + - ExpoWebBrowser (from `../node_modules/expo-web-browser/ios`) - fast_float (from `../node_modules/react-native/third-party-podspecs/fast_float.podspec`) - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) - fmt (from `../node_modules/react-native/third-party-podspecs/fmt.podspec`) @@ -2584,6 +2604,7 @@ DEPENDENCIES: - ReactAppDependencyProvider (from `build/generated/ios`) - ReactCodegen (from `build/generated/ios`) - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) + - ReactNativePasskeys (from `../node_modules/react-native-passkeys/ios`) - "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)" - "RNCCheckbox (from `../node_modules/@react-native-community/checkbox`)" - "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)" @@ -2625,16 +2646,24 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-linear-gradient" DoubleConversion: :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" + EXApplication: + :path: "../node_modules/expo-application/ios" EXConstants: :path: "../node_modules/expo-constants/ios" Expo: :path: "../node_modules/expo" + ExpoAppleAuthentication: + :path: "../node_modules/expo-apple-authentication/ios" ExpoAsset: :path: "../node_modules/expo-asset/ios" ExpoBlur: :path: "../node_modules/expo-blur/ios" ExpoCamera: :path: "../node_modules/expo-camera/ios" + ExpoClipboard: + :path: "../node_modules/expo-clipboard/ios" + ExpoCrypto: + :path: "../node_modules/expo-crypto/ios" ExpoFileSystem: :path: "../node_modules/expo-file-system/ios" ExpoFont: @@ -2649,10 +2678,14 @@ EXTERNAL SOURCES: :path: "../node_modules/expo-local-authentication/ios" ExpoModulesCore: :path: "../node_modules/expo-modules-core" + ExpoNativeExtensions: + :path: "../node_modules/@privy-io/expo-native-extensions/ios" ExpoSecureStore: :path: "../node_modules/expo-secure-store/ios" ExpoSplashScreen: :path: "../node_modules/expo-splash-screen/ios" + ExpoWebBrowser: + :path: "../node_modules/expo-web-browser/ios" fast_float: :podspec: "../node_modules/react-native/third-party-podspecs/fast_float.podspec" FBLazyVector: @@ -2826,6 +2859,8 @@ EXTERNAL SOURCES: :path: build/generated/ios ReactCommon: :path: "../node_modules/react-native/ReactCommon" + ReactNativePasskeys: + :path: "../node_modules/react-native-passkeys/ios" RNCAsyncStorage: :path: "../node_modules/@react-native-async-storage/async-storage" RNCCheckbox: @@ -2861,131 +2896,138 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: BCrypt: 712b656110e5020d319c547e4d8f3053ded82b2a - bcrypt-react-native: 5e42aa70cad6f92b886cfb0c991cca9b0d343a17 + bcrypt-react-native: 399775585257ae6c8717370a1119c7da0113e3bf BEMCheckBox: 5ba6e37ade3d3657b36caecc35c8b75c6c2b1a4e boost: 7e761d76ca2ce687f7cc98e698152abd03a18f90 - BVLinearGradient: 7815a70ab485b7b155186dd0cc836363e0288cad + BVLinearGradient: 34a999fda29036898a09c6a6b728b0b4189e1a44 Charts: ce0768268078eee0336f122c3c4ca248e4e204c5 DoubleConversion: cb417026b2400c8f53ae97020b2be961b59470cb - EXConstants: 98bcf0f22b820f9b28f9fee55ff2daededadd2f8 - Expo: a40d525c930dd1c8a158e082756ee071955baccb - ExpoAsset: ef06e880126c375f580d4923fdd1cdf4ee6ee7d6 - ExpoBlur: 3c8885b9bf9eef4309041ec87adec48b5f1986a9 - ExpoCamera: e1879906d41184e84b57d7643119f8509414e318 - ExpoFileSystem: 7f92f7be2f5c5ed40a7c9efc8fa30821181d9d63 - ExpoFont: cf508bc2e6b70871e05386d71cab927c8524cc8e - ExpoHaptics: 0ff6e0d83cd891178a306e548da1450249d54500 - ExpoKeepAwake: bf0811570c8da182bfb879169437d4de298376e7 - ExpoLinking: d5c183998ca6ada66ff45e407e0f965b398a8902 - ExpoLocalAuthentication: c35f18692dcb35775a1be0f37b2131096951a6bd - ExpoModulesCore: 00a1b5c73248465bd0b93f59f8538c4573dac579 - ExpoSecureStore: 3f1b632d6d40bcc62b4983ef9199cd079592a50a - ExpoSplashScreen: 0ad5acac1b5d2953c6e00d4319f16d616f70d4dd + EXApplication: 50cc8ea58c138da6e3f25cd789634219c86b90d5 + EXConstants: 9d62a46a36eae6d28cb978efcbc68aef354d1704 + Expo: 666a397fcb608d72b019e16ba139b74e93e0b7d7 + ExpoAppleAuthentication: 7e358fcbcbacb7685cddb0bbeede0acd677e58f6 + ExpoAsset: 7bdbbacf4e6752ae6e3cf70555cee076f6229e6e + ExpoBlur: 846780b2c90f59e964b9a50385d4deb67174ebfb + ExpoCamera: fc1ab0e1c665b543a307c577df107e37cc2edc8e + ExpoClipboard: 6b9aae54fd48a579473fb101051ad693435b9294 + ExpoCrypto: fcb6a8a08d1929f346cb95eb05a8f7818627177a + ExpoFileSystem: 9681caebda23fa1b38a12a9c68b2bade7072ce20 + ExpoFont: 091a47eeaa1b30b0b760aa1d0a2e7814e8bf6fe6 + ExpoHaptics: 68c215e070f660e0a29c45dcda4f60eeff08aefb + ExpoKeepAwake: e8dedc115d9f6f24b153ccd2d1d8efcdfd68a527 + ExpoLinking: 343a89ea864a851831fd4495e8aea01cf0f6a36f + ExpoLocalAuthentication: 78f74d187ee51126e1a789d73fee32d6d7e60f1f + ExpoModulesCore: 16f74d8df26d7e4b6bf7eb3d0effaf0f15df7b80 + ExpoNativeExtensions: 47c8a3b587ef9ea9ea04e8545e3cfefec6e7e284 + ExpoSecureStore: 833b24a0d7feffef4505184910c058221066011e + ExpoSplashScreen: 6f9213be0c60f2756a2f8220c36f4b90c55e3dbd + ExpoWebBrowser: eeb47f52e85b2686b56178749675cf90d0822f86 fast_float: 06eeec4fe712a76acc9376682e4808b05ce978b6 FBLazyVector: d2a9cd223302b6c9aa4aa34c1a775e9db609eb52 fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd glog: 5683914934d5b6e4240e497e0f4a3b42d1854183 - helium-react-native-sdk: 22ade11d0986df17d7233b1dedb58d9b8743032f + helium-react-native-sdk: 2e0741e3073b4defe3665bdf47772b9ff602391e hermes-engine: f03b0e06d3882d71e67e45b073bb827da1a21aae lottie-ios: a881093fab623c467d3bce374367755c272bdd59 - lottie-react-native: 4669b14d8ebd00d58e80caf862736d28ca5045e3 - maplibre-react-native: 275e81319b9d75e120902a09f4ca07cce9537234 + lottie-react-native: 9076d7f8e9059606483795e535cef7a38d209f76 + maplibre-react-native: 86193b158673e028ce10f4f3533e472ce8dbb7b2 MultiplatformBleAdapter: b1fddd0d499b96b607e00f0faa8e60648343dc1d OneSignalXCFramework: 1a3b28dfbff23aabce585796d23c1bef37772774 OpenSSL-Universal: 6082b0bf950e5636fe0d78def171184e2b3899c2 - RCT-Folly: e78785aa9ba2ed998ea4151e314036f6c49e6d82 + RCT-Folly: 36fe2295e44b10d831836cc0d1daec5f8abcf809 RCTDeprecation: 5f638f65935e273753b1f31a365db6a8d6dc53b5 RCTRequired: 8b46a520ea9071e2bc47d474aa9ca31b4a935bd8 RCTTypeSafety: cc4740278c2a52cbf740592b0a0a40df1587c9ab React: 6393ae1807614f017a84805bf2417e3497f518a6 React-callinvoker: c34f666f551f05a325b87e7e3e6df0e082fa3d99 - React-Core: 1ba9acdf7accbd46ccaae99999443ae2722c82b7 - React-CoreModules: 3c3cf4a91257f138e3feb47169a2d7fe341b5495 - React-cxxreact: 444d518a5d3a933e029b5e5ca6d8127c2e43255c + React-Core: fc07a4b69a963880b25142c51178f4cb75628c7d + React-CoreModules: 94d39315cfa791f6c477712fea47c34f8ecb26c6 + React-cxxreact: 628c28cdb3fdef93ee3bfc2bec8e2d776e81ae49 React-debug: a951cdb698321d78ebd955fc8788ebbe51af3519 - React-defaultsnativemodule: 35816c7cb315962495d815446b2c8f1f3d2396ad - React-domnativemodule: 94efa04e53aa12a6dc02d420f1564ee18f3059bd - React-Fabric: bb8ccdb10256fa8acfd98a189590e2e44878abd7 - React-FabricComponents: 60703b954ca7e3d09cdb8d6fff6a4118f3c1478f - React-FabricImage: 0a8cc153d20af111f966e14b3814faa692a6805d + React-defaultsnativemodule: 08779733c4541be5da1f1d3ec8492300dbc3c00a + React-domnativemodule: fdd4821b9a0c44e87ed9263231225aa65fe982e0 + React-Fabric: 8d905d8c41d666bf283a5b09db56bdaccfa07c8d + React-FabricComponents: 43aab5c94c7b5bbcabc3a9821b8536a0711a0f01 + React-FabricImage: 10708fa449d3f1b4a8d6eedb97f0c6476b098bb4 React-featureflags: 32d776f9bef34bdab6218ad99db535e75e5c1f4e - React-featureflagsnativemodule: dd5e1e8579d7c3e10b31969c4ca2f56ba3743ec2 - React-graphics: bce95f01799245fa58ca35bdc06a98677b67352e - React-hermes: 9ec11ce5f88c0778e027aa06a6e3e6eb19ddae09 - React-idlecallbacksnativemodule: 9d125d1b9bb3e0bb4de334fea94228e6eeac1852 - React-ImageManager: c40cb4a131371ddecbabc618ef354c57c864c550 - React-jserrorhandler: c00e040f76b32a1846d7eb43602a78ad1e1f60d1 - React-jsi: 8f065aa1ae1d35bef3c394cb1663d114c4952fd8 - React-jsiexecutor: fc8e69fb870cb6e69920fd482a76d4ae54a1c40a - React-jsinspector: 42760714871594f021b3bf223f2f9ac350183ed3 - React-jsinspectortracing: 237f149a09bab785ec6b3a15cc92fc51c0d15cc4 - React-jsitooling: ef1fca866f14d8d4bd80a9570118c19e62775f96 - React-jsitracing: cfa927f650c6f7da613da9fe2a6eeaebc6b2ad1b - React-logger: 85fa3509931497c72ccd2547fcc91e7299d8591e - React-Mapbuffer: 96a2f2a176268581733be182fa6eebab1c0193be - React-microtasksnativemodule: bda561d2648e1e52bd9e5a87f8889836bdbde2e2 - react-native-ble-plx: f2c13ceb441f17266d3dc6a56e603e2ae820a574 - react-native-charts-wrapper: d7b8f60a5ad07947798902bf805bcac01ea6273a - react-native-config: 8e425892a531627c52db765be3088185cb871e19 - react-native-get-random-values: 0fd2b6a3129988d701d10e30f0622d5f039531bc - react-native-mail: 6e83813066984b26403d3fdfe79ac7bb31857e3c - react-native-netinfo: be701059f57093572e5ba08cba14483d334b425d - react-native-network-info: 23b4f34419d7998727c9e50bf8dee3c1bd3f975a + React-featureflagsnativemodule: 413da7bc0d21aa86315dbea0fb2b2c27cb8b4bab + React-graphics: 83c676b633acc5044b5c5dfdb7f95aa3aaf7b7a5 + React-hermes: af1b3d79491295abc9d1b11f84e77d5dc00095b6 + React-idlecallbacksnativemodule: b039a595f29d9a87bbad12e731de45879a054b33 + React-ImageManager: 81dc38602ff1e7a8fd5fe3bf54772cf1a30d49c1 + React-jserrorhandler: b230f573b63a6a2a5540054d46cfb6087d26c86c + React-jsi: e9c3019e00db5d144e0a660616a52a605e12c39a + React-jsiexecutor: 3ed70a394b76f33e6c4ec4b382a457df7309d96c + React-jsinspector: 977527f0224edb5ae0970e946411f36dd1d70f43 + React-jsinspectortracing: 64ec4bde979134830c8f937758416f8d50daa8fb + React-jsitooling: 9dd45534fd158b508f785b547bf1350933bf465a + React-jsitracing: a645b2b3c4f6aa79051d5485c67b188ef49045a0 + React-logger: e6e6164f1753e46d1b7e2c8f0949cd7937eaf31b + React-Mapbuffer: 5b4959cbd91e7e8fae42ab0f4b7c25b86fd139a1 + React-microtasksnativemodule: 1695ab137281dd03de967b7bbeb4e392601f6432 + react-native-ble-plx: eac3b9fc70e1b605e7e76cd4b5324eeedfa517ed + react-native-charts-wrapper: 4268219d67a6fd7e94453d77d31b38ef1cd23860 + react-native-config: 7cd105e71d903104e8919261480858940a6b9c0e + react-native-get-random-values: a6ea6a8a65dc93e96e24a11105b1a9c8cfe1d72a + react-native-mail: 8fdcd3aef007c33a6877a18eb4cf7447a1d4ce4a + react-native-netinfo: 2517ad504b3d303e90d7a431b0fcaef76d207983 + react-native-network-info: d1290ffc0bd0709e11436f5b8d7f605dcc5c4530 react-native-onesignal: 33ade92bd91578374c31c5a5a91f45f49c2d6614 - react-native-pager-view: 919534782a0489f7e2aeeb9a8b8959edfd3f067a - react-native-quick-crypto: 25eea8fe1d2a2ae24b609cb8061b7ef5873e7615 - react-native-randombytes: 3c8f3e89d12487fd03a2f966c288d495415fc116 - react-native-safe-area-context: 895c49ee2613865f90318789be89a8e286fe7b69 - react-native-simple-toast: 59d8b58998dac9f063b46d95f9fd7fd7caab6101 - react-native-slider: 78ccabe016aef7418b1a846b31115b4165c4dde6 - react-native-video: 75309708e5e46a796f5ad2f26f7278c210c9fc86 - react-native-webview: 520bcb79c3f2af91e157cdd695732a34ab5f25c8 - React-NativeModulesApple: 1ecb83880dd11baf2228f8dd89d8419c387e03ad + react-native-pager-view: 32cf333014f4a55c85c5d1018a28e5f83675718b + react-native-quick-crypto: e31f76c7656fe44bf6cd5bf6ce2f9b61afd6eceb + react-native-randombytes: 421f1c7d48c0af8dbcd471b0324393ebf8fe7846 + react-native-safe-area-context: f2239c6eb3752c012c89f25aabb436a18d4265e6 + react-native-simple-toast: 8ee5d23f0b92b935ab7434cdb65159ce12dfb4b7 + react-native-slider: c4c1a975352113af59b59dc783abc111618ec37a + react-native-video: 41c5656296162463e42381c5143b342399d1d271 + react-native-webview: cde150463e7caa49b316b0ed1871e7ef8193bef4 + React-NativeModulesApple: 3ecc647742d33ad617bd2805902e3f91f2b3008f React-oscompat: 0592889a9fcf0eacb205532028e4a364e22907dd - React-perflogger: c584fa50e422a46f37404d083fad12eb289d5de4 - React-performancetimeline: 8deae06fc819e6f7d1f834818e72ab5581540e45 + React-perflogger: 634408a9a0f5753faa577dfa81bc009edca01062 + React-performancetimeline: faa22f963845ae2298c28ef6b84bd8b58d3d8a90 React-RCTActionSheet: ce67bdc050cc1d9ef673c7a93e9799288a183f24 - React-RCTAnimation: 8bb813eb29c6de85be99c62640f3a999df76ba02 - React-RCTAppDelegate: 0200dcd70e996a7061965cfa7f8c443013cc11a1 - React-RCTBlob: a1dd15758420b6a8154019c5c188cf90648bc487 - React-RCTFabric: c7825ff7180893c4213eae8d249b279fc6bf5253 - React-RCTFBReactNativeSpec: b42afeff81dfd0618a4d37c6c6cb99a66b93a363 - React-RCTImage: 8a4f6ce18e73a7e894b886dfb7625e9e9fbc90ef - React-RCTLinking: fa49c624cd63979e7a6295ae9b1351d23ac4395a - React-RCTNetwork: f236fd2897d18522bba24453e2995a4c83e01024 - React-RCTRuntime: 6b9e893b1d375b7a733fe26c8781e8f062f52951 - React-RCTSettings: 69e2f25a5a1bf6cb37eef2e5c3bd4bb7e848296b - React-RCTText: 515ce74ed79c31dbf509e6f12770420ebbf23755 - React-RCTVibration: ef30ada606dfed859b2c71577f6f041d47f2cfbb + React-RCTAnimation: 12193c2092a78012c7f77457806dcc822cc40d2c + React-RCTAppDelegate: 7225b51d5b6d3ddd3702165d717a1ffd4a90fb71 + React-RCTBlob: 923cf9b0098b9a641cb1e454c30a444d9d3cda70 + React-RCTFabric: a280fd9f2697c144b0d835200080a09ab15b2e07 + React-RCTFBReactNativeSpec: 50eabdca1efbf6ce1d774b816a68e6cc4b2a5598 + React-RCTImage: 580a5d0a6fdf9b69629d0582e5fb5a173e152099 + React-RCTLinking: 4ed7c5667709099bfd6b2b6246b1dfd79c89f7cb + React-RCTNetwork: 06a22dd0088392694df4fd098634811aa0b3e166 + React-RCTRuntime: 17c77bab5d39bc354c9983f8f11c7d3597fa8344 + React-RCTSettings: 9dbf433f302c8ebe43b280453e74624098fbc706 + React-RCTText: 92fcd78d6c44dbe64d147bb63f53698bcba7c971 + React-RCTVibration: 513659394c92491e6c749e981424f6e1e0abdb3c React-rendererconsistency: aedf87f8509bc0936ae5475d4ea1e26cb5e8def6 - React-renderercss: 636c2fffff5334897fc7745442c5e450a90eb549 - React-rendererdebug: 9c95cda4ebc6afb3b474924bb185b42ae317c02d + React-renderercss: 71727bedda678e0918506749f94f745e1050a080 + React-rendererdebug: 81a6b97bd089b49a8e7f4f5c7fd1de588c0e8a11 React-rncore: 3eb6f7bdfd181bc26f9f3edc87f70eb1a68a2f3c - React-RuntimeApple: 2cf5c8e38bfccd0e6aa47e3f87a1a3e85ae7fb87 - React-RuntimeCore: 2f87f504ca55b4a2a6bda1ee50c144b33cce0a15 + React-RuntimeApple: 368e8e7b0018f9e9ca4294a6a8167e6aebc6eb87 + React-RuntimeCore: 0f9a8bb41e043f3adaea111e5128801af0dfbc34 React-runtimeexecutor: ebfd71307b3166c73ac0c441c1ea42e0f17f821d - React-RuntimeHermes: a8391605396019d1f72079d3c72e80fcdc79c6a2 - React-runtimescheduler: 158b956675f624b3d3158ffab8f711ebf54fb3a6 + React-RuntimeHermes: 7f55a7285794023ccb3cfe3e89c66c632ed566b1 + React-runtimescheduler: 316243b204bb6a5fd80cea7a97df9b1614ee1b0e React-timing: acc3fa92c72dcc1de6300d752ebb84a1d55dc809 - React-utils: 525f1fe996874cff32a0ef8e523e31ebde23664d - ReactAppDependencyProvider: f3e842e6cb5a825b6918a74a38402ba1409411f8 - ReactCodegen: 6cb6e0d0b52471abc883541c76589d1c367c64c7 - ReactCommon: 1ab5451fc5da87c4cc4c3046e19a8054624ca763 - RNCAsyncStorage: 01062b75ce749e3a18091a9ad7749effdf09ea43 - RNCCheckbox: 33b44487ca8008394ce658cc32b26eab04f426ef - RNCClipboard: ea6045252d5c0753cf17f62290f647dc0096f6ac - RNDeviceInfo: d3e91ffb33ee97a7982108476edb68cb3672efa6 - RNGestureHandler: 0397fea67f39d5a2d17fcf4a028e206f7ba098ba - RNICloudStore: e0a579c3658e4ef49b84de2575886459c3ad695d - RNLocalize: 5bcbb34b6f9cb4c2010ccfedb03f6a2b6f98466d - RNOS: d07e5090b5060c6f2b83116d740a32cfdb33afe3 - RNPermissions: 9510a70fa724380332102d11514ad0d38f33f231 - RNReactNativeSharedGroupPreferences: d4869af3c7757405b6b5ac633d0ef5f9886a9be7 - RNReanimated: 722d67dfde539bfe29b572878f4bc805f727726b - RNScreens: 824a29c178e253fe8b08fb0b2903195d35f724f2 - RNShare: fd38ef4e36245bc590de292a139a2b9e332a4665 - RNSVG: ba22deba00b123dd9bca2e5540b6fbc0d3f858cb - RNTestFlight: b81078855c2739e90458ad2686a514ee5dcc60de + React-utils: 4efa98c1c602f5eacac3cece396c0b7c7d70c1d3 + ReactAppDependencyProvider: c42e7abdd2228ae583bdabc3dcd8e5cda6bef944 + ReactCodegen: 4d001cd4fa72b876bbff500bbb3811e458bb3c72 + ReactCommon: 41137f7e87cf7fd1c041a7124dfa3d0d48aa43f3 + ReactNativePasskeys: 893878413dcc9b047645047f61bb848989754585 + RNCAsyncStorage: b90b71f45b8b97be43bc4284e71a6af48ac9f547 + RNCCheckbox: 471ebdc33884c084f362615c1ef3507496cc07f1 + RNCClipboard: b202bc12352f3e213f94f6d9bf2e8c5a2739192e + RNDeviceInfo: aad3c663b25752a52bf8fce93f2354001dd185aa + RNGestureHandler: f8d0f8c032ba1209eb370bcc29e1138788208673 + RNICloudStore: bc6e225811637c09bd1eb055d6cd7448e61cd451 + RNLocalize: a64514b46a01375fdfae9349036b4dc7130333b5 + RNOS: 6f2f9a70895bbbfbdad7196abd952e7b01d45027 + RNPermissions: fa284ab02b262418c7c88f8ef61ce037ede4eaa6 + RNReactNativeSharedGroupPreferences: 29092869fc2e40d5baca5e15d82fa5c24a668977 + RNReanimated: 6a437c90e263e4a2202a282f9d6dea0ad28d018d + RNScreens: 5ec356ebbf743eafa3d263eda1f15d03299a9f64 + RNShare: be91a5c149585affb02c25b351bd07ba927c7006 + RNSVG: 719faa79d7c916706c128f0ea96073665c933e54 + RNTestFlight: 3419178faa8527ecfe803607fd338a3803f1fb0d SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 SwiftAlgorithms: 38dda4731d19027fdeee1125f973111bf3386b53 SwiftyJSON: 36413e04c44ee145039d332b4f4e2d3e8d6c4db7 @@ -2995,4 +3037,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: b6d833dce45b40b91462bb203f8554fb446f7257 -COCOAPODS: 1.15.2 +COCOAPODS: 1.16.2 diff --git a/metro.config.js b/metro.config.js index 94fe2c9c..1553f23d 100644 --- a/metro.config.js +++ b/metro.config.js @@ -1,3 +1,4 @@ +const path = require('path') const { getDefaultConfig } = require('expo/metro-config') const defaultConfig = getDefaultConfig(__dirname) @@ -20,10 +21,66 @@ defaultConfig.transformer = { }), } +const originalResolveRequest = defaultConfig.resolver.resolveRequest + defaultConfig.resolver = { ...defaultConfig.resolver, assetExts: [...assetExts.filter((ext) => ext !== 'svg'), 'lottie', 'ico'], sourceExts: [...sourceExts, 'svg', 'cjs', 'mjs'], + resolveRequest: (context, moduleName, platform) => { + // Force single copy of @tanstack/react-query to avoid duplicate contexts + if ( + moduleName === '@tanstack/react-query' || + moduleName.startsWith('@tanstack/react-query/') + ) { + const suffix = moduleName.replace('@tanstack/react-query', '') + const resolved = path.resolve( + __dirname, + 'node_modules/@tanstack/react-query' + suffix, + ) + return context.resolveRequest( + { ...context, resolveRequest: undefined }, + resolved, + platform, + ) + } + // Force single copy of @privy-io/expo to avoid duplicate contexts + if ( + moduleName === '@privy-io/expo' || + moduleName.startsWith('@privy-io/expo/') + ) { + const suffix = moduleName.replace('@privy-io/expo', '') + const resolved = path.resolve( + __dirname, + 'node_modules/@privy-io/expo' + suffix, + ) + return context.resolveRequest( + { ...context, resolveRequest: undefined }, + resolved, + platform, + ) + } + // Redirect jose to its browser build (avoids Node.js 'https' dependency) + if (moduleName === 'jose' || moduleName.startsWith('jose/')) { + const browserPath = moduleName.replace( + /^jose/, + path.resolve(__dirname, 'node_modules/jose/dist/browser'), + ) + return context.resolveRequest( + { ...context, resolveRequest: undefined }, + browserPath, + platform, + ) + } + if (originalResolveRequest) { + return originalResolveRequest(context, moduleName, platform) + } + return context.resolveRequest( + { ...context, resolveRequest: undefined }, + moduleName, + platform, + ) + }, } module.exports = defaultConfig diff --git a/package.json b/package.json index 39e2d10b..5923b714 100644 --- a/package.json +++ b/package.json @@ -31,41 +31,41 @@ "@coral-xyz/anchor": "0.31.0", "@gorhom/bottom-sheet": "5.1.2", "@gorhom/portal": "1.0.14", - "@helium/account-fetch-cache": "0.11.4", - "@helium/account-fetch-cache-hooks": "0.11.4", + "@helium/account-fetch-cache": "0.11.12", + "@helium/account-fetch-cache-hooks": "0.11.12", "@helium/address": "^5.0.4", - "@helium/automation-hooks": "^0.11.4", - "@helium/blockchain-api": "^0.3.12", - "@helium/circuit-breaker-sdk": "0.11.4", + "@helium/automation-hooks": "^0.11.12", + "@helium/blockchain-api": "^0.11.12", + "@helium/circuit-breaker-sdk": "0.11.12", "@helium/cron-sdk": "^0.0.8", "@helium/crypto-react-native": "^5.0.4", - "@helium/currency-utils": "0.11.4", - "@helium/data-credits-sdk": "0.11.4", - "@helium/distributor-oracle": "0.11.4", - "@helium/fanout-sdk": "0.11.4", - "@helium/helium-entity-manager-sdk": "0.11.4", - "@helium/helium-react-hooks": "0.11.4", - "@helium/helium-sub-daos-sdk": "0.11.4", - "@helium/hpl-crons-sdk": "^0.11.4", + "@helium/currency-utils": "0.11.12", + "@helium/data-credits-sdk": "0.11.12", + "@helium/distributor-oracle": "0.11.12", + "@helium/fanout-sdk": "0.11.12", + "@helium/helium-entity-manager-sdk": "0.11.12", + "@helium/helium-react-hooks": "0.11.12", + "@helium/helium-sub-daos-sdk": "0.11.12", + "@helium/hpl-crons-sdk": "^0.11.12", "@helium/http": "^5.0.4", - "@helium/idls": "0.11.4", - "@helium/lazy-distributor-sdk": "0.11.4", + "@helium/idls": "0.11.12", + "@helium/lazy-distributor-sdk": "0.11.12", "@helium/modular-governance-hooks": "0.1.5", "@helium/modular-governance-idls": "0.1.5", - "@helium/no-emit-sdk": "0.11.4", + "@helium/no-emit-sdk": "0.11.12", "@helium/onboarding": "^5.0.4", "@helium/organization-sdk": "0.1.5", "@helium/proto-ble": "^5.0.4", "@helium/react-native-sdk": "^4.0.4", - "@helium/spl-utils": "0.11.4", + "@helium/spl-utils": "0.11.12", "@helium/state-controller-sdk": "0.1.5", - "@helium/sus": "0.11.4", + "@helium/sus": "0.11.12", "@helium/transactions": "^5.0.4", - "@helium/treasury-management-sdk": "0.11.4", + "@helium/treasury-management-sdk": "0.11.12", "@helium/tuktuk-idls": "^0.0.8", "@helium/tuktuk-sdk": "^0.0.8", - "@helium/voter-stake-registry-hooks": "0.11.4", - "@helium/voter-stake-registry-sdk": "0.11.4", + "@helium/voter-stake-registry-hooks": "0.11.12", + "@helium/voter-stake-registry-sdk": "0.11.12", "@helium/wallet-link": "^5.0.4", "@jup-ag/api": "6.0.6", "@keystonehq/keystone-sdk": "0.11.6", @@ -81,6 +81,8 @@ "@noble/ed25519": "2.3.0", "@noble/hashes": "1.8.0", "@onsol/tldparser": "0.5.3", + "@privy-io/expo": "^0.63.9", + "@privy-io/expo-native-extensions": "^0.0.7", "@react-native-async-storage/async-storage": "1.18.1", "@react-native-clipboard/clipboard": "1.16.3", "@react-native-community/checkbox": "0.5.20", @@ -123,15 +125,21 @@ "ed25519-hd-key": "1.3.0", "events": "3.3.0", "expo": "53.0.20", + "expo-apple-authentication": "~7.2.4", + "expo-application": "~6.1.5", "expo-asset": "~11.1.7", "expo-blur": "~14.1.5", "expo-camera": "~16.1.10", + "expo-clipboard": "~7.1.5", "expo-constants": "~17.1.7", + "expo-crypto": "~14.1.5", + "expo-font": "~13.3.2", "expo-haptics": "~14.1.4", "expo-linking": "~7.1.7", "expo-local-authentication": "~16.0.5", - "expo-secure-store": "~14.2.3", + "expo-secure-store": "~14.2.4", "expo-splash-screen": "~0.30.1", + "expo-web-browser": "~14.2.0", "fuse.js": "6.6.2", "h3-js": "4.1.0", "i18next": "21.9.1", @@ -171,6 +179,7 @@ "react-native-onesignal": "5.2.9", "react-native-os": "1.2.6", "react-native-pager-view": "6.8.1", + "react-native-passkeys": "^0.4.0", "react-native-permissions": "5.3.0", "react-native-qrcode-svg": "6.1.2", "react-native-quick-crypto": "^0.7.17", @@ -199,6 +208,7 @@ "text-encoding-polyfill": "^0.6.7", "tinycolor2": "^1.6.0", "use-debounce": "^10.0.4", + "viem": "^2.47.5", "web-streams-polyfill": "^4.2.0" }, "devDependencies": { @@ -263,11 +273,11 @@ "@types/react": "^19.0.0", "react": "19.0.0", "@solana/wallet-adapter-react": "0.15.33", - "@helium/account-fetch-cache": "0.11.4", - "@helium/account-fetch-cache-hooks": "0.11.4", - "@helium/helium-react-hooks": "0.11.4", - "@helium/voter-stake-registry-hooks": "0.11.4", - "@helium/voter-stake-registry-sdk": "0.11.4", + "@helium/account-fetch-cache": "0.11.12", + "@helium/account-fetch-cache-hooks": "0.11.12", + "@helium/helium-react-hooks": "0.11.12", + "@helium/voter-stake-registry-hooks": "0.11.12", + "@helium/voter-stake-registry-sdk": "0.11.12", "@helium/modular-governance-hooks": "0.1.5", "@helium/onboarding": "^5.0.4" }, diff --git a/src/App.tsx b/src/App.tsx index 69d71d1c..e2a0edfc 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -28,6 +28,8 @@ import KeystoneOnboardingProvider from './features/keystone/KeystoneOnboardingPr import LockScreen from './features/lock/LockScreen' import DeprecatedTokensCheck from './features/modals/DeprecatedTokensCheck' import DeprecatedTokensModal from './features/modals/DeprecatedTokensModal' +import MigrateToWorldCheck from './features/modals/MigrateToWorldCheck' +import MigrateToWorldModal from './features/modals/MigrateToWorldModal' import InsufficientSolConversionModal from './features/modals/InsufficientSolConversionModal' import { DeprecatedTokensProvider } from './storage/DeprecatedTokensProvider' import WalletOnboardingProvider from './features/onboarding/OnboardingProvider' @@ -153,6 +155,8 @@ const App = () => { {/* place app specific modals here */} + + diff --git a/src/features/account/TokenListItem.tsx b/src/features/account/TokenListItem.tsx index a69c2c7f..9014ce97 100644 --- a/src/features/account/TokenListItem.tsx +++ b/src/features/account/TokenListItem.tsx @@ -23,6 +23,7 @@ import { useNavigation } from '@react-navigation/native' import { NATIVE_MINT } from '@solana/spl-token' import { PublicKey } from '@solana/web3.js' import { useColors } from '@theme/themeHooks' +import { useBalance } from '@utils/Balance' import { MIN_BALANCE_THRESHOLD } from '@utils/constants' import { humanReadable } from '@utils/solanaUtils' import BN from 'bn.js' @@ -67,15 +68,24 @@ export const TokenSkeleton = () => { export const TokenListItem = ({ mint }: Props) => { const navigation = useNavigation() const wallet = useCurrentWallet() + const { tokenAccounts } = useBalance() + const reduxAccount = tokenAccounts?.find((ta) => ta.mint === mint.toBase58()) + // Only use cache hook as fallback when Redux has no data for this mint. + // When ATA is closed (balance 0), the cache hook can throw since the + // account no longer exists on-chain. const { - amount, - decimals, + amount: cacheAmount, + decimals: cacheDecimals, loading: loadingOwned, - } = useOwnedAmount(wallet, mint) + } = useOwnedAmount(reduxAccount ? undefined : wallet, mint) const { triggerImpact } = useHaptic() const { json, symbol, loading } = useMetaplexMetadata(mint) const mintStr = mint.toBase58() + // Prefer Redux balance (updated on pull-to-refresh) over cache balance + const amount = reduxAccount ? BigInt(reduxAccount.balance) : cacheAmount + const decimals = reduxAccount?.decimals ?? cacheDecimals + const handleNavigation = useCallback(() => { triggerImpact('light') navigation.navigate('AccountTokenScreen', { diff --git a/src/features/migration/MigrateToWorld.tsx b/src/features/migration/MigrateToWorld.tsx new file mode 100644 index 00000000..793ce853 --- /dev/null +++ b/src/features/migration/MigrateToWorld.tsx @@ -0,0 +1,956 @@ +import Box from '@components/Box' +import ButtonPressable from '@components/ButtonPressable' +import CircleLoader from '@components/CircleLoader' +import SafeAreaBox from '@components/SafeAreaBox' +import Text from '@components/Text' +import { useCurrentWallet } from '@hooks/useCurrentWallet' +import { useNavigation } from '@react-navigation/native' +import { VersionedTransaction } from '@solana/web3.js' +import { useBlockchainApi } from '@storage/BlockchainApiProvider' +import { humanReadable, shortenAddress } from '@utils/formatting' +import Config from 'react-native-config' +import BN from 'bn.js' +import React, { memo, useCallback, useEffect, useMemo, useState } from 'react' +import { useAsync, useAsyncCallback } from 'react-async-hook' +import { useTranslation } from 'react-i18next' +import { Linking, ScrollView, TextInput, TouchableOpacity } from 'react-native' +import { Edge } from 'react-native-safe-area-context' +import { + usePrivy, + useLoginWithEmail, + useEmbeddedSolanaWallet, +} from '@privy-io/expo' +import { useSolana } from '../../solana/SolanaProvider' + +type MigrationStep = + | 'link-email' + | 'create-wallet' + | 'select-assets' + | 'confirm' + | 'migrating' + | 'success' + +interface Hotspot { + address: string + entityKey: string + name: string + type: string + deviceType: string + asset: string + inWelcomePack: boolean +} + +interface Token { + mint: string + balance: string + decimals: number + uiAmount: number + symbol?: string + name?: string + logoURI?: string +} + +// Convert human-readable decimal string back to raw balance string without float precision loss +function uiToRaw(ui: string, decimals: number): string { + if (decimals === 0) return ui + const [intPart = '0', fracPart = ''] = ui.split('.') + const paddedFrac = fracPart.slice(0, decimals).padEnd(decimals, '0') + const raw = (intPart + paddedFrac).replace(/^0+/, '') || '0' + return raw +} + +const MigrateToWorld = () => { + const { t } = useTranslation() + const navigation = useNavigation() + const edges = useMemo(() => ['top', 'bottom'] as Edge[], []) + const wallet = useCurrentWallet() + const client = useBlockchainApi() + const { anchorProvider } = useSolana() + + const { user, logout } = usePrivy() + const { sendCode, loginWithCode, state: emailState } = useLoginWithEmail() + const solanaWallet = useEmbeddedSolanaWallet() + + const hasEmail = user?.linked_accounts?.some((a) => a.type === 'email') + const emailAccount = user?.linked_accounts?.find((a) => a.type === 'email') + const userEmail = + emailAccount && 'address' in emailAccount ? emailAccount.address : undefined + const embeddedWallet = user?.linked_accounts?.find( + (a) => a.type === 'wallet' && a.wallet_client === 'privy', + ) + + const initialStep = (): MigrationStep => { + if (hasEmail && embeddedWallet && 'address' in embeddedWallet) { + return 'select-assets' + } + if (hasEmail) { + return 'create-wallet' + } + return 'link-email' + } + + const startStep = initialStep() + const [step, setStep] = useState(startStep) + const [destinationWallet, setDestinationWallet] = useState< + string | undefined + >( + embeddedWallet && 'address' in embeddedWallet + ? embeddedWallet.address + : undefined, + ) + const [hotspots, setHotspots] = useState([]) + const [tokens, setTokens] = useState([]) + const [selectedHotspots, setSelectedHotspots] = useState>( + new Set(), + ) + const [tokenAmounts, setTokenAmounts] = useState>({}) + const [batchNum, setBatchNum] = useState(0) + const [emailInput, setEmailInput] = useState('') + const [codeInput, setCodeInput] = useState('') + const [emailSent, setEmailSent] = useState(false) + + const sourceWallet = wallet?.toBase58() || '' + + // Step 1: Link email via Privy + const { execute: handleSendCode, error: sendCodeError } = useAsyncCallback( + async () => { + if (!emailInput) return + await sendCode({ email: emailInput }) + setEmailSent(true) + }, + ) + + const { execute: handleVerifyCode, error: verifyCodeError } = + useAsyncCallback(async () => { + if (!codeInput) return + await loginWithCode({ code: codeInput }) + setStep('create-wallet') + }) + + // Step 3: Load assets + const { + execute: loadAssets, + loading: loadingAssets, + error: loadAssetsError, + } = useAsyncCallback(async () => { + if (!sourceWallet) return + + const [hotspotsResult, tokensResult] = await Promise.all([ + client.migration.getHotspots({ walletAddress: sourceWallet }), + client.tokens.getBalances({ walletAddress: sourceWallet }), + ]) + + setHotspots(hotspotsResult.hotspots as Hotspot[]) + setSelectedHotspots( + new Set(hotspotsResult.hotspots.map((h) => h.entityKey)), + ) + + const splTokens = tokensResult.tokens.filter( + (tk) => tk.uiAmount > 0, + ) as Token[] + + // Add native SOL to the token list using the WSOL mint + const solBalance = (tokensResult as any).solBalance as number | undefined + const tokenList = + solBalance && solBalance > 0 + ? [ + { + mint: 'So11111111111111111111111111111111111111112', + balance: String(Math.round(solBalance * 1e9)), + decimals: 9, + uiAmount: solBalance, + symbol: 'SOL', + name: 'SOL', + } as Token, + ...splTokens, + ] + : splTokens + setTokens(tokenList) + + const amounts: Record = {} + tokenList.forEach((tk) => { + amounts[tk.mint] = humanReadable(new BN(tk.balance), tk.decimals) || '0' + }) + setTokenAmounts(amounts) + }) + + // Re-fetch assets every time the screen is focused + useEffect(() => { + const unsubscribe = navigation.addListener('focus', () => { + if (step === 'select-assets') { + loadAssets() + } + }) + return unsubscribe + }, [navigation, step, loadAssets]) + + // Load assets on mount if we already have email + wallet + useAsync(async () => { + if (initialStep() === 'select-assets') { + await loadAssets() + } + }, []) + + // Watch for solana wallet becoming connected (after create or on mount) + useEffect(() => { + if ( + solanaWallet.status === 'connected' && + solanaWallet.wallets?.length > 0 && + step === 'create-wallet' + ) { + setDestinationWallet(solanaWallet.wallets[0].address) + setStep('select-assets') + loadAssets() + } + }, [solanaWallet.status, step, loadAssets, solanaWallet.wallets]) + + // Step 2: Create embedded wallet + const { + execute: handleCreateWallet, + loading: creatingWallet, + error: createWalletError, + } = useAsyncCallback(async () => { + // Check if wallet already exists on the user object + const privyWallet = user?.linked_accounts?.find( + (account) => + account.type === 'wallet' && account.wallet_client === 'privy', + ) + + if (privyWallet && 'address' in privyWallet) { + setDestinationWallet(privyWallet.address) + setStep('select-assets') + await loadAssets() + return + } + + // If already connected via the hook + if ( + solanaWallet.status === 'connected' && + solanaWallet.wallets?.length > 0 + ) { + setDestinationWallet(solanaWallet.wallets[0].address) + setStep('select-assets') + await loadAssets() + return + } + + // No existing wallet - create one via the SDK + if (solanaWallet.status === 'not-created' && solanaWallet.create) { + await solanaWallet.create() + // The useEffect above will handle the transition when status becomes 'connected' + return + } + + throw new Error('No embedded wallet found. Please try again.') + }) + + const { execute: handleLogout, error: logoutError } = useAsyncCallback( + async () => { + await logout() + setDestinationWallet(undefined) + setHotspots([]) + setTokens([]) + setSelectedHotspots(new Set()) + setTokenAmounts({}) + setEmailInput('') + setCodeInput('') + setEmailSent(false) + setStep('link-email') + }, + ) + + const toggleHotspot = useCallback((address: string) => { + setSelectedHotspots((prev) => { + const next = new Set(prev) + if (next.has(address)) { + next.delete(address) + } else { + next.add(address) + } + return next + }) + }, []) + + const toggleAllHotspots = useCallback(() => { + if (selectedHotspots.size === hotspots.length) { + setSelectedHotspots(new Set()) + } else { + setSelectedHotspots(new Set(hotspots.map((h) => h.entityKey))) + } + }, [selectedHotspots, hotspots]) + + const setMaxTokenAmount = useCallback( + (mint: string) => { + const token = tokens.find((tk) => tk.mint === mint) + if (token) { + setTokenAmounts((prev) => ({ + ...prev, + [mint]: humanReadable(new BN(token.balance), token.decimals) || '0', + })) + } + }, + [tokens], + ) + + const updateTokenAmount = useCallback((mint: string, amount: string) => { + setTokenAmounts((prev) => ({ ...prev, [mint]: amount })) + }, []) + + // Step 5: Execute migration + const { execute: handleMigrate, error: migrateError } = useAsyncCallback( + async () => { + if (!anchorProvider || !destinationWallet) return + + setStep('migrating') + setBatchNum(1) + + try { + const selectedTokens = Object.entries(tokenAmounts) + .filter(([_, amount]) => amount && amount !== '0') + .map(([mint, amount]) => { + const token = tokens.find((tk) => tk.mint === mint) + return { + mint, + amount: token ? uiToRaw(amount, token.decimals) : amount, + } + }) + + let currentParams = { + sourceWallet, + destinationWallet, + hotspots: Array.from(selectedHotspots), + tokens: selectedTokens, + } + + let hasMore = true + let batch = 1 + + while (hasMore) { + setBatchNum(batch) + + // eslint-disable-next-line no-await-in-loop + const migrateResponse = await fetch( + `${Config.WALLET_REST_URI}/migrate`, + { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(currentParams), + }, + ) + if (!migrateResponse.ok) { + const errBody = await migrateResponse.json().catch(() => ({})) + throw new Error( + errBody.message || t('migrateToWorld.error.generic'), + ) + } + // eslint-disable-next-line no-await-in-loop + const result = await migrateResponse.json() + const { transactionData } = result + + // Deserialize transactions + const txs = transactionData.transactions.map((txData) => + VersionedTransaction.deserialize( + Buffer.from(txData.serializedTransaction, 'base64'), + ), + ) + + // Sign with source wallet + // eslint-disable-next-line no-await-in-loop + const signedTxs = await anchorProvider.wallet.signAllTransactions(txs) + + // Re-serialize signed transactions + const signedTransactionData = { + ...transactionData, + transactions: signedTxs.map((tx, i) => ({ + serializedTransaction: Buffer.from(tx.serialize()).toString( + 'base64', + ), + metadata: transactionData.transactions[i].metadata, + })), + } + + // Submit + // eslint-disable-next-line no-await-in-loop + const { batchId } = await client.transactions.submit( + signedTransactionData, + ) + + // Poll for confirmation + let confirmed = false + const startTime = Date.now() + const maxPollTime = 60000 + + while (!confirmed && Date.now() - startTime < maxPollTime) { + // eslint-disable-next-line no-await-in-loop + const status = await client.transactions.get({ + id: batchId, + commitment: 'confirmed', + }) + + if (status.status === 'confirmed') { + confirmed = true + } else if ( + status.status === 'failed' || + status.status === 'expired' + ) { + throw new Error(t('migrateToWorld.error.generic')) + } else { + // eslint-disable-next-line no-await-in-loop + await new Promise((resolve) => setTimeout(resolve, 2000)) + } + } + + if (!confirmed) { + throw new Error(t('migrateToWorld.error.generic')) + } + + if (result.hasMore && result.nextParams) { + currentParams = { + sourceWallet: result.nextParams.sourceWallet, + destinationWallet: result.nextParams.destinationWallet, + hotspots: result.nextParams.hotspots || [], + tokens: result.nextParams.tokens || [], + } + batch += 1 + } else { + hasMore = false + } + } + + setStep('success') + } catch (err) { + setStep('confirm') + throw err + } + }, + ) + + const error = ( + sendCodeError || + verifyCodeError || + loadAssetsError || + createWalletError || + logoutError || + migrateError + )?.message + + const loading = loadingAssets || creatingWallet + + const handleGoToWorld = useCallback(() => { + Linking.openURL('https://world.helium.com') + }, []) + + const handleBack = useCallback(() => { + setStep((current) => { + if (current === startStep) { + navigation.goBack() + return current + } + const order: MigrationStep[] = [ + 'link-email', + 'create-wallet', + 'select-assets', + 'confirm', + ] + const idx = order.indexOf(current) + if (idx > 0) { + return order[idx - 1] + } + navigation.goBack() + return current + }) + }, [navigation, startStep]) + + const renderLinkEmail = () => ( + + + + ← Back + + + + + {t('migrateToWorld.linkEmail.title')} + + + {t('migrateToWorld.linkEmail.body')} + + + {!emailSent ? ( + + + + + + + ) : ( + + + + + + + )} + + + ) + + const renderCreateWallet = () => ( + + + + ← Back + + + + + {t('migrateToWorld.createWallet.title')} + + + {t('migrateToWorld.createWallet.body')} + + {loading ? ( + + ) : ( + + )} + + + ) + + const renderSelectAssets = () => ( + + + + ← Back + + + + {t('migrateToWorld.selectAssets.title')} + + + + {userEmail && ( + + + Email + + + {userEmail} + + + )} + {destinationWallet && ( + + + New Wallet + + + {shortenAddress(destinationWallet, 8)} + + + )} + + + Log out and use a different email + + + + + {loading ? ( + + + + {t('migrateToWorld.selectAssets.loading')} + + + ) : ( + + {/* Hotspots */} + + + + {t('migrateToWorld.selectAssets.hotspots')} + + {hotspots.length > 0 && ( + + + {selectedHotspots.size === hotspots.length + ? t('migrateToWorld.selectAssets.deselectAll') + : t('migrateToWorld.selectAssets.selectAll')} + + + )} + + {hotspots.length === 0 ? ( + + {t('migrateToWorld.selectAssets.noHotspots')} + + ) : ( + hotspots.map((hotspot) => ( + toggleHotspot(hotspot.entityKey)} + > + + + + + {hotspot.name} + + + {hotspot.type} - {hotspot.deviceType} + + + + + )) + )} + + + {/* Tokens */} + + + {t('migrateToWorld.selectAssets.tokens')} + + {tokens.length === 0 ? ( + + {t('migrateToWorld.selectAssets.noTokens')} + + ) : ( + tokens.map((token) => ( + + + + {token.symbol || token.name || token.mint.slice(0, 8)} + + setMaxTokenAmount(token.mint)} + > + + Max + + + + + Balance:{' '} + {humanReadable(new BN(token.balance), token.decimals)} + + + updateTokenAmount(token.mint, val)} + placeholder="0" + placeholderTextColor="rgba(255,255,255,0.3)" + style={{ color: 'white', fontSize: 14 }} + keyboardType="decimal-pad" + /> + + + )) + )} + + + )} + + {!loading && ( + setStep('confirm')} + marginBottom="m" + disabled={ + selectedHotspots.size === 0 && + !Object.values(tokenAmounts).some((a) => a && a !== '0') + } + /> + )} + + ) + + const renderConfirm = () => ( + + + + ← Back + + + + {t('migrateToWorld.confirm.title')} + + + + + {t('migrateToWorld.confirm.source')} + + + {shortenAddress(sourceWallet, 8)} + + + + + + {t('migrateToWorld.confirm.destination')} + + + {shortenAddress(destinationWallet || '', 8)} + + + + {selectedHotspots.size > 0 && ( + + + Hotspots + + + {selectedHotspots.size} Hotspot + {selectedHotspots.size !== 1 ? 's' : ''} + + + )} + + {Object.entries(tokenAmounts) + .filter(([_, amount]) => amount && amount !== '0') + .map(([mint]) => { + const token = tokens.find((tk) => tk.mint === mint) + return ( + + + {tokenAmounts[mint]} {token?.symbol || mint.slice(0, 8)} + + + ) + })} + + + + + + ) + + const renderMigrating = () => ( + + + + {t('migrateToWorld.migrating.title')} + + + {t('migrateToWorld.migrating.batch', { num: batchNum })} + + + ) + + const renderSuccess = () => ( + + + {t('migrateToWorld.success.title')} + + + {t('migrateToWorld.success.body')} + + + navigation.goBack()} + /> + + ) + + const renderStep = () => { + switch (step) { + case 'link-email': + return renderLinkEmail() + case 'create-wallet': + return renderCreateWallet() + case 'select-assets': + return renderSelectAssets() + case 'confirm': + return renderConfirm() + case 'migrating': + return renderMigrating() + case 'success': + return renderSuccess() + default: + return null + } + } + + return ( + + {error && ( + + + {error} + + + )} + {renderStep()} + + ) +} + +export default memo(MigrateToWorld) diff --git a/src/features/migration/SolanaMigration.tsx b/src/features/migration/SolanaMigration.tsx index 6c055a80..6ab11c81 100644 --- a/src/features/migration/SolanaMigration.tsx +++ b/src/features/migration/SolanaMigration.tsx @@ -7,7 +7,7 @@ import { DelayedFadeIn } from '@components/FadeInOut' import IndeterminateProgressBar from '@components/IndeterminateProgressBar' import SafeAreaBox from '@components/SafeAreaBox' import Text from '@components/Text' -import { apiContract } from '@helium/blockchain-api' +import { fullApiContract } from '@helium/blockchain-api' import { ContractRouterClient } from '@orpc/contract' import { BoxProps } from '@shopify/restyle' import { VersionedTransaction } from '@solana/web3.js' @@ -29,7 +29,7 @@ import { useAppDispatch } from '../../store/store' import * as Logger from '../../utils/logger' async function migrateWallet( - client: ContractRouterClient, + client: ContractRouterClient, wallet: string, onProgress: (progress: number, total: number) => void, ) { @@ -106,7 +106,33 @@ const SolanaMigration = ({ !manual) ) return - // eslint-disable-next-line no-console + + // Check if there are actually transactions to migrate before proceeding + try { + const url = `${Config.MIGRATION_SERVER_URL}/migrate/${currentAccount.solanaAddress}` + const { transactions } = (await axios.get(url)).data + if (!transactions || transactions.length === 0) { + // No transactions to migrate — mark as done so overlay doesn't show again + if (!manual) { + await updateDoneSolanaMigration({ + cluster, + address: currentAccount.solanaAddress, + }) + } + return + } + } catch (e) { + Logger.error(e) + // If check fails, mark as done to avoid blocking the user + if (!manual) { + await updateDoneSolanaMigration({ + cluster, + address: currentAccount.solanaAddress, + }) + } + return + } + try { await migrateWallet(client, currentAccount?.solanaAddress, onProgress) diff --git a/src/features/modals/MigrateToWorldCheck.tsx b/src/features/modals/MigrateToWorldCheck.tsx new file mode 100644 index 00000000..481c07d6 --- /dev/null +++ b/src/features/modals/MigrateToWorldCheck.tsx @@ -0,0 +1,33 @@ +import { useCurrentWallet } from '@hooks/useCurrentWallet' +import { useAppStorage } from '@storage/AppStorageProvider' +import { useModal } from '@storage/ModalsProvider' +import { FC, useEffect, useRef } from 'react' + +const MigrateToWorldCheck: FC = () => { + const wallet = useCurrentWallet() + const { shouldShowMigrateToWorld } = useAppStorage() + const { showModal, type } = useModal() + const hasShown = useRef(false) + + useEffect(() => { + if (hasShown.current) return + + const walletAddress = wallet?.toBase58() + const shouldShow = walletAddress + ? shouldShowMigrateToWorld(walletAddress) + : false + + if (shouldShow && !type && wallet) { + const timer = setTimeout(() => { + hasShown.current = true + showModal({ type: 'MigrateToWorld' }) + }, 1500) + + return () => clearTimeout(timer) + } + }, [shouldShowMigrateToWorld, showModal, type, wallet]) + + return null +} + +export default MigrateToWorldCheck diff --git a/src/features/modals/MigrateToWorldModal.tsx b/src/features/modals/MigrateToWorldModal.tsx new file mode 100644 index 00000000..1d19cab7 --- /dev/null +++ b/src/features/modals/MigrateToWorldModal.tsx @@ -0,0 +1,572 @@ +import Box from '@components/Box' +import ButtonPressable from '@components/ButtonPressable' +import CircleLoader from '@components/CircleLoader' +import SafeAreaBox from '@components/SafeAreaBox' +import Text from '@components/Text' +import { useCurrentWallet } from '@hooks/useCurrentWallet' +import { useNavigation } from '@react-navigation/native' +import { useAppStorage } from '@storage/AppStorageProvider' +import { useModal } from '@storage/ModalsProvider' +import TouchableOpacityBox from '@components/TouchableOpacityBox' +import React, { FC, memo, useCallback, useMemo, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { Linking, ScrollView, TextInput } from 'react-native' +import { Edge } from 'react-native-safe-area-context' +import { useLoginWithEmail, useLinkEmail, usePrivy } from '@privy-io/expo' +import PrivyAppProvider from '../../providers/PrivyProvider' +import { HomeNavigationProp } from '../home/homeTypes' +import * as Logger from '../../utils/logger' + +type Step = 'welcome' | 'choosePath' | 'selfCustody' | 'emailLogin' + +// Inner component that uses Privy hooks (must be inside PrivyAppProvider) +const EmailLoginStep: FC<{ + onBack: () => void + onSuccess: () => void +}> = ({ onBack, onSuccess }) => { + const { t } = useTranslation() + const { user, isReady } = usePrivy() + + const { + sendCode: loginSendCode, + loginWithCode, + state: loginState, + } = useLoginWithEmail() + const { + sendCode: linkSendCode, + linkWithCode, + state: linkState, + } = useLinkEmail() + + const [emailInput, setEmailInput] = useState('') + const [codeInput, setCodeInput] = useState('') + const [codeSent, setCodeSent] = useState(false) + const [completed, setCompleted] = useState(false) + const [error, setError] = useState() + + const handleSendCode = useCallback(async () => { + if (!emailInput) return + try { + setError(undefined) + if (user) { + await linkSendCode({ email: emailInput }) + } else { + await loginSendCode({ email: emailInput }) + } + setCodeSent(true) + } catch (err) { + Logger.error(err) + setError((err as Error).message) + } + }, [emailInput, user, loginSendCode, linkSendCode]) + + const handleVerifyCode = useCallback(async () => { + if (!codeInput) return + try { + setError(undefined) + setCompleted(true) + if (user) { + await linkWithCode({ code: codeInput }) + } else { + await loginWithCode({ code: codeInput }) + } + onSuccess() + } catch (err) { + Logger.error(err) + setCompleted(false) + setError((err as Error).message) + } + }, [codeInput, user, loginWithCode, linkWithCode, onSuccess]) + + const emailState = user ? linkState : loginState + const sending = emailState.status === 'sending-code' + const verifying = emailState.status === 'submitting-code' + + if (!isReady || completed) { + return ( + + + + {completed ? 'Logging in...' : 'Loading...'} + + + ) + } + + return ( + + + + ← Back + + + + + {t('migrateToWorld.linkEmail.title')} + + + {t('migrateToWorld.linkEmail.body')} + + + {error && ( + + {error} + + )} + + {!codeSent ? ( + + + + + + ) : undefined + } + /> + + ) : ( + + + We sent a code to {emailInput} + + + + + + ) : undefined + } + /> + { + setCodeSent(false) + setCodeInput('') + }} + marginTop="m" + alignItems="center" + > + + Use a different email + + + + )} + + + ) +} + +const MigrateToWorldModal: FC = () => { + const { user } = usePrivy() + const { t } = useTranslation() + const { hideModal } = useModal() + const edges = useMemo(() => ['top', 'bottom'] as Edge[], []) + const wallet = useCurrentWallet() + const { dismissMigrateToWorld } = useAppStorage() + const homeNav = useNavigation() + const [step, setStep] = useState('welcome') + + const handleDismiss = useCallback(() => { + dismissMigrateToWorld(wallet?.toBase58() || '') + hideModal() + }, [dismissMigrateToWorld, wallet, hideModal]) + + const handleBack = useCallback(() => { + if (step === 'selfCustody' || step === 'emailLogin') { + setStep('choosePath') + } else if (step === 'choosePath') { + setStep('welcome') + } + }, [step]) + + const handleEmailSuccess = useCallback(() => { + // Email linked, navigate to the full migration flow + dismissMigrateToWorld(wallet?.toBase58() || '') + hideModal() + homeNav.navigate( + 'SettingsNavigator' as any, + { + screen: 'MigrateToWorld', + } as any, + ) + }, [dismissMigrateToWorld, wallet, hideModal, homeNav]) + + const handleChooseEmail = useCallback(() => { + const hasEmail = user?.linked_accounts?.some((a) => a.type === 'email') + if (hasEmail) { + handleEmailSuccess() + } else { + setStep('emailLogin') + } + }, [user, handleEmailSuccess]) + + const handleRevealPrivateKey = useCallback(() => { + hideModal() + homeNav.navigate( + 'SettingsNavigator' as any, + { + screen: 'RevealPrivateKey', + } as any, + ) + }, [hideModal, homeNav]) + + const renderWelcome = () => ( + + + + {t('migrateToWorldModal.welcome.title')} + + + {t('migrateToWorldModal.welcome.body')} + + + + setStep('choosePath')} + marginBottom="m" + /> + + + {t('migrateToWorldModal.findInSettings')} + + + + ) + + const renderChoosePath = () => ( + + + + ← Back + + + + + {t('migrateToWorldModal.choosePath.title')} + + + + + + {t('migrateToWorldModal.choosePath.emailBody')} + + + + + setStep('selfCustody')} + /> + + {t('migrateToWorldModal.choosePath.selfCustodyBody')} + + + + + + + + ) + + const renderSelfCustody = () => ( + + + + ← Back + + + + + + {t('migrateToWorldModal.selfCustody.title')} + + + + ⚠ {t('migrateToWorldModal.selfCustody.warning')} + + + + + {t('migrateToWorldModal.selfCustody.step1Title')} + + + {t('migrateToWorldModal.selfCustody.step1Body')} + + + Linking.openURL('https://phantom.app')} + > + phantom.app + + Linking.openURL('https://solflare.com')} + > + solflare.com + + + + + + + {t('migrateToWorldModal.selfCustody.step2Title')} + + + {t('migrateToWorldModal.selfCustody.step2Body')} + + + {t('migrateToWorldModal.selfCustody.step2Button')} → + + + + + + {t('migrateToWorldModal.selfCustody.step3Title')} + + + {t('migrateToWorldModal.selfCustody.step3Body')} + + + + + + {t('migrateToWorldModal.selfCustody.step4Title')} + + + {t('migrateToWorldModal.selfCustody.step4Body')} + + + + + + + + + ) + + return ( + + + {step === 'welcome' && renderWelcome()} + {step === 'choosePath' && renderChoosePath()} + {step === 'selfCustody' && renderSelfCustody()} + {step === 'emailLogin' && ( + + )} + + + ) +} + +export default memo(() => { + const { type } = useModal() + + if (type !== 'MigrateToWorld') return null + return ( + + + + ) +}) diff --git a/src/features/settings/Settings.tsx b/src/features/settings/Settings.tsx index 61677b6b..f488de4b 100644 --- a/src/features/settings/Settings.tsx +++ b/src/features/settings/Settings.tsx @@ -21,6 +21,7 @@ import { RootNavigationProp } from '../../navigation/rootTypes' import { useSolana } from '../../solana/SolanaProvider' import { useAccountStorage } from '../../storage/AccountStorageProvider' import { useAppStorage } from '../../storage/AppStorageProvider' +import { useModal } from '../../storage/ModalsProvider' import { useLanguageStorage } from '../../storage/LanguageProvider' import { checkSecureAccount, @@ -328,6 +329,11 @@ const Settings = () => { settingsNav.navigate('MigrateWallet') }, [settingsNav]) + const { showModal } = useModal() + const handleMigrateToWorld = useCallback(() => { + showModal({ type: 'MigrateToWorld' }) + }, [showModal]) + const SectionData = useMemo((): { title: string icon: React.ReactNode | null @@ -436,6 +442,11 @@ const Settings = () => { onPress: handleMigrateWallet, }) + accountSettings.push({ + title: t('settings.sections.account.migrateToWorld'), + onPress: handleMigrateToWorld, + }) + accountSettings.push({ title: t('settings.sections.account.signOut'), onPress: handleSignOut, @@ -570,6 +581,7 @@ const Settings = () => { isDefaultAccount, handleShareAddress, handleMigrateWallet, + handleMigrateToWorld, handleSignOut, hasWords, handleRevealWords, diff --git a/src/features/settings/SettingsNavigator.tsx b/src/features/settings/SettingsNavigator.tsx index 0253616a..5539f0ec 100644 --- a/src/features/settings/SettingsNavigator.tsx +++ b/src/features/settings/SettingsNavigator.tsx @@ -3,6 +3,8 @@ import { useOpacity } from '@theme/themeHooks' import React, { memo } from 'react' import SecretKeyWarningScreen from '@components/SecretKeyWarningScreen' import SolanaMigration from '../migration/SolanaMigration' +import MigrateToWorldScreen from '../migration/MigrateToWorld' +import PrivyAppProvider from '../../providers/PrivyProvider' import AutoGasManager from './AutoGasManager' import ConfirmSignoutScreen from './ConfirmSignoutScreen' import RevealPrivateKeyScreen from './RevealPrivateKeyScreen' @@ -19,6 +21,14 @@ const SolanaMigrationWrapper = () => { return } +const MigrateToWorldWrapper = () => { + return ( + + + + ) +} + const RevealWordsWrapper = () => { return ( @@ -79,6 +89,11 @@ const SettingsNavigator = () => { component={SolanaMigrationWrapper} options={{ presentation: 'transparentModal' }} /> + Reveal Private Key. Copy it somewhere safe — never share it with anyone.', + step2Button: 'Go to Reveal Private Key', + step3Title: '3. Import into your new wallet', + step3Body: + 'In Phantom or Solflare, choose "Import Wallet" and paste your private key. Your assets will appear automatically.', + step4Title: '4. Log in to Helium World', + step4Body: + "Go to world.helium.com and connect your Phantom or Solflare wallet. You're all set.", + openPhantom: 'Visit phantom.app', + openSolflare: 'Visit solflare.com', + warning: + 'Your private key gives full access to your wallet. Never share it, screenshot it, or paste it anywhere other than a trusted wallet app.', + }, + dismiss: 'Dismiss', + findInSettings: 'You can find this later in Settings', + }, + migrateToWorld: { + linkEmail: { + title: 'Link Your Email', + body: 'Link an email address to create your Helium World account.', + button: 'Link Email', + }, + createWallet: { + title: 'Create Wallet', + body: 'Creating a wallet linked to your email address.', + button: 'Create Wallet', + }, + selectAssets: { + title: 'Select Assets to Migrate', + hotspots: 'Hotspots', + tokens: 'Tokens', + selectAll: 'Select All', + deselectAll: 'Deselect All', + noHotspots: 'No Hotspots found.', + noTokens: 'No token balances found.', + loading: 'Loading assets...', + review: 'Review Migration', + }, + confirm: { + title: 'Confirm Migration', + source: 'From', + destination: 'To', + button: 'Confirm & Migrate', + back: 'Back', + }, + migrating: { + title: 'Migrating...', + batch: 'Processing batch {{num}}', + }, + success: { + title: 'Migration Complete', + body: 'Your assets have been successfully migrated to Helium World.', + goToWorld: 'Go to Helium World', + }, + error: { + signFailed: 'Wallet failed to sign the transaction.', + generic: 'Migration failed. Please try again.', + }, + }, } diff --git a/src/providers/PrivyProvider.tsx b/src/providers/PrivyProvider.tsx new file mode 100644 index 00000000..ebec153d --- /dev/null +++ b/src/providers/PrivyProvider.tsx @@ -0,0 +1,21 @@ +import React, { FC, ReactNode } from 'react' +import { PrivyProvider as PrivyProviderBase } from '@privy-io/expo' +import Config from 'react-native-config' + +const PrivyAppProvider: FC<{ children: ReactNode }> = ({ children }) => { + const appId = Config.PRIVY_APP_ID + const clientId = Config.PRIVY_CLIENT_ID + + if (!appId || !clientId) { + console.warn('Privy app ID or client ID not configured') + return <>{children} + } + + return ( + + {children} + + ) +} + +export default PrivyAppProvider diff --git a/src/storage/AppStorageProvider.tsx b/src/storage/AppStorageProvider.tsx index 195f6e7a..4f13aeb7 100644 --- a/src/storage/AppStorageProvider.tsx +++ b/src/storage/AppStorageProvider.tsx @@ -18,6 +18,7 @@ import { const VOTE_TUTORIAL_SHOWN = 'voteTutorialShown' const DAPP_TUTORIAL_SHOWN = 'dAppTutorialShown' const DEPRECATED_TOKENS_DISMISSED = 'deprecatedTokensDismissedByWallet' +const MIGRATE_TO_WORLD_DISMISSED = 'migrateToWorldDismissedByWallet' const useAppStorageHook = () => { const [autoGasManagementToken, setAutoGasManagementToken] = useState< @@ -53,6 +54,9 @@ const useAppStorageHook = () => { const [deprecatedTokensDismissed, setDeprecatedTokensDismissed] = useState< Record >({}) + const [migrateToWorldDismissed, setMigrateToWorldDismissed] = useState< + Record + >({}) const [doneSolanaMigration, setDoneSolanaMigration] = useState< Record >({ @@ -94,6 +98,12 @@ const useAppStorageHook = () => { const nextDeprecatedTokensDismissed = nextDeprecatedTokensDismissedStr ? JSON.parse(nextDeprecatedTokensDismissedStr) : {} + const nextMigrateToWorldDismissedStr = await AsyncStorage.getItem( + MIGRATE_TO_WORLD_DISMISSED, + ) + const nextMigrateToWorldDismissed = nextMigrateToWorldDismissedStr + ? JSON.parse(nextMigrateToWorldDismissedStr) + : {} const nextShowNumericChange = await getSecureItem('showNumericChange') const nextDoneSolanaMigration = await getSecureItem( SecureStorageKeys.DONE_SOLANA_MIGRATION, @@ -129,6 +139,7 @@ const useAppStorageHook = () => { ) setVoteTutorialShown(nextVoteShown === 'true') setDeprecatedTokensDismissed(nextDeprecatedTokensDismissed) + setMigrateToWorldDismissed(nextMigrateToWorldDismissed) setShowNumericChange(nextShowNumericChange === 'true') setSessionKey(nextSessionKey || '') setDoneSolanaMigration( @@ -256,6 +267,28 @@ const useAppStorageHook = () => { [deprecatedTokensDismissed], ) + const dismissMigrateToWorld = useCallback( + async (walletAddress: string) => { + const updated = { + ...migrateToWorldDismissed, + [walletAddress]: true, + } + setMigrateToWorldDismissed(updated) + return AsyncStorage.setItem( + MIGRATE_TO_WORLD_DISMISSED, + JSON.stringify(updated), + ) + }, + [migrateToWorldDismissed], + ) + + const shouldShowMigrateToWorld = useCallback( + (walletAddress: string) => { + return !migrateToWorldDismissed[walletAddress] + }, + [migrateToWorldDismissed], + ) + const updateShowNumericChange = useCallback(async (useNumeric: boolean) => { setShowNumericChange(useNumeric) return storeSecureItem('showNumericChange', useNumeric ? 'true' : 'false') @@ -319,6 +352,8 @@ const useAppStorageHook = () => { deprecatedTokensDismissed, dismissDeprecatedTokens, shouldShowDeprecatedTokens, + dismissMigrateToWorld, + shouldShowMigrateToWorld, showNumericChange, sessionKey, doneSolanaMigration, @@ -357,6 +392,8 @@ const initialState = { deprecatedTokensDismissed: {}, dismissDeprecatedTokens: async () => undefined, shouldShowDeprecatedTokens: () => true, + dismissMigrateToWorld: async () => undefined, + shouldShowMigrateToWorld: () => true, updateEnableHaptic: async () => undefined, updateAutoGasManagementToken: async () => undefined, updateAuthInterval: async () => undefined, diff --git a/src/storage/BlockchainApiProvider.tsx b/src/storage/BlockchainApiProvider.tsx index 2b232ac3..43c08571 100644 --- a/src/storage/BlockchainApiProvider.tsx +++ b/src/storage/BlockchainApiProvider.tsx @@ -1,4 +1,4 @@ -import { apiContract } from '@helium/blockchain-api' +import { fullApiContract } from '@helium/blockchain-api' import { createORPCClient, onError } from '@orpc/client' import { RPCLink } from '@orpc/client/fetch' import { ContractRouterClient } from '@orpc/contract' @@ -8,7 +8,7 @@ import Config from 'react-native-config' import { RootState } from '../store/rootReducer' const BlockchainApiContext = createContext | null>(null) export const BlockchainApiProvider: React.FC = ({ @@ -47,7 +47,7 @@ export const BlockchainApiProvider: React.FC = ({ }), ], }) - const orpcClient: ContractRouterClient = + const orpcClient: ContractRouterClient = createORPCClient(link) return orpcClient @@ -65,7 +65,7 @@ export const BlockchainApiProvider: React.FC = ({ } export const useBlockchainApi = (): ContractRouterClient< - typeof apiContract + typeof fullApiContract > => { const context = useContext(BlockchainApiContext) diff --git a/src/storage/ModalsProvider.tsx b/src/storage/ModalsProvider.tsx index 8b0a7c77..d3309a73 100644 --- a/src/storage/ModalsProvider.tsx +++ b/src/storage/ModalsProvider.tsx @@ -9,7 +9,7 @@ import React, { } from 'react' interface IModalProps { - type?: 'InsufficientSolConversion' | 'DeprecatedTokens' + type?: 'InsufficientSolConversion' | 'DeprecatedTokens' | 'MigrateToWorld' onHide?: () => Promise onCancel?: () => Promise diff --git a/yarn.lock b/yarn.lock index 2982a511..299a0acd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17,6 +17,13 @@ __metadata: languageName: node linkType: hard +"@adraffy/ens-normalize@npm:^1.11.0": + version: 1.11.1 + resolution: "@adraffy/ens-normalize@npm:1.11.1" + checksum: 10/dd19274d9fcaf99bf08a62b64e54f4748de11b235767addbd3f7385ae1b7777bd704d17ff003ffaa3295a0b9d035929381cf3b38329c96260bff96aab8ad7b37 + languageName: node + linkType: hard + "@ampproject/remapping@npm:^2.2.0": version: 2.3.0 resolution: "@ampproject/remapping@npm:2.3.0" @@ -2441,26 +2448,26 @@ __metadata: languageName: node linkType: hard -"@helium/account-fetch-cache-hooks@npm:0.11.4": - version: 0.11.4 - resolution: "@helium/account-fetch-cache-hooks@npm:0.11.4" +"@helium/account-fetch-cache-hooks@npm:0.11.12": + version: 0.11.12 + resolution: "@helium/account-fetch-cache-hooks@npm:0.11.12" dependencies: - "@helium/account-fetch-cache": "npm:^0.11.4" + "@helium/account-fetch-cache": "npm:^0.11.12" "@solana/web3.js": "npm:^1.91.1" react-async-hook: "npm:^4.0.0" peerDependencies: react: ^16.8 || ^17 || ^18 react-dom: ^16.8 || ^17 || ^18 - checksum: 10/bc883c87ee906288fae115a41b73e5c33b1e42b2da920fd677f94aa4a4112dd56690c97978d8f38dacba50597c96f06c7d5db899b992cd2568faea1c9a2cde8f + checksum: 10/7a3fdf3a9fae54fcf4eae0f1351f0a24789072d2c3bfa9d19bd37a9b143749806ae896f6438b022e8be4379cff69b107a03c22138ddeadd5aaf36f5ab1c8c596 languageName: node linkType: hard -"@helium/account-fetch-cache@npm:0.11.4": - version: 0.11.4 - resolution: "@helium/account-fetch-cache@npm:0.11.4" +"@helium/account-fetch-cache@npm:0.11.12": + version: 0.11.12 + resolution: "@helium/account-fetch-cache@npm:0.11.12" dependencies: "@solana/web3.js": "npm:^1.91.1" - checksum: 10/80111f717ccf8baec9b4325d79cf4e491487377bc7762360ae78740eb4c80513855a1502327b8ecf0dd1869a35734aef8b773c5bedaf759558b30970bd00f8bb + checksum: 10/6a42b90dfa99983fe9b7de3aee1ca6eab81229fe1ac4ae3b5908ae24da8def64c1957f54f40007b37aa580d06235131d8949d51352bc292fc15423b6a31a569b languageName: node linkType: hard @@ -2498,6 +2505,18 @@ __metadata: languageName: node linkType: hard +"@helium/anchor-resolvers@npm:^0.11.12": + version: 0.11.12 + resolution: "@helium/anchor-resolvers@npm:0.11.12" + dependencies: + "@solana/spl-token": "npm:^0.3.8" + "@solana/web3.js": "npm:^1.91.1" + peerDependencies: + "@coral-xyz/anchor": ^0.31.0 + checksum: 10/7b359f417bbdaac6cea39cf2909d564aec794367a3c64dcd353b3f61b4f700374439a946353a452c0ab4266bd6be483dfc310c6c04cd383a9731dcefe02a7d2d + languageName: node + linkType: hard + "@helium/anchor-resolvers@npm:^0.11.4": version: 0.11.4 resolution: "@helium/anchor-resolvers@npm:0.11.4" @@ -2510,15 +2529,15 @@ __metadata: languageName: node linkType: hard -"@helium/automation-hooks@npm:^0.11.4": - version: 0.11.4 - resolution: "@helium/automation-hooks@npm:0.11.4" +"@helium/automation-hooks@npm:^0.11.12": + version: 0.11.12 + resolution: "@helium/automation-hooks@npm:0.11.12" dependencies: "@coral-xyz/anchor": "npm:^0.31.0" - "@helium/account-fetch-cache": "npm:^0.11.4" - "@helium/account-fetch-cache-hooks": "npm:^0.11.4" - "@helium/hpl-crons-sdk": "npm:^0.11.4" - "@helium/spl-utils": "npm:^0.11.4" + "@helium/account-fetch-cache": "npm:^0.11.12" + "@helium/account-fetch-cache-hooks": "npm:^0.11.12" + "@helium/hpl-crons-sdk": "npm:^0.11.12" + "@helium/spl-utils": "npm:^0.11.12" "@helium/tuktuk-sdk": "npm:^0.0.9" "@solana/wallet-adapter-base": "npm:^0.9.22" "@solana/web3.js": "npm:^1.91.1" @@ -2529,7 +2548,7 @@ __metadata: "@solana/wallet-adapter-react": ^0.15.32 react: ^16.8 || ^17 || ^18 react-dom: ^16.8 || ^17 || ^18 - checksum: 10/de1b098d7f05f41beb4dc964ce6fb11d38f4c4bf811dac93493c3e12ff20f392f8379fdff02194740f8bf7932ebf8a3514fce9cebb2108cedcaf4ce2c17eaf5f + checksum: 10/5ca7f43cd0713d40ea3f404f7fabc522e78927242f5df2eac2bc707d9867ee2ddc411a2477999aba609c319be225656cdba47e1694ed1597e85e9283a7d5cf98 languageName: node linkType: hard @@ -2543,7 +2562,21 @@ __metadata: languageName: node linkType: hard -"@helium/circuit-breaker-sdk@npm:0.11.4, @helium/circuit-breaker-sdk@npm:^0.11.4": +"@helium/circuit-breaker-sdk@npm:0.11.12, @helium/circuit-breaker-sdk@npm:^0.11.12": + version: 0.11.12 + resolution: "@helium/circuit-breaker-sdk@npm:0.11.12" + dependencies: + "@coral-xyz/anchor": "npm:^0.31.0" + "@helium/anchor-resolvers": "npm:^0.11.12" + "@helium/idls": "npm:^0.11.12" + "@helium/spl-utils": "npm:^0.11.12" + bn.js: "npm:^5.2.0" + bs58: "npm:^4.0.1" + checksum: 10/278d88006a22eacaa8d420586209a8eba77009acabc34b224c9eb41c84275a56f9a0029e0002514f92dee85985f1711ca3e1cd1edfc30d3cc1770baa7b0a3cf1 + languageName: node + linkType: hard + +"@helium/circuit-breaker-sdk@npm:^0.11.4": version: 0.11.4 resolution: "@helium/circuit-breaker-sdk@npm:0.11.4" dependencies: @@ -2606,7 +2639,19 @@ __metadata: languageName: node linkType: hard -"@helium/currency-utils@npm:0.11.4, @helium/currency-utils@npm:^0.11.4": +"@helium/currency-utils@npm:0.11.12": + version: 0.11.12 + resolution: "@helium/currency-utils@npm:0.11.12" + dependencies: + "@helium/spl-utils": "npm:^0.11.12" + "@pythnetwork/hermes-client": "npm:^2.0.0" + "@solana/spl-token": "npm:^0.3.8" + "@solana/web3.js": "npm:^1.91.1" + checksum: 10/938653895bc55bf3bafb862375bf1d47f2155e8c270b2658db75d9c05ab8383bac0cf55723e5d8e0ba89d0c9aa7931c3d5b8867f2e1cc0b044399c48ed5819d7 + languageName: node + linkType: hard + +"@helium/currency-utils@npm:^0.11.4": version: 0.11.4 resolution: "@helium/currency-utils@npm:0.11.4" dependencies: @@ -2627,7 +2672,25 @@ __metadata: languageName: node linkType: hard -"@helium/data-credits-sdk@npm:0.11.4, @helium/data-credits-sdk@npm:^0.11.4": +"@helium/data-credits-sdk@npm:0.11.12": + version: 0.11.12 + resolution: "@helium/data-credits-sdk@npm:0.11.12" + dependencies: + "@coral-xyz/anchor": "npm:^0.31.0" + "@helium/anchor-resolvers": "npm:^0.11.12" + "@helium/circuit-breaker-sdk": "npm:^0.11.12" + "@helium/helium-sub-daos-sdk": "npm:^0.11.12" + "@helium/idls": "npm:^0.11.12" + "@helium/spl-utils": "npm:^0.11.12" + "@pythnetwork/hermes-client": "npm:^2.0.0" + "@pythnetwork/pyth-solana-receiver": "npm:^0.10.2" + bn.js: "npm:^5.2.0" + bs58: "npm:^4.0.1" + checksum: 10/bf6754e1556ae46fa7b61668e35f1ec122d724bbd6f4ae50bd29d397dc275294069ee04d90bbbc248f5328e747d6106ecb9958bb94b0982290a5e9b6b7519adf + languageName: node + linkType: hard + +"@helium/data-credits-sdk@npm:^0.11.4": version: 0.11.4 resolution: "@helium/data-credits-sdk@npm:0.11.4" dependencies: @@ -2645,21 +2708,21 @@ __metadata: languageName: node linkType: hard -"@helium/distributor-oracle@npm:0.11.4": - version: 0.11.4 - resolution: "@helium/distributor-oracle@npm:0.11.4" +"@helium/distributor-oracle@npm:0.11.12": + version: 0.11.12 + resolution: "@helium/distributor-oracle@npm:0.11.12" dependencies: "@coral-xyz/anchor": "npm:^0.31.0" "@fastify/cors": "npm:^8.1.1" - "@helium/account-fetch-cache": "npm:^0.11.4" + "@helium/account-fetch-cache": "npm:^0.11.12" "@helium/address": "npm:^4.12.0" - "@helium/helium-entity-manager-sdk": "npm:^0.11.4" - "@helium/helium-sub-daos-sdk": "npm:^0.11.4" - "@helium/hpl-crons-sdk": "npm:^0.11.4" - "@helium/idls": "npm:^0.11.4" - "@helium/lazy-distributor-sdk": "npm:^0.11.4" - "@helium/rewards-oracle-sdk": "npm:^0.11.4" - "@helium/spl-utils": "npm:^0.11.4" + "@helium/helium-entity-manager-sdk": "npm:^0.11.12" + "@helium/helium-sub-daos-sdk": "npm:^0.11.12" + "@helium/hpl-crons-sdk": "npm:^0.11.12" + "@helium/idls": "npm:^0.11.12" + "@helium/lazy-distributor-sdk": "npm:^0.11.12" + "@helium/rewards-oracle-sdk": "npm:^0.11.12" + "@helium/spl-utils": "npm:^0.11.12" "@helium/tuktuk-sdk": "npm:^0.0.9" "@metaplex-foundation/mpl-bubblegum": "npm:^0.7.0" "@solana/spl-memo": "npm:^0.2.5" @@ -2678,25 +2741,43 @@ __metadata: sequelize: "npm:^6.28.0" tweetnacl: "npm:^1.0.3" typescript-collections: "npm:^1.3.3" - checksum: 10/7e8eb52bf54c7c2bf569832b66c3bcff5a6143978a5ec2e6bd6578fe92dd41b0b840a4de51a4103a54bb8c89046154680cbc362eda296f9dcae8a46b6b3ef564 + checksum: 10/e197befe61f9a8a15ace923c8add564b4934c43624ca9c9c840b44392247adc0503bf73084bb0f788eb0b33a95fab771c485dedba58fefbbaf7b4767d2e7daed languageName: node linkType: hard -"@helium/fanout-sdk@npm:0.11.4": - version: 0.11.4 - resolution: "@helium/fanout-sdk@npm:0.11.4" +"@helium/fanout-sdk@npm:0.11.12": + version: 0.11.12 + resolution: "@helium/fanout-sdk@npm:0.11.12" dependencies: "@coral-xyz/anchor": "npm:^0.31.0" - "@helium/anchor-resolvers": "npm:^0.11.4" - "@helium/idls": "npm:^0.11.4" - "@helium/spl-utils": "npm:^0.11.4" + "@helium/anchor-resolvers": "npm:^0.11.12" + "@helium/idls": "npm:^0.11.12" + "@helium/spl-utils": "npm:^0.11.12" + bn.js: "npm:^5.2.0" + bs58: "npm:^4.0.1" + checksum: 10/0a04bef4df6109ba0debdf162accda115e5509524940748efda80f824168c44104343b50d1951435fed5887f6e98ce090f11a88ba62e3bd59ea0ed97528dd835 + languageName: node + linkType: hard + +"@helium/helium-entity-manager-sdk@npm:0.11.12, @helium/helium-entity-manager-sdk@npm:^0.11.12": + version: 0.11.12 + resolution: "@helium/helium-entity-manager-sdk@npm:0.11.12" + dependencies: + "@coral-xyz/anchor": "npm:^0.31.0" + "@helium/address": "npm:^4.12.0" + "@helium/anchor-resolvers": "npm:^0.11.12" + "@helium/helium-sub-daos-sdk": "npm:^0.11.12" + "@helium/idls": "npm:^0.11.12" + "@helium/no-emit-sdk": "npm:^0.11.12" + "@helium/spl-utils": "npm:^0.11.12" bn.js: "npm:^5.2.0" bs58: "npm:^4.0.1" - checksum: 10/9c723072d7f921b334ad91047d9234fe512301652675721aaa558f6773f45d4e3eb4ec99363d5452dd3d4d9fe680509fd28450930496a3331d89fafbc1048571 + js-sha256: "npm:^0.9.0" + checksum: 10/7c13d570158b483e4e99694e32f2d1b006158ab9d498d936588ef9b05bc337c60ac6b037e79c0bcb17f010a8e9cea08058926cb868bf7c5af6820235fdca65c5 languageName: node linkType: hard -"@helium/helium-entity-manager-sdk@npm:0.11.4, @helium/helium-entity-manager-sdk@npm:^0.11.4": +"@helium/helium-entity-manager-sdk@npm:^0.11.4": version: 0.11.4 resolution: "@helium/helium-entity-manager-sdk@npm:0.11.4" dependencies: @@ -2714,13 +2795,13 @@ __metadata: languageName: node linkType: hard -"@helium/helium-react-hooks@npm:0.11.4": - version: 0.11.4 - resolution: "@helium/helium-react-hooks@npm:0.11.4" +"@helium/helium-react-hooks@npm:0.11.12": + version: 0.11.12 + resolution: "@helium/helium-react-hooks@npm:0.11.12" dependencies: "@coral-xyz/anchor": "npm:^0.31.0" - "@helium/account-fetch-cache": "npm:^0.11.4" - "@helium/account-fetch-cache-hooks": "npm:^0.11.4" + "@helium/account-fetch-cache": "npm:^0.11.12" + "@helium/account-fetch-cache-hooks": "npm:^0.11.12" "@solana/spl-token": "npm:^0.3.8" "@solana/web3.js": "npm:^1.91.1" bs58: "npm:^4.0.1" @@ -2730,11 +2811,28 @@ __metadata: "@solana/wallet-adapter-react": ^0.15.32 react: ^16.8 || ^17 || ^18 react-dom: ^16.8 || ^17 || ^18 - checksum: 10/d132bea6c873b4315a4c69551e8d0ca6d31cc056f4df0f04776c2fd5ce95db4da7d238edfe524a824375aa588d2f30cd86faaf3396ecf9b9914f8365aa84c3ee + checksum: 10/5d99707d0eb3bf17ed89bacbb1c3c6334b8022d1973d69f65178da973b8d9ba1795717c12f2b3d82ae6575e8394c3bf982349b82e2ab8f2a1873e37cbaeb9af7 + languageName: node + linkType: hard + +"@helium/helium-sub-daos-sdk@npm:0.11.12, @helium/helium-sub-daos-sdk@npm:^0.11.12": + version: 0.11.12 + resolution: "@helium/helium-sub-daos-sdk@npm:0.11.12" + dependencies: + "@coral-xyz/anchor": "npm:^0.31.0" + "@helium/anchor-resolvers": "npm:^0.11.12" + "@helium/circuit-breaker-sdk": "npm:^0.11.12" + "@helium/nft-proxy-sdk": "npm:^0.1.5-alpha.0" + "@helium/spl-utils": "npm:^0.11.12" + "@helium/treasury-management-sdk": "npm:^0.11.12" + "@helium/voter-stake-registry-sdk": "npm:^0.11.12" + bn.js: "npm:^5.2.0" + bs58: "npm:^4.0.1" + checksum: 10/113af6db13c07da4b596ec9d33d487620f068eff83b0cc715bee84722dc997a488e513d13aecb3176dccf5739f6ed70ecdbcf57250211a6ac3c91e493a964932 languageName: node linkType: hard -"@helium/helium-sub-daos-sdk@npm:0.11.4, @helium/helium-sub-daos-sdk@npm:^0.11.4": +"@helium/helium-sub-daos-sdk@npm:^0.11.4": version: 0.11.4 resolution: "@helium/helium-sub-daos-sdk@npm:0.11.4" dependencies: @@ -2766,24 +2864,24 @@ __metadata: languageName: node linkType: hard -"@helium/hpl-crons-sdk@npm:^0.11.4": - version: 0.11.4 - resolution: "@helium/hpl-crons-sdk@npm:0.11.4" +"@helium/hpl-crons-sdk@npm:^0.11.12": + version: 0.11.12 + resolution: "@helium/hpl-crons-sdk@npm:0.11.12" dependencies: "@coral-xyz/anchor": "npm:^0.31.0" "@helium/cron-sdk": "npm:^0.0.9" - "@helium/helium-sub-daos-sdk": "npm:^0.11.4" + "@helium/helium-sub-daos-sdk": "npm:^0.11.12" "@helium/organization-sdk": "npm:^0.1.5-alpha.0" "@helium/proposal-sdk": "npm:^0.1.5-alpha.0" - "@helium/spl-utils": "npm:^0.11.4" + "@helium/spl-utils": "npm:^0.11.12" "@helium/state-controller-sdk": "npm:^0.1.5-alpha.0" "@helium/tuktuk-sdk": "npm:^0.0.9" - "@helium/voter-stake-registry-sdk": "npm:^0.11.4" + "@helium/voter-stake-registry-sdk": "npm:^0.11.12" "@solana/web3.js": "npm:^1.91.1" axios: "npm:^1.9.0" bn.js: "npm:^5.2.0" bs58: "npm:^4.0.1" - checksum: 10/2d1720d428d7fbab2fbc12a95029d4e0b345dfa17cab46b97e104651d4fa34540a4e7a0b6d582307581a5d93aa3025b5b06030d01295d01d582be448a11d5573 + checksum: 10/afba1762f99e24c2a500f46b83e9a707393b802735ef85fc39f0e83d8bb4e7078076017238907242385006876505f81f29ecfa1b814f131eea880dd03bcb8804 languageName: node linkType: hard @@ -2802,7 +2900,20 @@ __metadata: languageName: node linkType: hard -"@helium/idls@npm:0.11.4, @helium/idls@npm:^0.11.4": +"@helium/idls@npm:0.11.12, @helium/idls@npm:^0.11.12": + version: 0.11.12 + resolution: "@helium/idls@npm:0.11.12" + dependencies: + "@coral-xyz/anchor": "npm:^0.31.0" + "@solana/web3.js": "npm:^1.91.1" + bn.js: "npm:^5.2.0" + borsh: "npm:^0.7.0" + bs58: "npm:^4.0.1" + checksum: 10/3026217abdb76433b7afde9a6fadf956c199978d61dd7d5b745779af015b64e8208a8871c1ca12a33e6c461e9325ee9d053f300e0471bd8ecfc014b4c9527793 + languageName: node + linkType: hard + +"@helium/idls@npm:^0.11.4": version: 0.11.4 resolution: "@helium/idls@npm:0.11.4" dependencies: @@ -2815,17 +2926,17 @@ __metadata: languageName: node linkType: hard -"@helium/lazy-distributor-sdk@npm:0.11.4, @helium/lazy-distributor-sdk@npm:^0.11.4": - version: 0.11.4 - resolution: "@helium/lazy-distributor-sdk@npm:0.11.4" +"@helium/lazy-distributor-sdk@npm:0.11.12, @helium/lazy-distributor-sdk@npm:^0.11.12": + version: 0.11.12 + resolution: "@helium/lazy-distributor-sdk@npm:0.11.12" dependencies: "@coral-xyz/anchor": "npm:^0.31.0" - "@helium/anchor-resolvers": "npm:^0.11.4" - "@helium/circuit-breaker-sdk": "npm:^0.11.4" - "@helium/spl-utils": "npm:^0.11.4" + "@helium/anchor-resolvers": "npm:^0.11.12" + "@helium/circuit-breaker-sdk": "npm:^0.11.12" + "@helium/spl-utils": "npm:^0.11.12" bn.js: "npm:^5.2.0" bs58: "npm:^4.0.1" - checksum: 10/fe35cd040b09c8b0b24007a4c98097c73e70f2e50e409bb30a51908f6a45e28cfa3da7b32813561354f7fda1801fa1b2db251bf2213f71a6fc48cfe180953ce7 + checksum: 10/f1c75a2ed61853df14280e08a7d816d49a16f33eaf94b102f27491d682a4272ee2fb495e2df8ed9d141ee6bc64a20856275db6a851399f9d531d532bdc3e96bf languageName: node linkType: hard @@ -2879,7 +2990,21 @@ __metadata: languageName: node linkType: hard -"@helium/no-emit-sdk@npm:0.11.4, @helium/no-emit-sdk@npm:^0.11.4": +"@helium/no-emit-sdk@npm:0.11.12, @helium/no-emit-sdk@npm:^0.11.12": + version: 0.11.12 + resolution: "@helium/no-emit-sdk@npm:0.11.12" + dependencies: + "@coral-xyz/anchor": "npm:^0.31.0" + "@helium/anchor-resolvers": "npm:^0.11.12" + "@helium/idls": "npm:^0.11.12" + "@helium/spl-utils": "npm:^0.11.12" + bn.js: "npm:^5.2.0" + bs58: "npm:^4.0.1" + checksum: 10/650c26ece25d7dc706349b3ad577f4c5c5cda399ed4f4f8b46598fb100b518cd5fb62dcd3e31e080b876ea47ed2aa4b89f87603e0a9f6df4f1cc59064e3791ec + languageName: node + linkType: hard + +"@helium/no-emit-sdk@npm:^0.11.4": version: 0.11.4 resolution: "@helium/no-emit-sdk@npm:0.11.4" dependencies: @@ -3031,21 +3156,41 @@ __metadata: languageName: node linkType: hard -"@helium/rewards-oracle-sdk@npm:^0.11.4": - version: 0.11.4 - resolution: "@helium/rewards-oracle-sdk@npm:0.11.4" +"@helium/rewards-oracle-sdk@npm:^0.11.12": + version: 0.11.12 + resolution: "@helium/rewards-oracle-sdk@npm:0.11.12" dependencies: "@coral-xyz/anchor": "npm:^0.31.0" - "@helium/anchor-resolvers": "npm:^0.11.4" - "@helium/idls": "npm:^0.11.4" - "@helium/spl-utils": "npm:^0.11.4" + "@helium/anchor-resolvers": "npm:^0.11.12" + "@helium/idls": "npm:^0.11.12" + "@helium/spl-utils": "npm:^0.11.12" + bn.js: "npm:^5.2.0" + bs58: "npm:^4.0.1" + checksum: 10/9c7f31e46f80db66fb54b50955071ee94f834a91d77c5b63d62765b673d95cea0b37833f06a8d653b94d7c5fc12d83215a4e258764a7129e4a4fedd16d6bd6f1 + languageName: node + linkType: hard + +"@helium/spl-utils@npm:0.11.12, @helium/spl-utils@npm:^0.11.12": + version: 0.11.12 + resolution: "@helium/spl-utils@npm:0.11.12" + dependencies: + "@coral-xyz/anchor": "npm:^0.31.0" + "@helium/account-fetch-cache": "npm:^0.11.12" + "@helium/address": "npm:^4.12.0" + "@helium/anchor-resolvers": "npm:^0.11.12" + "@metaplex-foundation/mpl-token-metadata": "npm:^2.10.0" + "@solana/spl-account-compression": "npm:^0.1.7" + "@solana/spl-token": "npm:^0.3.8" + "@solana/web3.js": "npm:^1.91.1" + axios: "npm:^1.9.0" bn.js: "npm:^5.2.0" + borsh: "npm:^0.7.0" bs58: "npm:^4.0.1" - checksum: 10/ca88fd49c247307082ec36b49f0985269ad39f6878538a563c8e4ae0463176c34df485f66751987dea61c4f4d53679a34e7b0409b79fbc53278a569ea0ea5a0b + checksum: 10/942ec5ca0c2fd7778f22daa80fadeed321f3da49f3fa6bd5606f8caaca27ec8a64be48e6c909672f81c25acd84ccfa93521f2c7bc43bf9b19fc49c1e8d0d3302 languageName: node linkType: hard -"@helium/spl-utils@npm:0.11.4, @helium/spl-utils@npm:^0.11.4": +"@helium/spl-utils@npm:^0.11.4": version: 0.11.4 resolution: "@helium/spl-utils@npm:0.11.4" dependencies: @@ -3087,9 +3232,9 @@ __metadata: languageName: node linkType: hard -"@helium/sus@npm:0.11.4": - version: 0.11.4 - resolution: "@helium/sus@npm:0.11.4" +"@helium/sus@npm:0.11.12": + version: 0.11.12 + resolution: "@helium/sus@npm:0.11.12" dependencies: "@coral-xyz/anchor": "npm:^0.31.0" "@metaplex-foundation/mpl-token-metadata": "npm:^2.10.0" @@ -3098,7 +3243,7 @@ __metadata: axios: "npm:^1.9.0" bn.js: "npm:^5.2.0" bs58: "npm:^4.0.1" - checksum: 10/3b17c7e60a8b7bb4a42d192da6c38d5d7f42995013904eeaa5d40bd43e26d09008c043bf077459b6ac04873b31f6a76d2fb60d893f2152ea89cf5ca7425aa96e + checksum: 10/cf5527ce43fff583c13d6624ff9fe308350a1f4126bc57909847d270cc4cd7fe1a3af769baedad32fc5e44f3829aacfe2870f64190575eba8fd13af3fd6432a7 languageName: node linkType: hard @@ -3114,7 +3259,22 @@ __metadata: languageName: node linkType: hard -"@helium/treasury-management-sdk@npm:0.11.4, @helium/treasury-management-sdk@npm:^0.11.4": +"@helium/treasury-management-sdk@npm:0.11.12, @helium/treasury-management-sdk@npm:^0.11.12": + version: 0.11.12 + resolution: "@helium/treasury-management-sdk@npm:0.11.12" + dependencies: + "@coral-xyz/anchor": "npm:^0.31.0" + "@helium/anchor-resolvers": "npm:^0.11.12" + "@helium/circuit-breaker-sdk": "npm:^0.11.12" + "@helium/idls": "npm:^0.11.12" + "@helium/spl-utils": "npm:^0.11.12" + bn.js: "npm:^5.2.0" + bs58: "npm:^4.0.1" + checksum: 10/59af9227a09a125c4e0036cb9d0d78e0a90d99228e51f16a58e2fcb46ce2465714fe44eb0d12d37d23a28478ed6bfed2e893d5e87fde52095552325e64369cc0 + languageName: node + linkType: hard + +"@helium/treasury-management-sdk@npm:^0.11.4": version: 0.11.4 resolution: "@helium/treasury-management-sdk@npm:0.11.4" dependencies: @@ -3173,27 +3333,27 @@ __metadata: languageName: node linkType: hard -"@helium/voter-stake-registry-hooks@npm:0.11.4": - version: 0.11.4 - resolution: "@helium/voter-stake-registry-hooks@npm:0.11.4" +"@helium/voter-stake-registry-hooks@npm:0.11.12": + version: 0.11.12 + resolution: "@helium/voter-stake-registry-hooks@npm:0.11.12" dependencies: "@coral-xyz/anchor": "npm:^0.31.0" - "@helium/account-fetch-cache": "npm:^0.11.4" - "@helium/account-fetch-cache-hooks": "npm:^0.11.4" - "@helium/automation-hooks": "npm:^0.11.4" - "@helium/circuit-breaker-sdk": "npm:^0.11.4" - "@helium/helium-react-hooks": "npm:^0.11.4" - "@helium/helium-sub-daos-sdk": "npm:^0.11.4" - "@helium/hpl-crons-sdk": "npm:^0.11.4" + "@helium/account-fetch-cache": "npm:^0.11.12" + "@helium/account-fetch-cache-hooks": "npm:^0.11.12" + "@helium/automation-hooks": "npm:^0.11.12" + "@helium/circuit-breaker-sdk": "npm:^0.11.12" + "@helium/helium-react-hooks": "npm:^0.11.12" + "@helium/helium-sub-daos-sdk": "npm:^0.11.12" + "@helium/hpl-crons-sdk": "npm:^0.11.12" "@helium/modular-governance-hooks": "npm:^0.1.5-alpha.0" "@helium/modular-governance-idls": "npm:^0.1.5-alpha.0" "@helium/organization-sdk": "npm:^0.1.5-alpha.0" - "@helium/spl-utils": "npm:^0.11.4" + "@helium/spl-utils": "npm:^0.11.12" "@helium/tuktuk-sdk": "npm:^0.0.9" - "@helium/voter-stake-registry-sdk": "npm:^0.11.4" + "@helium/voter-stake-registry-sdk": "npm:^0.11.12" "@solana/wallet-adapter-base": "npm:^0.9.22" "@solana/web3.js": "npm:^1.91.1" - "@tanstack/react-query": "npm:^5.45.0" + "@tanstack/react-query": "npm:^5.80.0" axios: "npm:^1.9.0" bs58: "npm:^4.0.1" react-async-hook: "npm:^4.0.0" @@ -3201,24 +3361,24 @@ __metadata: "@solana/wallet-adapter-react": ^0.15.32 react: ^16.8 || ^17 || ^18 react-dom: ^16.8 || ^17 || ^18 - checksum: 10/6c52ae7956bf731f167a47579130338b97a91a93472d0eed181a71927507806649073a144b02c40a2196803a4d699ed20fe0740f48ce8003ece2cda7037bf1a5 + checksum: 10/ac8d83e5dbf04adfcf5b3770c9e7559cbf8fb6924249b1850096e4daa1f6364a453fd872e189133d2c5471a35c49450a395fdb7afd9ae75d78acb8f7b6ab437a languageName: node linkType: hard -"@helium/voter-stake-registry-sdk@npm:0.11.4": - version: 0.11.4 - resolution: "@helium/voter-stake-registry-sdk@npm:0.11.4" +"@helium/voter-stake-registry-sdk@npm:0.11.12": + version: 0.11.12 + resolution: "@helium/voter-stake-registry-sdk@npm:0.11.12" dependencies: "@coral-xyz/anchor": "npm:^0.31.0" - "@helium/anchor-resolvers": "npm:^0.11.4" - "@helium/idls": "npm:^0.11.4" + "@helium/anchor-resolvers": "npm:^0.11.12" + "@helium/idls": "npm:^0.11.12" "@helium/nft-proxy-sdk": "npm:^0.1.5-alpha.0" - "@helium/spl-utils": "npm:^0.11.4" + "@helium/spl-utils": "npm:^0.11.12" "@metaplex-foundation/mpl-token-metadata": "npm:^2.10.0" "@solana/spl-token": "npm:^0.3.8" bn.js: "npm:^5.2.0" bs58: "npm:^4.0.1" - checksum: 10/30c010529e15cf19fd820b4b3fd989a84e5decf80adf87c4464553186995c93ec8efd07e4ad601a681a49e51599d98741eb488ae9eb12bbf1d28bb26d3c31fe7 + checksum: 10/d6d0bbcb54484f108b682f9999836225aaae348eb4019e883bf6681ff55a29f1c5501a7aa91df7ac90e0f5accac3f5921d9dbf63a754318ffa67e439f1e4c81a languageName: node linkType: hard @@ -4119,7 +4279,7 @@ __metadata: languageName: node linkType: hard -"@noble/ciphers@npm:1.3.0": +"@noble/ciphers@npm:1.3.0, @noble/ciphers@npm:^1.3.0": version: 1.3.0 resolution: "@noble/ciphers@npm:1.3.0" checksum: 10/051660051e3e9e2ca5fb9dece2885532b56b7e62946f89afa7284a0fb8bc02e2bd1c06554dba68162ff42d295b54026456084198610f63c296873b2f1cd7a586 @@ -4144,7 +4304,16 @@ __metadata: languageName: node linkType: hard -"@noble/curves@npm:^1.0.0": +"@noble/curves@npm:1.9.1": + version: 1.9.1 + resolution: "@noble/curves@npm:1.9.1" + dependencies: + "@noble/hashes": "npm:1.8.0" + checksum: 10/5c82ec828ca4a4218b1666ba0ddffde17afd224d0bd5e07b64c2a0c83a3362483387f55c11cfd8db0fc046605394fe4e2c67fe024628a713e864acb541a7d2bb + languageName: node + linkType: hard + +"@noble/curves@npm:^1.0.0, @noble/curves@npm:~1.9.0": version: 1.9.7 resolution: "@noble/curves@npm:1.9.7" dependencies: @@ -4190,7 +4359,7 @@ __metadata: languageName: node linkType: hard -"@noble/hashes@npm:1.8.0, @noble/hashes@npm:^1.2.0, @noble/hashes@npm:^1.3.0, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:^1.3.3, @noble/hashes@npm:^1.4.0, @noble/hashes@npm:^1.5.0, @noble/hashes@npm:^1.8.0": +"@noble/hashes@npm:1.8.0, @noble/hashes@npm:^1.2.0, @noble/hashes@npm:^1.3.0, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:^1.3.3, @noble/hashes@npm:^1.4.0, @noble/hashes@npm:^1.5.0, @noble/hashes@npm:^1.8.0, @noble/hashes@npm:~1.8.0": version: 1.8.0 resolution: "@noble/hashes@npm:1.8.0" checksum: 10/474b7f56bc6fb2d5b3a42132561e221b0ea4f91e590f4655312ca13667840896b34195e2b53b7f097ec080a1fdd3b58d902c2a8d0fbdf51d2e238b53808a177e @@ -4343,6 +4512,138 @@ __metadata: languageName: node linkType: hard +"@privy-io/api-base@npm:1.8.2": + version: 1.8.2 + resolution: "@privy-io/api-base@npm:1.8.2" + dependencies: + zod: "npm:^3.24.3" + checksum: 10/10aa9d691054ed47ba3c7d42f8b6ac8e3a7fa25530829f55e2943fdc9eaf830d1a02fc1b818662cdba3441cf4f4eb54c2230dddc2c2f96b3db9a5f08d970f856 + languageName: node + linkType: hard + +"@privy-io/api-types@npm:0.6.1": + version: 0.6.1 + resolution: "@privy-io/api-types@npm:0.6.1" + checksum: 10/121d465cf7a067c798d94995a873575b4e6c17f1b8f427f5254b9f402266305d2ee615bb30e9195a807c2397bdafd945f0069781e2dfa027f2e3a1fb306d6a24 + languageName: node + linkType: hard + +"@privy-io/chains@npm:0.1.2": + version: 0.1.2 + resolution: "@privy-io/chains@npm:0.1.2" + checksum: 10/73557389a852161a25dca02a0436d38eab48cbb67b6c4cdac9ba0ed2900591b9de4898c5a87d678944cad4c8a69be9adfc435e7b91e1ee1f6916fe9e08e0b2e1 + languageName: node + linkType: hard + +"@privy-io/ethereum@npm:0.0.8": + version: 0.0.8 + resolution: "@privy-io/ethereum@npm:0.0.8" + peerDependencies: + viem: ^2.46.1 + checksum: 10/c442eba58873bb91d19e680096ee725c786ebf00f6e2cad8971d00c1589282c8d9ff045cbe4ab4473e6211752c10a29e9f9da7d5944d232dd008fd8995184356 + languageName: node + linkType: hard + +"@privy-io/expo-native-extensions@npm:^0.0.7": + version: 0.0.7 + resolution: "@privy-io/expo-native-extensions@npm:0.0.7" + peerDependencies: + expo: "*" + react: "*" + react-native: "*" + checksum: 10/e569b4a8cfecc62973ed666a27f169168ae12337e27684a5b94fa13ee11b5c1e2f6fb2c5d7b420cd561ecdf0c666ad078a52af356ce5acc9ee58e71c1d4a941e + languageName: node + linkType: hard + +"@privy-io/expo@npm:^0.63.9": + version: 0.63.9 + resolution: "@privy-io/expo@npm:0.63.9" + dependencies: + "@privy-io/api-types": "npm:0.6.1" + "@privy-io/js-sdk-core": "npm:0.60.5" + "@scure/base": "npm:^1.2.4" + react-fast-compare: "npm:^3.2.2" + tweetnacl: "npm:^1.0.3" + zustand: "npm:^5.0.4" + peerDependencies: + "@expo-google-fonts/inter": "*" + "@privy-io/expo-native-extensions": 0.0.7 + expo-apple-authentication: "*" + expo-application: "*" + expo-clipboard: "*" + expo-crypto: "*" + expo-font: "*" + expo-linking: "*" + expo-secure-store: "*" + expo-web-browser: "*" + permissionless: ^0.2.47 + react: "*" + react-native: "*" + react-native-passkeys: ^0.3.0 + react-native-qrcode-styled: 0.3.3 + react-native-safe-area-context: "*" + react-native-svg: "*" + react-native-webview: "*" + viem: ^2.46.1 + peerDependenciesMeta: + "@expo-google-fonts/inter": + optional: true + expo-clipboard: + optional: true + expo-font: + optional: true + permissionless: + optional: true + react-native-qrcode-styled: + optional: true + react-native-safe-area-context: + optional: true + react-native-svg: + optional: true + viem: + optional: true + checksum: 10/af05a1793f584e5b9531ba1f78ae5e8afeea95389b13515519a9547cdecfda5a347230f9d55815da8489a05459088453d2874b045e7b55eab810198cc20f17e5 + languageName: node + linkType: hard + +"@privy-io/js-sdk-core@npm:0.60.5": + version: 0.60.5 + resolution: "@privy-io/js-sdk-core@npm:0.60.5" + dependencies: + "@privy-io/api-base": "npm:1.8.2" + "@privy-io/api-types": "npm:0.6.1" + "@privy-io/chains": "npm:0.1.2" + "@privy-io/ethereum": "npm:0.0.8" + "@privy-io/routes": "npm:0.0.8" + canonicalize: "npm:^2.0.0" + eventemitter3: "npm:^5.0.1" + fetch-retry: "npm:^6.0.0" + jose: "npm:^4.15.5" + js-cookie: "npm:^3.0.5" + libphonenumber-js: "npm:^1.10.44" + set-cookie-parser: "npm:^2.6.0" + uuid: "npm:>=8 <10" + peerDependencies: + permissionless: ^0.2.47 + viem: ^2.46.1 + peerDependenciesMeta: + permissionless: + optional: true + viem: + optional: true + checksum: 10/a8ed99f9f789d26196cdcab2d12ed153a93db20d7cc8e925ad2e339bd775a8191162f2dfdbdba9f1067e94e6e822e7c60b24a8cb6d26c298b7b9362c8308be6a + languageName: node + linkType: hard + +"@privy-io/routes@npm:0.0.8": + version: 0.0.8 + resolution: "@privy-io/routes@npm:0.0.8" + dependencies: + "@privy-io/api-types": "npm:0.6.1" + checksum: 10/13632ed3c1e00523ce883f7cbf3884875f1134a3ccb1408677f386e089fcc65c968d3de5030a6f14e33a4a3cb1ba8fa9dedbd47bb8faa2891e1b09816c0d8d4f + languageName: node + linkType: hard + "@protobufjs/aspromise@npm:^1.1.1, @protobufjs/aspromise@npm:^1.1.2": version: 1.1.2 resolution: "@protobufjs/aspromise@npm:1.1.2" @@ -5132,6 +5433,13 @@ __metadata: languageName: node linkType: hard +"@scure/base@npm:^1.2.4, @scure/base@npm:~1.2.5": + version: 1.2.6 + resolution: "@scure/base@npm:1.2.6" + checksum: 10/c1a7bd5e0b0c8f94c36fbc220f4a67cc832b00e2d2065c7d8a404ed81ab1c94c5443def6d361a70fc382db3496e9487fb9941728f0584782b274c18a4bed4187 + languageName: node + linkType: hard + "@scure/base@npm:~1.1.6": version: 1.1.9 resolution: "@scure/base@npm:1.1.9" @@ -5150,6 +5458,17 @@ __metadata: languageName: node linkType: hard +"@scure/bip32@npm:1.7.0, @scure/bip32@npm:^1.7.0": + version: 1.7.0 + resolution: "@scure/bip32@npm:1.7.0" + dependencies: + "@noble/curves": "npm:~1.9.0" + "@noble/hashes": "npm:~1.8.0" + "@scure/base": "npm:~1.2.5" + checksum: 10/f90e0c23ab6a31a164856ae9cb9a8cae2886df608c74a6c0c4875095b017e30ffd92f28f73b8c52890d9a89fca86d19f6d60bb1ea7cad64c7987f92ae83509ad + languageName: node + linkType: hard + "@scure/bip39@npm:1.3.0": version: 1.3.0 resolution: "@scure/bip39@npm:1.3.0" @@ -5160,6 +5479,16 @@ __metadata: languageName: node linkType: hard +"@scure/bip39@npm:1.6.0, @scure/bip39@npm:^1.6.0": + version: 1.6.0 + resolution: "@scure/bip39@npm:1.6.0" + dependencies: + "@noble/hashes": "npm:~1.8.0" + "@scure/base": "npm:~1.2.5" + checksum: 10/63e60c40fa1bda2c1b50351546fee6d7b0947cc814aa7a4209dcedd3693b5053302c8fca28292f5f50735e11c613265359acdc019127393dbab17e53489fc449 + languageName: node + linkType: hard + "@shopify/restyle@npm:2.4.5": version: 2.4.5 resolution: "@shopify/restyle@npm:2.4.5" @@ -6163,7 +6492,14 @@ __metadata: languageName: node linkType: hard -"@tanstack/react-query@npm:5.84.1, @tanstack/react-query@npm:^5.45.0": +"@tanstack/query-core@npm:5.91.0": + version: 5.91.0 + resolution: "@tanstack/query-core@npm:5.91.0" + checksum: 10/2bee38703ed649a3451a6012005bd00a99459f66ca22a96e994fdba413537de2ebbfafd778b61751e9d824fba3454bc26d2624c4dd599bcbf660de917e898a77 + languageName: node + linkType: hard + +"@tanstack/react-query@npm:5.84.1": version: 5.84.1 resolution: "@tanstack/react-query@npm:5.84.1" dependencies: @@ -6174,6 +6510,17 @@ __metadata: languageName: node linkType: hard +"@tanstack/react-query@npm:^5.80.0": + version: 5.91.0 + resolution: "@tanstack/react-query@npm:5.91.0" + dependencies: + "@tanstack/query-core": "npm:5.91.0" + peerDependencies: + react: ^18 || ^19 + checksum: 10/7ae88b64c1122b62275a76b7f51f54ba611b946477bda32cad8ccba85aec51e6bb0ec9fd41192bb816dc5fc883d67244e1772ae137a46dad4a861d3f43a779b1 + languageName: node + linkType: hard + "@turf/distance@npm:^7.1.0, @turf/distance@npm:^7.2.0": version: 7.2.0 resolution: "@turf/distance@npm:7.2.0" @@ -7454,6 +7801,21 @@ __metadata: languageName: node linkType: hard +"abitype@npm:1.2.3, abitype@npm:^1.2.3": + version: 1.2.3 + resolution: "abitype@npm:1.2.3" + peerDependencies: + typescript: ">=5.0.4" + zod: ^3.22.0 || ^4.0.0 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + checksum: 10/94e744c2fc301b1cff59163a21b499aae0ddecdf4d3bef1579ff16b705e6f5738fd314125d791ed142487db2473d4fadcdbabb1e05e4b5d35715bc4ef35e400a + languageName: node + linkType: hard + "abort-controller@npm:^3.0.0": version: 3.0.0 resolution: "abort-controller@npm:3.0.0" @@ -8410,7 +8772,7 @@ __metadata: languageName: node linkType: hard -"base64-js@npm:^1.0.2, base64-js@npm:^1.2.3, base64-js@npm:^1.3.1, base64-js@npm:^1.5.1": +"base64-js@npm:^1.0.2, base64-js@npm:^1.2.3, base64-js@npm:^1.3.0, base64-js@npm:^1.3.1, base64-js@npm:^1.5.1": version: 1.5.1 resolution: "base64-js@npm:1.5.1" checksum: 10/669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005 @@ -9035,6 +9397,15 @@ __metadata: languageName: node linkType: hard +"canonicalize@npm:^2.0.0": + version: 2.1.0 + resolution: "canonicalize@npm:2.1.0" + bin: + canonicalize: bin/canonicalize.js + checksum: 10/6ab9b9c2b84e6a210e1d55f9f1194d69c1b955512f38cc53b0529c654807f469e21b5099750c76e2b8464650d829c01234c923526450fac263a1d89cf2bb61df + languageName: node + linkType: hard + "case-anything@npm:^2.1.13": version: 2.1.13 resolution: "case-anything@npm:2.1.13" @@ -11263,6 +11634,13 @@ __metadata: languageName: node linkType: hard +"eventemitter3@npm:5.0.1, eventemitter3@npm:^5.0.1": + version: 5.0.1 + resolution: "eventemitter3@npm:5.0.1" + checksum: 10/ac6423ec31124629c84c7077eed1e6987f6d66c31cf43c6fcbf6c87791d56317ce808d9ead483652436df171b526fc7220eccdc9f3225df334e81582c3cf7dd5 + languageName: node + linkType: hard + "eventemitter3@npm:^4.0.7": version: 4.0.7 resolution: "eventemitter3@npm:4.0.7" @@ -11270,13 +11648,6 @@ __metadata: languageName: node linkType: hard -"eventemitter3@npm:^5.0.1": - version: 5.0.1 - resolution: "eventemitter3@npm:5.0.1" - checksum: 10/ac6423ec31124629c84c7077eed1e6987f6d66c31cf43c6fcbf6c87791d56317ce808d9ead483652436df171b526fc7220eccdc9f3225df334e81582c3cf7dd5 - languageName: node - linkType: hard - "events@npm:1.1.1": version: 1.1.1 resolution: "events@npm:1.1.1" @@ -11377,6 +11748,25 @@ __metadata: languageName: node linkType: hard +"expo-apple-authentication@npm:~7.2.4": + version: 7.2.4 + resolution: "expo-apple-authentication@npm:7.2.4" + peerDependencies: + expo: "*" + react-native: "*" + checksum: 10/c08cf0f8e11c049d646217de90d2d257214b80a6064fdf6670eb47d67b1f3bd27e987df4b138756e948d2eb804ed3243fb849317cc08d9055a1997908cf33787 + languageName: node + linkType: hard + +"expo-application@npm:~6.1.5": + version: 6.1.5 + resolution: "expo-application@npm:6.1.5" + peerDependencies: + expo: "*" + checksum: 10/48fd42de09eb73eab7e6cb62878c8cd62457733641f0453ae7ce70d302275a619ad433e24ff32de9cec309ad020f966f96770f42f5ed4e858b3ed71dfcf51b56 + languageName: node + linkType: hard + "expo-asset@npm:~11.1.7": version: 11.1.7 resolution: "expo-asset@npm:11.1.7" @@ -11419,6 +11809,17 @@ __metadata: languageName: node linkType: hard +"expo-clipboard@npm:~7.1.5": + version: 7.1.5 + resolution: "expo-clipboard@npm:7.1.5" + peerDependencies: + expo: "*" + react: "*" + react-native: "*" + checksum: 10/30503db81e3d233ed257d81e894f9a15a9da03cc0e9a8e410e1cc3a6797a80dd74b6512daaeed2547b034eabe44473e46257ce55aa490411e8b18968c99bdc18 + languageName: node + linkType: hard + "expo-constants@npm:~17.1.7": version: 17.1.7 resolution: "expo-constants@npm:17.1.7" @@ -11432,6 +11833,17 @@ __metadata: languageName: node linkType: hard +"expo-crypto@npm:~14.1.5": + version: 14.1.5 + resolution: "expo-crypto@npm:14.1.5" + dependencies: + base64-js: "npm:^1.3.0" + peerDependencies: + expo: "*" + checksum: 10/7fa527a4a06f1ea33202fe0a1f35d4d2b2b021ff643f07cdb469ec6882986978d99c35573bc4cef5fcb5a0cd7224ecc790294926b78508934798670732c94182 + languageName: node + linkType: hard + "expo-file-system@npm:~18.1.11": version: 18.1.11 resolution: "expo-file-system@npm:18.1.11" @@ -11523,7 +11935,7 @@ __metadata: languageName: node linkType: hard -"expo-secure-store@npm:~14.2.3": +"expo-secure-store@npm:~14.2.4": version: 14.2.4 resolution: "expo-secure-store@npm:14.2.4" peerDependencies: @@ -11543,6 +11955,16 @@ __metadata: languageName: node linkType: hard +"expo-web-browser@npm:~14.2.0": + version: 14.2.0 + resolution: "expo-web-browser@npm:14.2.0" + peerDependencies: + expo: "*" + react-native: "*" + checksum: 10/5d3bf5b1443c5cf80440c47b43f7e09d96eb2b4f235dde9d08ff7d65e60cdae3d37eebacaf211fc1092d84a88ad527573bae3735592e7985a803be5e81172eac + languageName: node + linkType: hard + "expo@npm:53.0.20": version: 53.0.20 resolution: "expo@npm:53.0.20" @@ -11842,6 +12264,13 @@ __metadata: languageName: node linkType: hard +"fetch-retry@npm:^6.0.0": + version: 6.0.0 + resolution: "fetch-retry@npm:6.0.0" + checksum: 10/0c8d3082e2d76fff2df75adef6280bc854bc36fd3ef38506674f0216d0d819e2efd14da7477d3f1732415aea1d2cfde7cd3e1aeae46f45f2adbfc5133296e8de + languageName: node + linkType: hard + "file-entry-cache@npm:^6.0.1": version: 6.0.1 resolution: "file-entry-cache@npm:6.0.1" @@ -12639,41 +13068,41 @@ __metadata: "@coral-xyz/anchor": "npm:0.31.0" "@gorhom/bottom-sheet": "npm:5.1.2" "@gorhom/portal": "npm:1.0.14" - "@helium/account-fetch-cache": "npm:0.11.4" - "@helium/account-fetch-cache-hooks": "npm:0.11.4" + "@helium/account-fetch-cache": "npm:0.11.12" + "@helium/account-fetch-cache-hooks": "npm:0.11.12" "@helium/address": "npm:^5.0.4" - "@helium/automation-hooks": "npm:^0.11.4" + "@helium/automation-hooks": "npm:^0.11.12" "@helium/blockchain-api": "npm:^0.3.12" - "@helium/circuit-breaker-sdk": "npm:0.11.4" + "@helium/circuit-breaker-sdk": "npm:0.11.12" "@helium/cron-sdk": "npm:^0.0.8" "@helium/crypto-react-native": "npm:^5.0.4" - "@helium/currency-utils": "npm:0.11.4" - "@helium/data-credits-sdk": "npm:0.11.4" - "@helium/distributor-oracle": "npm:0.11.4" - "@helium/fanout-sdk": "npm:0.11.4" - "@helium/helium-entity-manager-sdk": "npm:0.11.4" - "@helium/helium-react-hooks": "npm:0.11.4" - "@helium/helium-sub-daos-sdk": "npm:0.11.4" - "@helium/hpl-crons-sdk": "npm:^0.11.4" + "@helium/currency-utils": "npm:0.11.12" + "@helium/data-credits-sdk": "npm:0.11.12" + "@helium/distributor-oracle": "npm:0.11.12" + "@helium/fanout-sdk": "npm:0.11.12" + "@helium/helium-entity-manager-sdk": "npm:0.11.12" + "@helium/helium-react-hooks": "npm:0.11.12" + "@helium/helium-sub-daos-sdk": "npm:0.11.12" + "@helium/hpl-crons-sdk": "npm:^0.11.12" "@helium/http": "npm:^5.0.4" - "@helium/idls": "npm:0.11.4" - "@helium/lazy-distributor-sdk": "npm:0.11.4" + "@helium/idls": "npm:0.11.12" + "@helium/lazy-distributor-sdk": "npm:0.11.12" "@helium/modular-governance-hooks": "npm:0.1.5" "@helium/modular-governance-idls": "npm:0.1.5" - "@helium/no-emit-sdk": "npm:0.11.4" + "@helium/no-emit-sdk": "npm:0.11.12" "@helium/onboarding": "npm:^5.0.4" "@helium/organization-sdk": "npm:0.1.5" "@helium/proto-ble": "npm:^5.0.4" "@helium/react-native-sdk": "npm:^4.0.4" - "@helium/spl-utils": "npm:0.11.4" + "@helium/spl-utils": "npm:0.11.12" "@helium/state-controller-sdk": "npm:0.1.5" - "@helium/sus": "npm:0.11.4" + "@helium/sus": "npm:0.11.12" "@helium/transactions": "npm:^5.0.4" - "@helium/treasury-management-sdk": "npm:0.11.4" + "@helium/treasury-management-sdk": "npm:0.11.12" "@helium/tuktuk-idls": "npm:^0.0.8" "@helium/tuktuk-sdk": "npm:^0.0.8" - "@helium/voter-stake-registry-hooks": "npm:0.11.4" - "@helium/voter-stake-registry-sdk": "npm:0.11.4" + "@helium/voter-stake-registry-hooks": "npm:0.11.12" + "@helium/voter-stake-registry-sdk": "npm:0.11.12" "@helium/wallet-link": "npm:^5.0.4" "@jup-ag/api": "npm:6.0.6" "@keystonehq/keystone-sdk": "npm:0.11.6" @@ -12690,6 +13119,8 @@ __metadata: "@noble/ed25519": "npm:2.3.0" "@noble/hashes": "npm:1.8.0" "@onsol/tldparser": "npm:0.5.3" + "@privy-io/expo": "npm:^0.63.9" + "@privy-io/expo-native-extensions": "npm:^0.0.7" "@react-native-async-storage/async-storage": "npm:1.18.1" "@react-native-clipboard/clipboard": "npm:1.16.3" "@react-native-community/checkbox": "npm:0.5.20" @@ -12772,15 +13203,21 @@ __metadata: eslint-plugin-react-hooks: "npm:4.6.0" events: "npm:3.3.0" expo: "npm:53.0.20" + expo-apple-authentication: "npm:~7.2.4" + expo-application: "npm:~6.1.5" expo-asset: "npm:~11.1.7" expo-blur: "npm:~14.1.5" expo-camera: "npm:~16.1.10" + expo-clipboard: "npm:~7.1.5" expo-constants: "npm:~17.1.7" + expo-crypto: "npm:~14.1.5" + expo-font: "npm:~13.3.2" expo-haptics: "npm:~14.1.4" expo-linking: "npm:~7.1.7" expo-local-authentication: "npm:~16.0.5" - expo-secure-store: "npm:~14.2.3" + expo-secure-store: "npm:~14.2.4" expo-splash-screen: "npm:~0.30.1" + expo-web-browser: "npm:~14.2.0" fuse.js: "npm:6.6.2" h3-js: "npm:4.1.0" husky: "npm:7.0.4" @@ -12827,6 +13264,7 @@ __metadata: react-native-onesignal: "npm:5.2.9" react-native-os: "npm:1.2.6" react-native-pager-view: "npm:6.8.1" + react-native-passkeys: "npm:^0.4.0" react-native-permissions: "npm:5.3.0" react-native-qrcode-svg: "npm:6.1.2" react-native-quick-crypto: "npm:^0.7.17" @@ -12860,6 +13298,7 @@ __metadata: tinycolor2: "npm:^1.6.0" typescript: "npm:5.0.4" use-debounce: "npm:^10.0.4" + viem: "npm:^2.47.5" web-streams-polyfill: "npm:^4.2.0" languageName: unknown linkType: soft @@ -13782,6 +14221,15 @@ __metadata: languageName: node linkType: hard +"isows@npm:1.0.7": + version: 1.0.7 + resolution: "isows@npm:1.0.7" + peerDependencies: + ws: "*" + checksum: 10/044b949b369872882af07b60b613b5801ae01b01a23b5b72b78af80c8103bbeed38352c3e8ceff13a7834bc91fd2eb41cf91ec01d59a041d8705680e6b0ec546 + languageName: node + linkType: hard + "istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0": version: 3.2.2 resolution: "istanbul-lib-coverage@npm:3.2.2" @@ -14389,6 +14837,13 @@ __metadata: languageName: node linkType: hard +"jose@npm:^4.15.5": + version: 4.15.9 + resolution: "jose@npm:4.15.9" + checksum: 10/256234b6f85cdc080b1331f2d475bd58c8ccf459cb20f70ac5e4200b271bce10002b1c2f8e5b96dd975d83065ae5a586d52cdf89d28471d56de5d297992f9905 + languageName: node + linkType: hard + "js-base64@npm:^3.7.5": version: 3.7.7 resolution: "js-base64@npm:3.7.7" @@ -14396,6 +14851,13 @@ __metadata: languageName: node linkType: hard +"js-cookie@npm:^3.0.5": + version: 3.0.5 + resolution: "js-cookie@npm:3.0.5" + checksum: 10/366494b1630b9fb8abaef3659748db5dfd52c58c6fc3459b9f0a03b492593bc1b01c6dfcc066b46f6413c28edb3a00cc68fb61ea8cdf6991bedf1f100f8a389d + languageName: node + linkType: hard + "js-sha256@npm:^0.11.0": version: 0.11.1 resolution: "js-sha256@npm:0.11.1" @@ -14880,6 +15342,13 @@ __metadata: languageName: node linkType: hard +"libphonenumber-js@npm:^1.10.44": + version: 1.12.40 + resolution: "libphonenumber-js@npm:1.12.40" + checksum: 10/d9883aa02cd6a19b37a6681c08e86e0fb3447ba952e1037bd0274cefa1982a57820cafed1fc70cb5f3cff70c5b1807847e0de34dc3a3762ca423d822bf58c32f + languageName: node + linkType: hard + "light-my-request@npm:^5.11.0": version: 5.14.0 resolution: "light-my-request@npm:5.14.0" @@ -16696,6 +17165,27 @@ __metadata: languageName: node linkType: hard +"ox@npm:0.14.5": + version: 0.14.5 + resolution: "ox@npm:0.14.5" + dependencies: + "@adraffy/ens-normalize": "npm:^1.11.0" + "@noble/ciphers": "npm:^1.3.0" + "@noble/curves": "npm:1.9.1" + "@noble/hashes": "npm:^1.8.0" + "@scure/bip32": "npm:^1.7.0" + "@scure/bip39": "npm:^1.6.0" + abitype: "npm:^1.2.3" + eventemitter3: "npm:5.0.1" + peerDependencies: + typescript: ">=5.4.0" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10/de08a4d7175b66e9ea53bdce7f6e5d663c5947d6207566b3cd13b4477ba21c0d53f7ec489dfdecc6902be4f44b6de00937768a37f5f9feaccab2aef106fbb9be + languageName: node + linkType: hard + "p-limit@npm:^2.0.0, p-limit@npm:^2.2.0": version: 2.3.0 resolution: "p-limit@npm:2.3.0" @@ -17796,6 +18286,13 @@ __metadata: languageName: node linkType: hard +"react-fast-compare@npm:^3.2.2": + version: 3.2.2 + resolution: "react-fast-compare@npm:3.2.2" + checksum: 10/a6826180ba75cefba1c8d3ac539735f9b627ca05d3d307fe155487f5d0228d376dac6c9708d04a283a7b9f9aee599b637446635b79c8c8753d0b4eece56c125c + languageName: node + linkType: hard + "react-freeze@npm:^1.0.0": version: 1.0.4 resolution: "react-freeze@npm:1.0.4" @@ -18173,6 +18670,17 @@ __metadata: languageName: node linkType: hard +"react-native-passkeys@npm:^0.4.0": + version: 0.4.0 + resolution: "react-native-passkeys@npm:0.4.0" + peerDependencies: + expo: ">=48.0.0" + react: "*" + react-native: ">=0.71.0" + checksum: 10/29e3d0cc50b5ef6a0947b94c1536e9125ef5d7c86c3a6eb0db54bc90fee43f46742abd6bc4b97d8abbb9f6097d08ab79c79bb0a18ad4bd8f75de27302720aa16 + languageName: node + linkType: hard + "react-native-permissions@npm:5.3.0": version: 5.3.0 resolution: "react-native-permissions@npm:5.3.0" @@ -19486,6 +19994,13 @@ __metadata: languageName: node linkType: hard +"set-cookie-parser@npm:^2.6.0": + version: 2.7.2 + resolution: "set-cookie-parser@npm:2.7.2" + checksum: 10/4b6f5ec4e3fa1aef471d9207117704d217ba6bb6443400b41f5ea945c4a7f6fc08e405a122c1a32b4ebde41f06dea75e02c2af87cee9abb27f3e3fe911e5839b + languageName: node + linkType: hard + "set-function-length@npm:^1.2.2": version: 1.2.2 resolution: "set-function-length@npm:1.2.2" @@ -21389,6 +21904,15 @@ __metadata: languageName: node linkType: hard +"uuid@npm:>=8 <10, uuid@npm:^9.0.0, uuid@npm:^9.0.1": + version: 9.0.1 + resolution: "uuid@npm:9.0.1" + bin: + uuid: dist/bin/uuid + checksum: 10/9d0b6adb72b736e36f2b1b53da0d559125ba3e39d913b6072f6f033e0c87835b414f0836b45bcfaf2bdf698f92297fea1c3cc19b0b258bc182c9c43cc0fab9f2 + languageName: node + linkType: hard + "uuid@npm:^7.0.3": version: 7.0.3 resolution: "uuid@npm:7.0.3" @@ -21407,15 +21931,6 @@ __metadata: languageName: node linkType: hard -"uuid@npm:^9.0.0, uuid@npm:^9.0.1": - version: 9.0.1 - resolution: "uuid@npm:9.0.1" - bin: - uuid: dist/bin/uuid - checksum: 10/9d0b6adb72b736e36f2b1b53da0d559125ba3e39d913b6072f6f033e0c87835b414f0836b45bcfaf2bdf698f92297fea1c3cc19b0b258bc182c9c43cc0fab9f2 - languageName: node - linkType: hard - "v8-compile-cache@npm:^2.0.3": version: 2.4.0 resolution: "v8-compile-cache@npm:2.4.0" @@ -21455,6 +21970,27 @@ __metadata: languageName: node linkType: hard +"viem@npm:^2.47.5": + version: 2.47.5 + resolution: "viem@npm:2.47.5" + dependencies: + "@noble/curves": "npm:1.9.1" + "@noble/hashes": "npm:1.8.0" + "@scure/bip32": "npm:1.7.0" + "@scure/bip39": "npm:1.6.0" + abitype: "npm:1.2.3" + isows: "npm:1.0.7" + ox: "npm:0.14.5" + ws: "npm:8.18.3" + peerDependencies: + typescript: ">=5.0.4" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10/4052afea21b67b52dc5a595ccd25c58d30636cb408406cea8e22f9ae19a6bf45defbb973ce285604c3ec0bde59b8f5b029c4083d63925949439a3c7730984613 + languageName: node + linkType: hard + "vlq@npm:^1.0.0": version: 1.0.1 resolution: "vlq@npm:1.0.1" @@ -21717,6 +22253,21 @@ __metadata: languageName: node linkType: hard +"ws@npm:8.18.3, ws@npm:^8.12.1, ws@npm:^8.5.0": + version: 8.18.3 + resolution: "ws@npm:8.18.3" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 10/725964438d752f0ab0de582cd48d6eeada58d1511c3f613485b5598a83680bedac6187c765b0fe082e2d8cc4341fc57707c813ae780feee82d0c5efe6a4c61b6 + languageName: node + linkType: hard + "ws@npm:^6.2.3": version: 6.2.3 resolution: "ws@npm:6.2.3" @@ -21741,21 +22292,6 @@ __metadata: languageName: node linkType: hard -"ws@npm:^8.12.1, ws@npm:^8.5.0": - version: 8.18.3 - resolution: "ws@npm:8.18.3" - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ">=5.0.2" - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - checksum: 10/725964438d752f0ab0de582cd48d6eeada58d1511c3f613485b5598a83680bedac6187c765b0fe082e2d8cc4341fc57707c813ae780feee82d0c5efe6a4c61b6 - languageName: node - linkType: hard - "xcode@npm:^3.0.1": version: 3.0.1 resolution: "xcode@npm:3.0.1" @@ -21933,7 +22469,7 @@ __metadata: languageName: node linkType: hard -"zod@npm:^3.23.8": +"zod@npm:^3.23.8, zod@npm:^3.24.3": version: 3.25.76 resolution: "zod@npm:3.25.76" checksum: 10/f0c963ec40cd96858451d1690404d603d36507c1fc9682f2dae59ab38b578687d542708a7fdbf645f77926f78c9ed558f57c3d3aa226c285f798df0c4da16995 @@ -21946,3 +22482,24 @@ __metadata: checksum: 10/3148bd52e56ab7c1641ec397e6be6eddbb1d8f5db71e95baab9bb9622a0ea49d8a385885fc1c22b90fa6d8c5234e051f4ef5d469cfe3fb90198d5a91402fd89c languageName: node linkType: hard + +"zustand@npm:^5.0.4": + version: 5.0.12 + resolution: "zustand@npm:5.0.12" + peerDependencies: + "@types/react": ">=18.0.0" + immer: ">=9.0.6" + react: ">=18.0.0" + use-sync-external-store: ">=1.2.0" + peerDependenciesMeta: + "@types/react": + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + checksum: 10/b84c85fc4133ec5ee05c11d0f2f3dff0f7537d9d0f1d3475a8e5a92f42ee1ba6d38039e09baf510075eb738e3d55018a635b3fa7db07c94e8d5717104abab9e5 + languageName: node + linkType: hard