Compare commits

...
Author SHA1 Message Date
Richard Ramos f49383db8e feat_: extract storenode cycle to go-waku 2024-11-22 11:26:00 -04:00
Mohsen 21c2a525cf [#21557] feat: show from account page in swap flow (#21611)
* [#21557] feat: show from account page in swap flow

* [#21557] feat: add disabled state to account-item

* [#21557] fix: apply suggestion

* [#21557] fix: add format address util and rename screen

* [#21557] fix: check and count account with token balance

* [#21557] fix: check for root screen
2024-11-22 16:12:00 +03:00
frank 26ae330476 chore_: add env STATUS_BACKEND_SERVER_MEDIA_SERVER_ENABLE_TLS (#21648)
* chore_: add env STATUS_BACKEND_SERVER_MEDIA_SERVER_ENABLE_TLS

https://github.com/status-im/status-go/compare/b3dbe91b...cae9d35d

* update status-go version and doc

https://github.com/status-im/status-go/compare/b3dbe91b...906c50bf
2024-11-22 11:00:02 +08:00
Volodymyr Kozieiev 5442a8567c Custom Option Menu for TX Parameters on SEND Flow (#21657)
* wip

* wip

* custom menu implemented

* sheets closing and navigation

* Hidden under feature flag

* emoji added to settings item
2024-11-21 16:28:45 +00:00
Parvesh Monu fa0777e25e fix Unable to tap on chats/channels after opening profile link (#21643) 2024-11-21 18:16:01 +05:30
Samuel Hawksby-Robinson c6c3e089ca Added the legal docs as a submodule (#21654)
Signed-off-by: Samuel Hawksby-Robinson <samuel@samyoul.com>
2024-11-21 12:19:58 +00:00
Lungu Cristian 6a30ce3de3 Use latest watchman (#21546)
* chore: upgraded watchman, otherwise it's not used with current metro

The latest metro version requires watchman capabilities that are not
available in the version we locked, so it was not used. Instead we
used the "node watcher", which is slower and buggier (at least for me
metro was timing out quite often)

* fix: watchman ignore .clj-kondo, .shadow-cljs
2024-11-21 11:55:32 +02:00
Ulises ManuelandYevheniia Berdnyk ac0a115f1d feat(onboarding): Switch profiles keeping biometrics valid (#21628)
* Rework login and logout flow to keep biometrics valid

- Move logout logic to a new namespace, the implementation no longer uses `rf/defn`

* Code style fixes

* Fix warning: "null is not an image" in login

* Fix biometric icons used all over the app

---------

Co-authored-by: Yevheniia Berdnyk <ie.berdnyk@gmail.com>
2024-11-20 13:51:06 -06:00
Yevheniia Berdnyk 58476a43da e2e: removed notifications button in tests 2024-11-20 20:25:51 +05:30
Parvesh Monu 92e6a1862b Onboarding skip enable notifications screen 2024-11-20 20:25:51 +05:30
flexsurfer 45cd66f908 [#21559] Keycard - Fresh instal sign in (#21612)
https://github.com/status-im/status-go/compare/00a8a72a...79e662e4
[#21592] No Oops, this isn't a Keycard screen when scanning not a Keycard
2024-11-20 12:57:46 +01:00
Mohamed Javid a1e3bb3bd6 fix(wallet)_: Paraswap contract address (#21635)
This commit fixes ParaSwap contract address displayed on the setting approval cap for a token.

Since we get the approval contract address in the swap proposal, we take that as higher precedence over the hardcoded value in the constants file

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-11-19 17:52:57 +05:30
Parvesh Monu e6f290c06a Remove jump to (#21634) 2024-11-19 17:21:24 +05:30
Alexander 65c872c6ec Wallet status badge for offline RPC handling (#21484) 2024-11-19 12:38:06 +01:00
frank 7acaff6167 feat_: support use status backend server (#21450)
* chore_: use status.go v2 endpoint

https://github.com/status-im/status-go/compare/39511298...e255fb8b

* feat: use status backend server (#21550)

* chore: add env variable STATUS_BACKEND_SERVER_IMAGE_SERVER_URI_PREFIX

* update doc

* fix_: image_server lint issue

* chore_: update status-go version
2024-11-19 18:50:01 +08:00
Lungu Cristian 08c97b078a fix: don't parse v signature component, as status-go expects 01/02 (#21589) 2024-11-19 12:27:22 +02:00
Lungu Cristian e59b782b86 Wallet design review fixes (#21542)
* feat: hide token price-change info if no token balance

* fix: show dapps header button only on account screen

* ref: renamed to above-zero? and using it where needed

* fix: removed bridge icon from submit button
2024-11-19 12:08:52 +02:00
Volodymyr Kozieiev 87483b1ef4 Swap: use correct fee on spending cap screen (#21532) 2024-11-18 16:15:14 +00:00
Lungu Cristian eb3ae3c928 Fix send no bonder fee included (#21116) 2024-11-14 18:47:42 +02:00
Yevheniia Berdnyk 3f12c04684 e2e: fix for fallback tests 2024-11-13 19:39:22 +02:00
Sean Hagstrom cf0fba7891 feature!: add maximum character limit to password length (#21593)
This change now limits the password for a profile to be a maximum of a 100 characters.
2024-11-13 09:30:47 -08:00
flexsurfer 9f0fb41713 [#21587] Unsupported light theme on Keycard profile key pair migration (#21588)
[#21586] Keycard migration crashes the app on Android
 [#21601] Keycard is not empty screen appears at the wrong place of migration flow
2024-11-13 11:15:14 +01:00
Mohsen 2a7da758aa [#20828] feat: display toast for all wallet connect actions (#21534) 2024-11-13 12:09:21 +03:00
Parvesh Monu 0f00f8439f Remove onboarding generating keys screen (#21608) 2024-11-13 00:46:59 +05:30
Ulises Manuel 76d6825dd5 fix(communities): incorrect drawer for non community members (#21597)
* Fix wrong community modal shown for non-members

* Fix button overlapped in community chat for non-members

* Fix shown options order in modal
2024-11-12 09:36:17 -06:00
Yevheniia Berdnyk 028f959bc3 e2e: updated onboarding flow 2024-11-12 15:06:23 +05:30
Parvesh Monu bc6de0722f Implement Onboarding - New intro screen 2024-11-12 15:06:09 +05:30
Icaro Motta 3e67a0f163 chore(perf): Do not transform large messenger initialization response to cljs (#21604)
This commit should help with potential freezes right after login, especially in
low-end devices and for users with more data.

The default behavior for the effect :json-rpc/call is to transform the
response to CLJS data using (js->clj data :keywordize-keys true), even if the
result is never used. The problem is that the response from
wakuext_startMessenger can be a very large struct! This PR simply adds the
missing line :js-response true.

https://github.com/status-im/status-mobile/blob/ca22b67d0e82a3cb123be2174b3ef2157e676e08/src/status_im/common/json_rpc/events.cljs#L85-L87

type MessengerResponse struct {
	Contacts                      []*Contact
	Invitations                   []*GroupChatInvitation
	CommunityChanges              []*communities.CommunityChanges
	AnonymousMetrics              []*appmetrics.AppMetric
	Mailservers                   []mailservers.Mailserver
	CommunityStorenodes           []storenodes.Storenode
	Bookmarks                     []*browsers.Bookmark
	Settings                      []*settings.SyncSettingField
	IdentityImages                []images.IdentityImage
	CustomizationColor            string
	WatchOnlyAccounts             []*accounts.Account
	Keypairs                      []*accounts.Keypair
	AccountsPositions             []*accounts.Account
	TokenPreferences              []walletsettings.TokenPreferences
	CollectiblePreferences        []walletsettings.CollectiblePreferences
	DiscordCategories             []*discord.Category
	DiscordChannels               []*discord.Channel
	DiscordOldestMessageTimestamp int
	BackupHandled                 bool

	// notifications a list of notifications derived from messenger events
	// that are useful to notify the user about
	installations                    map[string]*multidevice.Installation
	notifications                    map[string]*localnotifications.Notification
	requestsToJoinCommunity          map[string]*communities.RequestToJoin
	chats                            map[string]*Chat
	removedChats                     map[string]bool
	removedMessages                  map[string]*RemovedMessage
	deletedMessages                  map[string]string
	communities                      map[string]*communities.Community
	communitiesSettings              map[string]*communities.CommunitySettings
	activityCenterNotifications      map[string]*ActivityCenterNotification
	activityCenterState              *ActivityCenterState
	messages                         map[string]*common.Message
	pinMessages                      map[string]*common.PinMessage
	discordMessages                  map[string]*protobuf.DiscordMessage
	discordMessageAttachments        map[string]*protobuf.DiscordMessageAttachment
	discordMessageAuthors            map[string]*protobuf.DiscordMessageAuthor
	currentStatus                    *UserStatus
	statusUpdates                    map[string]UserStatus
	clearedHistories                 map[string]*ClearedHistory
	verificationRequests             map[string]*verification.Request
	trustStatus                      map[string]verification.TrustStatus
	emojiReactions                   map[string]*EmojiReaction
	savedAddresses                   map[string]*wallet.SavedAddress
	ensUsernameDetails               []*ensservice.UsernameDetail
	updatedProfileShowcaseContactIDs map[string]bool
	seenAndUnseenMessages            map[string]*SeenUnseenMessages
}
2024-11-12 05:46:26 -03:00
Icaro Motta 3787ac5b94 chore(url-preview): Remove old/unused code (#21603) 2024-11-11 22:43:44 -03:00
Icaro Motta a60e39cfd5 Update app metadata for Status 2.31.0 in F-Droid (#21606)
- Assets were compressed from Figma exports.
- Locale for Ukrainian fixed: from `uk` to `uk-UA` according to official reference https://android.googlesource.com/platform/frameworks/base/+/master/core/res/res/values/locale_config.xml.
- Titles for each locale are now translated.

Fixes https://github.com/status-im/status-mobile/issues/21605
2024-11-11 10:58:10 -03:00
Brian Sztamfater a7d330ecb3 fix(swap): refetch swap proposal when switching account (#21518)
Signed-off-by: Brian Sztamfater <brian@status.im>
2024-11-10 20:16:11 -03:00
Sean Hagstrom ca22b67d0e fix: only display spectated communities in opened tab (#21548)
This change resolves an issue with un-opened, joined, and pending communities being visible inside the "opened" communities tab. With this change, the "opened" community tab will only display spectated (opened) communities that have not been joined or pending to be joined.
2024-11-05 14:18:14 -08:00
flexsurfer 03ec410862 [#21446] Keycard - Current profile key pair migrate (#21558)
[#21470] Keycard - Keycard initialized but has no keys
2024-11-05 14:48:45 +01:00
Parvesh Monu e43a328c6f Improve push notification service initialization (#21553) 2024-11-05 19:10:15 +05:30
Sean Hagstrom cf72bcbe42 Fix appearance of Create Password and Change Password forms (#21544)
This change fixes the appearance of the disclaimer checkbox inside the create/change password forms to use the user's customization color. Additionally, this change also changes the password-hint success icons to use the check-circle because of its solid opacity.
2024-11-04 10:36:06 -08:00
Lungu Cristian 077b885617 Fix wallet action buttons alignment (#21514)
* fix: wallet-ctas dynamic spacing

* fix: updated bridge icon according to designs
2024-11-04 20:01:54 +02:00
Tetiana Churikova 2e42da5996 gh: added Type (#21472) 2024-11-04 16:53:18 +01:00
Tetiana Churikova f6dc9d1ad3 e2e: skipping waku tests and fixes (#21471) 2024-11-04 16:33:03 +01:00
Mohamed Javid 9f1eb60e21 chore_: Remove Goerli code (#21508)
This commit removes the goerli-related code from the mobile repo.

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-11-04 18:10:36 +05:30
Mohamed Javid 8e7d5233df fix(wallet)_: Bridging tx improvements (#21523)
This commit fixes two issues faced in L1 to L2 tx:

- fail with 'L1_ETH_BRG: Value does not match amount' error
- reverted tx due to out of gas error

Status go changes: https://github.com/status-im/status-go/pull/6012

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-11-04 15:04:36 +05:30
Mohamed Javid 4f40fda6a3 fix(wallet)_: Chain prefix for ENS resolved address (#21504)
This commit removes chain prefixes being added to ENS resolved address in send flow

Signed-off-by: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com>
2024-11-01 21:09:59 +05:30
360 changed files with 5194 additions and 5761 deletions
-1
View File
@@ -1,6 +1,5 @@
CACHED_WEBVIEWS_ENABLED=1
DEBUG_WEBVIEW=1
DEFAULT_NETWORK=mainnet_rpc
DEV_BUILD=1
ETHEREUM_DEV_CLUSTER=1
EXTENSIONS=0
+2 -3
View File
@@ -1,5 +1,4 @@
DEBUG_WEBVIEW=1
DEFAULT_NETWORK=goerli_rpc
ETHEREUM_DEV_CLUSTER=1
EXTENSIONS=0
FLEET=status.staging
@@ -22,8 +21,8 @@ KEYCARD_TEST_MENU=1
QR_READ_TEST_MENU=1
ENABLE_ROOT_ALERT=0
APN_TOPIC=im.status.ethereum.pr
VERIFY_TRANSACTION_CHAIN_ID=5
VERIFY_ENS_CHAIN_ID=5
VERIFY_TRANSACTION_CHAIN_ID=11155111
VERIFY_ENS_CHAIN_ID=11155111
TEST_STATEOFUS=1
DATABASE_MANAGEMENT_ENABLED=1
COMMUNITIES_ENABLED=1
+2 -3
View File
@@ -1,6 +1,5 @@
CACHED_WEBVIEWS_ENABLED=1
DEBUG_WEBVIEW=1
DEFAULT_NETWORK=goerli_rpc
ETHEREUM_DEV_CLUSTER=1
EXTENSIONS=0
GROUP_CHATS_ENABLED=1
@@ -21,8 +20,8 @@ KEYCARD_TEST_MENU=0
ENABLE_ROOT_ALERT=1
DISABLE_WALLET_ON_MOBILE_NETWORK=1
APN_TOPIC=im.status.ethereum.pr
VERIFY_TRANSACTION_CHAIN_ID=5
VERIFY_ENS_CHAIN_ID=5
VERIFY_TRANSACTION_CHAIN_ID=11155111
VERIFY_ENS_CHAIN_ID=11155111
TEST_STATEOFUS=1
BLANK_PREVIEW=0
DATABASE_MANAGEMENT_ENABLED=1
-1
View File
@@ -1,5 +1,4 @@
DEBUG_WEBVIEW=1
DEFAULT_NETWORK=mainnet_rpc
ETHEREUM_DEV_CLUSTER=1
EXTENSIONS=0
GROUP_CHATS_ENABLED=1
-1
View File
@@ -1,5 +1,4 @@
DEBUG_WEBVIEW=0
DEFAULT_NETWORK=mainnet_rpc
ETHEREUM_DEV_CLUSTER=0
EXTENSIONS=0
GROUP_CHATS_ENABLED=1
+1 -1
View File
@@ -2,7 +2,7 @@
name: Bug Report
about: Bug Report
title: ''
labels: ['bug', ':1234: low prio']
type: 'Bug'
assignees: ''
---
+3
View File
@@ -0,0 +1,3 @@
[submodule "legal-docs"]
path = legal-docs
url = https://github.com/status-im/status-software-legal-documents.git
+3 -1
View File
@@ -1,6 +1,8 @@
{
"ignore_dirs": [
"android/build",
"target"
"target",
".clj-kondo",
".shadow-cljs"
]
}
+1 -1
View File
@@ -92,7 +92,7 @@ For particular example it was failed on `Recover access(password:qwerty, keycard
Not all features of the app could be covered by e2e at the moment:
- Colours or place of an element on UI.
- Real ETH/token transactions. Thats the main reason we have separate .apk build for automation needs - it defaults to Goerli network. Also it has enabled keycard test menu, ENS names and chat commands are also on Goerli network (the same in PR builds, but not in nightlies / release)
- Real ETH/token transactions. Thats the main reason we have separate .apk build for automation needs - it defaults to Sepolia network. Also it has enabled keycard test menu, ENS names and chat commands are also on Sepolia network (the same in PR builds, but not in nightlies / release)
- Autologin/Biometric related actions (autologin available when device meets certain conditions like the it has set unlock password and device is not rooted: all emulators are rooted in SauceLabs)
## Brief flow for test to be automated
+61
View File
@@ -0,0 +1,61 @@
## What is Status Backend Server
Status Backend Server is a http server that runs status-go, it exposed endpoints come from [mobile/status.go](https://github.com/status-im/status-go/blob/master/mobile/status.go) so that you can call them through http requests. It brings the following benefits:
- When verifying changes made in status-go, you only need to run these commands once (unless modifying Kotlin/Objective-C code):
- `make clean && make run-clojure`
- `make run-android` or `make run-ios`
This avoids repeatedly rebuilding and saves development time.
- Debug status-go while running status mobile app
## Solution to use Status Backend Server for mobile development
`StatusBackendClient` is the entry point to use Status Backend Server. We need always to call `status-im.setup.status-backend-client/init` whether `STATUS_BACKEND_SERVER_ENABLED` is `1` or not. If it's not enabled, the invocation to functions in `native-module.core` will be delegated to built-in status-go library, otherwise it will be delegated to status-go running in status-backend server. Currently, all functions has usages in `native-module.core` should be supported delegated to.
NOTE: not all the native functions used `StatusBackendClient`, only the corresponding functions in `native-module.core` has usages should be supported delegated to ATM.
related [PR](https://github.com/status-im/status-mobile/pull/21550)
## Usage
### Add environment variables to your local machine:
```shell
# enable using status backend server or not, otherwise it will use built-in status-go library
export STATUS_BACKEND_SERVER_ENABLED=1
#The host should contain an IP address and a port separated by a colon.
#The port comes from your running status backend server.
#If you run it by PORT=60000 make run-status-backend , then host will likely be 127.0.0.1:60000
export STATUS_BACKEND_SERVER_HOST="127.0.0.1:60000"
export STATUS_BACKEND_SERVER_ROOT_DATA_DIR="/path/to/your/root/data/dir"
```
You need to change `STATUS_BACKEND_SERVER_ROOT_DATA_DIR` to your preferred directory and ensure it exists, it should be in absolute path.
All the db files and log files(requests.log/geth.log) and keystore files etc will be stored in this directory.
### Start the status backend server:
```shell
PORT=60000 make run-status-backend
```
MAKE SURE the status-backend is checked out to a revision that's at least compatible with the revision in status-mobile/status-go-version.json before starting the server.
For the Android simulator, you need to reverse the port:
```shell
adb reverse tcp:60000 tcp:60000
```
However, there is restriction when use adb reverse, we use random port for media server. So I'd suggest use "10.0.2.2:60000" as `STATUS_BACKEND_SERVER_HOST`.
### Debug status-go using IDEA
Assume you've already set up the development environment for status-go, open status-go project use IDEA, run `make generate` with terminal in the status-go project root directory to ensure all the generated files are up to date, then open `cmd/status-backend/main.go` file, navigate to function `main()`, click the green play button on the left of `main()`, choose `Modify Run Configuration`, in `Program arguments` section, add `--address=localhost:60000 --media-https=false`, then click `OK`, finally click the green play button on the left of `main()` again and choose `Debug ...`.
Basically, you don't have to run `make generate` again and again, just run it once at the beginning. So you can re-run and debug it faster!
## Known Android simulator issues
- Issue#1: Android simulator may not display images due to TLS certificate validation issues with the image server
- solution: use http instead of https for media server with set env: `export STATUS_BACKEND_SERVER_MEDIA_SERVER_ENABLE_TLS=0`, you also need to set env variable `STATUS_BACKEND_SERVER_IMAGE_SERVER_URI_PREFIX` to "http://10.0.2.2:" so that `image_server.cljs` can work, and to make `/accountInitials` work, you need to copy `Inter-Medium.ttf` to your host machine from the android simulator, let's say you store it in `/Users/mac/Downloads/Inter-Medium.ttf`, then you need to update `get-font-file-ready` manually in `image_server.cljs` to return the correct path so that status backend server can access it.
- Issue#2: exportUnencryptedDatabaseV2/import-multiaccount does not work for android, probably cause of tech debt, I found it during creating the draft PR.
- Issue#3: unable to invoke `multiaccounts_storeIdentityImage` to change avatar image.
- The reason is that we path the absolute path of the image to the backend server, but the image file is stored in the android simulator. the backend server cannot access it as it runs in the host machine.
If you're using ios simulator, you can skip above issues!
## Details for issue#1 if you're interested
- we use `react-native-fast-image` which use okhttpclient behind
- we were using custom cert for https
- we fetch the custom cert through endpoint `ImageServerTLSCert`
- we fetched it through built-in status-go before, now we need to fetch it through status backend server
- we expect `OkHttpClientProvider.setOkHttpClientFactory(StatusOkHttpClientFactory())` to be invoked early(will trigger fetching wrong custom cert via built-in status-go since StatusBackendClient is not initialised yet!) in `MainApplication.kt` before executing clojure code, otherwise we will get black screen after `make run-android` . After deep research, I found there's no way to update the cert okhttpclient used to the correct one return from status backend server
@@ -0,0 +1,21 @@
يجمع Status بين برنامج مراسلة مجهول الهوية يركز على الخصوصية ومحفظة العملات المشفرة الآمنة في أداة اتصال قوية واحدة. يمكنك الدردشة مع الأصدقاء والمجتمعات المتنامية. وشراء وتخزين وتبادل الأصول الرقمية.
Status هو نظام تشغيل Ethereum الخاص بك.
محفظة Ethereum آمنة
تتيح لك محفظة العملات المشفرة Status إرسال وتخزين وتبادل أصول Ethereum بأمان مثل ETH وSNT والعملات المستقرة مثل DAI، بالإضافة إلى المقتنيات. تحكم بثقة في عملاتك المشفرة والأصول الرقمية من خلال تطبيق محفظة Ethereum متعددة السلاسل، والذي يدعم الشبكة الرئيسية وArbitrum وOptimism. تدعم محفظة blockchain Status حاليًا أصول ETH وERC-20 وERC-721 وERC-1155 فقط؛ ولا تدعم Bitcoin.
PRIVATE MESSENGER
أرسل محادثات فردية وجماعية خاصة دون أن يتجسس أحد على اتصالاتك. Status هو تطبيق مراسلة يلغي عمليات نقل الرسائل المركزية لمزيد من الخصوصية والمراسلة الآمنة. يتم تشفير جميع الرسائل باستخدام تشفير من البداية إلى النهاية. بالإضافة إلى ذلك، لا تكشف أي رسالة عن هوية المؤلف أو المستلم المقصود، لذلك لا أحد، ولا حتى Status، يعرف من يتحدث إلى من أو ما قيل.
اربح مع DEFI
استخدم عملتك المشفرة مع أحدث تطبيقات التمويل اللامركزية والبورصات اللامركزية (DEX) مثل Maker وAave وUniswap وSynthetix وPoolTogether وZerion وKyber والمزيد.
تواصل مع مجتمعك
استكشف مجتمعاتك وأصدقائك المفضلين وتواصل معهم ودردش معهم. سواء كانت مجموعة صغيرة من الأصدقاء أو مجموعة فنانين أو تجار عملات مشفرة أو منظمة كبيرة قادمة - أرسل رسائل نصية وتواصل مع مجتمعات Status.
إنشاء حساب خاص
ابق خاصًا من خلال إنشاء حساب مجهول الهوية. عند إنشاء حسابك المجاني، لن تضطر أبدًا إلى إدخال رقم هاتف أو عنوان بريد إلكتروني أو حساب مصرفي. يتم إنشاء مفاتيح المحفظة الخاصة بك محليًا وتخزينها بشكل آمن لضمان حصولك أنت فقط على حق الوصول إلى أموالك ومعاملاتك المالية.
@@ -0,0 +1 @@
ربط Private Finance وWeb3
@@ -0,0 +1 @@
Status: محفظة تشفير اجتماعية
@@ -1,19 +0,0 @@
يجمع Status بين تطبيق مراسلة يركز على الخصوصية تحت اسم مستعار ومحفظة للعملات المشفرة آمنة في أداة تواصل قوية واحدة. تحدث مع الأصدقاء والمجتمعات المتنامية. قم بشراء وتخزين وتبادل الأصول الرقمية.
Status هو نظام التشغيل الخاص بك على Ethereum.
المُرَاسِل الخاص
أرسل محادثات خاصة 1:1 ومحادثات مجموعات خاصة دون أن يتجسس أحد على اتصالاتك. يعد Status تطبيق مراسلة يلغي الحاجة إلى نقاط التوجيه المركزية للرسائل من أجل خصوصية أكبر ومراسلة آمنة. يتم تشفير جميع الرسائل بتشفير من طرف إلى طرف. بالإضافة إلى ذلك، لا تكشف أي رسالة عن هوية المؤلف أو المستلم المستهدف، لذا لا أحد، حتى Status، يعرف من يتحدث مع من أو ماذا قيل.
محفظة Ethereum الآمنة
تتيح لك محفظة Status للعملات المشفرة إرسال وتخزين وتبادل أصول Ethereum مثل ETH و SNT والعملات المستقرة مثل DAI، بالإضافة إلى الأصول الرقمية القابلة للتحصيل بأمان. تحكم بثقة في عملاتك الرقمية وأصولك الرقمية باستخدام تطبيق محفظة Ethereum متعدد السلاسل الخاص بنا، الذي يدعم mainnet و Arbitrum و Optimism. تدعم محفظة Status حاليًا فقط أصول ETH و ERC-20 و ERC-721 و ERC-1155؛ لا تدعم Bitcoin.
اكسب مع DeFi
ضع عملاتك الرقمية في العمل مع أحدث تطبيقات التمويل اللامركزي وتبادلات العملات اللامركزية (DEX) مثل Maker و Aave و Uniswap و Synthetix و PoolTogether و Zerion و Kyber وغيرها.
تواصل مع مجتمعك
استكشف وتواصل وتحدث مع أصدقائك ومجتمعاتك المفضلة. سواء كان ذلك مع مجموعة صغيرة من الأصدقاء، أو مجموعة فنية، أو متداولي العملات المشفرة، أو المنظمة الكبيرة التالية - قم بإرسال النصوص والتواصل مع مجتمعات Status.
إنشاء حساب خاص
ابقَ خاصًا مع إنشاء حساب تحت اسم مستعار. عند إنشاء حسابك المجاني، لن تضطر أبدًا إلى إدخال رقم هاتف أو عنوان بريد إلكتروني أو حساب مصرفي. يتم توليد مفاتيح محفظتك الخاصة محليًا وتخزينها بشكل آمن لضمان أنك الوحيد الذي لديه حق الوصول إلى أموالك ومعاملاتك المالية.
@@ -1 +0,0 @@
محفظة مشفرة و ماسنجر خاص
@@ -2,17 +2,17 @@ Status combines pseudonymous privacy-focused messenger and secure crypto wallet
Status is your Ethereum operating system.
PRIVATE MESSENGER
Send private 1:1 and private group chats without anyone snooping on your communications. Status is a messenger app that eliminates centralized message relays for greater privacy and secure messaging. All messages are encrypted with end-to-end encryption. Additionally, no message exposes who the author or the intended recipient is, so nobody, not even Status, knows who is talking to who or what was said.
SECURE ETHEREUM WALLET
The Status crypto wallet allows you to securely send, store, and exchange Ethereum assets such as ETH, SNT, stable coins such as DAI, as well as collectibles. Confidently take control of your cryptocurrency and digital assets with our multichain Ethereum wallet app, supporting mainnet, Arbitrum and Optimism. The Status blockchain wallet currently only supports ETH, ERC-20, ERC-721 and ERC-1155 assets; it does not support Bitcoin.
The Status crypto wallet allows you to securely send, store, and exchange Ethereum assets such as ETH, SNT, stable coins such as DAI, as well as collectibles. Confidently take control of your cryptocurrency and digital assets with our multichain Ethereum wallet app, supporting mainnet, Arbitrum, and Optimism. The Status blockchain wallet currently only supports ETH, ERC-20, ERC-721, and ERC-1155 assets; it does not support Bitcoin.
PRIVATE MESSENGER
Send private 1:1 and private group chats without anyone snooping on your communications. Status is a messenger app that eliminates centralised message relays for greater privacy and secure messaging. All messages are encrypted with end-to-end encryption. Additionally, no message exposes who the author or the intended recipient is, so nobody, not even Status, knows who is talking to who or what was said.
EARN WITH DEFI
Put your crypto to work with the latest decentralized finance apps and decentralized exchanges (DEX) such as Maker, Aave, Uniswap, Synthetix, PoolTogether, Zerion, Kyber, and more.
Put your crypto to work with the latest decentralised finance apps and decentralised exchanges (DEX) such as Maker, Aave, Uniswap, Synthetix, PoolTogether, Zerion, Kyber, and more.
CONNECT WITH YOUR COMMUNITY
Explore, connect, and chat with your favorite communities and friends. Whether it is a small group of friends, an artist collective, crypto traders, or the next big organization - text and communicate with Status communities.
Explore, connect, and chat with your favourite communities and friends. Whether it is a small group of friends, an artist collective, crypto traders, or the next big organization - text and communicate with Status communities.
PRIVATE ACCOUNT CREATION
Stay private with pseudo-anonymous account creation. When creating your free account, you will NEVER have to enter a phone number, email address, or bank account. Your wallet private keys are locally generated and securely stored to ensure only you have access to your funds and financial transactions.

Before

Width:  |  Height:  |  Size: 192 KiB

After

Width:  |  Height:  |  Size: 192 KiB

Before

Width:  |  Height:  |  Size: 272 KiB

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 KiB

@@ -0,0 +1 @@
Connect Private Finance & Web3
@@ -0,0 +1 @@
Status: Social Crypto Wallet
Binary file not shown.

Before

Width:  |  Height:  |  Size: 363 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 437 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 488 KiB

@@ -1 +0,0 @@
Crypto Wallet & Private Messenger
@@ -1 +0,0 @@
Status
@@ -1,18 +1,18 @@
Status combina una mensajería centrada en la privacidad pseudónima y una billetera de criptomonedas segura en una poderosa herramienta de comunicación. Chatea con amigos y comunidades en crecimiento. Compra, almacena e intercambia activos digitales.
Status combina una mensajería seudónima centrada en la privacidad y una Billetera de criptomonedas segura en una poderosa herramienta de comunicación. Chatea con amigos y comunidades en crecimiento. Compra, almacena e intercambia activos digitales.
Status es tu sistema operativo para Ethereum.
Status es tu sistema operativo Ethereum.
BILLETERA ETHEREUM SEGURA
La Billetera de criptomonedas Status te permite enviar, almacenar e intercambiar de forma segura activos Ethereum como ETH, SNT, stablecoins como DAI, así como coleccionables. Toma el control de tu criptomoneda y activos digitales con confianza con nuestra Billetera multicadena, compatible con Ethereum Mainnet, Arbitrum y Optimism. La Billetera Status actualmente solo admite activos ETH, ERC-20, ERC-721 y ERC-1155; no admite Bitcoin.
MENSAJERÍA PRIVADA
Envía chats privados 1:1 y chats grupales privados sin que nadie espíe tus comunicaciones. Status es una aplicación de mensajería que elimina los retransmisores de mensajes centralizados para ofrecer mayor privacidad y mensajería segura. Todos los mensajes están cifrados con cifrado de extremo a extremo. Además, ningún mensaje revela quién es el autor o el destinatario previsto, por lo que nadie, ni siquiera Status, sabe quién está hablando con quién o qué se dijo.
BILLETERA SEGURA DE CRIPTOMONEDAS
La billetera de criptomonedas de Status te permite enviar, almacenar e intercambiar de forma segura activos de Ethereum como ETH, SNT, stablecoins como DAI, así como coleccionables digitales. Controla con confianza tus criptomonedas y activos digitales con nuestra aplicación de billetera multichain de Ethereum, que soporta mainnet, Arbitrum y Optimism. La billetera blockchain de Status actualmente solo soporta activos ETH, ERC-20, ERC-721 y ERC-1155; no soporta Bitcoin.
Envía chats privados 1:1 y grupales sin que nadie espíe tus comunicaciones. Status es una aplicación de mensajería que elimina los servidores de mensajes centralizados para una mayor privacidad y una mensajería segura. Todos los mensajes están encriptados de extremo a extremo. Además, ningún mensaje expone quién es el autor o el destinatario previsto, por lo que nadie, ni siquiera Status, sabe quién está hablando con quién o qué se dijo.
GANA CON DEFI
Pon tus criptomonedas a trabajar con las últimas aplicaciones de finanzas descentralizadas y exchanges descentralizados (DEX) como Maker, Aave, Uniswap, Synthetix, PoolTogether, Zerion, Kyber y más.
Pon tus criptomonedas a trabajar con las últimas aplicaciones financieras descentralizadas y plataformas de intercambio descentralizadas (DEX) como Maker, Aave, Uniswap, Synthetix, PoolTogether, Zerion, Kyber y más.
CONECTA CON TU COMUNIDAD
Explora, conecta y chatea con tus comunidades y amigos favoritos. Ya sea un pequeño grupo de amigos, un colectivo de artistas, traders de criptomonedas o la próxima gran organización, envía mensajes y comunícate con las comunidades de Status.
Explora, conéctate y chatea con tus comunidades y amigos. Ya sea un pequeño grupo de amigos, un colectivo de artistas, traders de criptomonedas o la próxima gran organización, envía mensajes de texto y comunícate con las comunidades de Status.
CREACIÓN DE CUENTAS PRIVADAS
Mantén tu privacidad con la creación de cuentas pseudónimas. Al crear tu cuenta gratuita, NUNCA tendrás que ingresar un número de teléfono, dirección de correo electrónico o cuenta bancaria. Las claves privadas de tu billetera se generan localmente y se almacenan de manera segura para garantizar que solo tú tengas acceso a tus fondos y transacciones financieras.
Mantén la privacidad con la creación de cuentas seudónimas. Al crear tu cuenta gratuita, NUNCA tendrás que compartir tu número de teléfono, tu dirección de correo electrónico o una cuenta bancaria. Las claves privadas de tu billetera se generan localmente y se almacenan de forma segura para garantizar que solo tú tienes acceso a tus fondos y transacciones financieras.
@@ -1 +1 @@
Criptobilletera y Chat Privado
Conecta tus finanzas y la web3
@@ -0,0 +1 @@
Status: Billetera social cripto
@@ -0,0 +1,18 @@
Status combine une messagerie pseudonyme axée sur la confidentialité et un portefeuille cryptographique sécurisé en un seul outil de communication puissant. Discutez avec des amis et des communautés en pleine croissance. Achetez, stockez et échangez des actifs numériques.
Status est votre système d'exploitation Ethereum.
PORTEFEUILLE ETHEREUM SÉCURISÉ
Le portefeuille cryptographique Status vous permet d'envoyer, de stocker et d'échanger en toute sécurité des actifs Ethereum tels que ETH, SNT, des pièces stables telles que DAI, ainsi que des objets de collection. Prenez le contrôle en toute confiance de votre cryptomonnaie et de vos actifs numériques avec notre application de portefeuille Ethereum multichaîne, prenant en charge le réseau principal, Arbitrum et Optimism. Le portefeuille blockchain Status ne prend actuellement en charge que les actifs ETH, ERC-20, ERC-721 et ERC-1155 ; il ne prend pas en charge Bitcoin.
MESSAGERIE PRIVÉE
Envoyez des conversations privées en tête-à-tête et en groupe sans que personne ne surveille vos communications. Status est une application de messagerie qui élimine les relais de messages centralisés pour une plus grande confidentialité et une messagerie sécurisée. Tous les messages sont cryptés avec un cryptage de bout en bout. De plus, aucun message n'expose l'identité de l'auteur ou du destinataire prévu, de sorte que personne, pas même Status, ne sait qui parle à qui ou ce qui a été dit.
GAGNEZ DE L'ARGENT AVEC DEFI
Mettez votre crypto au travail avec les dernières applications financières décentralisées et les échanges décentralisés (DEX) tels que Maker, Aave, Uniswap, Synthetix, PoolTogether, Zerion, Kyber, et plus encore.
CONNECTEZ-VOUS AVEC VOTRE COMMUNAUTÉ
Explorez, connectez-vous et discutez avec vos communautés et amis préférés. Qu'il s'agisse d'un petit groupe d'amis, d'un collectif d'artistes, de traders de crypto-monnaies ou de la prochaine grande organisation, envoyez des SMS et communiquez avec les communautés Status.
CRÉATION DE COMPTE PRIVÉ
Restez privé grâce à la création de compte pseudo-anonyme. Lors de la création de votre compte gratuit, vous n'aurez JAMAIS besoin de saisir un numéro de téléphone, une adresse e-mail ou un compte bancaire. Les clés privées de votre portefeuille sont générées localement et stockées en toute sécurité pour garantir que vous seul avez accès à vos fonds et à vos transactions financières.
@@ -0,0 +1 @@
Finance privée + Web3
@@ -0,0 +1 @@
Status : Portef. crypto social
@@ -0,0 +1,21 @@
Statusは、匿名のプライバシー重視のメッセンジャーと安全な暗号通貨ウォレットを1つの強力なコミュニケーションツールに組み合わせています。友達や成長中のコミュニティとチャットしましょう。デジタル資産を購入、保管、交換しましょう。
StatusはあなたのEthereumオペレーティングシステムです。
安全なEthereumウォレット
Status暗号通貨ウォレットを使用すると、ETH、SNT、DAIなどのステーブルコイン、収集品などのEthereum資産を安全に送信、保管、交換できます。メインネット、Arbitrum、OptimismをサポートするマルチチェーンEthereumウォレットアプリを使用して、暗号通貨とデジタル資産を自信を持って管理できます。 Status ブロックチェーン ウォレットは現在、ETH、ERC-20、ERC-721、ERC-1155 アセットのみをサポートしており、ビットコインはサポートしていません。
プライベート メッセンジャー
誰にも通信を覗かれることなく、プライベートな 1:1 チャットやプライベート グループ チャットを送信できます。Status は、集中型のメッセージ リレーを排除してプライバシーと安全なメッセージングを実現するメッセンジャー アプリです。すべてのメッセージはエンドツーエンドの暗号化で暗号化されます。さらに、メッセージの作成者や宛先の受信者が誰であるかは明らかにされないため、Status でさえ、誰が誰と話しているのか、何が話されたのかを知ることはできません。
DEFI で稼ぐ
Maker、Aave、Uniswap、Synthetix、PoolTogether、Zerion、Kyber などの最新の分散型金融アプリや分散型取引所 (DEX) で暗号通貨を活用しましょう。
コミュニティとつながる
お気に入りのコミュニティや友達を探索、接続、チャットしましょう。少人数の友人グループ、アーティスト集団、暗号通貨トレーダー、または次の大きな組織であっても、Status コミュニティとテキストでやり取りできます。
プライベート アカウントの作成
疑似匿名アカウントの作成でプライバシーを確保します。無料アカウントを作成するときに、電話番号、メール アドレス、銀行口座を入力する必要はありません。ウォレットの秘密鍵はローカルで生成され、安全に保管されるため、資金と金融取引にアクセスできるのはあなただけです。
@@ -0,0 +1 @@
プライベート ファイナンスと Web3 を接続
@@ -0,0 +1 @@
Status: ソーシャル クリプト ウォレット
@@ -1,18 +1,21 @@
Status는 익명성을 보장하는 프라이버시 중심 메신저와 안전한 암호화폐 지갑을 하나의 강력한 커뮤니케이션 도구로 결합했습니다. 친구들과 성장하는 커뮤니티와 채팅하세요. 디지털 자산을 구매, 저장, 교환할 수 있습니다.
Status는 익명의 개인 정보 보호 중심 메신저와 안전한 암호화폐 지갑을 하나의 강력한 커뮤니케이션 도구로 결합니다. 친구 성장하는 커뮤니티와 채팅하세요. 디지털 자산을 구매, 저장 교환하세요.
Status는 당신의 Ethereum 운영체제입니다.
Status는 귀하의 Ethereum 운영 체제입니다.
프라이빗 메신저
개인 1:1 채팅과 비공개 그룹 채팅을 통해 누구도 당신의 통신을 엿볼 수 없습니다. Status는 중앙 집중식 메시지 중계를 제거하여 더 큰 프라이버시와 안전한 메시징을 제공하는 메신저 앱입니다. 모든 메시지는 종단 간 암호화로 보호됩니다. 또한, 어떤 메시지도 작성자나 의도된 수신자의 신원을 노출하지 않기 때문에, Status조차도 누가 누구와 대화하는지, 무슨 말을 했는지 알 수 없습니다.
안전한 이더리움 지갑
Status 암호화폐 지갑을 사용하면 ETH, SNT, DAI와 같은 스테이블 코인, 수집품과 같은 이더리움 자산을 안전하게 보내고, 저장하고, 교환할 수 있습니다. 메인넷, Arbitrum 및 Optimism을 지원하는 멀티체인 이더리움 지갑 앱으로 암호화폐와 디지털 자산을 자신 있게 제어하세요. Status 블록체인 지갑은 현재 ETH, ERC-20, ERC-721 및 ERC-1155 자산만 지원하며 비트코인은 지원하지 않습니다.
안전한 Ethereum 지갑
Status 암호화폐 지갑을 통해 ETH, SNT, DAI와 같은 스테이블코인, 그리고 암호화 수집품과 같은 Ethereum 자산을 안전하게 송금, 저장 및 교환할 수 있습니다. 메인넷, Arbitrum, Optimism을 지원하는 우리의 멀티체인 Ethereum 지갑 앱을 사용해 당신의 암호화폐와 디지털 자산을 자신 있게 관리하세요. Status 블록체인 지갑은 현재 ETH, ERC-20, ERC-721, ERC-1155 자산만 지원하며, Bitcoin은 지원하지 않습니다.
개인 메신저
아무도 귀하의 커뮤니케이션을 엿보지 않고 개인 1:1 및 개인 그룹 채팅을 보내세요. Status는 중앙 집중식 메시지 릴레이를 제거하여 더 큰 프라이버시와 안전한 메시징을 제공하는 메신저 앱입니다. 모든 메시지는 종단 간 암호화로 암호화됩니다. 또한, 메시지에는 작성자 또는 의도된 수신자가 노출되지 않으므로 Status를 포함하여 아무도 누가 누구와 대화하고 있는지 또는 무슨 말을 했는지 알 수 없습니다.
DeFi로 수익 창출
Maker, Aave, Uniswap, Synthetix, PoolTogether, Zerion, Kyber 등 최신 탈중앙화 금융 앱과 탈중앙화 거래소(DEX)를 사용해 암호화폐를 활용하세요.
DEFI로 수익 창출
Maker, Aave, Uniswap, Synthetix, PoolTogether, Zerion, Kyber 등과 같은 최신 분산 금융 앱 및 분산 거래소(DEX)에서 암호화폐를 활용하세요.
커뮤니티와 연결
당신의 좋아하는 커뮤니티와 친구들과 탐색, 연결 및 채팅하세요. 작은 친구 모임이든, 아티스트 집단이든, 암호화폐 거래자든, 다음 큰 조직이든, Status 커뮤니티를 통해 텍스트를 보내고 소통하세요.
프라이빗 계정 생성
익명 계정 생성을 통해 프라이버시를 유지하세요. 무료 계정을 생성할 때 전화번호, 이메일 주소, 은행 계좌를 절대 입력할 필요가 없습니다. 지갑의 개인 키는 로컬에서 생성되고 안전하게 저장되어, 오직 당신만이 자금과 금융 거래에 접근할 수 있습니다.
좋아하는 커뮤니티와 친구를 탐색하고, 연결하고, 채팅하세요. 소규모 친구 그룹, 아티스트 집단, 암호화폐 거래자 또는 차세대 대기업이든 Status 커뮤니티에 문자를 보내고 소통하세요.
개인 계정 생성
익명 계정을 생성하여 개인 정보를 보호하세요. 무료 계정을 만들 때 전화번호, 이메일 주소 또는 은행 계좌를 입력할 필요가 없습니다. 지갑 개인 키는 로컬에서 생성되고 안전하게 저장되어 본인만 자금과 금융 거래에 액세스할 수 있습니다.
@@ -1 +1 @@
암호화폐 지갑 & 비밀 메신저
개인 금융 및 Web3 연결
@@ -0,0 +1 @@
Status: 소셜 크립토 지갑
@@ -2,22 +2,17 @@ Status é um app de mensagem e uma carteira de criptomoedas focado em privacidad
Status é o seu sistema operacional para Ethereum.
APP DE MENSAGEM PRIVADO
CARTEIRA ETHEREUM SEGURA
A carteira de criptomoedas Status permite que você envie, armazene e troque ativos Ethereum, como ETH, SNT, stablecoins como DAI, além de colecionáveis, de forma segura. Controle com confiança suas criptomoedas e ativos digitais com nosso aplicativo de carteira Ethereum multichain, que suporta Mainnet, Arbitrum e Optimism. A carteira blockchain da Status atualmente suporta apenas ativos ETH, ERC-20, ERC-721 e ERC-1155; não suporta Bitcoin.
APP DE MENSAGEM PRIVADO
Envie mensagens privadas em chats 1:1 ou em grupos. Status é um aplicativo de mensagem descentralizado que foca em privacidade e anonimato. Todas as mensagens são protegidas com criptografia de ponta a ponta. Além disso, nenhuma mensagem revela quem é o(a) autor(a) ou o(a) destinatário(a) pretendido(a), então ninguém, nem mesmo a Status, sabe quem está conversando com quem ou o que foi dito.
CARTEIRA SEGURA DE ETHEREUM
A carteira de criptomoedas Status permite que você envie, armazene e troque ativos Ethereum, como ETH, SNT, stablecoins como DAI, além de colecionáveis, de forma segura. Controle com confiança suas criptomoedas e ativos digitais com nosso aplicativo de carteira Ethereum multichain, que suporta mainnet, Arbitrum e Optimism. A carteira blockchain da Status atualmente suporta apenas ativos ETH, ERC-20, ERC-721 e ERC-1155; não suporta Bitcoin.
MONETIZE COM DEFI E STAKING
Coloque suas criptomoedas para trabalhar (staking) com os mais recentes aplicativos de finanças descentralizadas e exchanges descentralizadas (DEX), como Maker, Aave, Uniswap, Synthetix, PoolTogether, Zerion, Kyber e mais.
CONECTE-SE COM SUA COMUNIDADE
Explore, conecte-se e converse com seus amigos e comunidades favoritas. Seja um grupo de amigos, de artistas, de traders de criptomoedas ou a próxima grande empresa - envie textos e comunique-se através das comunidades da Status.
CRIAÇÃO DE CONTA PRIVADA
Mantenha sua privacidade com a criação de conta anônima. Ao criar sua conta gratuita, você NUNCA precisará inserir um número de telefone, endereço de e-mail ou conta bancária. Suas chaves privadas da carteira são geradas localmente e armazenadas com segurança para garantir que apenas você tenha acesso aos seus fundos e transações financeiras.
@@ -1 +1 @@
Crypto Wallet & Private Chat
Privacidade Financeira e Web3
@@ -0,0 +1 @@
Status: Carteira social cripto
@@ -1,18 +1,18 @@
Status сочетает в себе мессенджер, ориентированный на анонимность и конфиденциальность, и безопасный криптовалютный кошелек в одном мощном инструменте для общения. Общайтесь с друзьями и развивающимися сообществами. Покупайте, отправляйте и обменивайте цифровые активы.
Status объединяет анонимный мессенджер, ориентированный на конфиденциальность, и защищенный криптокошелек в один мощный инструмент для финансов и общения. Общайтесь с друзьями, находите новые сообщества, а также покупайте, храните и обменивайте цифровые активы.
Status — это ваша операционная система для Ethereum.
ПРИВАТНЫЙ МЕССЕНДЖЕР
Отправляйте приватные сообщения 1:1 и участвуйте в групповых чатах, будучи уверенными в том, что никто не может перехватить или прочитать ваши сообщения. Status — это мессенджер, который устраняет необходимость в централизованных серверах для передачи сообщений, обеспечивая высшую степень конфиденциальности и безопасности. Все сообщения защищены сквозным шифрованием. Более того, ни одно сообщение не раскрывает, кто является автором или предполагаемым получателем, поэтому никто, включая Status, не знает, кто с кем общается и что было сказано.
БЕЗОПАСНЫЙ КОШЕЛЕК ETHEREUM
Крипто-кошелек Status позволяет вам безопасно отправлять, хранить и обменивать активы Ethereum, такие как ETH, SNT, стейблкоины, такие как DAI, а также невзаимозаменяемые токены. Контролируйте свою криптовалюту с помощью нашего криптокошелека для Ethereum, поддерживающего Ethereum, Arbitrum и Optimism. В настоящее время криптокошелек Status поддерживает такие активы ETH, ERC-20, ERC-721 и ERC-1155.
БЕЗОПАСНЫЙ КРИПТОКОШЕЛЕК ДЛЯ ETHEREUM
Кошелек Status позволяет вам безопасно отправлять, хранить и обменивать Ethereum-активы, такие как ETH, SNT, стейблкоины (например, DAI), а также цифровые коллекционные предметы. Контролируйте свои криптовалюты и цифровые активы с уверенностью с помощью нашего мультичейн Ethereum-кошелька, поддерживающего mainnet, Arbitrum и Optimism. Кошелек Status в настоящее время поддерживает активы ETH, ERC-20, ERC-721 и ERC-1155; поддержка Bitcoin отсутствует.
ПРИВАТНИЙ МЕСЕНДЖЕР
Отправляйте приватные сообщения друзьям или группам. Status — это приложение для обмена сообщениями, которое поддерживает децентрализованную систему для повышения конфиденциальности и безопасного обмена сообщениями. Все сообщения зашифрованы с помощью сквозного шифрования. Более того, ни одно сообщение не содержит информации об авторе или получателе, поэтому никто, даже Status, не знает, кто с кем общается или что было отправлено.
ЗАРАБАТЫВАЙТЕ С DEFI
Заставьте свои криптовалюты работать на вас с актуальными приложениями децентрализованных финансов и децентрализованными биржами (DEX), такими как Maker, Aave, Uniswap, Synthetix, PoolTogether, Zerion, Kyber и другими.
Используйте свою криптовалюту для работы с новейшими приложениями для децентрализованных финансов и децентрализованными криптобиржами (DEX), такими как Maker, Aave, Uniswap, Synthetix, PoolTogether, Kyber и другие.
СВЯЗЬ С СООБЩЕСТВОМ
Исследуйте, присоединяйтесь и общайтесь с любимыми сообществами и друзьями. Независимо от того, являетесь ли вы частью небольшой группы друзей, художественного коллектива, трейдеров криптовалют или крупной организации — отправляйте сообщения и общайтесь в сообществах Status.
НАЙДИТЕ ВАШЕ СООБЩЕСТВО
Находите, исследуйте и общайтесь с любимыми сообществами и друзьями. Независимо от того, является ли это небольшой группой друзей, коллективом художников, криптотрейдеров или следующим большим сообществом единомышленников — отправляйте текстовые сообщения и общайтесь с сообществами в Status.
КОНФИДЕНЦИАЛЬНАЯ РЕГИСТРАЦИЯ
Создайте анонимный профиль и оставайтесь конфиденциальными. При создании бесплатного профиля вам НИКОГДА не потребуется вводить номер телефона, адрес электронной почты или банковские данные. Ваши приватные ключи кошелька генерируются локально и хранятся безопасно, чтобы только вы имели доступ к своим средствам и финансовым операциям.
СОЗДАНИЕ ПРИВАТНОГО АККАУНТА
Оставайтесь конфиденциальными с помощью создания анонимного аккаунта. При создании аккаунта вам НИКОГДА не нужно будет вводить номер телефона, адрес электронной почты или банковский счет. Приватные ключи вашего криптокошелька генерируются локально на вашем устройстве и надежно хранятся, чтобы только вы имели доступ к своим средствам и финансовым транзакциям.
@@ -1 +1 @@
Crypto Wallet & Private Chat
Web3 финансы и приват чат
@@ -0,0 +1 @@
Status: Криптокошелек
@@ -1,18 +1,18 @@
Status, gizlilik odaklı takma adla kullanılan bir mesajlaşma uygulaması ile güvenli bir kripto cüzdanını birleştirerek güçlü bir iletişim aracı sunar. Arkadaşlarınız ve büyüyen topluluklarla sohbet edin. Dijital varlıklar satın alın, saklayın ve değiştirin.
Status, takma adlı gizlilik odaklı mesajlaşmayı ve güvenli kripto cüzdanını tek bir güçlü iletişim aracında birleştiriyor. Arkadaşlarınızla ve büyüyen topluluklarla sohbet edin. Dijital varlıkları satın alın, saklayın ve değiştirin.
Status, Ethereum için işletim sisteminizdir.
ÖZEL MESAJLAŞMA UYGULAMASI
Özel 1:1 ve grup sohbetlerini kimsenin iletişiminizi gözetlemesine izin vermeden gönderin. Status, merkezi mesaj iletimini ortadan kaldırarak daha fazla gizlilik ve güvenli mesajlaşma sağlayan bir mesajlaşma uygulamasıdır. Tüm mesajlar uçtan uca şifreleme ile korunur. Ayrıca, hiçbir mesaj yazarın veya hedeflenen alıcının kim olduğunu ortaya çıkarmaz, bu yüzden kimse, hatta Status bile, kimin kiminle konuştuğunu veya ne konuşulduğunu bilmez.
Status, Ethereum işletim sisteminizdir.
GÜVENLİ ETHEREUM CÜZDANI
Status kripto cüzdanı, ETH, SNT, DAI gibi stabilcoinler ve koleksiyon gibi Ethereum varlıklarını güvenle göndermenize, saklamanıza ve değiştirmenize olanak tanır. Ana ağ, Arbitrum ve Optimism'i destekleyen çok zincirli Ethereum cüzdan uygulamamızla kripto paralarınız ve dijital varlıklarınız üzerinde güvenle kontrol sahibi olun. Status blok zinciri cüzdanı şu anda yalnızca ETH, ERC-20, ERC-721 ve ERC-1155 varlıklarını destekler; Bitcoin desteklenmemektedir.
Status kripto cüzdanı, ETH, SNT, DAI gibi sabit paralar ve koleksiyonluk eşyalar gibi Ethereum varlıklarını güvenli bir şekilde göndermenize, saklamanıza ve değiştirmenize olanak tanır. Ana ağ, Arbitrum ve Optimism'i destekleyen çok zincirli Ethereum cüzdan uygulamamızla kripto paranızın ve dijital varlıklarınızın kontrolünü güvenle ele alın. Status blok zinciri cüzdanı şu anda yalnızca ETH, ERC-20, ERC-721 ve ERC-1155 varlıklarını destekliyor; Bitcoin'i desteklemiyor.
ÖZEL MESAJLAŞMACI
İletişimlerinizi kimse gözetlemeden özel 1:1 ve özel grup sohbetleri gönderin. Status, daha fazla gizlilik ve güvenli mesajlaşma için merkezi mesaj iletimlerini ortadan kaldıran bir mesajlaşma uygulamasıdır. Tüm mesajlar uçtan uca şifrelemeyle şifrelenir. Ayrıca, hiçbir mesaj yazarının veya hedeflenen alıcının kim olduğunu ifşa etmez, bu nedenle hiç kimse, Status bile kimin kiminle konuştuğunu veya ne söylendiğini bilmez.
DEFI İLE KAZANIN
Kripto paralarınızı Maker, Aave, Uniswap, Synthetix, PoolTogether, Zerion, Kyber gibi en son merkeziyetsiz finans uygulamaları ve merkeziyetsiz borsalar (DEX) ile değerlendirin.
Kripto paranızı Maker, Aave, Uniswap, Synthetix, PoolTogether, Zerion, Kyber ve daha fazlası gibi en son merkezi olmayan finans uygulamaları ve merkezi olmayan borsalarla (DEX) çalıştırın.
TOPLULUĞUNUZLA BAĞLANTI KURUN
Favori topluluklarınız ve arkadaşlarınızla keşfedin, bağlantı kurun ve sohbet edin. İster küçük bir arkadaş grubu, bir sanatçı kolektifi, kripto para tacirleri veya bir sonraki büyük organizasyon olsun - Status topluluklarıyla mesajlaşın ve iletişim kurun.
En sevdiğiniz toplulukları ve arkadaşlarınızla keşfedin, bağlantı kurun ve sohbet edin. İster küçük bir arkadaş grubu, ister bir sanatçı kolektifi, kripto tüccarları veya bir sonraki büyük organizasyon olsun - Status topluluklarıyla mesajlaşın ve iletişim kurun.
ÖZEL HESAP OLUŞTURMA
Takma adla hesap oluşturarak gizliliğinizi koruyun. Ücretsiz hesabınızı oluştururken asla telefon numarası, e-posta adresi veya banka hesabı girmenize gerek yoktur. Cüzdanınızın özel anahtarları yerel olarak oluşturulur ve yalnızca sizin fonlarınıza ve finansal işlemlerinize erişiminiz olmasını sağlamak için güvenli bir şekilde saklanır.
Sahte anonim hesap oluşturma ile gizli kalın. Ücretsiz hesabınızı oluştururken ASLA bir telefon numarası, e-posta adresi veya banka hesabı girmeniz gerekmeyecek. Cüzdan özel anahtarlarınız yerel olarak oluşturulur ve yalnızca sizin fonlarınıza ve finansal işlemlerinize erişebilmenizi sağlamak için güvenli bir şekilde saklanır.
@@ -1 +1 @@
Kripto Cüzdanı ve Özel Sohbet
Özel Finans ve Web3'ü Bağlayın
@@ -0,0 +1 @@
Status: Sosyal Kripto Cüzdanı
@@ -0,0 +1,18 @@
Status поєднує анонімний месенджер, орієнтований на конфіденційність та захищений криптогаманець в один потужний інструмент для фінансів та спілкування. Спілкуйтеся з друзями та спільнотами. Купуйте, зберігайте та обмінюйте крипто активи.
Status — це ваша операційна система для Ethereum.
БЕЗПЕЧНИЙ КРИПТОГАМАНЕЦЬ ДЛЯ ETHEREUM
Криптогаманець Status дозволяє безпечно надсилати, зберігати та обмінювати крипто активи на Ethereum, такі як ETH, SNT, стейблкоїни та DAI, а також невзаємозамінні токени. Впевнено контролюйте свої крипто активи за допомогою нашого блокчейн гаманця для Ethereum, який підтримує Ethereum, Arbitrum і Optimism. Криптогаманець Status наразі підтримує такі кприпто активи як ETH, ERC-20, ERC-721 та ERC-1155.
ПРИВАТНИЙ МЕСЕНДЖЕР
Надсилайте приватні повідомлення друзям або групам. Status — це програма для обміну повідомленнями, яка підтримує децентралізовану систему повідомлень для більшої конфіденційності та безпечного обміну повідомленнями. Усі повідомлення зашифровано за допомогою наскрізного шифрування. Крім того, жодне повідомлення не містить інформації про автора чи одержувача, тому ніхто, навіть Status, не знає, хто з ким спілкувється або що було надіслано.
ЗАРОБЛЯЙТЕ З DEFI
Налаштуйте свою криптовалюту на роботу з найновішими програмами для децентралізованих фінансів і децентралізованими крипто біржами (DEX), такими як Maker, Aave, Uniswap, Synthetix, PoolTogether, Kyber тощо.
ЗНАЙДІТЬ ВАШУ СПІЛЬНОТУ
Знаходьте, досліджуйте та спілкуйтеся з улюбленими спільнотами та друзями. Незалежно від того, чи це невелика група друзів, колектив художників, криптотрейдерів чи наступна велика спільнота однодумців – надсилайте текстові повідомлення та спілкуйтеся зі спільнотами у Status.
СТВОРЕННЯ ПРИВАТНОГО ОБЛІКОВОГО ЗАПИСУ
Залишайтеся конфіденційними за допомогою створення анонімного облікового запису. Під час створення облікового запису вам НІКОЛИ не доведеться вводити номер телефону, адресу електронної пошти чи банківський рахунок. Приватні ключі вашого крипто гаманця генеруються локально на вашому пристрої та надійно зберігаються, щоб лише Ви мали доступ до своїх коштів і фінансових транзакцій.
@@ -0,0 +1 @@
Web3 фінанси та приват чат
@@ -0,0 +1 @@
Status: Криптогаманець
@@ -1,18 +0,0 @@
Status поєднує у собі месенджер, орієнтований на анонімність і конфіденційність, з безпечним криптовалютним гаманцем в одному потужному інструменті для спілкування. Спілкуйтеся з друзями та зростаючими спільнотами. Купуйте, надсилайте та обмінюйте цифрові активи.
Status — це ваша операційна система для Ethereum.
ПРИВАТНИЙ МЕСЕНДЖЕР
Надсилайте приватні повідомлення та беріть участь у групових чатах, будучи впевненими, що ніхто не може перехопити або прочитати ваші листування. Status усуває необхідність у централізованих серверах для передачі повідомлень, забезпечуючи найвищий рівень конфіденційності та безпеки. Усі повідомлення захищені наскрізним шифруванням. Крім того, жодне повідомлення не розкриває, хто є його автором або передбачуваним отримувачем, тому ніхто, включаючи Status, не знає, хто з ким спілкується і що було сказано.
БЕЗПЕЧНИЙ КРИПТОГАМАНЕЦЬ ДЛЯ ETHEREUM
Гаманець Status дозволяє вам безпечно надсилати, зберігати та обмінювати активи Ethereum, такі як ETH, SNT, стейблкоїни (наприклад, DAI), а також цифрові колекційні предмети. Контролюйте свої криптовалюти та цифрові активи з упевненістю за допомогою нашого мультичейн Ethereum-гаманця, що підтримує Mainnet, Arbitrum та Optimism. Гаманець Status наразі підтримує активи ETH, ERC-20, ERC-721 і ERC-1155; підтримка Bitcoin відсутня.
ЗАРОБЛЯЙТЕ ЗА ДОПОМОГОЮ DEFI
Змусьте свої криптовалюти працювати на вас за допомогою актуальних додатків децентралізованих фінансів і децентралізованих бірж (DEX), таких як Maker, Aave, Uniswap, Synthetix, PoolTogether, Zerion, Kyber та інших.
ЗВ’ЯЗОК ІЗ СПІЛЬНОТОЮ
Відкривайте, знаходьте й спілкуйтесь зі своїми улюбленими спільнотами та друзями. Незалежно від того, чи є ви частиною невеликої групи друзів, творчого колективу, криптотрейдерів або великої організації — надсилайте повідомлення та спілкуйтесь у спільнотах Status.
КОНФІДЕНЦІЙНА РЕЄСТРАЦІЯ
Створіть анонімний профіль і залишайтеся конфіденційними. Під час створення безкоштовного профілю вам НІКОЛИ не потрібно буде вводити номер телефону, адресу електронної пошти або банківські дані. Ваші приватні ключі гаманця генеруються локально та зберігаються надійно, щоб лише ви мали доступ до своїх коштів і фінансових операцій.
@@ -1 +0,0 @@
Crypto Wallet & Private Chat
@@ -2,12 +2,12 @@ Status 将保护匿名私密的消息应用,与安全的加密货币钱包结
Status 是你的以太坊操作系统。
安全的以太坊钱包
Status 加密货币钱包支持安全地发送、存储和交换以太坊资产(例如 ETH、SNT)、稳定币(例如 DAI)以及数字藏品。Status 多链以太坊钱包支持主网、Arbitrum 和 Optimism,让您安心掌控加密货币和数字资产。Status 区块链钱包目前仅支持 ETH、ERC-20、ERC-721 和 ERC-1155 资产;不支持 Bitcoin。
私密通信
一对一或同多人发送私密消息,没有人能窥探你的通信内容。Status 不使用中心化消息中继,提升消息的隐私和安全。所有消息都经过端到端加密。此外,消息不含发送或接收者的身份信息,包括 Status 在内的任何人都无法获知消息内容或交流者身份。
安全的以太坊钱包
Status 加密货币钱包支持安全地发送、存储和交换以太坊上的资产,如 ETH、SNT,DAI 等稳定币以及数字藏品。Status 多链以太坊钱包支持主网、Arbitrum 和 Optimism,让您安心掌控加密货币和数字资产。Status 区块链钱包目前仅支持 ETH、ERC-20、ERC-721 和 ERC-1155 资产;不支持 Bitcoin。
赚取 DeFi 收益
使用最新的去中心化金融应用和去中心化交易所 (DEX),如 Maker、Aave、Uniswap、Synthetix、PoolTogether、Zerion、Kyber 等,充分发挥加密货币的作用。
@@ -1 +1 @@
安全地聊天和交易
连接个人金融和Web3
@@ -0,0 +1 @@
Status: 可以社交的加密货币钱包
+8 -1
View File
@@ -29,6 +29,8 @@
#import <Security/Security.h>
#import <react/config/ReactNativeConfig.h>
#import "StatusBackendClient.h"
//TODO: properly import the framework
extern "C" NSString* StatusgoImageServerTLSCert();
@@ -188,7 +190,12 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response
NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
__block NSURLCredential *credential = nil;
NSString *pemCert = StatusgoImageServerTLSCert();
NSString *pemCert = [StatusBackendClient executeStatusGoRequestWithResult:@"ImageServerTLSCert"
body:@""
statusgoFunction:^NSString *{
return StatusgoImageServerTLSCert();
}];
pemCert = [pemCert stringByReplacingOccurrencesOfString:@"-----BEGIN CERTIFICATE-----\n" withString:@""];
pemCert = [pemCert stringByReplacingOccurrencesOfString:@"\n-----END CERTIFICATE-----" withString:@""];
NSData *derCert = [[NSData alloc] initWithBase64EncodedString:pemCert options:NSDataBase64DecodingIgnoreUnknownCharacters];
Submodule
+1
Submodule legal-docs added at 3943b281b0
@@ -24,25 +24,23 @@ class AccountManager(private val reactContext: ReactApplicationContext) : ReactC
@ReactMethod
fun createAccountAndLogin(createAccountRequest: String) {
Log.d(TAG, "createAccountAndLogin")
val result = Statusgo.createAccountAndLogin(createAccountRequest)
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "createAccountAndLogin success: $result")
Log.d(TAG, "Geth node started")
} else {
Log.e(TAG, "createAccountAndLogin failed: $result")
}
StatusBackendClient.executeStatusGoRequest(
endpoint = "CreateAccountAndLogin",
requestBody = createAccountRequest,
statusgoFunction = { Statusgo.createAccountAndLogin(createAccountRequest) }
)
}
@ReactMethod
fun restoreAccountAndLogin(restoreAccountRequest: String) {
Log.d(TAG, "restoreAccountAndLogin")
val result = Statusgo.restoreAccountAndLogin(restoreAccountRequest)
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "restoreAccountAndLogin success: $result")
Log.d(TAG, "Geth node started")
} else {
Log.e(TAG, "restoreAccountAndLogin failed: $result")
}
StatusBackendClient.executeStatusGoRequest(
endpoint = "RestoreAccountAndLogin",
requestBody = restoreAccountRequest,
statusgoFunction = { Statusgo.restoreAccountAndLogin(restoreAccountRequest) }
)
}
private fun updateConfig(jsonConfigString: String, absRootDirPath: String, keystoreDirPath: String): String {
@@ -173,12 +171,7 @@ class AccountManager(private val reactContext: ReactApplicationContext) : ReactC
accountsData,
chatKey
)
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "saveAccountAndLoginWithKeycard result: $result")
Log.d(TAG, "Geth node started")
} else {
Log.e(TAG, "saveAccountAndLoginWithKeycard failed: $result")
}
utils.handleStatusGoResponse(result, "saveAccountAndLoginWithKeycard")
} catch (e: JSONException) {
Log.e(TAG, "JSON conversion failed: ${e.message}")
}
@@ -189,11 +182,7 @@ class AccountManager(private val reactContext: ReactApplicationContext) : ReactC
Log.d(TAG, "loginWithKeycard")
utils.migrateKeyStoreDir(accountData, password)
val result = Statusgo.loginWithKeycard(accountData, password, chatKey, nodeConfigJSON)
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "LoginWithKeycard result: $result")
} else {
Log.e(TAG, "LoginWithKeycard failed: $result")
}
utils.handleStatusGoResponse(result, "loginWithKeycard")
}
@ReactMethod
@@ -201,22 +190,17 @@ class AccountManager(private val reactContext: ReactApplicationContext) : ReactC
Log.d(TAG, "loginWithConfig")
utils.migrateKeyStoreDir(accountData, password)
val result = Statusgo.loginWithConfig(accountData, password, configJSON)
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "LoginWithConfig result: $result")
} else {
Log.e(TAG, "LoginWithConfig failed: $result")
}
utils.handleStatusGoResponse(result, "loginWithConfig")
}
@ReactMethod
fun loginAccount(request: String) {
Log.d(TAG, "loginAccount")
val result = Statusgo.loginAccount(request)
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "loginAccount result: $result")
} else {
Log.e(TAG, "loginAccount failed: $result")
}
StatusBackendClient.executeStatusGoRequest(
endpoint = "LoginAccount",
requestBody = request,
statusgoFunction = { Statusgo.loginAccount(request) }
)
}
@ReactMethod
@@ -224,16 +208,31 @@ class AccountManager(private val reactContext: ReactApplicationContext) : ReactC
val absRootDirPath = utils.getNoBackupDirectory()
val newKeystoreDir = utils.pathCombine(absRootDirPath, "keystore")
utils.executeRunnableStatusGoMethod(
{ Statusgo.verifyAccountPassword(newKeystoreDir, address, password) },
val jsonParams = JSONObject()
jsonParams.put("keyStoreDir", newKeystoreDir)
jsonParams.put("address", address)
jsonParams.put("password", password)
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "VerifyAccountPasswordV2",
requestBody = jsonParams.toString(),
statusgoFunction = { Statusgo.verifyAccountPasswordV2(jsonParams.toString()) },
callback
)
}
@ReactMethod
fun verifyDatabasePassword(keyUID: String, password: String, callback: Callback) {
utils.executeRunnableStatusGoMethod(
{ Statusgo.verifyDatabasePassword(keyUID, password) },
val jsonParams = JSONObject()
jsonParams.put("keyUID", keyUID)
jsonParams.put("password", password)
val jsonString = jsonParams.toString()
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "VerifyDatabasePasswordV2",
requestBody = jsonString,
statusgoFunction = { Statusgo.verifyDatabasePasswordV2(jsonString) },
callback
)
}
@@ -249,79 +248,136 @@ class AccountManager(private val reactContext: ReactApplicationContext) : ReactC
@ReactMethod
private fun initializeApplication(request: String, callback: Callback) {
Log.d(TAG, "initializeApplication")
Log.d(TAG, "[Initializing application $request")
utils.executeRunnableStatusGoMethod({ Statusgo.initializeApplication(request) }, callback)
StatusBackendClient.executeStatusGoRequestWithCallback(
"InitializeApplication",
request,
{ Statusgo.initializeApplication(request) },
callback
)
}
@ReactMethod
private fun acceptTerms(callback: Callback) {
Log.d(TAG, "acceptTerms")
utils.executeRunnableStatusGoMethod({ Statusgo.acceptTerms() }, callback)
StatusBackendClient.executeStatusGoRequestWithCallback(
"AcceptTerms",
"",
{ Statusgo.acceptTerms() },
callback
)
}
@ReactMethod
fun logout() {
Log.d(TAG, "logout")
val runnable = Runnable {
val result = Statusgo.logout()
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "Logout result: $result")
} else {
Log.e(TAG, "Logout failed: $result")
}
}
StatusThreadPoolExecutor.getInstance().execute(runnable)
StatusBackendClient.executeStatusGoRequest(
endpoint = "Logout",
requestBody = "",
statusgoFunction = { Statusgo.logout() }
)
}
@ReactMethod
fun multiAccountStoreAccount(json: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountStoreAccount(json) }, callback)
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "MultiAccountStoreAccount",
requestBody = json,
statusgoFunction = { Statusgo.multiAccountStoreAccount(json) },
callback = callback
)
}
@ReactMethod
fun multiAccountLoadAccount(json: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountLoadAccount(json) }, callback)
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "MultiAccountLoadAccount",
requestBody = json,
statusgoFunction = { Statusgo.multiAccountLoadAccount(json) },
callback = callback
)
}
@ReactMethod
fun multiAccountDeriveAddresses(json: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountDeriveAddresses(json) }, callback)
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "MultiAccountDeriveAddresses",
requestBody = json,
statusgoFunction = { Statusgo.multiAccountDeriveAddresses(json) },
callback = callback
)
}
@ReactMethod
fun multiAccountGenerateAndDeriveAddresses(json: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountGenerateAndDeriveAddresses(json) }, callback)
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "MultiAccountGenerateAndDeriveAddresses",
requestBody = json,
statusgoFunction = { Statusgo.multiAccountGenerateAndDeriveAddresses(json) },
callback = callback
)
}
@ReactMethod
fun multiAccountStoreDerived(json: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountStoreDerivedAccounts(json) }, callback)
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "MultiAccountStoreDerivedAccounts",
requestBody = json,
statusgoFunction = { Statusgo.multiAccountStoreDerivedAccounts(json) },
callback = callback
)
}
@ReactMethod
fun multiAccountImportMnemonic(json: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountImportMnemonic(json) }, callback)
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "MultiAccountImportMnemonic",
requestBody = json,
statusgoFunction = { Statusgo.multiAccountImportMnemonic(json) },
callback = callback
)
}
@ReactMethod
fun multiAccountImportPrivateKey(json: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountImportPrivateKey(json) }, callback)
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "MultiAccountImportPrivateKey",
requestBody = json,
statusgoFunction = { Statusgo.multiAccountImportPrivateKey(json) },
callback = callback
)
}
@ReactMethod
fun deleteMultiaccount(keyUID: String, callback: Callback) {
val keyStoreDir = utils.getKeyStorePath(keyUID)
utils.executeRunnableStatusGoMethod({ Statusgo.deleteMultiaccount(keyUID, keyStoreDir) }, callback)
val params = JSONObject().apply {
put("keyUID", keyUID)
put("keyStoreDir", keyStoreDir)
}
val jsonString = params.toString()
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "DeleteMultiaccountV2",
requestBody = jsonString,
statusgoFunction = { Statusgo.deleteMultiaccountV2(jsonString) },
callback
)
}
@ReactMethod
fun getRandomMnemonic(callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.getRandomMnemonic() }, callback)
StatusBackendClient.executeStatusGoRequestWithCallback(
"GetRandomMnemonic",
"",
{ Statusgo.getRandomMnemonic() },
callback
)
}
@ReactMethod
fun createAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic: String, callback: Callback) {
utils.executeRunnableStatusGoMethod(
StatusBackendClient.executeStatusGoRequestWithCallback(
"CreateAccountFromMnemonicAndDeriveAccountsForPaths",
mnemonic,
{ Statusgo.createAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic) },
callback
)
@@ -329,7 +385,12 @@ class AccountManager(private val reactContext: ReactApplicationContext) : ReactC
@ReactMethod
fun createAccountFromPrivateKey(json: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.createAccountFromPrivateKey(json) }, callback)
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "CreateAccountFromPrivateKey",
requestBody = json,
statusgoFunction = { Statusgo.createAccountFromPrivateKey(json) },
callback = callback
)
}
companion object {
@@ -9,6 +9,8 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import statusgo.Statusgo
import java.io.File
import org.json.JSONObject
import org.json.JSONException
class DatabaseManager(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
@@ -17,22 +19,43 @@ class DatabaseManager(private val reactContext: ReactApplicationContext) : React
override fun getName() = "DatabaseManager"
private fun getExportDBFile(): File {
StatusBackendClient.getInstance()?.let {
if (it.serverEnabled) {
return File(it.rootDataDir, exportDBFileName)
}
}
val pubDirectory = reactContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
return File(pubDirectory, exportDBFileName)
}
@ReactMethod
fun exportUnencryptedDatabase(accountData: String, password: String, callback: Callback) {
Log.d(TAG, "login")
Log.d(TAG, "exportUnencryptedDatabase")
val newFile = getExportDBFile()
utils.migrateKeyStoreDir(accountData, password)
val result = Statusgo.exportUnencryptedDatabase(accountData, password, newFile.absolutePath)
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "Login result: $result")
} else {
Log.e(TAG, "Login failed: $result")
try {
val accountJson = JSONObject(accountData)
val params = JSONObject().apply {
put("account", accountJson)
put("password", password)
put("databasePath", newFile.absolutePath)
}
val jsonParams = params.toString()
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "ExportUnencryptedDatabaseV2",
requestBody = jsonParams,
statusgoFunction = { Statusgo.exportUnencryptedDatabaseV2(jsonParams) },
callback = null
)
callback.invoke(newFile.absolutePath)
} catch (e: JSONException) {
Log.e(TAG, "Error parsing account data: ${e.message}")
}
}
@@ -43,11 +66,25 @@ class DatabaseManager(private val reactContext: ReactApplicationContext) : React
val newFile = getExportDBFile()
utils.migrateKeyStoreDir(accountData, password)
val result = Statusgo.importUnencryptedDatabase(accountData, password, newFile.absolutePath)
if (result.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "import result: $result")
} else {
Log.e(TAG, "import failed: $result")
try {
val accountJson = JSONObject(accountData)
val params = JSONObject().apply {
put("account", accountJson)
put("password", password)
put("databasePath", newFile.absolutePath)
}
val jsonParams = params.toString()
StatusBackendClient.executeStatusGoRequest(
endpoint = "ImportUnencryptedDatabaseV2",
requestBody = jsonParams,
statusgoFunction = { Statusgo.importUnencryptedDatabaseV2(jsonParams) }
)
} catch (e: JSONException) {
Log.e(TAG, "Error parsing account data: ${e.message}")
}
}
@@ -7,6 +7,7 @@ import com.facebook.react.bridge.Callback;
import android.util.Log;
import statusgo.Statusgo;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.function.Function;
import android.app.Activity;
import android.view.WindowManager;
@@ -39,67 +40,151 @@ public class EncryptionUtils extends ReactContextBaseJavaModule {
final String commonKeydir = this.utils.pathCombine(this.utils.getNoBackupDirectory(), "/keystore");
final String keydir = this.utils.pathCombine(commonKeydir, keyUID);
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.initKeystore(keydir), callback);
StatusBackendClient.executeStatusGoRequestWithCallback(
"InitKeystore",
keydir,
() -> Statusgo.initKeystore(keydir),
callback
);
}
@ReactMethod
public void reEncryptDbAndKeystore(final String keyUID, final String password, final String newPassword, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.changeDatabasePassword(keyUID, password, newPassword), callback);
JSONObject params = new JSONObject();
params.put("keyUID", keyUID);
params.put("oldPassword", password);
params.put("newPassword", newPassword);
String jsonParams = params.toString();
StatusBackendClient.executeStatusGoRequestWithCallback(
"ChangeDatabasePasswordV2",
jsonParams,
() -> Statusgo.changeDatabasePasswordV2(jsonParams),
callback
);
}
@ReactMethod
public void convertToKeycardAccount(final String keyUID, final String accountData, final String options, final String keycardUID, final String password,
final String newPassword, final Callback callback) throws JSONException {
final String keyStoreDir = this.utils.getKeyStorePath(keyUID);
this.utils.executeRunnableStatusGoMethod(() -> {
Statusgo.initKeystore(keyStoreDir);
return Statusgo.convertToKeycardAccount(accountData, options, keycardUID, password, newPassword);
}, callback);
JSONObject params = new JSONObject();
params.put("keyUID", keyUID);
params.put("account", new JSONObject(accountData));
params.put("settings", new JSONObject(options));
params.put("keycardUID", keycardUID);
params.put("oldPassword", password);
params.put("newPassword", newPassword);
final String jsonParams = params.toString();
StatusBackendClient.executeStatusGoRequest(
"InitKeystore",
keyStoreDir,
() -> Statusgo.initKeystore(keyStoreDir)
);
StatusBackendClient.executeStatusGoRequestWithCallback(
"ConvertToKeycardAccountV2",
jsonParams,
() -> Statusgo.convertToKeycardAccountV2(jsonParams),
callback
);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String encodeTransfer(final String to, final String value) {
return Statusgo.encodeTransfer(to, value);
try {
JSONObject params = new JSONObject();
params.put("to", to);
params.put("value", value);
String jsonParams = params.toString();
return StatusBackendClient.executeStatusGoRequestWithResult(
"EncodeTransferV2",
jsonParams,
() -> Statusgo.encodeTransferV2(jsonParams)
);
} catch (JSONException e) {
Log.e(TAG, "Error creating JSON for encodeTransfer: " + e.getMessage());
return null;
}
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String encodeFunctionCall(final String method, final String paramsJSON) {
return Statusgo.encodeFunctionCall(method, paramsJSON);
try {
JSONObject params = new JSONObject();
params.put("method", method);
params.put("paramsJSON", new JSONObject(paramsJSON));
String jsonString = params.toString();
return StatusBackendClient.executeStatusGoRequestWithResult(
"EncodeFunctionCallV2",
jsonString,
() -> Statusgo.encodeFunctionCallV2(jsonString)
);
} catch (JSONException e) {
Log.e(TAG, "Error creating JSON for encodeFunctionCall: " + e.getMessage());
return null;
}
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String decodeParameters(final String decodeParamJSON) {
return Statusgo.decodeParameters(decodeParamJSON);
return StatusBackendClient.executeStatusGoRequestWithResult(
"DecodeParameters",
decodeParamJSON,
() -> Statusgo.decodeParameters(decodeParamJSON)
);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String hexToNumber(final String hex) {
return Statusgo.hexToNumber(hex);
return StatusBackendClient.executeStatusGoRequestWithResult(
"HexToNumber",
hex,
() -> Statusgo.hexToNumber(hex)
);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String numberToHex(final String numString) {
return Statusgo.numberToHex(numString);
return StatusBackendClient.executeStatusGoRequestWithResult(
"NumberToHex",
numString,
() -> Statusgo.numberToHex(numString)
);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String sha3(final String str) {
return Statusgo.sha3(str);
return StatusBackendClient.executeStatusGoRequestWithResult(
"Sha3",
str,
() -> Statusgo.sha3(str)
);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String utf8ToHex(final String str) {
return Statusgo.utf8ToHex(str);
return StatusBackendClient.executeStatusGoRequestWithResult(
"Utf8ToHex",
str,
() -> Statusgo.utf8ToHex(str)
);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String hexToUtf8(final String str) {
return Statusgo.hexToUtf8(str);
return StatusBackendClient.executeStatusGoRequestWithResult(
"HexToUtf8",
str,
() -> Statusgo.hexToUtf8(str)
);
}
@ReactMethod(isBlockingSynchronousMethod = true)
public String serializeLegacyKey(final String publicKey) {
return Statusgo.serializeLegacyKey(publicKey);
return StatusBackendClient.executeStatusGoRequestWithResult(
"SerializeLegacyKey",
publicKey,
() -> Statusgo.serializeLegacyKey(publicKey)
);
}
@ReactMethod
@@ -130,22 +215,46 @@ public class EncryptionUtils extends ReactContextBaseJavaModule {
@ReactMethod
public void hashTransaction(final String txArgsJSON, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.hashTransaction(txArgsJSON), callback);
StatusBackendClient.executeStatusGoRequestWithCallback(
"HashTransaction",
txArgsJSON,
() -> Statusgo.hashTransaction(txArgsJSON),
callback
);
}
@ReactMethod
public void hashMessage(final String message, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.hashMessage(message), callback);
StatusBackendClient.executeStatusGoRequestWithCallback(
"HashMessage",
message,
() -> Statusgo.hashMessage(message),
callback
);
}
@ReactMethod
public void multiformatDeserializePublicKey(final String multiCodecKey, final String base58btc, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiformatDeserializePublicKey(multiCodecKey,base58btc), callback);
JSONObject params = new JSONObject();
params.put("key", multiCodecKey);
params.put("outBase", base58btc);
String jsonParams = params.toString();
StatusBackendClient.executeStatusGoRequestWithCallback(
"MultiformatDeserializePublicKeyV2",
jsonParams,
() -> Statusgo.multiformatDeserializePublicKeyV2(jsonParams),
callback
);
}
@ReactMethod
public void deserializeAndCompressKey(final String desktopKey, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.deserializeAndCompressKey(desktopKey), callback);
StatusBackendClient.executeStatusGoRequestWithCallback(
"DeserializeAndCompressKey",
desktopKey,
() -> Statusgo.deserializeAndCompressKey(desktopKey),
callback
);
}
@ReactMethod
@@ -160,7 +269,12 @@ public class EncryptionUtils extends ReactContextBaseJavaModule {
@ReactMethod
public void signMessage(final String rpcParams, final Callback callback) throws JSONException {
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.signMessage(rpcParams), callback);
StatusBackendClient.executeStatusGoRequestWithCallback(
"SignMessage",
rpcParams,
() -> Statusgo.signMessage(rpcParams),
callback
);
}
@ReactMethod
@@ -206,7 +206,12 @@ class LogManager(private val reactContext: ReactApplicationContext) : ReactConte
put("LogRequestFile", getRequestLogFile().absolutePath)
}
val config = jsonConfig.toString()
utils.executeRunnableStatusGoMethod({ Statusgo.initLogging(config) }, callback)
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "InitLogging",
requestBody = config,
statusgoFunction = { Statusgo.initLogging(config) },
callback = callback
)
}
@ReactMethod(isBlockingSynchronousMethod = true)
@@ -16,7 +16,12 @@ class NetworkManager(private val reactContext: ReactApplicationContext) : ReactC
@ReactMethod
fun startSearchForLocalPairingPeers(callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.startSearchForLocalPairingPeers() }, callback)
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "StartSearchForLocalPairingPeers",
requestBody = "",
statusgoFunction = { Statusgo.startSearchForLocalPairingPeers() },
callback = callback
)
}
@ReactMethod
@@ -26,48 +31,85 @@ class NetworkManager(private val reactContext: ReactApplicationContext) : ReactC
val keyUID = senderConfig.getString("keyUID")
val keyStorePath = utils.getKeyStorePath(keyUID)
senderConfig.put("keystorePath", keyStorePath)
val jsonString = jsonConfig.toString()
utils.executeRunnableStatusGoMethod(
{ Statusgo.getConnectionStringForBootstrappingAnotherDevice(jsonConfig.toString()) },
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "GetConnectionStringForBootstrappingAnotherDevice",
requestBody = jsonString,
statusgoFunction = { Statusgo.getConnectionStringForBootstrappingAnotherDevice(jsonString) },
callback
)
}
@ReactMethod
fun inputConnectionStringForBootstrapping(connectionString: String, configJSON: String, callback: Callback) {
val jsonConfig = JSONObject(configJSON)
utils.executeRunnableStatusGoMethod(
{ Statusgo.inputConnectionStringForBootstrapping(connectionString, jsonConfig.toString()) },
val receiverClientConfig = JSONObject(configJSON)
val params = JSONObject().apply {
put("connectionString", connectionString)
put("receiverClientConfig", receiverClientConfig)
}
val jsonString = params.toString()
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "InputConnectionStringForBootstrappingV2",
requestBody = jsonString,
statusgoFunction = { Statusgo.inputConnectionStringForBootstrappingV2(jsonString) },
callback
)
}
@ReactMethod
fun sendTransactionWithSignature(txArgsJSON: String, signature: String, callback: Callback) {
utils.executeRunnableStatusGoMethod(
{ Statusgo.sendTransactionWithSignature(txArgsJSON, signature) },
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "SendTransactionWithSignature",
requestBody = txArgsJSON,
statusgoFunction = { Statusgo.sendTransactionWithSignature(txArgsJSON, signature) },
callback
)
}
@ReactMethod
fun sendTransaction(txArgsJSON: String, password: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.sendTransaction(txArgsJSON, password) }, callback)
val jsonParams = JSONObject().apply {
put("txArgs", JSONObject(txArgsJSON))
put("password", password)
}
val jsonString = jsonParams.toString()
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "SendTransactionV2",
requestBody = jsonString,
statusgoFunction = { Statusgo.sendTransactionV2(jsonString) },
callback
)
}
@ReactMethod
fun callRPC(payload: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.callRPC(payload) }, callback)
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "CallRPC",
requestBody = payload,
statusgoFunction = { Statusgo.callRPC(payload) },
callback = callback
)
}
@ReactMethod
fun callPrivateRPC(payload: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.callPrivateRPC(payload) }, callback)
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "CallPrivateRPC",
requestBody = payload,
statusgoFunction = { Statusgo.callPrivateRPC(payload) },
callback = callback
)
}
@ReactMethod
fun recover(rpcParams: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.recover(rpcParams) }, callback)
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "Recover",
requestBody = rpcParams,
statusgoFunction = { Statusgo.recover(rpcParams) },
callback
)
}
@ReactMethod
@@ -77,22 +119,33 @@ class NetworkManager(private val reactContext: ReactApplicationContext) : ReactC
val keyUID = senderConfig.getString("loggedInKeyUid")
val keyStorePath = utils.getKeyStorePath(keyUID)
senderConfig.put("keystorePath", keyStorePath)
val jsonString = jsonConfig.toString()
utils.executeRunnableStatusGoMethod(
{ Statusgo.getConnectionStringForExportingKeypairsKeystores(jsonConfig.toString()) },
callback)
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "GetConnectionStringForExportingKeypairsKeystores",
requestBody = jsonString,
statusgoFunction = { Statusgo.getConnectionStringForExportingKeypairsKeystores(jsonString) },
callback = callback
)
}
@ReactMethod
fun inputConnectionStringForImportingKeypairsKeystores(connectionString: String, configJSON: String, callback: Callback) {
val jsonConfig = JSONObject(configJSON)
val receiverConfig = jsonConfig.getJSONObject("receiverConfig")
val keystoreFilesReceiverClientConfig = JSONObject(configJSON)
val receiverConfig = keystoreFilesReceiverClientConfig.getJSONObject("receiverConfig")
val keyStorePath = utils.pathCombine(utils.getNoBackupDirectory(), "/keystore")
receiverConfig.put("keystorePath", keyStorePath)
utils.executeRunnableStatusGoMethod(
{ Statusgo.inputConnectionStringForImportingKeypairsKeystores(connectionString, jsonConfig.toString()) },
callback
val params = JSONObject().apply {
put("connectionString", connectionString)
put("keystoreFilesReceiverClientConfig", keystoreFilesReceiverClientConfig)
}
val jsonString = params.toString()
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "InputConnectionStringForImportingKeypairsKeystoresV2",
requestBody = jsonString,
statusgoFunction = { Statusgo.inputConnectionStringForImportingKeypairsKeystoresV2(jsonString) },
callback = callback
)
}
}
@@ -0,0 +1,209 @@
package im.status.ethereum.module
import android.util.Log
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import okhttp3.WebSocket
import okhttp3.WebSocketListener
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.Callback
import java.net.SocketException
import java.net.SocketTimeoutException
import java.util.concurrent.TimeUnit
class StatusBackendClient(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
companion object {
private const val TAG = "StatusBackendClient"
private val JSON = "application/json; charset=utf-8".toMediaType()
private const val TIMEOUT_SECONDS = 30L
@Volatile private var instance: StatusBackendClient? = null
private lateinit var utils: Utils
fun getInstance(): StatusBackendClient? = instance
@JvmStatic
fun executeStatusGoRequest(
endpoint: String,
requestBody: String,
statusgoFunction: () -> String
) {
val statusBackendClient = getInstance()
if (statusBackendClient?.serverEnabled == true) {
val result = statusBackendClient.request(endpoint, requestBody)
result.onSuccess { response ->
utils.handleStatusGoResponse(response, endpoint)
}.onFailure { error ->
Log.e(TAG, "request to $endpoint failed", error)
}
} else {
val result = statusgoFunction()
utils.handleStatusGoResponse(result, endpoint)
}
}
@JvmStatic
fun executeStatusGoRequestWithCallback(
endpoint: String,
requestBody: String,
statusgoFunction: () -> String,
callback: Callback?
) {
val statusBackendClient = getInstance()
if (statusBackendClient?.serverEnabled == true) {
val runnable = Runnable {
val result = statusBackendClient.request(endpoint, requestBody)
result.onSuccess { response ->
callback?.invoke(response)
}.onFailure { error ->
Log.e(TAG, "request to $endpoint failed", error)
callback?.invoke(false)
}
}
StatusThreadPoolExecutor.getInstance().execute(runnable)
} else {
utils.executeRunnableStatusGoMethod(statusgoFunction, callback)
}
}
@JvmStatic
fun executeStatusGoRequestWithResult(
endpoint: String,
requestBody: String,
statusgoFunction: () -> String
): String {
val statusBackendClient = getInstance()
return if (statusBackendClient?.serverEnabled == true) {
val result = statusBackendClient.request(endpoint, requestBody)
result.getOrElse { error ->
Log.e(TAG, "request to $endpoint failed", error)
""
}
} else {
statusgoFunction()
}
}
}
init {
instance = this
utils = Utils(reactContext)
}
override fun getName(): String = "StatusBackendClient"
private val httpClient = OkHttpClient.Builder()
.connectTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS)
.writeTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS)
.readTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build()
private val wsClient = OkHttpClient.Builder()
.retryOnConnectionFailure(true)
.build()
private var webSocket: WebSocket? = null
@Volatile var serverEnabled = false
@Volatile private var statusGoEndpoint: String? = null
@Volatile private var signalEndpoint: String? = null
@Volatile var rootDataDir: String? = null
@ReactMethod
fun configStatusBackendServer(
serverEnabled: Boolean,
statusGoEndpoint: String,
signalEndpoint: String,
rootDataDir: String
) {
configure(serverEnabled, statusGoEndpoint, signalEndpoint, rootDataDir)
}
private fun configure(
serverEnabled: Boolean,
statusGoEndpoint: String,
signalEndpoint: String,
rootDataDir: String
) {
Log.d(TAG, "configure: serverEnabled=$serverEnabled, statusGoEndpoint=$statusGoEndpoint, " +
"signalEndpoint=$signalEndpoint, rootDataDir=$rootDataDir")
this.serverEnabled = serverEnabled
if (serverEnabled) {
this.statusGoEndpoint = statusGoEndpoint
this.signalEndpoint = signalEndpoint
this.rootDataDir = rootDataDir
connectWebSocket()
} else {
disconnectWebSocket()
this.statusGoEndpoint = null
this.signalEndpoint = null
this.rootDataDir = null
}
}
private fun connectWebSocket() {
if (!serverEnabled || signalEndpoint == null) {
return
}
val request = Request.Builder()
.url("$signalEndpoint")
.build()
webSocket = wsClient.newWebSocket(request, object : WebSocketListener() {
override fun onMessage(webSocket: WebSocket, text: String) {
StatusModule.getInstance()?.handleSignal(text)
}
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
Log.e(TAG, "WebSocket error: ${t.message}")
}
})
}
private fun disconnectWebSocket() {
webSocket?.cancel()
webSocket = null
}
fun request(endpoint: String, body: String): Result<String> {
if (!serverEnabled || statusGoEndpoint == null) {
return Result.failure(IllegalStateException("Status backend server is not enabled"))
}
val fullUrl = "$statusGoEndpoint$endpoint"
return try {
val request = Request.Builder()
.url(fullUrl)
.post(body.toRequestBody(JSON))
.build()
httpClient.newCall(request).execute().use { response ->
val responseBody = response.body?.string() ?: ""
if (response.isSuccessful) {
Log.d(TAG, "Request to $endpoint succeeded: $responseBody")
Result.success(responseBody)
} else {
val errorMsg = "Request failed with code ${response.code}: $responseBody"
Log.e(TAG, "Request to $endpoint failed: $errorMsg")
Result.failure(Exception(errorMsg))
}
}
} catch (e: Exception) {
when (e) {
is SocketTimeoutException -> Log.e(TAG, "Request to $endpoint timed out", e)
is SocketException -> Log.e(TAG, "Socket error for $endpoint", e)
else -> Log.e(TAG, "Request to $endpoint failed with exception", e)
}
Result.failure(e)
}
}
}
@@ -9,12 +9,17 @@ import statusgo.SignalHandler
import statusgo.Statusgo
import org.json.JSONException
import android.view.WindowManager
import org.json.JSONObject
class StatusModule(private val reactContext: ReactApplicationContext, private val rootedDevice: Boolean) : ReactContextBaseJavaModule(reactContext), LifecycleEventListener, SignalHandler {
companion object {
private const val TAG = "StatusModule"
private var module: StatusModule? = null
fun getInstance(): StatusModule? {
return module
}
}
private val utils: Utils = Utils(reactContext)
@@ -56,45 +61,97 @@ class StatusModule(private val reactContext: ReactApplicationContext, private va
@ReactMethod
fun connectionChange(type: String, isExpensive: Boolean) {
Log.d(TAG, "ConnectionChange: $type, is expensive $isExpensive")
Statusgo.connectionChange(type, if (isExpensive) 1 else 0)
val params = JSONObject().apply {
put("type", type)
put("expensive", isExpensive)
}
val jsonString = params.toString()
StatusBackendClient.executeStatusGoRequest(
endpoint = "ConnectionChangeV2",
requestBody = jsonString,
statusgoFunction = { Statusgo.connectionChangeV2(jsonString) }
)
}
@ReactMethod
fun appStateChange(type: String) {
Log.d(TAG, "AppStateChange: $type")
Statusgo.appStateChange(type)
fun appStateChange(state: String) {
Log.d(TAG, "AppStateChange: $state")
val params = JSONObject().apply {
put("state", state)
}
val jsonString = params.toString()
StatusBackendClient.executeStatusGoRequest(
endpoint = "AppStateChangeV2",
requestBody = jsonString,
statusgoFunction = { Statusgo.appStateChangeV2(jsonString) }
)
}
@ReactMethod
fun startLocalNotifications() {
Log.d(TAG, "startLocalNotifications")
Statusgo.startLocalNotifications()
StatusBackendClient.executeStatusGoRequest(
endpoint = "StartLocalNotifications",
requestBody = "",
statusgoFunction = { Statusgo.startLocalNotifications() }
)
}
@ReactMethod
fun getNodeConfig(callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.getNodeConfig() }, callback)
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "GetNodeConfig",
requestBody = "",
statusgoFunction = { Statusgo.getNodeConfig() },
callback = callback
)
}
@ReactMethod
fun addCentralizedMetric(request: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.addCentralizedMetric(request) }, callback)
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "AddCentralizedMetric",
requestBody = request,
statusgoFunction = { Statusgo.addCentralizedMetric(request) },
callback
)
}
@ReactMethod
fun toggleCentralizedMetrics(request: String, callback: Callback) {
utils.executeRunnableStatusGoMethod({ Statusgo.toggleCentralizedMetrics(request) }, callback)
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "ToggleCentralizedMetrics",
requestBody = request,
statusgoFunction = { Statusgo.toggleCentralizedMetrics(request) },
callback
)
}
@ReactMethod
fun deleteImportedKey(keyUID: String, address: String, password: String, callback: Callback) {
val keyStoreDir = utils.getKeyStorePath(keyUID)
utils.executeRunnableStatusGoMethod({ Statusgo.deleteImportedKey(address, password, keyStoreDir) }, callback)
val params = JSONObject().apply {
put("address", address)
put("password", password)
put("keyStoreDir", keyStoreDir)
}
val jsonString = params.toString()
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "DeleteImportedKeyV2",
requestBody = jsonString,
statusgoFunction = { Statusgo.deleteImportedKeyV2(jsonString) },
callback
)
}
@ReactMethod(isBlockingSynchronousMethod = true)
fun fleets(): String {
return Statusgo.fleets()
return StatusBackendClient.executeStatusGoRequestWithResult(
endpoint = "Fleets",
requestBody = "",
statusgoFunction = { Statusgo.fleets() }
)
}
override fun getConstants(): Map<String, Any>? {
@@ -9,7 +9,12 @@ import statusgo.Statusgo
class StatusPackage(private val rootedDevice: Boolean) : ReactPackage {
companion object {
fun getImageTLSCert(): String = Statusgo.imageServerTLSCert()
fun getImageTLSCert(): String =
StatusBackendClient.executeStatusGoRequestWithResult(
endpoint = "ImageServerTLSCert",
requestBody = "",
statusgoFunction = { Statusgo.imageServerTLSCert() }
)
}
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
@@ -26,6 +31,7 @@ class StatusPackage(private val rootedDevice: Boolean) : ReactPackage {
add(NetworkManager(reactContext))
add(MailManager(reactContext))
add(RNSelectableTextInputModule(reactContext))
add(StatusBackendClient(reactContext))
}
return modules
@@ -25,6 +25,11 @@ class Utils(private val reactContext: ReactApplicationContext) : ReactContextBas
}
fun getNoBackupDirectory(): String {
StatusBackendClient.getInstance()?.let { client ->
if (client.serverEnabled && client.rootDataDir != null) {
return client.rootDataDir!!
}
}
return reactContext.noBackupFilesDir.absolutePath
}
@@ -34,6 +39,11 @@ class Utils(private val reactContext: ReactApplicationContext) : ReactContextBas
}
fun getPublicStorageDirectory(): File? {
StatusBackendClient.getInstance()?.let { client ->
if (client.serverEnabled && client.rootDataDir != null) {
return File(client.rootDataDir!!)
}
}
// Environment.getExternalStoragePublicDirectory doesn't work as expected on Android Q
// https://developer.android.com/reference/android/os/Environment#getExternalStoragePublicDirectory(java.lang.String)
return reactContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
@@ -69,8 +79,22 @@ class Utils(private val reactContext: ReactApplicationContext) : ReactContextBas
val keydirFile = File(keydir)
if (!keydirFile.exists() || keydirFile.list().isEmpty()) {
Log.d(TAG, "migrateKeyStoreDir")
Statusgo.migrateKeyStoreDir(accountData, password, commonKeydir, keydir)
Statusgo.initKeystore(keydir)
val jsonParams = JSONObject()
jsonParams.put("account", JSONObject(accountData)) // Remove 'new' keyword
jsonParams.put("password", password)
jsonParams.put("oldDir", commonKeydir)
jsonParams.put("newDir", keydir)
StatusBackendClient.executeStatusGoRequest(
endpoint = "MigrateKeyStoreDirV2",
requestBody = jsonParams.toString(),
statusgoFunction = { Statusgo.migrateKeyStoreDirV2(jsonParams.toString()) }
)
StatusBackendClient.executeStatusGoRequest(
endpoint = "InitKeystore",
requestBody = keydir,
statusgoFunction = { Statusgo.initKeystore(keydir) }
)
}
} catch (e: JSONException) {
Log.e(TAG, "JSON conversion failed: ${e.message}")
@@ -99,15 +123,15 @@ class Utils(private val reactContext: ReactApplicationContext) : ReactContextBas
return false
}
fun executeRunnableStatusGoMethod(method: Supplier<String>, callback: Callback) {
fun executeRunnableStatusGoMethod(method: Supplier<String>, callback: Callback?) {
if (!checkAvailability()) {
callback.invoke(false)
callback?.invoke(false)
return
}
val runnableTask = Runnable {
val res = method.get()
callback.invoke(res)
callback?.invoke(res)
}
StatusThreadPoolExecutor.getInstance().execute(runnableTask)
@@ -115,7 +139,15 @@ class Utils(private val reactContext: ReactApplicationContext) : ReactContextBas
@ReactMethod
fun validateMnemonic(seed: String, callback: Callback) {
executeRunnableStatusGoMethod({ Statusgo.validateMnemonic(seed) }, callback)
val jsonParams = JSONObject()
jsonParams.put("mnemonic", seed)
val jsonString = jsonParams.toString()
StatusBackendClient.executeStatusGoRequestWithCallback(
endpoint = "ValidateMnemonicV2",
requestBody = jsonString,
statusgoFunction = { Statusgo.validateMnemonicV2(jsonString) },
callback
)
}
fun is24Hour(): Boolean {
@@ -124,17 +156,29 @@ class Utils(private val reactContext: ReactApplicationContext) : ReactContextBas
@ReactMethod(isBlockingSynchronousMethod = true)
fun checkAddressChecksum(address: String): String {
return Statusgo.checkAddressChecksum(address)
return StatusBackendClient.executeStatusGoRequestWithResult(
endpoint = "CheckAddressChecksum",
requestBody = address,
statusgoFunction = { Statusgo.checkAddressChecksum(address) }
)
}
@ReactMethod(isBlockingSynchronousMethod = true)
fun isAddress(address: String): String {
return Statusgo.isAddress(address)
return StatusBackendClient.executeStatusGoRequestWithResult(
endpoint = "IsAddress",
requestBody = address,
statusgoFunction = { Statusgo.isAddress(address) }
)
}
@ReactMethod(isBlockingSynchronousMethod = true)
fun toChecksumAddress(address: String): String {
return Statusgo.toChecksumAddress(address)
return StatusBackendClient.executeStatusGoRequestWithResult(
endpoint = "ToChecksumAddress",
requestBody = address,
statusgoFunction = { Statusgo.toChecksumAddress(address) }
)
}
fun readableArrayToStringArray(r: ReadableArray): Array<String> {
@@ -150,6 +194,19 @@ class Utils(private val reactContext: ReactApplicationContext) : ReactContextBas
@ReactMethod(isBlockingSynchronousMethod = true)
fun validateConnectionString(connectionString: String): String {
return Statusgo.validateConnectionString(connectionString)
return StatusBackendClient.executeStatusGoRequestWithResult(
endpoint = "ValidateConnectionString",
requestBody = connectionString,
statusgoFunction = { Statusgo.validateConnectionString(connectionString) }
)
}
fun handleStatusGoResponse(response: String, source: String) {
//TODO(frank) we should remove sensitive data from the response
if (response.startsWith("{\"error\":\"\"")) {
Log.d(TAG, "$source success: $response")
} else {
Log.e(TAG, "$source failed: $response")
}
}
}
@@ -870,7 +870,11 @@ public class PushNotificationHelper {
public void start() {
Log.e(LOG_TAG, "Starting Foreground Service");
Intent serviceIntent = new Intent(context, ForegroundService.class);
context.startService(serviceIntent);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(serviceIntent);
} else {
context.startService(serviceIntent);
}
this.registerBroadcastReceiver();
}
@@ -3,6 +3,7 @@
#import "React/RCTEventDispatcher.h"
#import "Statusgo.h"
#import "Utils.h"
#import "StatusBackendClient.h"
@implementation AccountManager
@@ -12,23 +13,29 @@ RCT_EXPORT_METHOD(createAccountAndLogin:(NSString *)request) {
#if DEBUG
NSLog(@"createAccountAndLogin() method called");
#endif
StatusgoCreateAccountAndLogin(request);
[StatusBackendClient executeStatusGoRequest:@"CreateAccountAndLogin"
body:request
statusgoFunction:^NSString *{
return StatusgoCreateAccountAndLogin(request);
}];
}
RCT_EXPORT_METHOD(restoreAccountAndLogin:(NSString *)request) {
#if DEBUG
NSLog(@"restoreAccountAndLogin() method called");
#endif
StatusgoRestoreAccountAndLogin(request);
[StatusBackendClient executeStatusGoRequest:@"RestoreAccountAndLogin"
body:request
statusgoFunction:^NSString *{
return StatusgoRestoreAccountAndLogin(request);
}];
}
-(NSString *) prepareDirAndUpdateConfig:(NSString *)config
withKeyUID:(NSString *)keyUID {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error = nil;
NSURL *rootUrl =[[fileManager
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];
NSURL *rootUrl =[Utils getRootUrl];
NSURL *absTestnetFolderName = [rootUrl URLByAppendingPathComponent:@"ethereum/testnet"];
if (![fileManager fileExistsAtPath:absTestnetFolderName.path])
@@ -102,8 +109,24 @@ RCT_EXPORT_METHOD(deleteMultiaccount:(NSString *)keyUID
NSLog(@"DeleteMultiaccount() method called");
#endif
NSURL *multiaccountKeystoreDir = [Utils getKeyStoreDirForKeyUID:keyUID];
NSString *result = StatusgoDeleteMultiaccount(keyUID, multiaccountKeystoreDir.path);
callback(@[result]);
NSDictionary *params = @{
@"keyUID": keyUID,
@"keyStoreDir": multiaccountKeystoreDir.path
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", error);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequestWithCallback:@"DeleteMultiaccountV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoDeleteMultiaccountV2(jsonString);
}
callback:callback];
}
RCT_EXPORT_METHOD(prepareDirAndUpdateConfig:(NSString *)keyUID
@@ -163,36 +186,69 @@ RCT_EXPORT_METHOD(loginWithConfig:(NSString *)accountData
RCT_EXPORT_METHOD(loginAccount:(NSString *)request) {
#if DEBUG
NSLog(@"LoginAccount() method called");
NSLog(@"loginAccount() method called");
#endif
NSString *result = StatusgoLoginAccount(request);
NSLog(@"%@", result);
[StatusBackendClient executeStatusGoRequest:@"LoginAccount"
body:request
statusgoFunction:^NSString *{
return StatusgoLoginAccount(request);
}];
}
RCT_EXPORT_METHOD(verify:(NSString *)address
password:(NSString *)password
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"VerifyAccountPassword() method called");
NSLog(@"VerifyAccountPasswordV2() method called");
#endif
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl =[[fileManager
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];
NSURL *absKeystoreUrl = [rootUrl URLByAppendingPathComponent:@"keystore"];
NSString *result = StatusgoVerifyAccountPassword(absKeystoreUrl.path, address, password);
callback(@[result]);
NSURL *rootUrl = [Utils getRootUrl];
NSString *keystorePath = [rootUrl.path stringByAppendingPathComponent:@"keystore"];
NSDictionary *params = @{
@"keyStoreDir": keystorePath,
@"address": address,
@"password": password
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", error);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequestWithCallback:@"VerifyAccountPasswordV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoVerifyAccountPasswordV2(jsonString);
}
callback:callback];
}
RCT_EXPORT_METHOD(verifyDatabasePassword:(NSString *)keyUID
password:(NSString *)password
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"VerifyDatabasePassword() method called");
NSLog(@"VerifyDatabasePasswordV2() method called");
#endif
NSString *result = StatusgoVerifyDatabasePassword(keyUID, password);
callback(@[result]);
NSDictionary *params = @{
@"keyUID": keyUID,
@"password": password
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", error);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequestWithCallback:@"VerifyDatabasePasswordV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoVerifyDatabasePasswordV2(jsonString);
}
callback:callback];
}
RCT_EXPORT_METHOD(initializeApplication:(NSString *)request
@@ -200,62 +256,173 @@ RCT_EXPORT_METHOD(initializeApplication:(NSString *)request
#if DEBUG
NSLog(@"initializeApplication() method called");
#endif
NSString *result = StatusgoInitializeApplication(request);
callback(@[result]);
[StatusBackendClient executeStatusGoRequestWithCallback:@"InitializeApplication"
body:request
statusgoFunction:^NSString *{
return StatusgoInitializeApplication(request);
}
callback:callback];
}
RCT_EXPORT_METHOD(acceptTerms:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"acceptTerms() method called");
#endif
NSString *result = StatusgoAcceptTerms();
callback(@[result]);
[StatusBackendClient executeStatusGoRequestWithCallback:@"AcceptTerms"
body:@""
statusgoFunction:^NSString *{
return StatusgoAcceptTerms();
}
callback:callback];
}
RCT_EXPORT_METHOD(openAccounts:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"OpenAccounts() method called");
#endif
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl =[[fileManager
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];
NSURL *rootUrl =[Utils getRootUrl];
NSString *result = StatusgoOpenAccounts(rootUrl.path);
callback(@[result]);
}
RCT_EXPORT_METHOD(logout) {
#if DEBUG
NSLog(@"Logout() method called");
NSLog(@"Logout() method called");
#endif
NSString *result = StatusgoLogout();
[StatusBackendClient executeStatusGoRequest:@"Logout"
body:@""
statusgoFunction:^NSString *{
return StatusgoLogout();
}];
}
NSLog(@"%@", result);
RCT_EXPORT_METHOD(multiAccountStoreAccount:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountStoreAccount() method called");
#endif
[StatusBackendClient executeStatusGoRequestWithCallback:@"MultiAccountStoreAccount"
body:json
statusgoFunction:^NSString *{
return StatusgoMultiAccountStoreAccount(json);
}
callback:callback];
}
RCT_EXPORT_METHOD(multiAccountLoadAccount:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountLoadAccount() method called");
#endif
[StatusBackendClient executeStatusGoRequestWithCallback:@"MultiAccountLoadAccount"
body:json
statusgoFunction:^NSString *{
return StatusgoMultiAccountLoadAccount(json);
}
callback:callback];
}
RCT_EXPORT_METHOD(multiAccountDeriveAddresses:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"multiAccountDeriveAddresses() method called");
#endif
[StatusBackendClient executeStatusGoRequestWithCallback:@"MultiAccountDeriveAddresses"
body:json
statusgoFunction:^NSString *{
return StatusgoMultiAccountDeriveAddresses(json);
}
callback:callback];
}
RCT_EXPORT_METHOD(multiAccountGenerateAndDeriveAddresses:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountGenerateAndDeriveAddresses() method called");
#endif
[StatusBackendClient executeStatusGoRequestWithCallback:@"MultiAccountGenerateAndDeriveAddresses"
body:json
statusgoFunction:^NSString *{
return StatusgoMultiAccountGenerateAndDeriveAddresses(json);
}
callback:callback];
}
RCT_EXPORT_METHOD(multiAccountStoreDerived:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountStoreDerived() method called");
#endif
[StatusBackendClient executeStatusGoRequestWithCallback:@"MultiAccountStoreDerivedAccounts"
body:json
statusgoFunction:^NSString *{
return StatusgoMultiAccountStoreDerivedAccounts(json);
}
callback:callback];
}
RCT_EXPORT_METHOD(multiAccountImportMnemonic:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountImportMnemonic() method called");
#endif
[StatusBackendClient executeStatusGoRequestWithCallback:@"MultiAccountImportMnemonic"
body:json
statusgoFunction:^NSString *{
return StatusgoMultiAccountImportMnemonic(json);
}
callback:callback];
}
RCT_EXPORT_METHOD(multiAccountImportPrivateKey:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountImportPrivateKey() method called");
#endif
[StatusBackendClient executeStatusGoRequestWithCallback:@"MultiAccountImportPrivateKey"
body:json
statusgoFunction:^NSString *{
return StatusgoMultiAccountImportPrivateKey(json);
}
callback:callback];
}
RCT_EXPORT_METHOD(getRandomMnemonic:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"GetRandomMnemonic() method called");
#endif
NSString *result = StatusgoGetRandomMnemonic();
callback(@[result]);
[StatusBackendClient executeStatusGoRequestWithCallback:@"GetRandomMnemonic"
body:@""
statusgoFunction:^NSString *{
return StatusgoGetRandomMnemonic();
}
callback:callback];
}
RCT_EXPORT_METHOD(createAccountFromMnemonicAndDeriveAccountsForPaths:(NSString *)mnemonic callback:(RCTResponseSenderBlock)callback) {
RCT_EXPORT_METHOD(createAccountFromMnemonicAndDeriveAccountsForPaths:(NSString *)mnemonic
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"createAccountFromMnemonicAndDeriveAccountsForPaths() method called");
#endif
NSString *result = StatusgoCreateAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic);
callback(@[result]);
[StatusBackendClient executeStatusGoRequestWithCallback:@"CreateAccountFromMnemonicAndDeriveAccountsForPaths"
body:mnemonic
statusgoFunction:^NSString *{
return StatusgoCreateAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic);
}
callback:callback];
}
RCT_EXPORT_METHOD(createAccountFromPrivateKey:(NSString *)configJSON callback:(RCTResponseSenderBlock)callback) {
RCT_EXPORT_METHOD(createAccountFromPrivateKey:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"createAccountFromPrivateKey() method called");
#endif
NSString *result = StatusgoCreateAccountFromPrivateKey(configJSON);
callback(@[result]);
[StatusBackendClient executeStatusGoRequestWithCallback:@"CreateAccountFromPrivateKey"
body:json
statusgoFunction:^NSString *{
return StatusgoCreateAccountFromPrivateKey(json);
}
callback:callback];
}
@end
@@ -3,7 +3,7 @@
#import "React/RCTEventDispatcher.h"
#import "Statusgo.h"
#import "Utils.h"
#import "StatusBackendClient.h"
@implementation DatabaseManager
RCT_EXPORT_MODULE();
@@ -16,8 +16,31 @@ RCT_EXPORT_METHOD(exportUnencryptedDatabase:(NSString *)accountData
#endif
NSString *filePath = [Utils getExportDbFilePath];
StatusgoExportUnencryptedDatabase(accountData, password, filePath);
NSDictionary *params = @{
@"account": [NSJSONSerialization JSONObjectWithData:[accountData dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil],
@"password": password,
@"databasePath": filePath
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", [error localizedDescription]);
callback(@[filePath]);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequestWithCallback:@"ExportUnencryptedDatabaseV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoExportUnencryptedDatabaseV2(jsonString);
}
callback:nil];
callback(@[filePath]);
}
@@ -26,7 +49,31 @@ RCT_EXPORT_METHOD(importUnencryptedDatabase:(NSString *)accountData
#if DEBUG
NSLog(@"importUnencryptedDatabase() method called");
#endif
"";
NSString *filePath = [Utils getExportDbFilePath];
[Utils migrateKeystore:accountData password:password];
NSDictionary *params = @{
@"account": [NSJSONSerialization JSONObjectWithData:[accountData dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil],
@"password": password,
@"databasePath": filePath
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", [error localizedDescription]);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequest:@"ImportUnencryptedDatabaseV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoImportUnencryptedDatabaseV2(jsonString);
}];
}
@@ -3,6 +3,7 @@
#import "React/RCTEventDispatcher.h"
#import "Statusgo.h"
#import "Utils.h"
#import "StatusBackendClient.h"
@implementation EncryptionUtils
@@ -15,21 +16,14 @@ RCT_EXPORT_METHOD(initKeystore:(NSString *)keyUID
#if DEBUG
NSLog(@"initKeystore() method called");
#endif
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl =[[fileManager
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];
NSURL *commonKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"];
NSURL *keystoreDir = [commonKeystoreDir URLByAppendingPathComponent:keyUID];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^(void)
{
NSString *res = StatusgoInitKeystore(keystoreDir.path);
NSLog(@"InitKeyStore result %@", res);
callback(@[]);
});
NSURL *multiaccountKeystoreDir = [Utils getKeyStoreDirForKeyUID:keyUID];
[StatusBackendClient executeStatusGoRequestWithCallback:@"InitKeystore"
body:multiaccountKeystoreDir.path
statusgoFunction:^NSString *{
return StatusgoInitKeystore(multiaccountKeystoreDir.path);
}
callback:callback];
}
RCT_EXPORT_METHOD(reEncryptDbAndKeystore:(NSString *)keyUID
@@ -39,9 +33,26 @@ RCT_EXPORT_METHOD(reEncryptDbAndKeystore:(NSString *)keyUID
#if DEBUG
NSLog(@"reEncryptDbAndKeystore() method called");
#endif
// changes password and re-encrypts keystore
NSString *result = StatusgoChangeDatabasePassword(keyUID, currentPassword, newPassword);
callback(@[result]);
// Construct params into JSON string
NSDictionary *params = @{
@"keyUID": keyUID,
@"oldPassword": currentPassword,
@"newPassword": newPassword
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", error);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequestWithCallback:@"ChangeDatabasePasswordV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoChangeDatabasePasswordV2(jsonString);
}
callback:callback];
}
RCT_EXPORT_METHOD(convertToKeycardAccount:(NSString *)keyUID
@@ -55,47 +66,141 @@ RCT_EXPORT_METHOD(convertToKeycardAccount:(NSString *)keyUID
NSLog(@"convertToKeycardAccount() method called");
#endif
NSURL *multiaccountKeystoreDir = [Utils getKeyStoreDirForKeyUID:keyUID];
StatusgoInitKeystore(multiaccountKeystoreDir.path);
NSString *result = StatusgoConvertToKeycardAccount(accountData, settings, keycardUID, currentPassword, newPassword);
callback(@[result]);
// First initialize keystore
[StatusBackendClient executeStatusGoRequest:@"InitKeystore"
body:multiaccountKeystoreDir.path
statusgoFunction:^NSString *{
return StatusgoInitKeystore(multiaccountKeystoreDir.path);
}];
// Prepare parameters for conversion
NSDictionary *params = @{
@"keyUID": keyUID,
@"account": [NSJSONSerialization JSONObjectWithData:[accountData dataUsingEncoding:NSUTF8StringEncoding]
options:0
error:nil],
@"settings": [NSJSONSerialization JSONObjectWithData:[settings dataUsingEncoding:NSUTF8StringEncoding]
options:0
error:nil],
@"keycardUID": keycardUID,
@"oldPassword": currentPassword,
@"newPassword": newPassword
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", [error localizedDescription]);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequestWithCallback:@"ConvertToKeycardAccountV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoConvertToKeycardAccountV2(jsonString);
}
callback:callback];
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(encodeTransfer:(NSString *)to
value:(NSString *)value) {
return StatusgoEncodeTransfer(to,value);
value:(NSString *)value) {
NSDictionary *params = @{
@"to": to,
@"value": value
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", [error localizedDescription]);
return nil;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
return [StatusBackendClient executeStatusGoRequestWithResult:@"EncodeTransferV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoEncodeTransferV2(jsonString);
}];
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(encodeFunctionCall:(NSString *)method
paramsJSON:(NSString *)paramsJSON) {
return StatusgoEncodeFunctionCall(method,paramsJSON);
paramsJSON:(NSString *)paramsJSON) {
NSDictionary *params = @{
@"method": method,
@"paramsJSON": paramsJSON
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", [error localizedDescription]);
return nil;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
return [StatusBackendClient executeStatusGoRequestWithResult:@"EncodeFunctionCallV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoEncodeFunctionCallV2(jsonString);
}];
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(decodeParameters:(NSString *)decodeParamJSON) {
return StatusgoDecodeParameters(decodeParamJSON);
return [StatusBackendClient executeStatusGoRequestWithResult:@"DecodeParameters"
body:decodeParamJSON
statusgoFunction:^NSString *{
return StatusgoDecodeParameters(decodeParamJSON);
}];
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(hexToNumber:(NSString *)hex) {
return StatusgoHexToNumber(hex);
return [StatusBackendClient executeStatusGoRequestWithResult:@"HexToNumber"
body:hex
statusgoFunction:^NSString *{
return StatusgoHexToNumber(hex);
}];
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(numberToHex:(NSString *)numString) {
return StatusgoNumberToHex(numString);
return [StatusBackendClient executeStatusGoRequestWithResult:@"NumberToHex"
body:numString
statusgoFunction:^NSString *{
return StatusgoNumberToHex(numString);
}];
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(sha3:(NSString *)str) {
return StatusgoSha3(str);
return [StatusBackendClient executeStatusGoRequestWithResult:@"Sha3"
body:str
statusgoFunction:^NSString *{
return StatusgoSha3(str);
}];
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(utf8ToHex:(NSString *)str) {
return StatusgoUtf8ToHex(str);
return [StatusBackendClient executeStatusGoRequestWithResult:@"Utf8ToHex"
body:str
statusgoFunction:^NSString *{
return StatusgoUtf8ToHex(str);
}];
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(hexToUtf8:(NSString *)str) {
return StatusgoHexToUtf8(str);
return [StatusBackendClient executeStatusGoRequestWithResult:@"HexToUtf8"
body:str
statusgoFunction:^NSString *{
return StatusgoHexToUtf8(str);
}];
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(serializeLegacyKey:(NSString *)str) {
return StatusgoSerializeLegacyKey(str);
return [StatusBackendClient executeStatusGoRequestWithResult:@"SerializeLegacyKey"
body:str
statusgoFunction:^NSString *{
return StatusgoSerializeLegacyKey(str);
}];
}
RCT_EXPORT_METHOD(setBlankPreviewFlag:(BOOL *)newValue)
@@ -110,10 +215,14 @@ RCT_EXPORT_METHOD(setBlankPreviewFlag:(BOOL *)newValue)
RCT_EXPORT_METHOD(hashTransaction:(NSString *)txArgsJSON
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"HashTransaction() method called");
NSLog(@"hashTransaction() method called");
#endif
NSString *result = StatusgoHashTransaction(txArgsJSON);
callback(@[result]);
[StatusBackendClient executeStatusGoRequestWithCallback:@"HashTransaction"
body:txArgsJSON
statusgoFunction:^NSString *{
return StatusgoHashTransaction(txArgsJSON);
}
callback:callback];
}
RCT_EXPORT_METHOD(hashMessage:(NSString *)message
@@ -121,8 +230,12 @@ RCT_EXPORT_METHOD(hashMessage:(NSString *)message
#if DEBUG
NSLog(@"hashMessage() method called");
#endif
NSString *result = StatusgoHashMessage(message);
callback(@[result]);
[StatusBackendClient executeStatusGoRequestWithCallback:@"HashMessage"
body:message
statusgoFunction:^NSString *{
return StatusgoHashMessage(message);
}
callback:callback];
}
RCT_EXPORT_METHOD(localPairingPreflightOutboundCheck:(RCTResponseSenderBlock)callback) {
@@ -136,14 +249,34 @@ RCT_EXPORT_METHOD(localPairingPreflightOutboundCheck:(RCTResponseSenderBlock)cal
RCT_EXPORT_METHOD(multiformatDeserializePublicKey:(NSString *)multiCodecKey
base58btc:(NSString *)base58btc
callback:(RCTResponseSenderBlock)callback) {
NSString *result = StatusgoMultiformatDeserializePublicKey(multiCodecKey,base58btc);
callback(@[result]);
NSDictionary *params = @{
@"key": multiCodecKey,
@"outBase": base58btc
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", error);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequestWithCallback:@"MultiformatDeserializePublicKeyV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoMultiformatDeserializePublicKeyV2(jsonString);
}
callback:callback];
}
RCT_EXPORT_METHOD(deserializeAndCompressKey:(NSString *)desktopKey
callback:(RCTResponseSenderBlock)callback) {
NSString *result = StatusgoDeserializeAndCompressKey(desktopKey);
callback(@[result]);
[StatusBackendClient executeStatusGoRequestWithCallback:@"DeserializeAndCompressKey"
body:desktopKey
statusgoFunction:^NSString *{
return StatusgoDeserializeAndCompressKey(desktopKey);
}
callback:callback];
}
RCT_EXPORT_METHOD(hashTypedData:(NSString *)data
@@ -166,13 +299,14 @@ RCT_EXPORT_METHOD(hashTypedDataV4:(NSString *)data
#pragma mark - SignMessage
RCT_EXPORT_METHOD(signMessage:(NSString *)message
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"SignMessage() method called");
#endif
NSString *result = StatusgoSignMessage(message);
callback(@[result]);
RCT_EXPORT_METHOD(signMessage:(NSString *)rpcParams
callback:(RCTResponseSenderBlock)callback) {
[StatusBackendClient executeStatusGoRequestWithCallback:@"SignMessage"
body:rpcParams
statusgoFunction:^NSString *{
return StatusgoSignMessage(rpcParams);
}
callback:callback];
}
#pragma mark - SignTypedData
@@ -4,6 +4,7 @@
#import "Statusgo.h"
#import "Utils.h"
#import "SSZipArchive.h"
#import "StatusBackendClient.h"
@implementation LogManager
@@ -14,15 +15,12 @@ RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(sendLogs:(NSString *)dbJson
jsLogs:(NSString *)jsLogs
callback:(RCTResponseSenderBlock)callback) {
// TODO: Implement SendLogs for iOS
#if DEBUG
NSLog(@"SendLogs() method called, not implemented");
NSLog(@"SendLogs() method called");
#endif
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error = nil;
NSURL *rootUrl =[[fileManager
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];
NSURL *rootUrl =[Utils getRootUrl];
NSURL *zipFile = [rootUrl URLByAppendingPathComponent:@"logs.zip"];
[fileManager removeItemAtPath:zipFile.path error:nil];
@@ -34,25 +32,6 @@ RCT_EXPORT_METHOD(sendLogs:(NSString *)dbJson
NSURL *dbFile = [logsFolderName URLByAppendingPathComponent:@"db.json"];
NSURL *jsLogsFile = [logsFolderName URLByAppendingPathComponent:@"Status.log"];
#if DEBUG
NSString *networkDirPath = @"ethereum/mainnet_rpc_dev";
#else
NSString *networkDirPath = @"ethereum/mainnet_rpc";
#endif
#if DEBUG
NSString *goerliNetworkDirPath = @"ethereum/goerli_rpc_dev";
#else
NSString *goerliNetworkDirPath = @"ethereum/goerli_rpc";
#endif
NSURL *networkDir = [rootUrl URLByAppendingPathComponent:networkDirPath];
NSURL *originalGethLogsFile = [networkDir URLByAppendingPathComponent:@"geth.log"];
NSURL *gethLogsFile = [logsFolderName URLByAppendingPathComponent:@"mainnet_geth.log"];
NSURL *goerliNetworkDir = [rootUrl URLByAppendingPathComponent:goerliNetworkDirPath];
NSURL *goerliGethLogsFile = [goerliNetworkDir URLByAppendingPathComponent:@"geth.log"];
NSURL *goerliLogsFile = [logsFolderName URLByAppendingPathComponent:@"goerli_geth.log"];
NSURL *mainGethLogsFile = [rootUrl URLByAppendingPathComponent:@"geth.log"];
NSURL *mainLogsFile = [logsFolderName URLByAppendingPathComponent:@"geth.log"];
@@ -62,10 +41,6 @@ RCT_EXPORT_METHOD(sendLogs:(NSString *)dbJson
[dbJson writeToFile:dbFile.path atomically:YES encoding:NSUTF8StringEncoding error:nil];
[jsLogs writeToFile:jsLogsFile.path atomically:YES encoding:NSUTF8StringEncoding error:nil];
//NSString* gethLogs = StatusgoExportNodeLogs();
//[gethLogs writeToFile:gethLogsFile.path atomically:YES encoding:NSUTF8StringEncoding error:nil];
[fileManager copyItemAtPath:originalGethLogsFile.path toPath:gethLogsFile.path error:nil];
[fileManager copyItemAtPath:goerliGethLogsFile.path toPath:goerliLogsFile.path error:nil];
[fileManager copyItemAtPath:mainGethLogsFile.path toPath:mainLogsFile.path error:nil];
if ([fileManager fileExistsAtPath:requestsLogFile.path]) {
@@ -88,37 +63,36 @@ RCT_EXPORT_METHOD(initLogging:(BOOL)enabled
NSString *logFilePath = [logDirectory stringByAppendingPathComponent:@"geth.log"];
NSString *logRequestFilePath = [logDirectory stringByAppendingPathComponent:@"requests.log"];
NSMutableDictionary *jsonConfig = [NSMutableDictionary dictionary];
jsonConfig[@"Enabled"] = @(enabled);
jsonConfig[@"MobileSystem"] = @(mobileSystem);
jsonConfig[@"Level"] = logLevel;
jsonConfig[@"File"] = logFilePath;
jsonConfig[@"LogRequestGo"] = @(logRequestGo);
jsonConfig[@"LogRequestFile"] = logRequestFilePath;
NSError *error = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonConfig options:0 error:&error];
NSDictionary *config = @{
@"Enabled": @(enabled),
@"MobileSystem": @(mobileSystem),
@"Level": logLevel,
@"File": logFilePath,
@"LogRequestGo": @(logRequestGo),
@"LogRequestFile": logRequestFilePath
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:config options:0 error:&error];
if (error) {
// Handle JSON serialization error
callback(@[error.localizedDescription]);
NSLog(@"Error creating JSON: %@", [error localizedDescription]);
return;
}
NSString *configJson = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSString *config = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
// Call your native logging initialization method here
NSString *initResult = StatusgoInitLogging(config);
callback(@[initResult]);
[StatusBackendClient executeStatusGoRequestWithCallback:@"InitLogging"
body:configJson
statusgoFunction:^NSString *{
return StatusgoInitLogging(configJson);
}
callback:callback];
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(logFileDirectory) {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl =[[fileManager
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];
NSURL *rootUrl = [Utils getRootUrl];
return rootUrl.path;
}
@end
@@ -3,14 +3,18 @@
#import "React/RCTEventDispatcher.h"
#import "Statusgo.h"
#import "Utils.h"
#import "StatusBackendClient.h"
@implementation NetworkManager
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(startSearchForLocalPairingPeers:(RCTResponseSenderBlock)callback) {
NSString *result = StatusgoStartSearchForLocalPairingPeers();
callback(@[result]);
[StatusBackendClient executeStatusGoRequestWithCallback:@"StartSearchForLocalPairingPeers"
body:@""
statusgoFunction:^NSString *{
return StatusgoStartSearchForLocalPairingPeers();
}
callback:callback];
}
RCT_EXPORT_METHOD(getConnectionStringForBootstrappingAnotherDevice:(NSString *)configJSON
@@ -19,6 +23,11 @@ RCT_EXPORT_METHOD(getConnectionStringForBootstrappingAnotherDevice:(NSString *)c
NSData *configData = [configJSON dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
NSMutableDictionary *configDict = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:&error];
if (error) {
NSLog(@"Error parsing JSON: %@", error);
return;
}
NSMutableDictionary *senderConfig = configDict[@"senderConfig"];
NSString *keyUID = senderConfig[@"keyUID"];
NSURL *multiaccountKeystoreDir = [Utils getKeyStoreDirForKeyUID:keyUID];
@@ -27,16 +36,43 @@ RCT_EXPORT_METHOD(getConnectionStringForBootstrappingAnotherDevice:(NSString *)c
[senderConfig setValue:keystoreDir forKey:@"keystorePath"];
NSString *modifiedConfigJSON = [Utils jsonStringWithPrettyPrint:NO fromDictionary:configDict];
NSString *result = StatusgoGetConnectionStringForBootstrappingAnotherDevice(modifiedConfigJSON);
callback(@[result]);
[StatusBackendClient executeStatusGoRequestWithCallback:@"GetConnectionStringForBootstrappingAnotherDevice"
body:modifiedConfigJSON
statusgoFunction:^NSString *{
return StatusgoGetConnectionStringForBootstrappingAnotherDevice(modifiedConfigJSON);
}
callback:callback];
}
RCT_EXPORT_METHOD(inputConnectionStringForBootstrapping:(NSString *)cs
configJSON:(NSString *)configJSON
callback:(RCTResponseSenderBlock)callback) {
NSString *result = StatusgoInputConnectionStringForBootstrapping(cs, configJSON);
callback(@[result]);
NSData *configData = [configJSON dataUsingEncoding:NSUTF8StringEncoding];
NSError *jsonError;
NSDictionary *configDict = [NSJSONSerialization JSONObjectWithData:configData options:0 error:&jsonError];
if (jsonError) {
NSLog(@"Error parsing JSON: %@", jsonError);
return;
}
NSDictionary *params = @{
@"connectionString": cs,
@"receiverClientConfig": configDict
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", error);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequestWithCallback:@"InputConnectionStringForBootstrappingV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoInputConnectionStringForBootstrappingV2(jsonString);
}
callback:callback];
}
RCT_EXPORT_METHOD(sendTransactionWithSignature:(NSString *)txArgsJSON
@@ -45,8 +81,12 @@ RCT_EXPORT_METHOD(sendTransactionWithSignature:(NSString *)txArgsJSON
#if DEBUG
NSLog(@"sendTransactionWithSignature() method called");
#endif
NSString *result = StatusgoSendTransactionWithSignature(txArgsJSON, signature);
callback(@[result]);
[StatusBackendClient executeStatusGoRequestWithCallback:@"SendTransactionWithSignature"
body:txArgsJSON
statusgoFunction:^NSString *{
return StatusgoSendTransactionWithSignature(txArgsJSON, signature);
}
callback:callback];
}
#pragma mark - SendTransaction
@@ -55,30 +95,53 @@ RCT_EXPORT_METHOD(sendTransaction:(NSString *)txArgsJSON
password:(NSString *)password
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"SendTransaction() method called");
NSLog(@"SendTransactionV2() method called");
#endif
NSString *result = StatusgoSendTransaction(txArgsJSON, password);
callback(@[result]);
NSData *txArgsData = [txArgsJSON dataUsingEncoding:NSUTF8StringEncoding];
NSError *jsonError;
NSDictionary *txArgsDict = [NSJSONSerialization JSONObjectWithData:txArgsData options:0 error:&jsonError];
if (jsonError) {
NSLog(@"Error parsing JSON: %@", jsonError);
return;
}
NSDictionary *params = @{
@"txArgs": txArgsDict,
@"password": password
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", error);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequestWithCallback:@"SendTransactionV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoSendTransactionV2(jsonString);
}
callback:callback];
}
RCT_EXPORT_METHOD(callRPC:(NSString *)payload
callback:(RCTResponseSenderBlock)callback) {
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSString *result = StatusgoCallRPC(payload);
dispatch_async(dispatch_get_main_queue(), ^{
callback(@[result]);
});
});
[StatusBackendClient executeStatusGoRequestWithCallback:@"CallRPC"
body:payload
statusgoFunction:^NSString *{
return StatusgoCallRPC(payload);
}
callback:callback];
}
RCT_EXPORT_METHOD(callPrivateRPC:(NSString *)payload
callback:(RCTResponseSenderBlock)callback) {
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSString *result = StatusgoCallPrivateRPC(payload);
dispatch_async(dispatch_get_main_queue(), ^{
callback(@[result]);
});
});
[StatusBackendClient executeStatusGoRequestWithCallback:@"CallPrivateRPC"
body:payload
statusgoFunction:^NSString *{
return StatusgoCallPrivateRPC(payload);
}
callback:callback];
}
#pragma mark - Recover
@@ -88,8 +151,12 @@ RCT_EXPORT_METHOD(recover:(NSString *)message
#if DEBUG
NSLog(@"Recover() method called");
#endif
NSString *result = StatusgoRecover(message);
callback(@[result]);
[StatusBackendClient executeStatusGoRequestWithCallback:@"Recover"
body:message
statusgoFunction:^NSString *{
return StatusgoRecover(message);
}
callback:callback];
}
RCT_EXPORT_METHOD(getConnectionStringForExportingKeypairsKeystores:(NSString *)configJSON
@@ -106,8 +173,12 @@ RCT_EXPORT_METHOD(getConnectionStringForExportingKeypairsKeystores:(NSString *)c
[senderConfig setValue:keystoreDir forKey:@"keystorePath"];
NSString *modifiedConfigJSON = [Utils jsonStringWithPrettyPrint:NO fromDictionary:configDict];
NSString *result = StatusgoGetConnectionStringForExportingKeypairsKeystores(modifiedConfigJSON);
callback(@[result]);
[StatusBackendClient executeStatusGoRequestWithCallback:@"GetConnectionStringForExportingKeypairsKeystores"
body:modifiedConfigJSON
statusgoFunction:^NSString *{
return StatusgoGetConnectionStringForExportingKeypairsKeystores(modifiedConfigJSON);
}
callback:callback];
}
RCT_EXPORT_METHOD(inputConnectionStringForImportingKeypairsKeystores:(NSString *)cs
@@ -119,14 +190,25 @@ RCT_EXPORT_METHOD(inputConnectionStringForImportingKeypairsKeystores:(NSString *
NSMutableDictionary *configDict = [NSJSONSerialization JSONObjectWithData:configData options:NSJSONReadingMutableContainers error:&error];
NSMutableDictionary *receiverConfig = configDict[@"receiverConfig"];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl =[[fileManager URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *rootUrl =[Utils getRootUrl];
NSURL *multiaccountKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"];
NSString *keystoreDir = multiaccountKeystoreDir.path;
[receiverConfig setValue:keystoreDir forKey:@"keystorePath"];
NSString *modifiedConfigJSON = [Utils jsonStringWithPrettyPrint:NO fromDictionary:configDict];
NSString *result = StatusgoInputConnectionStringForImportingKeypairsKeystores(cs, modifiedConfigJSON);
callback(@[result]);
NSDictionary *params = @{
@"connectionString": cs,
@"keystoreFilesReceiverClientConfig": modifiedConfigJSON
};
NSString *paramsJSON = [Utils jsonStringWithPrettyPrint:NO fromDictionary:params];
[StatusBackendClient executeStatusGoRequestWithCallback:@"InputConnectionStringForImportingKeypairsKeystoresV2"
body:paramsJSON
statusgoFunction:^NSString *{
return StatusgoInputConnectionStringForImportingKeypairsKeystoresV2(paramsJSON);
}
callback:callback];
}
@end
@@ -5,5 +5,6 @@
#import "RCTLog.h"
@interface Status : NSObject <RCTBridgeModule, StatusgoSignalHandler>
+ (Status *)sharedInstance;
- (void)handleSignal:(NSString *)signal;
@end
@@ -2,13 +2,22 @@
#import "React/RCTBridge.h"
#import "React/RCTEventDispatcher.h"
#import "Statusgo.h"
#import "StatusBackendClient.h"
#import "Utils.h"
static RCTBridge *bridge;
@implementation Status
+ (Status *)sharedInstance {
static Status *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
self = [super init];
if (!self) {
@@ -73,74 +82,17 @@ RCT_EXPORT_METHOD(deleteImportedKey:(NSString *)keyUID
password:(NSString *)password
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"DeleteImportedKey() method called");
NSLog(@"DeleteImportedKeyV2() method called");
#endif
NSURL *multiaccountKeystoreDir = [Utils getKeyStoreDirForKeyUID:keyUID];
NSString *result = StatusgoDeleteImportedKey(address, password, multiaccountKeystoreDir.path);
callback(@[result]);
}
RCT_EXPORT_METHOD(multiAccountGenerateAndDeriveAddresses:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountGenerateAndDeriveAddresses() method called");
#endif
NSString *result = StatusgoMultiAccountGenerateAndDeriveAddresses(json);
callback(@[result]);
}
RCT_EXPORT_METHOD(multiAccountStoreAccount:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountStoreAccount() method called");
#endif
NSString *result = StatusgoMultiAccountStoreAccount(json);
callback(@[result]);
}
RCT_EXPORT_METHOD(multiAccountLoadAccount:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountLoadAccount() method called");
#endif
NSString *result = StatusgoMultiAccountLoadAccount(json);
callback(@[result]);
}
RCT_EXPORT_METHOD(multiAccountStoreDerived:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountStoreDerived() method called");
#endif
NSString *result = StatusgoMultiAccountStoreDerivedAccounts(json);
callback(@[result]);
}
RCT_EXPORT_METHOD(multiAccountImportPrivateKey:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountImportPrivateKey() method called");
#endif
NSString *result = StatusgoMultiAccountImportPrivateKey(json);
callback(@[result]);
}
RCT_EXPORT_METHOD(multiAccountImportMnemonic:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountImportMnemonic() method called");
#endif
NSString *result = StatusgoMultiAccountImportMnemonic(json);
callback(@[result]);
}
RCT_EXPORT_METHOD(multiAccountDeriveAddresses:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"MultiAccountDeriveAddresses() method called");
#endif
NSString *result = StatusgoMultiAccountDeriveAddresses(json);
callback(@[result]);
NSString *jsonParams = [NSString stringWithFormat:@"{\"address\":\"%@\",\"password\":\"%@\",\"keyStoreDir\":\"%@\"}",
address, password, multiaccountKeystoreDir.path];
[StatusBackendClient executeStatusGoRequestWithCallback:@"DeleteImportedKeyV2"
body:jsonParams
statusgoFunction:^NSString *{
return StatusgoDeleteImportedKeyV2(jsonParams);
}
callback:callback];
}
#pragma mark - GetNodeConfig
@@ -149,12 +101,20 @@ RCT_EXPORT_METHOD(getNodeConfig:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"GetNodeConfig() method called");
#endif
NSString *result = StatusgoGetNodeConfig();
callback(@[result]);
[StatusBackendClient executeStatusGoRequestWithCallback:@"GetNodeConfig"
body:@""
statusgoFunction:^NSString *{
return StatusgoGetNodeConfig();
}
callback:callback];
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(fleets) {
return StatusgoFleets();
return [StatusBackendClient executeStatusGoRequestWithResult:@"Fleets"
body:@""
statusgoFunction:^NSString *{
return StatusgoFleets();
}];
}
RCT_EXPORT_METHOD(closeApplication) {
@@ -166,14 +126,55 @@ RCT_EXPORT_METHOD(connectionChange:(NSString *)type
#if DEBUG
NSLog(@"ConnectionChange() method called");
#endif
StatusgoConnectionChange(type, isExpensive ? 1 : 0);
NSDictionary *params = @{
@"type": type,
@"expensive": @(isExpensive)
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params
options:0
error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", error);
return;
}
if (jsonData) {
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequest:@"ConnectionChangeV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoConnectionChangeV2(jsonString);
}];
} else {
NSLog(@"Failed to create JSON data");
}
}
RCT_EXPORT_METHOD(appStateChange:(NSString *)type) {
RCT_EXPORT_METHOD(appStateChange:(NSString *)state) {
#if DEBUG
NSLog(@"AppStateChange() method called");
#endif
StatusgoAppStateChange(type);
NSDictionary *params = @{@"state": state};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params
options:0
error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", error);
return;
}
if (jsonData) {
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[StatusBackendClient executeStatusGoRequest:@"AppStateChangeV2"
body:jsonString
statusgoFunction:^NSString *{
return StatusgoAppStateChangeV2(jsonString);
}];
} else {
NSLog(@"Failed to create JSON data");
}
}
RCT_EXPORT_METHOD(addCentralizedMetric:(NSString *)request
@@ -181,8 +182,12 @@ RCT_EXPORT_METHOD(addCentralizedMetric:(NSString *)request
#if DEBUG
NSLog(@"addCentralizedMetric() method called");
#endif
NSString *result = StatusgoAddCentralizedMetric(request);
callback(@[result]);
[StatusBackendClient executeStatusGoRequestWithCallback:@"AddCentralizedMetric"
body:request
statusgoFunction:^NSString *{
return StatusgoAddCentralizedMetric(request);
}
callback:callback];
}
RCT_EXPORT_METHOD(toggleCentralizedMetrics:(NSString *)request
@@ -190,15 +195,23 @@ RCT_EXPORT_METHOD(toggleCentralizedMetrics:(NSString *)request
#if DEBUG
NSLog(@"toggleCentralizedMetrics() method called");
#endif
NSString *result = StatusgoToggleCentralizedMetrics(request);
callback(@[result]);
[StatusBackendClient executeStatusGoRequestWithCallback:@"ToggleCentralizedMetrics"
body:request
statusgoFunction:^NSString *{
return StatusgoToggleCentralizedMetrics(request);
}
callback:callback];
}
RCT_EXPORT_METHOD(startLocalNotifications) {
#if DEBUG
NSLog(@"StartLocalNotifications() method called");
#endif
StatusgoStartLocalNotifications();
[StatusBackendClient executeStatusGoRequest:@"StartLocalNotifications"
body:@""
statusgoFunction:^NSString *{
return StatusgoStartLocalNotifications();
}];
}
#pragma mark - deviceinfo
@@ -0,0 +1,31 @@
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
@interface StatusBackendClient : NSObject <RCTBridgeModule>
@property (nonatomic) BOOL serverEnabled;
@property (nonatomic, strong) NSString *statusGoEndpoint;
@property (nonatomic, strong) NSString *signalEndpoint;
@property (nonatomic, strong) NSString *rootDataDir;
@property (nonatomic, strong) NSURLSessionWebSocketTask *webSocket;
// Add sharedInstance class method declaration
+ (instancetype)sharedInstance;
- (void)request:(NSString *)endpoint
body:(NSString *)body
callback:(void (^)(NSString *response, NSError *error))callback;
+ (void)executeStatusGoRequest:(NSString *)endpoint
body:(NSString *)body
statusgoFunction:(NSString * (^)(void))statusgoFunction;
+ (void)executeStatusGoRequestWithCallback:(NSString *)endpoint
body:(NSString *)body
statusgoFunction:(NSString * (^)(void))statusgoFunction
callback:(RCTResponseSenderBlock)callback;
+ (NSString *)executeStatusGoRequestWithResult:(NSString *)endpoint
body:(NSString *)body
statusgoFunction:(NSString * (^)(void))statusgoFunction;
@end
@@ -0,0 +1,246 @@
#import "StatusBackendClient.h"
#import "RCTStatus.h"
#import "Utils.h"
@implementation StatusBackendClient {
NSURLSessionWebSocketTask *_webSocket;
BOOL _serverEnabled;
NSString *_statusGoEndpoint;
NSString *_signalEndpoint;
NSString *_rootDataDir;
}
RCT_EXPORT_MODULE();
+ (BOOL)requiresMainQueueSetup {
return YES;
}
+ (instancetype)allocWithZone:(NSZone *)zone {
static StatusBackendClient *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [super allocWithZone:zone];
});
return sharedInstance;
}
+ (instancetype)sharedInstance {
return [[self alloc] init];
}
- (instancetype)init {
static StatusBackendClient *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [super init];
if (sharedInstance) {
sharedInstance->_serverEnabled = NO;
sharedInstance->_statusGoEndpoint = nil;
sharedInstance->_signalEndpoint = nil;
sharedInstance->_rootDataDir = nil;
sharedInstance->_webSocket = nil;
}
});
return sharedInstance;
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (BOOL)serverEnabled {
return _serverEnabled;
}
- (NSString *)statusGoEndpoint {
return _statusGoEndpoint;
}
- (NSString *)signalEndpoint {
return _signalEndpoint;
}
- (NSString *)rootDataDir {
return _rootDataDir;
}
- (void)connectWebSocket {
if (!self.serverEnabled || !self.signalEndpoint) {
return;
}
NSString *fullUrl = [NSString stringWithFormat:@"%@", self.signalEndpoint];
NSURL *url = [NSURL URLWithString:fullUrl];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
self.webSocket = [session webSocketTaskWithURL:url];
[self.webSocket resume];
[self receiveMessage];
}
- (void)receiveMessage {
__weak typeof(self) weakSelf = self;
[self.webSocket receiveMessageWithCompletionHandler:^(NSURLSessionWebSocketMessage *message, NSError *error) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf || !strongSelf.webSocket) {
return;
}
if (error) {
NSLog(@"WebSocket error: %@", error);
// Attempt to reconnect after error
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[strongSelf connectWebSocket];
});
return;
}
if (message) {
if (message.type == NSURLSessionWebSocketMessageTypeString && message.string) {
[[Status sharedInstance] handleSignal:message.string];
}
// Continue receiving messages only if the connection is still active
if (strongSelf.webSocket) {
[strongSelf receiveMessage];
}
}
}];
}
- (void)disconnectWebSocket {
if (self.webSocket) {
[self.webSocket cancel];
self.webSocket = nil;
}
}
- (void)request:(NSString *)endpoint
body:(NSString *)body
callback:(void (^)(NSString *response, NSError *error))callback {
NSString *fullUrlString = [NSString stringWithFormat:@"%@%@", self.statusGoEndpoint, endpoint];
NSURL *url = [NSURL URLWithString:fullUrlString];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
request.HTTPMethod = @"POST";
[request setValue:@"application/json; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
NSData *bodyData = [body dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPBody = bodyData;
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"request error: %@", error);
callback(nil, error);
return;
}
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
callback(responseString, nil);
}];
[task resume];
}
RCT_EXPORT_METHOD(configStatusBackendServer:(BOOL)serverEnabled
statusGoEndpoint:(NSString *)statusGoEndpoint
signalEndpoint:(NSString *)signalEndpoint
rootDataDir:(NSString *)rootDataDir) {
[self configureWithEnabled:serverEnabled
statusGoEndpoint:statusGoEndpoint
signalEndpoint:signalEndpoint
rootDataDir:rootDataDir];
}
- (void)configureWithEnabled:(BOOL)serverEnabled
statusGoEndpoint:(NSString *)statusGoEndpoint
signalEndpoint:(NSString *)signalEndpoint
rootDataDir:(NSString *)rootDataDir {
_serverEnabled = serverEnabled;
if (serverEnabled) {
_statusGoEndpoint = statusGoEndpoint;
_signalEndpoint = signalEndpoint;
_rootDataDir = rootDataDir;
[self connectWebSocket];
} else {
[self disconnectWebSocket];
_statusGoEndpoint = nil;
_signalEndpoint = nil;
_rootDataDir = nil;
}
}
+ (void)executeStatusGoRequest:(NSString *)endpoint
body:(NSString *)body
statusgoFunction:(NSString * (^)(void))statusgoFunction {
StatusBackendClient *client = [StatusBackendClient sharedInstance];
if (client.serverEnabled) {
[client request:endpoint body:body callback:^(NSString *response, NSError *error) {
[Utils handleStatusGoResponse:response source:endpoint error:error];
}];
} else {
NSString *result = statusgoFunction();
[Utils handleStatusGoResponse:result source:endpoint error:nil];
}
}
+ (void)executeStatusGoRequestWithCallback:(NSString *)endpoint
body:(NSString *)body
statusgoFunction:(NSString * (^)(void))statusgoFunction
callback:(RCTResponseSenderBlock)callback {
StatusBackendClient *client = [StatusBackendClient sharedInstance];
if (client.serverEnabled) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[client request:endpoint body:body callback:^(NSString *response, NSError *error) {
if (error) {
NSLog(@"request to %@ failed: %@", endpoint, error);
if (callback) {
callback(@[@(NO)]);
}
} else {
if (callback) {
callback(@[response]);
}
}
}];
});
} else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSString *result = statusgoFunction();
if (callback) {
callback(@[result]);
}
});
}
}
+ (NSString *)executeStatusGoRequestWithResult:(NSString *)endpoint
body:(NSString *)body
statusgoFunction:(NSString * (^)(void))statusgoFunction {
StatusBackendClient *client = [StatusBackendClient sharedInstance];
if (client.serverEnabled) {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block NSString *resultString = @"";
[client request:endpoint body:body callback:^(NSString *response, NSError *error) {
if (error) {
NSLog(@"request to %@ failed: %@", endpoint, error);
resultString = @"";
} else {
resultString = response;
}
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return resultString;
} else {
return statusgoFunction();
}
}
@end
@@ -6,11 +6,13 @@
@interface Utils : NSObject <RCTBridgeModule>
+ (NSURL *)getRootUrl;
+ (NSString *)jsonStringWithPrettyPrint:(BOOL)prettyPrint fromDictionary:(NSDictionary *)dictionary;
+ (NSString *)jsonStringWithPrettyPrint:(BOOL)prettyPrint fromArray:(NSArray *)array;
+ (NSURL *)getKeyStoreDirForKeyUID:(NSString *)keyUID;
+ (NSString *)getExportDbFilePath;
+ (NSString *)getKeyUID:(NSString *)jsonString;
+ (void)migrateKeystore:(NSString *)accountData password:(NSString *)password;
+ (void)handleStatusGoResponse:(NSString *)response source:(NSString *)source error:(NSError *)error;
@end
@@ -3,11 +3,28 @@
#import "React/RCTEventDispatcher.h"
#import "Statusgo.h"
#import "Utils.h"
#import "StatusBackendClient.h"
@implementation Utils
RCT_EXPORT_MODULE();
#pragma mark - Private Methods
+ (NSURL *)getRootUrl {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl;
StatusBackendClient *client = [StatusBackendClient sharedInstance];
if (client.serverEnabled && client.rootDataDir) {
rootUrl = [NSURL fileURLWithPath:client.rootDataDir];
} else {
rootUrl = [[fileManager URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject];
}
return rootUrl;
}
+ (NSString *)jsonStringWithPrettyPrint:(BOOL)prettyPrint fromDictionary:(NSDictionary *)dictionary {
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary
@@ -38,7 +55,7 @@ RCT_EXPORT_MODULE();
+ (NSURL *)getKeyStoreDirForKeyUID:(NSString *)keyUID {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl = [[fileManager URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *rootUrl = [self getRootUrl];
NSURL *oldKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"];
NSURL *multiaccountKeystoreDir = [oldKeystoreDir URLByAppendingPathComponent:keyUID];
@@ -57,6 +74,11 @@ RCT_EXPORT_MODULE();
}
+ (NSString *) getExportDbFilePath {
StatusBackendClient *client = [StatusBackendClient sharedInstance];
if (client.serverEnabled && client.rootDataDir) {
return [client.rootDataDir stringByAppendingPathComponent:@"export.db"];
}
NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"export.db"];
NSFileManager *fileManager = [NSFileManager defaultManager];
@@ -70,17 +92,36 @@ RCT_EXPORT_MODULE();
+ (void) migrateKeystore:(NSString *)accountData
password:(NSString *)password {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl =[[fileManager
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];
NSURL *rootUrl =[self getRootUrl];
NSURL *keyUID = [self getKeyStoreDirForKeyUID:accountData];
NSData *jsonData = [accountData dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
NSDictionary *accountJson = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
if (error) {
NSLog(@"Error parsing accountData: %@", error);
return;
}
NSString *keyUID = [self getKeyUID:accountData];
NSURL *oldKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"];
NSURL *multiaccountKeystoreDir = [self getKeyStoreDirForKeyUID:keyUID.path];
NSURL *multiaccountKeystoreDir = [self getKeyStoreDirForKeyUID:keyUID];
NSArray *keys = [fileManager contentsOfDirectoryAtPath:multiaccountKeystoreDir.path error:nil];
if (keys.count == 0) {
NSString *migrationResult = StatusgoMigrateKeyStoreDir(accountData, password, oldKeystoreDir.path, multiaccountKeystoreDir.path);
NSDictionary *params = @{
@"account": accountJson,
@"password": password,
@"oldDir": oldKeystoreDir.path,
@"newDir": multiaccountKeystoreDir.path
};
NSData *paramsJsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating params JSON: %@", error);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:paramsJsonData encoding:NSUTF8StringEncoding];
NSString *migrationResult = StatusgoMigrateKeyStoreDirV2(jsonString);
NSLog(@"keystore migration result %@", migrationResult);
NSString *initKeystoreResult = StatusgoInitKeystore(multiaccountKeystoreDir.path);
@@ -89,18 +130,19 @@ RCT_EXPORT_MODULE();
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(backupDisabledDataDir) {
StatusBackendClient *client = [StatusBackendClient sharedInstance];
if (client.serverEnabled && client.rootDataDir) {
return client.rootDataDir;
}
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl =[[fileManager
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];
NSURL *rootUrl = [Utils getRootUrl];
return rootUrl.path;
}
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(keystoreDir) {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *rootUrl =[[fileManager
URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]
lastObject];
NSURL *rootUrl =[Utils getRootUrl];
NSURL *commonKeystoreDir = [rootUrl URLByAppendingPathComponent:@"keystore"];
@@ -110,9 +152,17 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(keystoreDir) {
RCT_EXPORT_METHOD(validateMnemonic:(NSString *)seed
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"validateMnemonic() method called");
NSLog(@"validateMnemonicV2() method called");
#endif
NSString *result = StatusgoValidateMnemonic(seed);
NSDictionary *params = @{@"mnemonic": seed};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];
if (error) {
NSLog(@"Error creating JSON: %@", error);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSString *result = StatusgoValidateMnemonicV2(jsonString);
callback(@[result]);
}
@@ -132,4 +182,17 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(validateConnectionString:(NSString *)cs)
return StatusgoValidateConnectionString(cs);
}
+ (void)handleStatusGoResponse:(NSString *)response source:(NSString *)source error:(NSError *)error {
if (error) {
NSLog(@"%@ failed: %@", source, error);
return;
}
if ([response hasPrefix:@"{\"error\":\"\""]) {
NSLog(@"%@ success: %@", source, response);
} else {
NSLog(@"%@ failed: %@", source, response);
}
}
@end
-5
View File
@@ -44,11 +44,6 @@ in {
doCheck = false;
});
# Downgrade watchman in attempt to fix "too many files open issue"
watchman = callPackage ./pkgs/watchman {
inherit (super.darwin.apple_sdk.frameworks) CoreServices;
autoconf = super.buildPackages.autoconf269;
};
# Package version adjustments
nodejs = super.nodejs_20;
-23
View File
@@ -1,23 +0,0 @@
# Issue
`watchman` was upgraded significantly during the last nixpkgs upgrade (`4.9.0` (Aug 16, 2017) to `2023.01.30.00` - 6 years between):
- https://github.com/status-im/status-mobile/pull/14944
- https://github.com/status-im/nixpkgs/commit/4e9c02bcc709fe1737a746add0e8e0109133d808
Probably causing developers to have "too many files open" issue:
https://github.com/status-im/status-mobile/issues/16341
```
Error: A non-recoverable condition has triggered. Watchman needs your help!
The triggering condition was at timestamp=1687286390: opendir(/Users/javid/Projects/status-mobile/node_modules/metro-core/node_modules/jest-regex-util/build) -> Too many open files
All requests will continue to fail with this message until you resolve
the underlying problem. You will find more information on fixing this at
https://facebook.github.io/watchman/docs/troubleshooting.html#poison-opendir
```
# Fix
This is an attempt to fix the issue by downgrading the watchman
# Upgrade
When upgrading in the future, please read the comments:
https://github.com/status-im/status-mobile/issues/16341
-48
View File
@@ -1,48 +0,0 @@
{ stdenv, lib, config, fetchFromGitHub, autoconf, automake, pcre
, libtool, pkg-config, openssl
, confFile ? config.watchman.confFile or null
, withApple ? stdenv.isDarwin, CoreServices
}:
stdenv.mkDerivation rec {
pname = "watchman";
version = "4.9.0";
src = fetchFromGitHub {
owner = "facebook";
repo = "watchman";
rev = "v${version}";
sha256 = "0fdaj5pmicm6j17d5q7px800m5rmam1a400x3hv1iiifnmhgnkal";
};
nativeBuildInputs = [ autoconf automake pkg-config libtool ];
buildInputs = [ pcre openssl ]
#++ lib.optionals withApple [ CoreServices ];
++ lib.optionals stdenv.isDarwin [ CoreServices ];
configureFlags = [
"--enable-lenient"
"--enable-conffile=${if confFile == null then "no" else confFile}"
"--with-pcre=yes"
# For security considerations re: --disable-statedir, see:
# https://github.com/facebook/watchman/issues/178
"--disable-statedir"
];
prePatch = ''
patchShebangs .
'';
preConfigure = ''
./autogen.sh
'';
meta = with lib; {
description = "Watches files and takes action when they change";
homepage = "https://facebook.github.io/watchman";
maintainers = with maintainers; [ cstrahan ];
platforms = with platforms; linux ++ darwin;
license = licenses.asl20;
};
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 673 B

After

Width:  |  Height:  |  Size: 810 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1001 B

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

-3
View File
@@ -32,12 +32,9 @@ trap "rm -vf ${SECRETS_FILE_PATH}" EXIT ERR INT QUIT
# Names of variables containing secrets to save in env file.
SECRETS_ENV_VARS=(
'ALCHEMY_ETHEREUM_MAINNET_TOKEN'
'ALCHEMY_ETHEREUM_GOERLI_TOKEN'
'ALCHEMY_ETHEREUM_SEPOLIA_TOKEN'
'ALCHEMY_ARBITRUM_GOERLI_TOKEN'
'ALCHEMY_ARBITRUM_MAINNET_TOKEN'
'ALCHEMY_ARBITRUM_SEPOLIA_TOKEN'
'ALCHEMY_OPTIMISM_GOERLI_TOKEN'
'ALCHEMY_OPTIMISM_MAINNET_TOKEN'
'ALCHEMY_OPTIMISM_SEPOLIA_TOKEN'
'RARIBLE_MAINNET_API_KEY'
+2 -1
View File
@@ -9,7 +9,8 @@ if test -n "$INVALID_CHANGES"; then
exit 1
fi
INVALID_CHANGES2=$(grep -E -r '(status-im\.)' --include '*.cljs' --include '*.clj' './src/utils')
# Add exception for status-im.config in the utils package check
INVALID_CHANGES2=$(grep -E -r '(status-im\.)' --include '*.cljs' --include '*.clj' './src/utils' | grep -v 'status-im.config')
if test -n "$INVALID_CHANGES2"; then
echo "WARNING: status-im are not allowed in utils package"
+55 -56
View File
@@ -51,56 +51,61 @@
;; the target files (a.k.a hot reload). When false, you can manually
;; reload by calling `shadow.cljs.devtools.api/watch-compile-all!`.
:devtools {:autobuild #shadow/env ["SHADOW_AUTOBUILD_ENABLED" :default true :as :bool]}
:dev {:devtools {:before-load-async status-im.setup.hot-reload/before-reload
:after-load-async status-im.setup.hot-reload/reload
:build-notify status-im.setup.hot-reload/build-notify
:preloads [;; The official recommendation is to
;; load the debugger preload first.
flow-storm.api
re-frisk-remote.preload
status-im.setup.schema-preload
;; In order to use component test helpers in the REPL we
;; need to preload namespaces that are not normally required
;; by production code, such as
;; @testing-library/react-native.
test-helpers.component]}
:closure-defines
{status-im.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im.config/INFURA_TOKEN #shadow/env "INFURA_TOKEN"
status-im.config/STATUS_BUILD_PROXY_USER #shadow/env "STATUS_BUILD_PROXY_USER"
status-im.config/STATUS_BUILD_PROXY_PASSWORD #shadow/env "STATUS_BUILD_PROXY_PASSWORD"
status-im.config/MIXPANEL_APP_ID #shadow/env "MIXPANEL_APP_ID"
status-im.config/MIXPANEL_TOKEN #shadow/env "MIXPANEL_TOKEN"
status-im.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"
status-im.config/RARIBLE_MAINNET_API_KEY #shadow/env "RARIBLE_MAINNET_API_KEY"
status-im.config/RARIBLE_TESTNET_API_KEY #shadow/env "RARIBLE_TESTNET_API_KEY"
status-im.config/ALCHEMY_ETHEREUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ETHEREUM_MAINNET_TOKEN"
status-im.config/ALCHEMY_ETHEREUM_GOERLI_TOKEN #shadow/env "ALCHEMY_ETHEREUM_GOERLI_TOKEN"
status-im.config/ALCHEMY_ETHEREUM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_ETHEREUM_SEPOLIA_TOKEN"
status-im.config/ALCHEMY_ARBITRUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ARBITRUM_MAINNET_TOKEN"
status-im.config/ALCHEMY_ARBITRUM_GOERLI_TOKEN #shadow/env "ALCHEMY_ARBITRUM_GOERLI_TOKEN"
status-im.config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_ARBITRUM_SEPOLIA_TOKEN"
status-im.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN"
status-im.config/ALCHEMY_OPTIMISM_GOERLI_TOKEN #shadow/env "ALCHEMY_OPTIMISM_GOERLI_TOKEN"
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"}
:compiler-options {:output-feature-set :es5
;; We disable `:fn-deprecated` warnings because we
;; are managing deprecation via clj-kondo and we
;; don't want the terminal output to be littered
;; with warnings on every code reload.
:warnings {:fn-deprecated false}
:closure-defines {re-frame.trace/trace-enabled? true}
:source-map false
;; This seems to be necessary while using the REPL,
;; otherwise sometimes you'll get weird errors when
;; instrumenting functions.
:static-fns false
:infer-externs true
:reader-features #{:mobile}}
;; if you want to use a real device, set your local ip
;; in the SHADOW_HOST env variable to make sure that
;; it will use the right interface
:local-ip #shadow/env "SHADOW_HOST"}
:dev
{:devtools {:before-load-async status-im.setup.hot-reload/before-reload
:after-load-async status-im.setup.hot-reload/reload
:build-notify status-im.setup.hot-reload/build-notify
:preloads [;; The official recommendation is to
;; load the debugger preload first.
flow-storm.api
re-frisk-remote.preload
status-im.setup.schema-preload
;; In order to use component test helpers in the REPL we need to
;; preload namespaces that are not normally required by
;; production code, such as @testing-library/react-native.
test-helpers.component]}
:closure-defines
{status-im.config/POKT_TOKEN #shadow/env "POKT_TOKEN"
status-im.config/INFURA_TOKEN #shadow/env "INFURA_TOKEN"
status-im.config/STATUS_BUILD_PROXY_USER #shadow/env "STATUS_BUILD_PROXY_USER"
status-im.config/STATUS_BUILD_PROXY_PASSWORD #shadow/env "STATUS_BUILD_PROXY_PASSWORD"
status-im.config/STATUS_BACKEND_SERVER_ENABLED #shadow/env "STATUS_BACKEND_SERVER_ENABLED"
status-im.config/STATUS_BACKEND_SERVER_HOST #shadow/env "STATUS_BACKEND_SERVER_HOST"
status-im.config/STATUS_BACKEND_SERVER_MEDIA_SERVER_ENABLE_TLS
#shadow/env "STATUS_BACKEND_SERVER_MEDIA_SERVER_ENABLE_TLS"
status-im.config/STATUS_BACKEND_SERVER_IMAGE_SERVER_URI_PREFIX
#shadow/env "STATUS_BACKEND_SERVER_IMAGE_SERVER_URI_PREFIX"
status-im.config/STATUS_BACKEND_SERVER_ROOT_DATA_DIR #shadow/env
"STATUS_BACKEND_SERVER_ROOT_DATA_DIR"
status-im.config/MIXPANEL_APP_ID #shadow/env "MIXPANEL_APP_ID"
status-im.config/MIXPANEL_TOKEN #shadow/env "MIXPANEL_TOKEN"
status-im.config/OPENSEA_API_KEY #shadow/env "OPENSEA_API_KEY"
status-im.config/RARIBLE_MAINNET_API_KEY #shadow/env "RARIBLE_MAINNET_API_KEY"
status-im.config/RARIBLE_TESTNET_API_KEY #shadow/env "RARIBLE_TESTNET_API_KEY"
status-im.config/ALCHEMY_ETHEREUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ETHEREUM_MAINNET_TOKEN"
status-im.config/ALCHEMY_ETHEREUM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_ETHEREUM_SEPOLIA_TOKEN"
status-im.config/ALCHEMY_ARBITRUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ARBITRUM_MAINNET_TOKEN"
status-im.config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_ARBITRUM_SEPOLIA_TOKEN"
status-im.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN"
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"}
:compiler-options {:output-feature-set :es5
;; We disable `:fn-deprecated` warnings because we
;; are managing deprecation via clj-kondo and we
;; don't want the terminal output to be littered
;; with warnings on every code reload.
:warnings {:fn-deprecated false}
:closure-defines {re-frame.trace/trace-enabled? true}
:source-map false
;; This seems to be necessary while using the REPL,
;; otherwise sometimes you'll get weird errors when
;; instrumenting functions.
:static-fns false
:infer-externs true
:reader-features #{:mobile}}
;; if you want to use a real device, set your local ip
;; in the SHADOW_HOST env variable to make sure that
;; it will use the right interface
:local-ip #shadow/env "SHADOW_HOST"}
:chunks {:fleets legacy.status-im.fleet.default-fleet/default-fleets}
:release
{:closure-defines
@@ -114,13 +119,10 @@
status-im.config/RARIBLE_MAINNET_API_KEY #shadow/env "RARIBLE_MAINNET_API_KEY"
status-im.config/RARIBLE_TESTNET_API_KEY #shadow/env "RARIBLE_TESTNET_API_KEY"
status-im.config/ALCHEMY_ETHEREUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ETHEREUM_MAINNET_TOKEN"
status-im.config/ALCHEMY_ETHEREUM_GOERLI_TOKEN #shadow/env "ALCHEMY_ETHEREUM_GOERLI_TOKEN"
status-im.config/ALCHEMY_ETHEREUM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_ETHEREUM_SEPOLIA_TOKEN"
status-im.config/ALCHEMY_ARBITRUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ARBITRUM_MAINNET_TOKEN"
status-im.config/ALCHEMY_ARBITRUM_GOERLI_TOKEN #shadow/env "ALCHEMY_ARBITRUM_GOERLI_TOKEN"
status-im.config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_ARBITRUM_SEPOLIA_TOKEN"
status-im.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN"
status-im.config/ALCHEMY_OPTIMISM_GOERLI_TOKEN #shadow/env "ALCHEMY_OPTIMISM_GOERLI_TOKEN"
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"}
:compiler-options {:output-feature-set :es6
;;disable for android build as there
@@ -158,13 +160,10 @@
status-im.config/RARIBLE_MAINNET_API_KEY #shadow/env "RARIBLE_MAINNET_API_KEY"
status-im.config/RARIBLE_TESTNET_API_KEY #shadow/env "RARIBLE_TESTNET_API_KEY"
status-im.config/ALCHEMY_ETHEREUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ETHEREUM_MAINNET_TOKEN"
status-im.config/ALCHEMY_ETHEREUM_GOERLI_TOKEN #shadow/env "ALCHEMY_ETHEREUM_GOERLI_TOKEN"
status-im.config/ALCHEMY_ETHEREUM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_ETHEREUM_SEPOLIA_TOKEN"
status-im.config/ALCHEMY_ARBITRUM_MAINNET_TOKEN #shadow/env "ALCHEMY_ARBITRUM_MAINNET_TOKEN"
status-im.config/ALCHEMY_ARBITRUM_GOERLI_TOKEN #shadow/env "ALCHEMY_ARBITRUM_GOERLI_TOKEN"
status-im.config/ALCHEMY_ARBITRUM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_ARBITRUM_SEPOLIA_TOKEN"
status-im.config/ALCHEMY_OPTIMISM_MAINNET_TOKEN #shadow/env "ALCHEMY_OPTIMISM_MAINNET_TOKEN"
status-im.config/ALCHEMY_OPTIMISM_GOERLI_TOKEN #shadow/env "ALCHEMY_OPTIMISM_GOERLI_TOKEN"
status-im.config/ALCHEMY_OPTIMISM_SEPOLIA_TOKEN #shadow/env "ALCHEMY_OPTIMISM_SEPOLIA_TOKEN"
status-im.config/WALLET_CONNECT_PROJECT_ID #shadow/env "WALLET_CONNECT_PROJECT_ID"}
:compiler-options
@@ -10,40 +10,3 @@ export function scrollDownButtonOpacity(chatListScrollY, isComposerFocused, wind
}
});
}
export function jumpToButtonOpacity(scrollDownButtonOpacity, isComposerFocused) {
return useDerivedValue(function () {
'worklet';
return withTiming(scrollDownButtonOpacity.value == 1 || isComposerFocused.value ? 0 : 1);
});
}
export function jumpToButtonPosition(scrollDownButtonOpacity, isComposerFocused) {
return useDerivedValue(function () {
'worklet';
return withTiming(scrollDownButtonOpacity.value == 1 || isComposerFocused.value ? 35 : 0);
});
}
export function composerContainerOpacity(isComposerFocused, isEmptyInput, emptyOpacity) {
return useDerivedValue(function () {
'worklet';
return isEmptyInput.value && !isComposerFocused.value
? withDelay(300, withTiming(emptyOpacity, { duration: 0 }))
: 1;
});
}
export function blurContainerElevation(isComposerFocused, isEmptyInput) {
return useDerivedValue(function () {
'worklet';
return isEmptyInput.value && !isComposerFocused.value ? 10 : 0;
});
}
export function composerElevation(isComposerFocused, isEmptyInput) {
return useDerivedValue(function () {
'worklet';
return isEmptyInput.value && !isComposerFocused.value ? 0 : 10;
});
}
+2 -37
View File
@@ -1,47 +1,12 @@
import { useDerivedValue, withTiming } from 'react-native-reanimated';
import * as constants from './constants';
export function bottomTabIconColor(
stackId,
selectedStackId,
homeStackState,
passThrough,
selectedTabColor,
defaultColor,
passThroughColor,
) {
export function bottomTabIconColor(stackId, selectedStackId, selectedTabColor, defaultColor) {
return useDerivedValue(function () {
'worklet';
var homeStackStateValue = homeStackState.value;
if (
selectedStackId.value == stackId &&
(homeStackStateValue == constants.OPEN_WITH_ANIMATION || homeStackStateValue == constants.OPEN_WITHOUT_ANIMATION)
) {
if (selectedStackId.value == stackId) {
return selectedTabColor;
} else if (passThrough.value) {
return passThroughColor;
} else {
return defaultColor;
}
});
}
export function bottomTabsHeight(homeStackState, height, extendedHeight) {
return useDerivedValue(function () {
'worklet';
switch (homeStackState.value) {
case constants.OPEN_WITH_ANIMATION:
return withTiming(extendedHeight, constants.LINEAR_EASING);
break;
case constants.CLOSE_WITH_ANIMATION:
return withTiming(height, constants.LINEAR_EASING);
break;
case constants.OPEN_WITHOUT_ANIMATION:
return extendedHeight;
break;
case constants.CLOSE_WITHOUT_ANIMATION:
return height;
break;
}
});
}
-29
View File
@@ -1,29 +0,0 @@
import { Easing } from 'react-native-reanimated';
// Home Stack States
export const CLOSE_WITHOUT_ANIMATION = 0;
export const OPEN_WITHOUT_ANIMATION = 1;
export const CLOSE_WITH_ANIMATION = 2;
export const OPEN_WITH_ANIMATION = 3;
// Floating Screen States
export const CLOSE_SCREEN_WITHOUT_ANIMATION = 0;
export const OPEN_SCREEN_WITHOUT_ANIMATION = 1;
export const CLOSE_SCREEN_WITH_SHELL_ANIMATION = 2;
export const OPEN_SCREEN_WITH_SHELL_ANIMATION = 3;
export const CLOSE_SCREEN_WITH_SLIDE_TO_RIGHT_ANIMATION = 4;
export const OPEN_SCREEN_WITH_SLIDE_FROM_RIGHT_ANIMATION = 5;
export const CLOSE_SCREEN_WITH_SLIDE_TO_BOTTOM_ANIMATION = 6;
export const OPEN_SCREEN_WITH_SLIDE_FROM_BOTTOM_ANIMATION = 7;
export const SHELL_ANIMATION_TIME = 200;
export const LINEAR_EASING = {
duration: SHELL_ANIMATION_TIME,
easing: Easing.bezier(0, 0, 1, 1),
};
export const EASE_OUT_EASING = {
duration: SHELL_ANIMATION_TIME,
easing: Easing.bezier(0, 0, 0.58, 1),
};
-180
View File
@@ -1,180 +0,0 @@
import { useDerivedValue, withTiming, withSequence, withDelay, Easing, runOnJS } from 'react-native-reanimated';
import * as constants from './constants';
// Derived Values
export function screenLeft(screenState, screenWidth, switcherCardLeftPosition) {
return useDerivedValue(function () {
'worklet';
switch (screenState.value) {
case constants.CLOSE_SCREEN_WITHOUT_ANIMATION:
return screenWidth;
case constants.OPEN_SCREEN_WITHOUT_ANIMATION:
// Note - don't use return 0; its not working in ios
// https://github.com/software-mansion/react-native-reanimated/issues/3296#issuecomment-1573900172
return withSequence(withTiming(-1, { duration: 0 }), withTiming(0, { duration: 0 }));
case constants.CLOSE_SCREEN_WITH_SHELL_ANIMATION:
return withSequence(
withTiming(switcherCardLeftPosition, constants.EASE_OUT_EASING),
withTiming(screenWidth, { duration: 0 }),
);
case constants.OPEN_SCREEN_WITH_SHELL_ANIMATION:
return withTiming(0, constants.EASE_OUT_EASING);
case constants.CLOSE_SCREEN_WITH_SLIDE_TO_RIGHT_ANIMATION:
return withTiming(screenWidth, constants.EASE_OUT_EASING);
case constants.OPEN_SCREEN_WITH_SLIDE_FROM_RIGHT_ANIMATION:
return withTiming(0, constants.EASE_OUT_EASING);
case constants.CLOSE_SCREEN_WITH_SLIDE_TO_BOTTOM_ANIMATION:
return withDelay(constants.SHELL_ANIMATION_TIME, withTiming(screenWidth, { duration: 0 }));
case constants.OPEN_SCREEN_WITH_SLIDE_FROM_BOTTOM_ANIMATION:
return 0;
default:
return screenWidth;
}
});
}
export function screenTop(screenState, screenHeight, switcherCardTopPosition) {
return useDerivedValue(function () {
'worklet';
switch (screenState.value) {
case constants.CLOSE_SCREEN_WITHOUT_ANIMATION:
return screenHeight;
case constants.OPEN_SCREEN_WITHOUT_ANIMATION:
return withSequence(withTiming(-1, { duration: 0 }), withTiming(0, { duration: 0 }));
case constants.CLOSE_SCREEN_WITH_SHELL_ANIMATION:
return withSequence(
withTiming(switcherCardTopPosition, constants.EASE_OUT_EASING),
withTiming(screenHeight, { duration: 0 }),
);
case constants.OPEN_SCREEN_WITH_SHELL_ANIMATION:
return withTiming(0, constants.EASE_OUT_EASING);
case constants.CLOSE_SCREEN_WITH_SLIDE_TO_RIGHT_ANIMATION:
return withDelay(constants.SHELL_ANIMATION_TIME, withTiming(screenHeight, { duration: 0 }));
case constants.OPEN_SCREEN_WITH_SLIDE_FROM_RIGHT_ANIMATION:
return 0;
case constants.CLOSE_SCREEN_WITH_SLIDE_TO_BOTTOM_ANIMATION:
return withTiming(screenHeight, constants.EASE_OUT_EASING);
case constants.OPEN_SCREEN_WITH_SLIDE_FROM_BOTTOM_ANIMATION:
return withTiming(0, constants.EASE_OUT_EASING);
default:
return screenHeight;
}
});
}
export function screenWidth(screenState, screenWidth, switcherCardSize) {
return useDerivedValue(function () {
'worklet';
switch (screenState.value) {
case constants.CLOSE_SCREEN_WITH_SHELL_ANIMATION:
return withTiming(switcherCardSize, constants.EASE_OUT_EASING);
case constants.OPEN_SCREEN_WITH_SHELL_ANIMATION:
return withSequence(
withTiming(switcherCardSize, { duration: 0 }),
withTiming(screenWidth, constants.EASE_OUT_EASING),
);
default:
return screenWidth;
}
});
}
export function screenHeight(screenState, screenHeight, switcherCardSize) {
return useDerivedValue(function () {
'worklet';
switch (screenState.value) {
case constants.CLOSE_SCREEN_WITH_SHELL_ANIMATION:
return withTiming(switcherCardSize, constants.EASE_OUT_EASING);
case constants.OPEN_SCREEN_WITH_SHELL_ANIMATION:
return withSequence(
withTiming(switcherCardSize, { duration: 0 }),
withTiming(screenHeight, constants.EASE_OUT_EASING),
);
default:
return screenHeight;
}
});
}
export function screenZIndex(screenState) {
return useDerivedValue(function () {
'worklet';
switch (screenState.value) {
case constants.CLOSE_SCREEN_WITH_SHELL_ANIMATION:
case constants.CLOSE_SCREEN_WITH_SLIDE_TO_RIGHT_ANIMATION:
case constants.CLOSE_SCREEN_WITH_SLIDE_TO_BOTTOM_ANIMATION:
return withDelay(constants.SHELL_ANIMATION_TIME, withTiming(-1, { duration: 0 }));
case constants.CLOSE_SCREEN_WITHOUT_ANIMATION:
return -1;
default:
return 1;
}
});
}
export function screenBorderRadius(screenState) {
return useDerivedValue(function () {
'worklet';
switch (screenState.value) {
case constants.OPEN_SCREEN_WITH_SHELL_ANIMATION:
return withDelay(constants.SHELL_ANIMATION_TIME, withTiming(0, { duration: 0 }));
case constants.OPEN_SCREEN_WITH_SLIDE_FROM_RIGHT_ANIMATION:
case constants.OPEN_SCREEN_WITH_SLIDE_FROM_BOTTOM_ANIMATION:
case constants.OPEN_SCREEN_WITHOUT_ANIMATION:
return 0;
case constants.CLOSE_SCREEN_WITH_SLIDE_TO_RIGHT_ANIMATION:
case constants.CLOSE_SCREEN_WITH_SLIDE_TO_BOTTOM_ANIMATION:
return withDelay(constants.SHELL_ANIMATION_TIME, withTiming(20, { duration: 0 }));
case constants.CLOSE_SCREEN_WITHOUT_ANIMATION:
case constants.CLOSE_SCREEN_WITH_SHELL_ANIMATION:
return 20;
}
});
}
export function screenGestureOnUpdate(screenLeft) {
return function (event) {
'worklet';
const absoluteX = event.absoluteX;
if (absoluteX !== null) {
screenLeft.value = event.absoluteX;
}
};
}
export function screenGestureOnEnd(data) {
return function (event) {
'worklet';
const {
'screen-left': screenLeft,
'screen-state': screenState,
'screen-width': screenWidth,
'left-velocity': leftVelocity,
'right-velocity': rightVelocity,
'screen-closed-callback': screenClosedCallback,
} = data;
const absoluteX = event.absoluteX ?? 0;
const velocityX = event.velocityX ?? 0;
const closeScreen = velocityX > rightVelocity || (velocityX > leftVelocity && absoluteX >= screenWidth / 2);
// Velocity (points/sec) = Distance/time
var animationVelocity = (screenWidth * 1000) / constants.SHELL_ANIMATION_TIME;
if (Math.abs(velocityX) > animationVelocity) {
animationVelocity = velocityX; // Faster fling
}
const newDistance = closeScreen ? screenWidth - absoluteX : absoluteX;
const animationTime = (newDistance * 1000) / animationVelocity;
screenLeft.value = withTiming(closeScreen ? screenWidth : 0, {
duration: animationTime,
easing: Easing.bezier(0, 0, 0.58, 1),
});
if (closeScreen) {
runOnJS(screenClosedCallback)(animationTime);
}
};
}
-97
View File
@@ -1,5 +1,4 @@
import { useDerivedValue, withTiming, withSequence, withDelay } from 'react-native-reanimated';
import * as constants from './constants';
// Derived values for each stack (communities, chat, wallet, browser)
export function stackOpacity(stackId, selectedStackId) {
@@ -15,99 +14,3 @@ export function stackZIndex(stackId, selectedStackId) {
return selectedStackId.value == stackId ? 10 : 9;
});
}
// Derived values for home stack (container)
export function homeStackOpacity(homeStackState) {
return useDerivedValue(function () {
'worklet';
switch (homeStackState.value) {
case constants.OPEN_WITH_ANIMATION:
return withTiming(1, constants.LINEAR_EASING);
case constants.CLOSE_WITH_ANIMATION:
return withTiming(0, constants.LINEAR_EASING);
case constants.OPEN_WITHOUT_ANIMATION:
return 1;
case constants.CLOSE_WITHOUT_ANIMATION:
return 0;
}
});
}
export function homeStackTop(homeStackState, top) {
return useDerivedValue(function () {
'worklet';
switch (homeStackState.value) {
case constants.OPEN_WITH_ANIMATION:
return withTiming(0, constants.LINEAR_EASING);
case constants.CLOSE_WITH_ANIMATION:
return withTiming(top, constants.LINEAR_EASING);
case constants.OPEN_WITHOUT_ANIMATION:
return 0;
case constants.CLOSE_WITHOUT_ANIMATION:
return top;
}
});
}
export function homeStackLeft(selectedStackId, animateHomeStackLeft, homeStackState, left) {
return useDerivedValue(function () {
'worklet';
if (animateHomeStackLeft.value) {
var leftValue = left[selectedStackId.value];
switch (homeStackState.value) {
case constants.OPEN_WITH_ANIMATION:
return withSequence(withTiming(leftValue, { duration: 0 }), withTiming(0, constants.LINEAR_EASING));
case constants.CLOSE_WITH_ANIMATION:
return withTiming(leftValue, constants.LINEAR_EASING);
case constants.OPEN_WITHOUT_ANIMATION:
return 0;
case constants.CLOSE_WITHOUT_ANIMATION:
return leftValue;
}
} else {
return 0;
}
});
}
export function homeStackPointer(homeStackState) {
return useDerivedValue(function () {
'worklet';
var homeStackStateValue = homeStackState.value;
return homeStackStateValue == constants.OPEN_WITH_ANIMATION ||
homeStackStateValue == constants.OPEN_WITHOUT_ANIMATION
? 'auto'
: 'none';
});
}
export function homeStackScale(homeStackState, minimizeScale) {
return useDerivedValue(function () {
'worklet';
switch (homeStackState.value) {
case constants.OPEN_WITH_ANIMATION:
return withTiming(1, constants.LINEAR_EASING);
case constants.CLOSE_WITH_ANIMATION:
return withTiming(minimizeScale, constants.LINEAR_EASING);
case constants.OPEN_WITHOUT_ANIMATION:
return 1;
case constants.CLOSE_WITHOUT_ANIMATION:
return minimizeScale;
}
});
}
export function homeStackBorderRadius(homeStackState) {
return useDerivedValue(function () {
'worklet';
switch (homeStackState.value) {
case constants.OPEN_WITH_ANIMATION:
return withDelay(constants.SHELL_ANIMATION_TIME, withTiming(0, { duration: 0 }));
case constants.CLOSE_WITH_ANIMATION:
case constants.CLOSE_WITHOUT_ANIMATION:
return 20;
case constants.OPEN_WITHOUT_ANIMATION:
return 0;
}
});
}

Some files were not shown because too many files have changed in this diff Show More