Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13cf34634c | ||
|
|
2e2104d4d1 | ||
|
|
ac48fbef44 | ||
|
|
8f67f38de9 | ||
|
|
ea4578b3e0 | ||
|
|
2b40a4d0c4 | ||
|
|
17afff272e | ||
|
|
3526355e23 | ||
|
|
f708cdcf50 | ||
|
|
3af4384e00 | ||
|
|
a6b19c021f | ||
|
|
a258717e83 | ||
|
|
a8395e51a4 | ||
|
|
db501b5efd | ||
|
|
44732e9736 | ||
|
|
d12c05aab6 | ||
|
|
4134d18cbc | ||
|
|
8600c1d3a5 | ||
|
|
570c62e30e | ||
|
|
549efdb77c | ||
|
|
8807a63989 | ||
|
|
c0be0b7670 | ||
|
|
6e854428f2 | ||
|
|
c81dd8e3e3 | ||
|
|
24f4c4a07e | ||
|
|
98762c74f1 | ||
|
|
f3aeddb53a | ||
|
|
f5fcc9f45e | ||
|
|
9aa9dc1b4c | ||
|
|
61974dae4d | ||
|
|
8b3e639abd | ||
|
|
7c901fa045 | ||
|
|
8a12ad3510 | ||
|
|
c8044cd2f2 | ||
|
|
6872d1a857 | ||
|
|
98d4969ca5 | ||
|
|
5412092ca1 | ||
|
|
a8695116e2 | ||
|
|
76773a4165 | ||
|
|
32fc7b14e8 | ||
|
|
82a8f9f44d | ||
|
|
8df72d0c29 | ||
|
|
794cd57961 | ||
|
|
6bc29088ab | ||
|
|
658f62e8ce | ||
|
|
e6b346ca32 | ||
|
|
00b0755a73 | ||
|
|
f8cc85f5e2 | ||
|
|
6ba89d0c6e | ||
|
|
2614131426 | ||
|
|
cfc43be3cc | ||
|
|
3164cc6a6c | ||
|
|
5badb5bdb5 | ||
|
|
292fd78ff8 | ||
|
|
c875fb33fa | ||
|
|
b5962fd83a | ||
|
|
1d1eae13a9 | ||
|
|
63a168b6f4 | ||
|
|
ce7912632c | ||
|
|
ec53f17897 | ||
|
|
7987e537c8 | ||
|
|
074a2b292d | ||
|
|
8b417524fa | ||
|
|
f6a433c818 | ||
|
|
4940341504 | ||
|
|
06aa4671b6 | ||
|
|
7eaa5f6bb1 | ||
|
|
d48f933502 | ||
|
|
14d76eb4d4 | ||
|
|
ae1f82f33c |
@@ -35,3 +35,4 @@ LOCAL_PAIRING_ENABLED=1
|
||||
TEST_STATEOFUS=1
|
||||
FAST_CREATE_COMMUNITY_ENABLED=1
|
||||
TEST_NETWORKS_ENABLED=1
|
||||
SHOW_NOT_IMPLEMENTED_FEATURES=1
|
||||
|
||||
@@ -34,3 +34,6 @@ STICKERS_TEST_ENABLED=1
|
||||
LOCAL_PAIRING_ENABLED=1
|
||||
FAST_CREATE_COMMUNITY_ENABLED=1
|
||||
TEST_NETWORKS_ENABLED=1
|
||||
SHOW_NOT_IMPLEMENTED_FEATURES=1
|
||||
DELETE_MESSAGE_FOR_ME_UNDO_TIME_LIMIT=10000
|
||||
DELETE_MESSAGE_UNDO_TIME_LIMIT=10000
|
||||
|
||||
@@ -36,3 +36,4 @@ STICKERS_TEST_ENABLED=1
|
||||
LOCAL_PAIRING_ENABLED=1
|
||||
FAST_CREATE_COMMUNITY_ENABLED=1
|
||||
TEST_NETWORKS_ENABLED=1
|
||||
SHOW_NOT_IMPLEMENTED_FEATURES=1
|
||||
|
||||
@@ -36,6 +36,12 @@ pipeline {
|
||||
))
|
||||
}
|
||||
|
||||
environment {
|
||||
/* Avoid race conditions with other builds using virtualenv. */
|
||||
VIRTUAL_ENV = "${WORKSPACE_TMP}/venv"
|
||||
PATH = "${VIRTUAL_ENV}/bin:${PATH}"
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Fetch') {
|
||||
steps { script {
|
||||
@@ -52,7 +58,8 @@ pipeline {
|
||||
stage('Setup') {
|
||||
steps { script {
|
||||
dir('test/appium') {
|
||||
sh 'pip3 install --user -r requirements.txt'
|
||||
sh "python3 -m venv ${VIRTUAL_ENV}"
|
||||
sh 'pip3 install -r requirements.txt'
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
@@ -54,6 +54,12 @@ pipeline {
|
||||
))
|
||||
}
|
||||
|
||||
environment {
|
||||
/* Avoid race conditions with other builds using virtualenv. */
|
||||
VIRTUAL_ENV = "${WORKSPACE_TMP}/venv"
|
||||
PATH = "${VIRTUAL_ENV}/bin:${PATH}"
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Prep') {
|
||||
steps { script {
|
||||
@@ -79,7 +85,8 @@ pipeline {
|
||||
stage('Setup') {
|
||||
steps { script {
|
||||
dir('test/appium') {
|
||||
sh 'pip3 install --user -r requirements.txt'
|
||||
sh "python3 -m venv ${VIRTUAL_ENV}"
|
||||
sh 'pip3 install -r requirements.txt'
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
@@ -35,6 +35,11 @@ pipeline {
|
||||
))
|
||||
}
|
||||
|
||||
environment {
|
||||
/* Avoid race conditions with other builds using virtualenv. */
|
||||
VIRTUAL_ENV = "${WORKSPACE_TMP}/venv"
|
||||
PATH = "${VIRTUAL_ENV}/bin:${PATH}"
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Prep') {
|
||||
@@ -51,7 +56,8 @@ pipeline {
|
||||
stage('Setup') {
|
||||
steps { script {
|
||||
dir('test/appium') {
|
||||
sh 'pip3 install --user -r requirements.txt'
|
||||
sh "python3 -m venv ${VIRTUAL_ENV}"
|
||||
sh 'pip3 install -r requirements.txt'
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ The generally accepted requirements for its use are described below:
|
||||
- Once a PR is created, it moves to the ```REVIEW``` column where a review will be requested automatically.
|
||||
- You can also request a review inside the PR from a particular person if needed.
|
||||
- When creating a PR, do not forget to assign it to yourself.
|
||||
- Also in case the PR adds new functionality, a short description would be appreciated.
|
||||
- Also in case the PR adds new functionality, a description **MUST** be added.
|
||||
|
||||
### What if the work is still in progress?
|
||||
|
||||
@@ -28,26 +28,11 @@ Ready for testing, a PR should meet the following criteria:
|
||||
4. Has the label: `request-manual-qa` or `skip-manual-qa`.
|
||||
5. PRs **MUST** identify what area is affected and should have a description.
|
||||
|
||||
**NOTE:** Make sure that QAs are OK with that
|
||||
|
||||
### Adding `skip-manual-qa`
|
||||
|
||||
- Please ask another team member before adding the `skip-manual-qa` label (PR/Status community/DMs) so that there's a second opinion.
|
||||
- The PR MUST have a proper reasoning why manual QA is skipped.
|
||||
- The PR MUST include the steps of testing that has been done by the developer prior to moving it forward.
|
||||
**From the perspective of a developer it means that once work on PR is finished:**
|
||||
|
||||
1. It should be rebased to the latest `develop`. If there are conflicts - they should be resolved if possible.
|
||||
2. If the PR was in the `Contributor` column - it should be moved to `Review` column.
|
||||
3. Wait for the review.
|
||||
4. Make sure that after review and before requesting manual QA your PR is rebased to current develop.
|
||||
5. The PR **MUST** be moved to the E2E column when it is ready for testing (**mandatory for all PRs**).
|
||||
That will also trigger e2e tests run. QAs are monitoring PRs from E2E column and take it into test.
|
||||
|
||||
6. After that - PR will be taken into manual testing by the QA team.
|
||||
|
||||
### E2E tests and analyzing the results
|
||||
|
||||
The PR **MUST** be moved to the E2E column when it is ready for testing (**mandatory for all PRs**).
|
||||
That will also trigger e2e tests run. QAs are monitoring PRs from E2E column and take it into test.
|
||||
This step cannot be skipped. So, at least one comment from the `status-im-auto` bot with results is a prerequisite for moving forward.
|
||||
Information on how to analyze tests can be found [here](https://github.com/status-im/status-mobile/blob/develop/doc/how-to-launch-e2e.md).
|
||||
Tests might be flaky, as they depend on infrastructure - SauceLabs and Waku.
|
||||
@@ -59,6 +44,20 @@ Please, respect this rule.**
|
||||
|
||||
## Testing PR
|
||||
|
||||
### Adding `skip-manual-qa`
|
||||
|
||||
**Do not hesitate to use a `skip-manual-qa`** if you're sure that it is a simple flow and you checked it.
|
||||
- Please ask another team member before adding the `skip-manual-qa` label (PR/Status community/DMs) so that there's a second opinion.
|
||||
- The PR MUST have a proper reasoning why manual QA is skipped.
|
||||
- The PR MUST include the steps of testing that has been done by the developer prior to moving it forward.
|
||||
|
||||
**NOTE:** Make sure that QAs are OK with that;
|
||||
|
||||
Before merging PRs, please make sure that information is added about how you tested the PRs, that e2s have been passed and their results have been reviewed.
|
||||
|
||||
The QA team appreciates your help!
|
||||
|
||||
|
||||
### Manual testing
|
||||
|
||||
#### Prerequisites for manual testing
|
||||
@@ -99,7 +98,7 @@ There are three possible scenarios when the design review is completed:
|
||||
---
|
||||
**Notes:**
|
||||
- If your PR has a long story and started from `develop` branch several days ago, please rebase it to current develop before adding label
|
||||
- if PR can be tested by developer (in case of small changes) and/or developer is sure that the changes made cannot introduce a regression, then PR can be merged without manual testing. Also, currently, PRs are not manually tested if the changes relate only the design (creation of components, etc.) and do not affect the functionality.
|
||||
- if PR can be tested by developer (in case of small changes) and/or developer is sure that the changes made cannot introduce a regression, then PR can be merged without manual testing. Also, currently, PRs are not manually tested if the changes relate only the design (creation of components, etc.) and do not affect the functionality (see `skip-manual-qa` label)
|
||||
---
|
||||
|
||||
#### Why my PR is in `Contributor` column?
|
||||
|
||||
@@ -128,3 +128,19 @@ Status-mobile uses `shadow-cljs` for hot reloading changes and uses its own [rel
|
||||
|
||||
### Solution
|
||||
Open react native's [In-App Developer Menu](https://reactnative.dev/docs/debugging#accessing-the-in-app-developer-menu) and press "Disable Fast Refresh" or "Disable Hot Reloading"
|
||||
|
||||
# App crashing after running `make run-ios`
|
||||
|
||||
### Cause
|
||||
It's possible that installing XCode from a `.xip` file might cause XCode to act funny
|
||||
Since it's not installed from the App Store, Or you might be missing a Rosetta installation.
|
||||
|
||||
[Reference/Similar issue](https://github.com/expo/expo-cli/issues/3197)
|
||||
|
||||
You might see something like this after running `make run-ios`:
|
||||
```
|
||||
Underlying error (domain=FBSOpenApplicationServiceErrorDomain, code=1):
|
||||
```
|
||||
### Solution
|
||||
Run `softwareupdate --install-rosetta --agree-to-license`
|
||||
to accept XCode's license and install Rosetta.
|
||||
|
||||
@@ -217,6 +217,7 @@ GEM
|
||||
|
||||
PLATFORMS
|
||||
arm64-darwin-22
|
||||
x86_64-darwin-22
|
||||
|
||||
DEPENDENCIES
|
||||
activesupport (>= 6.1.7.3, < 7.1.0)
|
||||
|
||||
@@ -881,7 +881,9 @@ PODS:
|
||||
- React-Core
|
||||
- react-native-blur (4.3.3):
|
||||
- React-Core
|
||||
- react-native-cameraroll (5.10.0):
|
||||
- react-native-cameraroll (7.5.2):
|
||||
- glog
|
||||
- RCT-Folly (= 2022.05.16.00)
|
||||
- React-Core
|
||||
- react-native-config (1.5.0):
|
||||
- react-native-config/App (= 1.5.0)
|
||||
@@ -1475,7 +1477,7 @@ SPEC CHECKSUMS:
|
||||
react-native-biometrics: 352e5a794bfffc46a0c86725ea7dc62deb085bdc
|
||||
react-native-blob-util: 600972b1782380a5a7d5db61a3817ea32349dae9
|
||||
react-native-blur: c6d0a1dc2b4b519f7afe3b14d8151998632b6d18
|
||||
react-native-cameraroll: 4701ae7c3dbcd3f5e9e150ca17f250a276154b35
|
||||
react-native-cameraroll: af8eec1e585d053ff485d98ec837f9a8a11b5745
|
||||
react-native-config: 5330c8258265c1e5fdb8c009d2cabd6badd96727
|
||||
react-native-hole-view: 6935448993bac79f2b5a4ad7e9741094cf810679
|
||||
react-native-image-resizer: 2f1577efa3bc762597681f530c8e8d05ce0ceeb3
|
||||
|
||||
@@ -1,351 +0,0 @@
|
||||
package im.status.ethereum.module;
|
||||
|
||||
import com.facebook.react.bridge.Callback;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import statusgo.Statusgo;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONException;
|
||||
import android.util.Log;
|
||||
import android.content.Context;
|
||||
import android.app.Activity;
|
||||
|
||||
public class AccountManager extends ReactContextBaseJavaModule {
|
||||
private static final String TAG = "AccountManager";
|
||||
private static final String gethLogFileName = "geth.log";
|
||||
private ReactApplicationContext reactContext;
|
||||
|
||||
private Utils utils;
|
||||
private LogManager logManager;
|
||||
|
||||
public AccountManager(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
this.reactContext = reactContext;
|
||||
this.utils = new Utils(reactContext);
|
||||
this.logManager = new LogManager(reactContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "AccountManager";
|
||||
}
|
||||
|
||||
private String getTestnetDataDir(final String absRootDirPath) {
|
||||
return this.utils.pathCombine(absRootDirPath, "ethereum/testnet");
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void createAccountAndLogin(final String createAccountRequest) {
|
||||
Log.d(TAG, "createAccountAndLogin");
|
||||
String 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);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void restoreAccountAndLogin(final String restoreAccountRequest) {
|
||||
Log.d(TAG, "restoreAccountAndLogin");
|
||||
String 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);
|
||||
}
|
||||
}
|
||||
|
||||
private String updateConfig(final String jsonConfigString, final String absRootDirPath, final String keystoreDirPath) throws JSONException {
|
||||
final JSONObject jsonConfig = new JSONObject(jsonConfigString);
|
||||
// retrieve parameters from app config, that will be applied onto the Go-side config later on
|
||||
final String dataDirPath = jsonConfig.getString("DataDir");
|
||||
final Boolean logEnabled = jsonConfig.getBoolean("LogEnabled");
|
||||
final Context context = this.getReactApplicationContext();
|
||||
final File gethLogFile = logEnabled ? this.logManager.prepareLogsFile(context) : null;
|
||||
String gethLogDirPath = null;
|
||||
if (gethLogFile != null) {
|
||||
gethLogDirPath = gethLogFile.getParent();
|
||||
}
|
||||
|
||||
Log.d(TAG, "log dir: " + gethLogDirPath + " log name: " + gethLogFileName);
|
||||
|
||||
jsonConfig.put("DataDir", dataDirPath);
|
||||
jsonConfig.put("KeyStoreDir", keystoreDirPath);
|
||||
jsonConfig.put("LogDir", gethLogDirPath);
|
||||
jsonConfig.put("LogFile", gethLogFileName);
|
||||
|
||||
return jsonConfig.toString();
|
||||
}
|
||||
|
||||
private static void prettyPrintConfig(final String config) {
|
||||
Log.d(TAG, "startNode() with config (see below)");
|
||||
String configOutput = config;
|
||||
final int maxOutputLen = 4000;
|
||||
Log.d(TAG, "********************** NODE CONFIG ****************************");
|
||||
while (!configOutput.isEmpty()) {
|
||||
Log.d(TAG, "Node config:" + configOutput.substring(0, Math.min(maxOutputLen, configOutput.length())));
|
||||
if (configOutput.length() > maxOutputLen) {
|
||||
configOutput = configOutput.substring(maxOutputLen);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Log.d(TAG, "******************* ENDOF NODE CONFIG *************************");
|
||||
}
|
||||
|
||||
private void copyDirectory(File sourceLocation, File targetLocation) throws IOException {
|
||||
if (sourceLocation.isDirectory()) {
|
||||
if (!targetLocation.exists() && !targetLocation.mkdirs()) {
|
||||
throw new IOException("Cannot create dir " + targetLocation.getAbsolutePath());
|
||||
}
|
||||
|
||||
String[] children = sourceLocation.list();
|
||||
for (int i = 0; i < children.length; i++) {
|
||||
copyDirectory(new File(sourceLocation, children[i]), new File(targetLocation, children[i]));
|
||||
}
|
||||
} else {
|
||||
File directory = targetLocation.getParentFile();
|
||||
if (directory != null && !directory.exists() && !directory.mkdirs()) {
|
||||
throw new IOException("Cannot create dir " + directory.getAbsolutePath());
|
||||
}
|
||||
|
||||
InputStream in = new FileInputStream(sourceLocation);
|
||||
OutputStream out = new FileOutputStream(targetLocation);
|
||||
|
||||
byte[] buf = new byte[1024];
|
||||
int len;
|
||||
while ((len = in.read(buf)) > 0) {
|
||||
out.write(buf, 0, len);
|
||||
}
|
||||
in.close();
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
private String prepareDirAndUpdateConfig(final String jsonConfigString, final String keyUID) {
|
||||
|
||||
final String absRootDirPath = this.utils.getNoBackupDirectory();
|
||||
final String dataFolder = this.getTestnetDataDir(absRootDirPath);
|
||||
Log.d(TAG, "Starting Geth node in folder: " + dataFolder);
|
||||
|
||||
try {
|
||||
final File newFile = new File(dataFolder);
|
||||
// todo handle error?
|
||||
newFile.mkdir();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "error making folder: " + dataFolder, e);
|
||||
}
|
||||
|
||||
final String ropstenFlagPath = this.utils.pathCombine(absRootDirPath, "ropsten_flag");
|
||||
final File ropstenFlag = new File(ropstenFlagPath);
|
||||
if (!ropstenFlag.exists()) {
|
||||
try {
|
||||
final String chaindDataFolderPath = this.utils.pathCombine(dataFolder, "StatusIM/lightchaindata");
|
||||
final File lightChainFolder = new File(chaindDataFolderPath);
|
||||
if (lightChainFolder.isDirectory()) {
|
||||
String[] children = lightChainFolder.list();
|
||||
for (int i = 0; i < children.length; i++) {
|
||||
new File(lightChainFolder, children[i]).delete();
|
||||
}
|
||||
}
|
||||
lightChainFolder.delete();
|
||||
ropstenFlag.createNewFile();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
String testnetDataDir = dataFolder;
|
||||
String oldKeystoreDir = this.utils.pathCombine(testnetDataDir, "keystore");
|
||||
String newKeystoreDir = this.utils.pathCombine(absRootDirPath, "keystore");
|
||||
final File oldKeystore = new File(oldKeystoreDir);
|
||||
if (oldKeystore.exists()) {
|
||||
try {
|
||||
final File newKeystore = new File(newKeystoreDir);
|
||||
copyDirectory(oldKeystore, newKeystore);
|
||||
|
||||
if (oldKeystore.isDirectory()) {
|
||||
String[] children = oldKeystore.list();
|
||||
for (int i = 0; i < children.length; i++) {
|
||||
new File(oldKeystoreDir, children[i]).delete();
|
||||
}
|
||||
}
|
||||
oldKeystore.delete();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
final String multiaccountKeystoreDir = this.utils.pathCombine("/keystore", keyUID);
|
||||
final String updatedJsonConfigString = this.updateConfig(jsonConfigString, absRootDirPath, multiaccountKeystoreDir);
|
||||
|
||||
prettyPrintConfig(updatedJsonConfigString);
|
||||
|
||||
return updatedJsonConfigString;
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "updateConfig failed: " + e.getMessage());
|
||||
System.exit(1);
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void prepareDirAndUpdateConfig(final String keyUID, final String config, final Callback callback) {
|
||||
Log.d(TAG, "prepareDirAndUpdateConfig");
|
||||
String finalConfig = prepareDirAndUpdateConfig(config, keyUID);
|
||||
callback.invoke(finalConfig);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void saveAccountAndLoginWithKeycard(final String multiaccountData, final String password, final String settings, final String config, final String accountsData, final String chatKey) {
|
||||
Log.d(TAG, "saveAccountAndLoginWithKeycard");
|
||||
String finalConfig = prepareDirAndUpdateConfig(config, this.utils.getKeyUID(multiaccountData));
|
||||
String result = Statusgo.saveAccountAndLoginWithKeycard(multiaccountData, password, settings, finalConfig, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void loginWithKeycard(final String accountData, final String password, final String chatKey, final String nodeConfigJSON) {
|
||||
Log.d(TAG, "loginWithKeycard");
|
||||
this.utils.migrateKeyStoreDir(accountData, password);
|
||||
String result = Statusgo.loginWithKeycard(accountData, password, chatKey, nodeConfigJSON);
|
||||
if (result.startsWith("{\"error\":\"\"")) {
|
||||
Log.d(TAG, "LoginWithKeycard result: " + result);
|
||||
} else {
|
||||
Log.e(TAG, "LoginWithKeycard failed: " + result);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void loginWithConfig(final String accountData, final String password, final String configJSON) {
|
||||
Log.d(TAG, "loginWithConfig");
|
||||
this.utils.migrateKeyStoreDir(accountData, password);
|
||||
String result = Statusgo.loginWithConfig(accountData, password, configJSON);
|
||||
if (result.startsWith("{\"error\":\"\"")) {
|
||||
Log.d(TAG, "LoginWithConfig result: " + result);
|
||||
} else {
|
||||
Log.e(TAG, "LoginWithConfig failed: " + result);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void loginAccount(final String request) {
|
||||
Log.d(TAG, "loginAccount");
|
||||
String result = Statusgo.loginAccount(request);
|
||||
if (result.startsWith("{\"error\":\"\"")) {
|
||||
Log.d(TAG, "loginAccount result: " + result);
|
||||
} else {
|
||||
Log.e(TAG, "loginAccount failed: " + result);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void verify(final String address, final String password, final Callback callback) throws JSONException {
|
||||
Activity currentActivity = getCurrentActivity();
|
||||
|
||||
final String absRootDirPath = this.utils.getNoBackupDirectory();
|
||||
final String newKeystoreDir = this.utils.pathCombine(absRootDirPath, "keystore");
|
||||
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.verifyAccountPassword(newKeystoreDir, address, password), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void verifyDatabasePassword(final String keyUID, final String password, final Callback callback) throws JSONException {
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.verifyDatabasePassword(keyUID, password), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
private void openAccounts(final Callback callback) throws JSONException {
|
||||
Log.d(TAG, "openAccounts");
|
||||
final String rootDir = this.utils.getNoBackupDirectory();
|
||||
Log.d(TAG, "[Opening accounts" + rootDir);
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.openAccounts(rootDir), callback);
|
||||
}
|
||||
|
||||
//TODO : refactor logout usage to accept callback so that we can do this.utils.executeRunnableStatusGoMethod
|
||||
@ReactMethod
|
||||
public void logout() {
|
||||
Log.d(TAG, "logout");
|
||||
Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String result = Statusgo.logout();
|
||||
if (result.startsWith("{\"error\":\"\"")) {
|
||||
Log.d(TAG, "Logout result: " + result);
|
||||
} else {
|
||||
Log.e(TAG, "Logout failed: " + result);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
StatusThreadPoolExecutor.getInstance().execute(r);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void multiAccountStoreAccount(final String json, final Callback callback) throws JSONException {
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountStoreAccount(json), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void multiAccountLoadAccount(final String json, final Callback callback) throws JSONException {
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountLoadAccount(json), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void multiAccountDeriveAddresses(final String json, final Callback callback) throws JSONException {
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountDeriveAddresses(json), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void multiAccountGenerateAndDeriveAddresses(final String json, final Callback callback) throws JSONException {
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountGenerateAndDeriveAddresses(json), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void multiAccountStoreDerived(final String json, final Callback callback) throws JSONException {
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountStoreDerivedAccounts(json), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void multiAccountImportMnemonic(final String json, final Callback callback) throws JSONException {
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountImportMnemonic(json), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void multiAccountImportPrivateKey(final String json, final Callback callback) throws JSONException {
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.multiAccountImportPrivateKey(json), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void deleteMultiaccount(final String keyUID, final Callback callback) throws JSONException {
|
||||
final String keyStoreDir = this.utils.getKeyStorePath(keyUID);
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.deleteMultiaccount(keyUID, keyStoreDir), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void getRandomMnemonic(final Callback callback) throws JSONException {
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.getRandomMnemonic(), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void createAccountFromMnemonicAndDeriveAccountsForPaths(final String mnemonic, final Callback callback) throws JSONException {
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.createAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic), callback);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,333 @@
|
||||
package im.status.ethereum.module
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import com.facebook.react.bridge.Callback
|
||||
import com.facebook.react.bridge.ReactApplicationContext
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
||||
import com.facebook.react.bridge.ReactMethod
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import statusgo.Statusgo
|
||||
import java.io.*
|
||||
|
||||
class AccountManager(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
|
||||
|
||||
private val utils = Utils(reactContext)
|
||||
private val logManager = LogManager(reactContext)
|
||||
|
||||
override fun getName() = "AccountManager"
|
||||
|
||||
private fun getTestnetDataDir(absRootDirPath: String) = utils.pathCombine(absRootDirPath, "ethereum/testnet")
|
||||
|
||||
@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")
|
||||
}
|
||||
}
|
||||
|
||||
@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")
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateConfig(jsonConfigString: String, absRootDirPath: String, keystoreDirPath: String): String {
|
||||
val jsonConfig = JSONObject(jsonConfigString)
|
||||
val dataDirPath = jsonConfig.getString("DataDir")
|
||||
val logEnabled = jsonConfig.getBoolean("LogEnabled")
|
||||
val gethLogFile = if (logEnabled) logManager.prepareLogsFile(reactContext) else null
|
||||
val gethLogDirPath = gethLogFile?.parent
|
||||
|
||||
Log.d(TAG, "log dir: $gethLogDirPath log name: $gethLogFileName")
|
||||
|
||||
jsonConfig.put("DataDir", dataDirPath)
|
||||
jsonConfig.put("KeyStoreDir", keystoreDirPath)
|
||||
jsonConfig.put("LogDir", gethLogDirPath)
|
||||
jsonConfig.put("LogFile", gethLogFileName)
|
||||
|
||||
return jsonConfig.toString()
|
||||
}
|
||||
|
||||
private fun copyDirectory(sourceLocation: File, targetLocation: File) {
|
||||
if (sourceLocation.isDirectory) {
|
||||
if (!targetLocation.exists() && !targetLocation.mkdirs()) {
|
||||
throw IOException("Cannot create dir ${targetLocation.absolutePath}")
|
||||
}
|
||||
|
||||
val children = sourceLocation.list()
|
||||
children?.forEach { child ->
|
||||
copyDirectory(File(sourceLocation, child), File(targetLocation, child))
|
||||
}
|
||||
} else {
|
||||
val directory = targetLocation.parentFile
|
||||
if (directory != null && !directory.exists() && !directory.mkdirs()) {
|
||||
throw IOException("Cannot create dir ${directory.absolutePath}")
|
||||
}
|
||||
|
||||
sourceLocation.inputStream().use { input ->
|
||||
targetLocation.outputStream().use { output ->
|
||||
input.copyTo(output)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareDirAndUpdateConfig(jsonConfigString: String, keyUID: String): String {
|
||||
val absRootDirPath = utils.getNoBackupDirectory()
|
||||
val dataFolder = getTestnetDataDir(absRootDirPath)
|
||||
Log.d(TAG, "Starting Geth node in folder: $dataFolder")
|
||||
|
||||
try {
|
||||
File(dataFolder).mkdir()
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "error making folder: $dataFolder", e)
|
||||
}
|
||||
|
||||
val ropstenFlagPath = utils.pathCombine(absRootDirPath, "ropsten_flag")
|
||||
val ropstenFlag = File(ropstenFlagPath)
|
||||
if (!ropstenFlag.exists()) {
|
||||
try {
|
||||
val chaindDataFolderPath = utils.pathCombine(dataFolder, "StatusIM/lightchaindata")
|
||||
val lightChainFolder = File(chaindDataFolderPath)
|
||||
if (lightChainFolder.isDirectory) {
|
||||
lightChainFolder.listFiles()?.forEach { it.delete() }
|
||||
}
|
||||
lightChainFolder.delete()
|
||||
ropstenFlag.createNewFile()
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
val testnetDataDir = dataFolder
|
||||
val oldKeystoreDir = utils.pathCombine(testnetDataDir, "keystore")
|
||||
val newKeystoreDir = utils.pathCombine(absRootDirPath, "keystore")
|
||||
val oldKeystore = File(oldKeystoreDir)
|
||||
if (oldKeystore.exists()) {
|
||||
try {
|
||||
val newKeystore = File(newKeystoreDir)
|
||||
copyDirectory(oldKeystore, newKeystore)
|
||||
|
||||
if (oldKeystore.isDirectory) {
|
||||
oldKeystore.listFiles()?.forEach { it.delete() }
|
||||
}
|
||||
oldKeystore.delete()
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
return try {
|
||||
val multiaccountKeystoreDir = utils.pathCombine("/keystore", keyUID)
|
||||
val updatedJsonConfigString = updateConfig(jsonConfigString, absRootDirPath, multiaccountKeystoreDir)
|
||||
|
||||
prettyPrintConfig(updatedJsonConfigString)
|
||||
|
||||
updatedJsonConfigString
|
||||
} catch (e: JSONException) {
|
||||
Log.e(TAG, "updateConfig failed: ${e.message}")
|
||||
System.exit(1)
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun prepareDirAndUpdateConfig(keyUID: String, config: String, callback: Callback) {
|
||||
Log.d(TAG, "prepareDirAndUpdateConfig")
|
||||
val finalConfig = prepareDirAndUpdateConfig(config, keyUID)
|
||||
callback.invoke(finalConfig)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun saveAccountAndLoginWithKeycard(
|
||||
multiaccountData: String,
|
||||
password: String,
|
||||
settings: String,
|
||||
config: String,
|
||||
accountsData: String,
|
||||
chatKey: String
|
||||
) {
|
||||
try {
|
||||
Log.d(TAG, "saveAccountAndLoginWithKeycard")
|
||||
val keyUID = utils.getKeyUID(multiaccountData)
|
||||
val finalConfig = prepareDirAndUpdateConfig(config, keyUID)
|
||||
val result = Statusgo.saveAccountAndLoginWithKeycard(
|
||||
multiaccountData,
|
||||
password,
|
||||
settings,
|
||||
finalConfig,
|
||||
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")
|
||||
}
|
||||
} catch (e: JSONException) {
|
||||
Log.e(TAG, "JSON conversion failed: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun loginWithKeycard(accountData: String, password: String, chatKey: String, nodeConfigJSON: String) {
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun loginWithConfig(accountData: String, password: String, configJSON: String) {
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
@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")
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun verify(address: String, password: String, callback: Callback) {
|
||||
val absRootDirPath = utils.getNoBackupDirectory()
|
||||
val newKeystoreDir = utils.pathCombine(absRootDirPath, "keystore")
|
||||
|
||||
utils.executeRunnableStatusGoMethod(
|
||||
{ Statusgo.verifyAccountPassword(newKeystoreDir, address, password) },
|
||||
callback
|
||||
)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun verifyDatabasePassword(keyUID: String, password: String, callback: Callback) {
|
||||
utils.executeRunnableStatusGoMethod(
|
||||
{ Statusgo.verifyDatabasePassword(keyUID, password) },
|
||||
callback
|
||||
)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
private fun openAccounts(callback: Callback) {
|
||||
Log.d(TAG, "openAccounts")
|
||||
val rootDir = utils.getNoBackupDirectory()
|
||||
Log.d(TAG, "[Opening accounts $rootDir")
|
||||
utils.executeRunnableStatusGoMethod({ Statusgo.openAccounts(rootDir) }, 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)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun multiAccountStoreAccount(json: String, callback: Callback) {
|
||||
utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountStoreAccount(json) }, callback)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun multiAccountLoadAccount(json: String, callback: Callback) {
|
||||
utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountLoadAccount(json) }, callback)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun multiAccountDeriveAddresses(json: String, callback: Callback) {
|
||||
utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountDeriveAddresses(json) }, callback)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun multiAccountGenerateAndDeriveAddresses(json: String, callback: Callback) {
|
||||
utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountGenerateAndDeriveAddresses(json) }, callback)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun multiAccountStoreDerived(json: String, callback: Callback) {
|
||||
utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountStoreDerivedAccounts(json) }, callback)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun multiAccountImportMnemonic(json: String, callback: Callback) {
|
||||
utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountImportMnemonic(json) }, callback)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun multiAccountImportPrivateKey(json: String, callback: Callback) {
|
||||
utils.executeRunnableStatusGoMethod({ Statusgo.multiAccountImportPrivateKey(json) }, callback)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun deleteMultiaccount(keyUID: String, callback: Callback) {
|
||||
val keyStoreDir = utils.getKeyStorePath(keyUID)
|
||||
utils.executeRunnableStatusGoMethod({ Statusgo.deleteMultiaccount(keyUID, keyStoreDir) }, callback)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun getRandomMnemonic(callback: Callback) {
|
||||
utils.executeRunnableStatusGoMethod({ Statusgo.getRandomMnemonic() }, callback)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun createAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic: String, callback: Callback) {
|
||||
utils.executeRunnableStatusGoMethod(
|
||||
{ Statusgo.createAccountFromMnemonicAndDeriveAccountsForPaths(mnemonic) },
|
||||
callback
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "AccountManager"
|
||||
private const val gethLogFileName = "geth.log"
|
||||
|
||||
private fun prettyPrintConfig(config: String) {
|
||||
Log.d(TAG, "startNode() with config (see below)")
|
||||
var configOutput = config
|
||||
val maxOutputLen = 4000
|
||||
Log.d(TAG, "********************** NODE CONFIG ****************************")
|
||||
while (configOutput.isNotEmpty()) {
|
||||
Log.d(TAG, "Node config:${configOutput.take(maxOutputLen)}")
|
||||
configOutput = configOutput.drop(maxOutputLen)
|
||||
}
|
||||
Log.d(TAG, "******************* ENDOF NODE CONFIG *************************")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package im.status.ethereum.module;
|
||||
|
||||
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 statusgo.Statusgo;
|
||||
import android.util.Log;
|
||||
import java.io.File;
|
||||
import android.os.Environment;
|
||||
import android.content.Context;
|
||||
public class DatabaseManager extends ReactContextBaseJavaModule {
|
||||
private static final String TAG = "DatabaseManager";
|
||||
private ReactApplicationContext reactContext;
|
||||
private static final String exportDBFileName = "export.db";
|
||||
private Utils utils;
|
||||
public DatabaseManager(ReactApplicationContext reactContext) {
|
||||
this.reactContext = reactContext;
|
||||
this.utils = new Utils(reactContext);
|
||||
}
|
||||
@Override
|
||||
public String getName() {
|
||||
return "DatabaseManager";
|
||||
}
|
||||
|
||||
private File getExportDBFile() {
|
||||
final Context context = this.getReactApplicationContext();
|
||||
// Environment.getExternalStoragePublicDirectory doesn't work as expected on Android Q
|
||||
// https://developer.android.com/reference/android/os/Environment#getExternalStoragePublicDirectory(java.lang.String)
|
||||
final File pubDirectory = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
|
||||
final File filename = new File(pubDirectory, exportDBFileName);
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void exportUnencryptedDatabase(final String accountData, final String password, final Callback callback) {
|
||||
Log.d(TAG, "login");
|
||||
|
||||
final File newFile = getExportDBFile();
|
||||
|
||||
this.utils.migrateKeyStoreDir(accountData, password);
|
||||
String result = Statusgo.exportUnencryptedDatabase(accountData, password, newFile.getAbsolutePath());
|
||||
if (result.startsWith("{\"error\":\"\"")) {
|
||||
Log.d(TAG, "Login result: " + result);
|
||||
} else {
|
||||
Log.e(TAG, "Login failed: " + result);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void importUnencryptedDatabase(final String accountData, final String password) {
|
||||
Log.d(TAG, "importUnencryptedDatabase");
|
||||
|
||||
final File newFile = getExportDBFile();
|
||||
|
||||
this.utils.migrateKeyStoreDir(accountData, password);
|
||||
String result = Statusgo.importUnencryptedDatabase(accountData, password, newFile.getAbsolutePath());
|
||||
if (result.startsWith("{\"error\":\"\"")) {
|
||||
Log.d(TAG, "import result: " + result);
|
||||
} else {
|
||||
Log.e(TAG, "import failed: " + result);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package im.status.ethereum.module
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Environment
|
||||
import android.util.Log
|
||||
import com.facebook.react.bridge.Callback
|
||||
import com.facebook.react.bridge.ReactApplicationContext
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
||||
import com.facebook.react.bridge.ReactMethod
|
||||
import statusgo.Statusgo
|
||||
import java.io.File
|
||||
|
||||
class DatabaseManager(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
|
||||
|
||||
private val utils = Utils(reactContext)
|
||||
|
||||
override fun getName() = "DatabaseManager"
|
||||
|
||||
private fun getExportDBFile(): File {
|
||||
val pubDirectory = reactContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
|
||||
return File(pubDirectory, exportDBFileName)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun exportUnencryptedDatabase(accountData: String, password: String, callback: Callback) {
|
||||
Log.d(TAG, "login")
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun importUnencryptedDatabase(accountData: String, password: String) {
|
||||
Log.d(TAG, "importUnencryptedDatabase")
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "DatabaseManager"
|
||||
private const val exportDBFileName = "export.db"
|
||||
}
|
||||
}
|
||||
@@ -1,227 +0,0 @@
|
||||
package im.status.ethereum.module;
|
||||
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.Callback;
|
||||
import java.io.File;
|
||||
import java.util.Stack;
|
||||
import android.util.Log;
|
||||
import android.net.Uri;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.IOException;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import androidx.core.content.FileProvider;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import org.json.JSONObject;
|
||||
import statusgo.Statusgo;
|
||||
import android.content.Context;
|
||||
import org.json.JSONException;
|
||||
public class LogManager extends ReactContextBaseJavaModule {
|
||||
private static final String TAG = "LogManager";
|
||||
private static final String gethLogFileName = "geth.log";
|
||||
private static final String statusLogFileName = "Status.log";
|
||||
private static final String logsZipFileName = "Status-debug-logs.zip";
|
||||
private ReactApplicationContext reactContext;
|
||||
private Utils utils;
|
||||
|
||||
public LogManager(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
this.reactContext = reactContext;
|
||||
this.utils = new Utils(reactContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "LogManager";
|
||||
}
|
||||
|
||||
private File getLogsFile() {
|
||||
final File pubDirectory = this.utils.getPublicStorageDirectory();
|
||||
final File logFile = new File(pubDirectory, gethLogFileName);
|
||||
|
||||
return logFile;
|
||||
}
|
||||
|
||||
public File prepareLogsFile(final Context context) {
|
||||
final File logFile = this.utils.getLogsFile();
|
||||
|
||||
try {
|
||||
logFile.setReadable(true);
|
||||
File parent = logFile.getParentFile();
|
||||
if (!parent.canWrite()) {
|
||||
return null;
|
||||
}
|
||||
if (!parent.exists()) {
|
||||
parent.mkdirs();
|
||||
}
|
||||
logFile.createNewFile();
|
||||
logFile.setWritable(true);
|
||||
Log.d(TAG, "Can write " + logFile.canWrite());
|
||||
Uri gethLogUri = Uri.fromFile(logFile);
|
||||
|
||||
String gethLogFilePath = logFile.getAbsolutePath();
|
||||
Log.d(TAG, gethLogFilePath);
|
||||
|
||||
return logFile;
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "Can't create geth.log file! " + e.getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void showErrorMessage(final String message) {
|
||||
final Activity activity = getCurrentActivity();
|
||||
|
||||
new AlertDialog.Builder(activity)
|
||||
.setTitle("Error")
|
||||
.setMessage(message)
|
||||
.setNegativeButton("Exit", new DialogInterface.OnClickListener() {
|
||||
public void onClick(final DialogInterface dialog, final int id) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
|
||||
private void dumpAdbLogsTo(final FileOutputStream statusLogStream) throws IOException {
|
||||
final String filter = "logcat -d -b main ReactNativeJS:D StatusModule:D StatusService:D StatusNativeLogs:D *:S";
|
||||
final java.lang.Process p = Runtime.getRuntime().exec(filter);
|
||||
final java.io.BufferedReader in = new java.io.BufferedReader(new java.io.InputStreamReader(p.getInputStream()));
|
||||
final java.io.BufferedWriter out = new java.io.BufferedWriter(new java.io.OutputStreamWriter(statusLogStream));
|
||||
String line;
|
||||
while ((line = in.readLine()) != null) {
|
||||
out.write(line);
|
||||
out.newLine();
|
||||
}
|
||||
out.close();
|
||||
in.close();
|
||||
}
|
||||
|
||||
private Boolean zip(File[] _files, File zipFile, Stack<String> errorList) {
|
||||
final int BUFFER = 0x8000;
|
||||
|
||||
try {
|
||||
BufferedInputStream origin = null;
|
||||
FileOutputStream dest = new FileOutputStream(zipFile);
|
||||
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest));
|
||||
byte data[] = new byte[BUFFER];
|
||||
|
||||
for (int i = 0; i < _files.length; i++) {
|
||||
final File file = _files[i];
|
||||
if (file == null || !file.exists()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Log.v("Compress", "Adding: " + file.getAbsolutePath());
|
||||
try {
|
||||
FileInputStream fi = new FileInputStream(file);
|
||||
origin = new BufferedInputStream(fi, BUFFER);
|
||||
|
||||
ZipEntry entry = new ZipEntry(file.getName());
|
||||
out.putNextEntry(entry);
|
||||
int count;
|
||||
|
||||
while ((count = origin.read(data, 0, BUFFER)) != -1) {
|
||||
out.write(data, 0, count);
|
||||
}
|
||||
origin.close();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, e.getMessage());
|
||||
errorList.push(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
out.close();
|
||||
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, e.getMessage());
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void sendLogs(final String dbJson, final String jsLogs, final Callback callback) {
|
||||
Log.d(TAG, "sendLogs");
|
||||
if (!this.utils.checkAvailability()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Context context = this.getReactApplicationContext();
|
||||
final File logsTempDir = new File(context.getCacheDir(), "logs"); // This path needs to be in sync with android/app/src/main/res/xml/file_provider_paths.xml
|
||||
logsTempDir.mkdir();
|
||||
|
||||
final File dbFile = new File(logsTempDir, "db.json");
|
||||
try {
|
||||
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(dbFile));
|
||||
outputStreamWriter.write(dbJson);
|
||||
outputStreamWriter.close();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "File write failed: " + e.toString());
|
||||
showErrorMessage(e.getLocalizedMessage());
|
||||
}
|
||||
|
||||
final File zipFile = new File(logsTempDir, logsZipFileName);
|
||||
final File statusLogFile = new File(logsTempDir, statusLogFileName);
|
||||
final File gethLogFile = getLogsFile();
|
||||
|
||||
try {
|
||||
if (zipFile.exists() || zipFile.createNewFile()) {
|
||||
final long usableSpace = zipFile.getUsableSpace();
|
||||
if (usableSpace < 20 * 1024 * 1024) {
|
||||
final String message = String.format("Insufficient space available on device (%s) to write logs.\nPlease free up some space.", android.text.format.Formatter.formatShortFileSize(context, usableSpace));
|
||||
Log.e(TAG, message);
|
||||
showErrorMessage(message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dumpAdbLogsTo(new FileOutputStream(statusLogFile));
|
||||
|
||||
final Stack<String> errorList = new Stack<String>();
|
||||
final Boolean zipped = zip(new File[]{dbFile, gethLogFile, statusLogFile}, zipFile, errorList);
|
||||
if (zipped && zipFile.exists()) {
|
||||
zipFile.setReadable(true, false);
|
||||
Uri extUri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", zipFile);
|
||||
callback.invoke(extUri.toString());
|
||||
} else {
|
||||
Log.d(TAG, "File " + zipFile.getAbsolutePath() + " does not exist");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, e.getMessage());
|
||||
showErrorMessage(e.getLocalizedMessage());
|
||||
e.printStackTrace();
|
||||
return;
|
||||
} finally {
|
||||
dbFile.delete();
|
||||
statusLogFile.delete();
|
||||
zipFile.deleteOnExit();
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void initLogging(final boolean enabled, final boolean mobileSystem, final String logLevel, final Callback callback) throws JSONException {
|
||||
final JSONObject jsonConfig = new JSONObject();
|
||||
jsonConfig.put("Enabled", enabled);
|
||||
jsonConfig.put("MobileSystem", mobileSystem);
|
||||
jsonConfig.put("Level", logLevel);
|
||||
jsonConfig.put("File", getLogsFile().getAbsolutePath());
|
||||
final String config = jsonConfig.toString();
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.initLogging(config), callback);
|
||||
}
|
||||
|
||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||
public String logFileDirectory() {
|
||||
return this.utils.getPublicStorageDirectory().getAbsolutePath();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
package im.status.ethereum.module
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import androidx.core.content.FileProvider
|
||||
import com.facebook.react.bridge.Callback
|
||||
import com.facebook.react.bridge.ReactApplicationContext
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
||||
import com.facebook.react.bridge.ReactMethod
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import statusgo.Statusgo
|
||||
import java.io.*
|
||||
import java.util.*
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
|
||||
class LogManager(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
|
||||
|
||||
private val utils = Utils(reactContext)
|
||||
|
||||
override fun getName() = "LogManager"
|
||||
|
||||
private fun getLogsFile(): File {
|
||||
val pubDirectory = utils.getPublicStorageDirectory()
|
||||
return File(pubDirectory, gethLogFileName)
|
||||
}
|
||||
|
||||
fun prepareLogsFile(context: Context): File? {
|
||||
val logFile = utils.getLogsFile()
|
||||
|
||||
try {
|
||||
logFile.setReadable(true)
|
||||
val parent = logFile.parentFile
|
||||
if (!parent?.canWrite()!!) {
|
||||
return null
|
||||
}
|
||||
if (!parent.exists()) {
|
||||
parent.mkdirs()
|
||||
}
|
||||
logFile.createNewFile()
|
||||
logFile.setWritable(true)
|
||||
Log.d(TAG, "Can write ${logFile.canWrite()}")
|
||||
val gethLogUri = Uri.fromFile(logFile)
|
||||
|
||||
val gethLogFilePath = logFile.absolutePath
|
||||
Log.d(TAG, gethLogFilePath)
|
||||
|
||||
return logFile
|
||||
} catch (e: Exception) {
|
||||
Log.d(TAG, "Can't create geth.log file! ${e.message}")
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun showErrorMessage(message: String) {
|
||||
val activity = currentActivity
|
||||
|
||||
AlertDialog.Builder(activity)
|
||||
.setTitle("Error")
|
||||
.setMessage(message)
|
||||
.setNegativeButton("Exit") { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
}.show()
|
||||
}
|
||||
|
||||
private fun dumpAdbLogsTo(statusLogStream: FileOutputStream) {
|
||||
val filter = "logcat -d -b main ReactNativeJS:D StatusModule:D StatusService:D StatusNativeLogs:D *:S"
|
||||
val p = Runtime.getRuntime().exec(filter)
|
||||
val input = BufferedReader(InputStreamReader(p.inputStream))
|
||||
val output = BufferedWriter(OutputStreamWriter(statusLogStream))
|
||||
var line: String?
|
||||
while (input.readLine().also { line = it } != null) {
|
||||
output.write(line)
|
||||
output.newLine()
|
||||
}
|
||||
output.close()
|
||||
input.close()
|
||||
}
|
||||
|
||||
private fun zip(files: Array<File>, zipFile: File, errorList: Stack<String>): Boolean {
|
||||
val BUFFER = 0x8000
|
||||
|
||||
try {
|
||||
var origin: BufferedInputStream? = null
|
||||
val dest = FileOutputStream(zipFile)
|
||||
val out = ZipOutputStream(BufferedOutputStream(dest))
|
||||
val data = ByteArray(BUFFER)
|
||||
|
||||
for (file in files) {
|
||||
if (file == null || !file.exists()) {
|
||||
continue
|
||||
}
|
||||
|
||||
Log.v("Compress", "Adding: ${file.absolutePath}")
|
||||
try {
|
||||
val fi = FileInputStream(file)
|
||||
origin = BufferedInputStream(fi, BUFFER)
|
||||
|
||||
val entry = ZipEntry(file.name)
|
||||
out.putNextEntry(entry)
|
||||
var count: Int
|
||||
|
||||
while (origin.read(data, 0, BUFFER).also { count = it } != -1) {
|
||||
out.write(data, 0, count)
|
||||
}
|
||||
origin.close()
|
||||
} catch (e: IOException) {
|
||||
Log.e(TAG, e.message!!)
|
||||
errorList.push(e.message!!)
|
||||
}
|
||||
}
|
||||
|
||||
out.close()
|
||||
|
||||
return true
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, e.message!!)
|
||||
e.printStackTrace()
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun sendLogs(dbJson: String, jsLogs: String, callback: Callback) {
|
||||
Log.d(TAG, "sendLogs")
|
||||
if (!utils.checkAvailability()) {
|
||||
return
|
||||
}
|
||||
|
||||
val context = reactApplicationContext
|
||||
val logsTempDir = File(context.cacheDir, "logs") // This path needs to be in sync with android/app/src/main/res/xml/file_provider_paths.xml
|
||||
logsTempDir.mkdir()
|
||||
|
||||
val dbFile = File(logsTempDir, "db.json")
|
||||
try {
|
||||
val outputStreamWriter = OutputStreamWriter(FileOutputStream(dbFile))
|
||||
outputStreamWriter.write(dbJson)
|
||||
outputStreamWriter.close()
|
||||
} catch (e: IOException) {
|
||||
Log.e(TAG, "File write failed: ${e}")
|
||||
showErrorMessage(e.localizedMessage!!)
|
||||
}
|
||||
|
||||
val zipFile = File(logsTempDir, logsZipFileName)
|
||||
val statusLogFile = File(logsTempDir, statusLogFileName)
|
||||
val gethLogFile = getLogsFile()
|
||||
|
||||
try {
|
||||
if (zipFile.exists() || zipFile.createNewFile()) {
|
||||
val usableSpace = zipFile.usableSpace
|
||||
if (usableSpace < 20 * 1024 * 1024) {
|
||||
val message = "Insufficient space available on device (${android.text.format.Formatter.formatShortFileSize(context, usableSpace)}) to write logs.\nPlease free up some space."
|
||||
Log.e(TAG, message)
|
||||
showErrorMessage(message)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
dumpAdbLogsTo(FileOutputStream(statusLogFile))
|
||||
|
||||
val errorList = Stack<String>()
|
||||
val zipped = zip(arrayOf(dbFile, gethLogFile, statusLogFile), zipFile, errorList)
|
||||
if (zipped && zipFile.exists()) {
|
||||
zipFile.setReadable(true, false)
|
||||
val extUri = FileProvider.getUriForFile(context, "${context.packageName}.provider", zipFile)
|
||||
callback.invoke(extUri.toString())
|
||||
} else {
|
||||
Log.d(TAG, "File ${zipFile.absolutePath} does not exist")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, e.message!!)
|
||||
showErrorMessage(e.localizedMessage!!)
|
||||
e.printStackTrace()
|
||||
return
|
||||
} finally {
|
||||
dbFile.delete()
|
||||
statusLogFile.delete()
|
||||
zipFile.deleteOnExit()
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun initLogging(enabled: Boolean, mobileSystem: Boolean, logLevel: String, callback: Callback) {
|
||||
val jsonConfig = JSONObject().apply {
|
||||
put("Enabled", enabled)
|
||||
put("MobileSystem", mobileSystem)
|
||||
put("Level", logLevel)
|
||||
put("File", getLogsFile().absolutePath)
|
||||
}
|
||||
val config = jsonConfig.toString()
|
||||
utils.executeRunnableStatusGoMethod({ Statusgo.initLogging(config) }, callback)
|
||||
}
|
||||
|
||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||
fun logFileDirectory(): String? {
|
||||
return utils.getPublicStorageDirectory()?.absolutePath
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "LogManager"
|
||||
private const val gethLogFileName = "geth.log"
|
||||
private const val statusLogFileName = "Status.log"
|
||||
private const val logsZipFileName = "Status-debug-logs.zip"
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package im.status.ethereum.module;
|
||||
|
||||
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 org.json.JSONException;
|
||||
import statusgo.Statusgo;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class NetworkManager extends ReactContextBaseJavaModule {
|
||||
private ReactApplicationContext reactContext;
|
||||
private Utils utils;
|
||||
|
||||
public NetworkManager(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
this.reactContext = reactContext;
|
||||
this.utils = new Utils(reactContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "NetworkManager";
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void startSearchForLocalPairingPeers(final Callback callback) throws JSONException {
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.startSearchForLocalPairingPeers(), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void getConnectionStringForBootstrappingAnotherDevice(final String configJSON, final Callback callback) throws JSONException {
|
||||
final JSONObject jsonConfig = new JSONObject(configJSON);
|
||||
final JSONObject senderConfig = jsonConfig.getJSONObject("senderConfig");
|
||||
final String keyUID = senderConfig.getString("keyUID");
|
||||
final String keyStorePath = this.utils.getKeyStorePath(keyUID);
|
||||
senderConfig.put("keystorePath", keyStorePath);
|
||||
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.getConnectionStringForBootstrappingAnotherDevice(jsonConfig.toString()), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void inputConnectionStringForBootstrapping(final String connectionString, final String configJSON, final Callback callback) throws JSONException {
|
||||
final JSONObject jsonConfig = new JSONObject(configJSON);
|
||||
final JSONObject receiverConfig = jsonConfig.getJSONObject("receiverConfig");
|
||||
final String keyStorePath = this.utils.pathCombine(this.utils.getNoBackupDirectory(), "/keystore");
|
||||
receiverConfig.put("keystorePath", keyStorePath);
|
||||
receiverConfig.getJSONObject("nodeConfig").put("rootDataDir", this.utils.getNoBackupDirectory());
|
||||
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.inputConnectionStringForBootstrapping(connectionString, jsonConfig.toString()), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void sendTransactionWithSignature(final String txArgsJSON, final String signature, final Callback callback) throws JSONException {
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.sendTransactionWithSignature(txArgsJSON, signature), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void sendTransaction(final String txArgsJSON, final String password, final Callback callback) throws JSONException {
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.sendTransaction(txArgsJSON, password), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void callRPC(final String payload, final Callback callback) throws JSONException {
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.callRPC(payload), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void callPrivateRPC(final String payload, final Callback callback) throws JSONException {
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.callPrivateRPC(payload), callback);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void recover(final String rpcParams, final Callback callback) throws JSONException {
|
||||
this.utils.executeRunnableStatusGoMethod(() -> Statusgo.recover(rpcParams), callback);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package im.status.ethereum.module
|
||||
|
||||
import com.facebook.react.bridge.Callback
|
||||
import com.facebook.react.bridge.ReactApplicationContext
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
||||
import com.facebook.react.bridge.ReactMethod
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import statusgo.Statusgo
|
||||
|
||||
class NetworkManager(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
|
||||
|
||||
private val utils = Utils(reactContext)
|
||||
|
||||
override fun getName() = "NetworkManager"
|
||||
|
||||
@ReactMethod
|
||||
fun startSearchForLocalPairingPeers(callback: Callback) {
|
||||
utils.executeRunnableStatusGoMethod({ Statusgo.startSearchForLocalPairingPeers() }, callback)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun getConnectionStringForBootstrappingAnotherDevice(configJSON: String, callback: Callback) {
|
||||
val jsonConfig = JSONObject(configJSON)
|
||||
val senderConfig = jsonConfig.getJSONObject("senderConfig")
|
||||
val keyUID = senderConfig.getString("keyUID")
|
||||
val keyStorePath = utils.getKeyStorePath(keyUID)
|
||||
senderConfig.put("keystorePath", keyStorePath)
|
||||
|
||||
utils.executeRunnableStatusGoMethod(
|
||||
{ Statusgo.getConnectionStringForBootstrappingAnotherDevice(jsonConfig.toString()) },
|
||||
callback
|
||||
)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun inputConnectionStringForBootstrapping(connectionString: String, configJSON: String, callback: Callback) {
|
||||
val jsonConfig = JSONObject(configJSON)
|
||||
val receiverConfig = jsonConfig.getJSONObject("receiverConfig")
|
||||
val keyStorePath = utils.pathCombine(utils.getNoBackupDirectory(), "/keystore")
|
||||
receiverConfig.put("keystorePath", keyStorePath)
|
||||
receiverConfig.getJSONObject("nodeConfig").put("rootDataDir", utils.getNoBackupDirectory())
|
||||
|
||||
utils.executeRunnableStatusGoMethod(
|
||||
{ Statusgo.inputConnectionStringForBootstrapping(connectionString, jsonConfig.toString()) },
|
||||
callback
|
||||
)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun sendTransactionWithSignature(txArgsJSON: String, signature: String, callback: Callback) {
|
||||
utils.executeRunnableStatusGoMethod(
|
||||
{ Statusgo.sendTransactionWithSignature(txArgsJSON, signature) },
|
||||
callback
|
||||
)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun sendTransaction(txArgsJSON: String, password: String, callback: Callback) {
|
||||
utils.executeRunnableStatusGoMethod({ Statusgo.sendTransaction(txArgsJSON, password) }, callback)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun callRPC(payload: String, callback: Callback) {
|
||||
utils.executeRunnableStatusGoMethod({ Statusgo.callRPC(payload) }, callback)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun callPrivateRPC(payload: String, callback: Callback) {
|
||||
utils.executeRunnableStatusGoMethod({ Statusgo.callPrivateRPC(payload) }, callback)
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun recover(rpcParams: String, callback: Callback) {
|
||||
utils.executeRunnableStatusGoMethod({ Statusgo.recover(rpcParams) }, callback)
|
||||
}
|
||||
}
|
||||
@@ -60,10 +60,10 @@ in {
|
||||
version = "15.0";
|
||||
allowHigher = true;
|
||||
};
|
||||
go = super.go_1_19;
|
||||
go = super.go_1_20;
|
||||
clang = super.clang_15;
|
||||
buildGoPackage = super.buildGo119Package;
|
||||
buildGoModule = super.buildGo119Module;
|
||||
buildGoPackage = super.buildGo120Package;
|
||||
buildGoModule = super.buildGo120Module;
|
||||
gomobile = (super.gomobile.overrideAttrs (old: {
|
||||
patches = [
|
||||
(self.fetchurl { # https://github.com/golang/mobile/pull/84
|
||||
|
||||
@@ -27,6 +27,7 @@ nix_install_type() {
|
||||
if [[ "$(os_name)" =~ NixOS ]]; then
|
||||
echo "nixos"
|
||||
else
|
||||
USER=$(id -un) # Missing in Docker.
|
||||
case "${NIX_STORE_DIR_GROUP}" in
|
||||
"nixbld") echo "multi";;
|
||||
"30000") echo "multi";;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-native-async-storage/async-storage": "1.19.3",
|
||||
"@react-native-camera-roll/camera-roll": "git+https://github.com/status-im/react-native-camera-roll.git#refs/tags/v5.1.1.1",
|
||||
"@react-native-camera-roll/camera-roll": "7.5.2",
|
||||
"@react-native-clipboard/clipboard": "1.13.2",
|
||||
"@react-native-community/audio-toolkit": "git+https://github.com/tbenr/react-native-audio-toolkit.git#refs/tags/v2.0.3-status-v6",
|
||||
"@react-native-community/blur": "git+https://github.com/status-im/react-native-blur.git#refs/tags/v4.3.3-status",
|
||||
@@ -48,7 +48,7 @@
|
||||
"react-native-keychain": "8.1.2",
|
||||
"react-native-linear-gradient": "^2.8.0",
|
||||
"react-native-lottie-splash-screen": "^1.0.1",
|
||||
"react-native-mail": "git+https://github.com/status-im/react-native-mail.git#refs/tags/v6.1.2-status",
|
||||
"react-native-mail": "6.1.1",
|
||||
"react-native-navigation": "7.38.3",
|
||||
"react-native-orientation-locker": "^1.5.0",
|
||||
"react-native-permissions": "3.8.0",
|
||||
@@ -94,7 +94,6 @@
|
||||
"prettier": "^2.8.8",
|
||||
"process": "0.11.10",
|
||||
"react-test-renderer": "18.1.0",
|
||||
"rn-snoopy": "git+https://github.com/status-im/rn-snoopy.git#refs/tags/v2.0.2-status",
|
||||
"shadow-cljs": "2.26.2"
|
||||
},
|
||||
"binary": {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
--- /tmp/tmp-status-mobile-3907e6b2e/tmp.re8kHerusA/CameraRoll.ts 2024-04-16 15:17:12.942432000 +0200
|
||||
+++ ./node_modules/@react-native-camera-roll/camera-roll/src/CameraRoll.ts 2024-04-16 15:17:42.455250986 +0200
|
||||
@@ -239,6 +239,19 @@
|
||||
}
|
||||
|
||||
/**
|
||||
+ * Returns total iOS image count
|
||||
+ */
|
||||
+ static getPhotosCountiOS(): Promise<number> {
|
||||
+ return RNCCameraRoll.getPhotosCountiOS('');
|
||||
+ }
|
||||
+ /**
|
||||
+ * Returns favorites and their count iOS
|
||||
+ */
|
||||
+ static getFavoritesiOS(): Promise<Album> {
|
||||
+ return RNCCameraRoll.getFavoritesiOS('');
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
* Saves the photo or video to the camera roll or photo library, and returns the URI of the newly created asset.
|
||||
*
|
||||
* @deprecated `save(...)` is deprecated - use `saveAsset(...)` instead.
|
||||
@@ -0,0 +1,11 @@
|
||||
--- /tmp/tmp-status-mobile-3907e6b2e/tmp.juxTO1BeCM/NativeCameraRollModule.ts 2024-04-16 15:21:28.379979000 +0200
|
||||
+++ ./node_modules/@react-native-camera-roll/camera-roll/src/NativeCameraRollModule.ts 2024-04-16 15:21:40.490391291 +0200
|
||||
@@ -81,6 +81,8 @@
|
||||
getPhotos(params: Object): Promise<PhotoIdentifiersPage>;
|
||||
getAlbums(params: Object): Promise<Album[]>;
|
||||
deletePhotos(photoUris: Array<string>): Promise<void>;
|
||||
+ getPhotosCountiOS(arg: string): Promise<number>;
|
||||
+ getFavoritesiOS(arg: string): Promise<Album>;
|
||||
getPhotoByInternalID(
|
||||
internalID: string,
|
||||
options: Object,
|
||||
@@ -0,0 +1,56 @@
|
||||
--- /tmp/tmp-status-mobile-3907e6b2e/tmp.O0mkyjqnsy/RNCCameraRoll.mm 2024-04-16 15:26:23.070258000 +0200
|
||||
+++ ./node_modules/@react-native-camera-roll/camera-roll/ios/RNCCameraRoll.mm 2024-04-16 15:26:32.664996066 +0200
|
||||
@@ -955,6 +955,53 @@
|
||||
return [albumTitles copy];
|
||||
}
|
||||
|
||||
+RCT_EXPORT_METHOD(getPhotosCountiOS:(NSString *)blank
|
||||
+ resolve:(RCTPromiseResolveBlock)resolve
|
||||
+ reject:(RCTPromiseRejectBlock)reject)
|
||||
+{
|
||||
+ __block NSInteger intTotalCount=0;
|
||||
+ PHFetchOptions *allPhotosOptions = [PHFetchOptions new];
|
||||
+ allPhotosOptions.predicate = [NSPredicate predicateWithFormat:@"mediaType == %d ",PHAssetMediaTypeImage];
|
||||
+ PHFetchResult *allPhotosResult = [PHAsset fetchAssetsWithOptions:allPhotosOptions];
|
||||
+ intTotalCount+=allPhotosResult.count;
|
||||
+
|
||||
+ resolve(@(intTotalCount));
|
||||
+}
|
||||
+
|
||||
+RCT_EXPORT_METHOD(getFavoritesiOS:(NSString *)blank
|
||||
+ resolve:(RCTPromiseResolveBlock)resolve
|
||||
+ reject:(RCTPromiseRejectBlock)reject)
|
||||
+{
|
||||
+ __block NSInteger intTotalCount=0;
|
||||
+ PHFetchOptions *fetchOptions = [PHFetchOptions new];
|
||||
+ NSString *format = @"(favorite == true)";
|
||||
+ fetchOptions.predicate = [NSPredicate predicateWithFormat:format];
|
||||
+ PHFetchResult<PHAsset *> *const assetsFetchResult = [PHAsset fetchAssetsWithOptions:fetchOptions];
|
||||
+ PHAsset *imageAsset = [assetsFetchResult firstObject];
|
||||
+ NSMutableArray * result = [NSMutableArray new];
|
||||
+
|
||||
+ for (PHAsset* asset in assetsFetchResult) {
|
||||
+ NSArray *resources = [PHAssetResource assetResourcesForAsset:asset ];
|
||||
+ if ([resources count] < 1) continue;
|
||||
+ NSString *orgFilename = ((PHAssetResource*)resources[0]).originalFilename;
|
||||
+ NSString *uit = ((PHAssetResource*)resources[0]).uniformTypeIdentifier;
|
||||
+ NSString *mimeType = (NSString *)CFBridgingRelease(UTTypeCopyPreferredTagWithClass((__bridge CFStringRef _Nonnull)(uit), kUTTagClassMIMEType));
|
||||
+ CFStringRef extension = UTTypeCopyPreferredTagWithClass((__bridge CFStringRef _Nonnull)(uit), kUTTagClassFilenameExtension);
|
||||
+ [result addObject:@{
|
||||
+ @"width": @([asset pixelWidth]),
|
||||
+ @"height": @([asset pixelHeight]),
|
||||
+ @"filename": orgFilename ?: @"",
|
||||
+ @"mimeType": mimeType ?: @"",
|
||||
+ @"id": [asset localIdentifier],
|
||||
+ @"creationDate": [asset creationDate],
|
||||
+ @"uri": [NSString stringWithFormat:@"ph://%@", [asset localIdentifier]],
|
||||
+ @"duration": @([asset duration])
|
||||
+ }];
|
||||
+ }
|
||||
+ [result addObject:@{@"count": @(assetsFetchResult.count)}];
|
||||
+ resolve(result);
|
||||
+}
|
||||
+
|
||||
static void checkPhotoLibraryConfig()
|
||||
{
|
||||
#if RCT_DEV
|
||||
@@ -0,0 +1,15 @@
|
||||
--- /tmp/tmp-status-mobile-6e854428f/tmp.PSruc8WtHx/build.gradle 2024-04-17 11:08:46.857319000 +0200
|
||||
+++ ./node_modules/react-native-mail/android/build.gradle 2024-04-17 11:09:22.935436792 +0200
|
||||
@@ -1,7 +1,11 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
+def safeExtGet(prop, fallback) {
|
||||
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
||||
+}
|
||||
+
|
||||
android {
|
||||
- compileSdkVersion project.hasProperty('compileSdkVersion') ? project.compileSdkVersion : 23
|
||||
+ compileSdkVersion safeExtGet('compileSdkVersion', 30)
|
||||
buildToolsVersion project.hasProperty('buildToolsVersion') ? project.buildToolsVersion : "23.0.1"
|
||||
|
||||
defaultConfig {
|
||||
|
After Width: | Height: | Size: 707 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 1.8 KiB |
@@ -1,9 +1,9 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
INVALID_CHANGES=$(grep -E -r '(re-frame/dispatch|rf/dispatch|re-frame/subscribe|rf/subscribe|rf/sub|<sub|>evt|status-im\.)' --include '*.cljs' --include '*.clj' './src/quo')
|
||||
INVALID_CHANGES=$(grep -E -r '(/atom|re-frame/dispatch|rf/dispatch|re-frame/subscribe|rf/subscribe|rf/sub|<sub|>evt|status-im\.)' --include '*.cljs' --include '*.clj' './src/quo')
|
||||
|
||||
if test -n "$INVALID_CHANGES"; then
|
||||
echo "WARNING: re-frame, status-im are not allowed in quo components"
|
||||
echo "WARNING: re-frame, status-im, reagent atoms are not allowed in quo components"
|
||||
echo ''
|
||||
echo "$INVALID_CHANGES"
|
||||
exit 1
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
(ns legacy.status-im.bootnodes.core
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def address-regex #"enode://[a-zA-Z0-9]+:?(.*)\@\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b:(\d{1,5})")
|
||||
|
||||
(defn valid-address?
|
||||
[address]
|
||||
(re-matches address-regex address))
|
||||
|
||||
(defn- build
|
||||
[id bootnode-name address chain]
|
||||
{:address address
|
||||
:chain chain
|
||||
:id (string/replace id "-" "")
|
||||
:name bootnode-name})
|
||||
|
||||
(rf/defn fetch
|
||||
[cofx id]
|
||||
(let [network (get-in cofx [:db :networks/current-network])]
|
||||
(get-in cofx [:db :profile/profile :custom-bootnodes network id])))
|
||||
|
||||
(rf/defn set-input
|
||||
{:events [:bootnodes.ui/input-changed]}
|
||||
[{:keys [db]} input-key value]
|
||||
{:db (update
|
||||
db
|
||||
:bootnodes/manage
|
||||
assoc
|
||||
input-key
|
||||
{:value value
|
||||
:error (case input-key
|
||||
:id false
|
||||
:name (string/blank? value)
|
||||
:url (not (valid-address? value)))})})
|
||||
|
||||
(rf/defn edit
|
||||
{:events [:bootnodes.ui/add-bootnode-pressed]}
|
||||
[{:keys [db] :as cofx} id]
|
||||
(let [{:keys [id
|
||||
address
|
||||
name]}
|
||||
(fetch cofx id)
|
||||
fxs (rf/merge cofx
|
||||
(set-input :id id)
|
||||
(set-input :url (str address))
|
||||
(set-input :name (str name)))]
|
||||
(assoc fxs :dispatch [:navigate-to :edit-bootnode])))
|
||||
|
||||
(defn custom-bootnodes-in-use?
|
||||
[{:keys [db]}]
|
||||
(let [network (:networks/current-network db)]
|
||||
(get-in db [:profile/profile :custom-bootnodes-enabled? network])))
|
||||
|
||||
(rf/defn delete
|
||||
[{{:profile/keys [profile] :as db} :db :as cofx} id]
|
||||
(let [network (:networks/current-network db)
|
||||
new-profile (update-in profile [:custom-bootnodes network] dissoc id)]
|
||||
(rf/merge cofx
|
||||
{:db (assoc db :profile/profile new-profile)}
|
||||
(multiaccounts.update/multiaccount-update
|
||||
:custom-bootnodes
|
||||
(:custom-bootnodes new-profile)
|
||||
{:success-event (when (custom-bootnodes-in-use? cofx)
|
||||
[:multiaccounts.update.callback/save-settings-success])}))))
|
||||
|
||||
(rf/defn upsert
|
||||
{:events [:bootnodes.ui/save-pressed]
|
||||
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
|
||||
[{{:bootnodes/keys [manage] :profile/keys [profile] :as db} :db
|
||||
random-id-generator :random-id-generator
|
||||
:as cofx}]
|
||||
(let [{:keys [name id url]} manage
|
||||
network (:networks/current-network db)
|
||||
bootnode (build
|
||||
(or (:value id) (random-id-generator))
|
||||
(:value name)
|
||||
(:value url)
|
||||
network)
|
||||
new-bootnodes (assoc-in
|
||||
(:custom-bootnodes profile)
|
||||
[network (:id bootnode)]
|
||||
bootnode)]
|
||||
|
||||
(rf/merge cofx
|
||||
{:db (dissoc db :bootnodes/manage)
|
||||
:dispatch [:navigate-back]}
|
||||
(multiaccounts.update/multiaccount-update
|
||||
:custom-bootnodes
|
||||
new-bootnodes
|
||||
{:success-event (when (custom-bootnodes-in-use? cofx)
|
||||
[:multiaccounts.update.callback/save-settings-success])}))))
|
||||
|
||||
(rf/defn toggle-custom-bootnodes
|
||||
{:events [:bootnodes.ui/custom-bootnodes-switch-toggled]}
|
||||
[{:keys [db] :as cofx} value]
|
||||
(let [current-network (:networks/current-network db)
|
||||
bootnodes-settings (get-in db [:profile/profile :custom-bootnodes-enabled?])]
|
||||
(multiaccounts.update/multiaccount-update
|
||||
cofx
|
||||
:custom-bootnodes-enabled?
|
||||
(assoc bootnodes-settings current-network value)
|
||||
{:success-event [:multiaccounts.update.callback/save-settings-success]})))
|
||||
|
||||
(rf/defn set-bootnodes-from-qr
|
||||
{:events [:bootnodes.callback/qr-code-scanned]}
|
||||
[cofx url]
|
||||
(assoc (set-input cofx :url (string/trim url))
|
||||
:dispatch
|
||||
[:navigate-back]))
|
||||
|
||||
(rf/defn show-delete-bootnode-confirmation
|
||||
{:events [:bootnodes.ui/delete-pressed]}
|
||||
[_ bootnode-id]
|
||||
{:ui/show-confirmation {:title (i18n/label :t/delete-bootnode-title)
|
||||
:content (i18n/label :t/delete-bootnode-are-you-sure)
|
||||
:confirm-button-text (i18n/label :t/delete-bootnode)
|
||||
:on-accept #(re-frame/dispatch [:bootnodes.ui/delete-confirmed
|
||||
bootnode-id])}})
|
||||
|
||||
(rf/defn delete-bootnode
|
||||
{:events [:bootnodes.ui/delete-confirmed]}
|
||||
[cofx bootnode-id]
|
||||
(rf/merge cofx
|
||||
(delete bootnode-id)
|
||||
(navigation/navigate-back)))
|
||||
@@ -1,180 +0,0 @@
|
||||
(ns legacy.status-im.bootnodes.core-test
|
||||
(:require
|
||||
[cljs.test :refer-macros [deftest is testing]]
|
||||
[legacy.status-im.bootnodes.core :as model]))
|
||||
|
||||
(def bootnode-id
|
||||
"1da276e34126e93babf24ec88aac1a7602b4cbb2e11b0961d0ab5e989ca9c261aa7f7c1c85f15550a5f1e5a5ca2305b53b9280cf5894d5ecf7d257b173136d40")
|
||||
(def host "167.99.209.61:30504")
|
||||
|
||||
(def valid-bootnode-address (str "enode://" bootnode-id "@" host))
|
||||
|
||||
(deftest upsert-bootnode
|
||||
(testing "adding a new bootnode"
|
||||
(let [new-bootnode {:name {:value "name"}
|
||||
:url {:value "url"}}
|
||||
expected {"mainnet_rpc" {"someid" {:name "name"
|
||||
:address "url"
|
||||
:chain "mainnet_rpc"
|
||||
:id "someid"}}}
|
||||
actual (model/upsert
|
||||
{:random-id-generator (constantly "some-id")
|
||||
:db {:bootnodes/manage new-bootnode
|
||||
:networks/current-network "mainnet_rpc"
|
||||
:profile/profile {:not-empty
|
||||
"would throw an error if was empty"}}})]
|
||||
(is (= expected (get-in actual [:db :profile/profile :custom-bootnodes])))))
|
||||
(testing "adding an existing bootnode"
|
||||
(let [new-bootnode {:id {:value "a"}
|
||||
:name {:value "new-name"}
|
||||
:url {:value "new-url"}}
|
||||
expected {"mainnet_rpc" {"a" {:name "new-name"
|
||||
:address "new-url"
|
||||
:chain "mainnet_rpc"
|
||||
:id "a"}}}
|
||||
actual (model/upsert
|
||||
{:random-id-generator (constantly "some-id")
|
||||
:db {:bootnodes/manage new-bootnode
|
||||
:networks/current-network "mainnet_rpc"
|
||||
:profile/profile {:custom-bootnodes
|
||||
{"mainnet_rpc"
|
||||
{"a" {:name "name"
|
||||
:address "url"
|
||||
:chain "mainnet_rpc"
|
||||
:id "a"}}}}}})]
|
||||
(is (= expected (get-in actual [:db :profile/profile :custom-bootnodes]))))))
|
||||
|
||||
(deftest set-input-bootnode
|
||||
(testing "it validates names"
|
||||
(testing "correct name"
|
||||
(is (= {:db {:bootnodes/manage {:name {:value "value"
|
||||
:error false}}}}
|
||||
(model/set-input {:db {}} :name "value"))))
|
||||
(testing "blank name"
|
||||
(is (= {:db {:bootnodes/manage {:name {:value ""
|
||||
:error true}}}}
|
||||
(model/set-input {:db {}} :name "")))))
|
||||
(testing "it validates bootnode url"
|
||||
(testing "correct url"
|
||||
(is (= {:db {:bootnodes/manage {:url {:value valid-bootnode-address
|
||||
:error false}}}}
|
||||
(model/set-input {:db {}} :url valid-bootnode-address))))
|
||||
(testing "broken url"
|
||||
(is (= {:db {:bootnodes/manage {:url {:value "broken"
|
||||
:error true}}}}
|
||||
(model/set-input {:db {}} :url "broken"))))))
|
||||
|
||||
(deftest set-bootnode-from-qr
|
||||
(testing "correct name"
|
||||
(is (= {:dispatch [:navigate-back]
|
||||
:db {:bootnodes/manage {:url {:value valid-bootnode-address
|
||||
:error false}}}}
|
||||
(model/set-bootnodes-from-qr {:db {}} (str valid-bootnode-address " "))))))
|
||||
|
||||
(deftest edit-bootnode
|
||||
(let [db {:networks/current-network "mainnet_rpc"
|
||||
:profile/profile
|
||||
{:custom-bootnodes
|
||||
{"mainnet_rpc"
|
||||
{"a" {:id "a"
|
||||
:name "name"
|
||||
:address valid-bootnode-address}}}}}
|
||||
cofx {:db db}]
|
||||
(testing "when no id is given"
|
||||
(let [actual (model/edit cofx nil)]
|
||||
(testing "it resets :bootnodes/manage"
|
||||
(is (= {:id {:value nil
|
||||
:error false}
|
||||
:url {:value ""
|
||||
:error true}
|
||||
:name {:value ""
|
||||
:error true}}
|
||||
(-> actual :db :bootnodes/manage))))
|
||||
(testing "it navigates to edit-bootnode view"
|
||||
(is (= [:navigate-to :edit-bootnode]
|
||||
(-> actual :dispatch))))))
|
||||
(testing "when an id is given"
|
||||
(testing "when the bootnode is in the list"
|
||||
(let [actual (model/edit cofx "a")]
|
||||
(testing "it populates the fields with the correct values"
|
||||
(is (= {:id {:value "a"
|
||||
:error false}
|
||||
:url {:value valid-bootnode-address
|
||||
:error false}
|
||||
:name {:value "name"
|
||||
:error false}}
|
||||
(-> actual :db :bootnodes/manage))))
|
||||
(testing "it navigates to edit-bootnode view"
|
||||
(is (= [:navigate-to :edit-bootnode]
|
||||
(-> actual :dispatch))))))
|
||||
(testing "when the bootnode is not in the list"
|
||||
(let [actual (model/edit cofx "not-existing")]
|
||||
(testing "it populates the fields with the correct values"
|
||||
(is (= {:id {:value nil
|
||||
:error false}
|
||||
:url {:value ""
|
||||
:error true}
|
||||
:name {:value ""
|
||||
:error true}}
|
||||
(-> actual :db :bootnodes/manage))))
|
||||
(testing "it navigates to edit-bootnode view"
|
||||
(is (= [:navigate-to :edit-bootnode]
|
||||
(-> actual :dispatch)))))))))
|
||||
|
||||
(deftest fetch-bootnode
|
||||
(testing "it fetches the bootnode from the db"
|
||||
(let [cofx {:db {:networks/current-network "mainnet_rpc"
|
||||
:profile/profile {:custom-bootnodes
|
||||
{"mainnet_rpc"
|
||||
{"a" {:id "a"
|
||||
:name "name"
|
||||
:address
|
||||
"enode://old-id:old-password@url:port"}}}}}}]
|
||||
(is (model/fetch cofx "a")))))
|
||||
|
||||
(deftest custom-bootnodes-in-use?
|
||||
(testing "is on the same network"
|
||||
(testing "it returns false when not enabled"
|
||||
(is (not (model/custom-bootnodes-in-use? {:db {:networks/current-network "mainnet_rpc"}}))))
|
||||
(testing "it returns true when enabled"
|
||||
(is (model/custom-bootnodes-in-use?
|
||||
{:db {:networks/current-network "mainnet_rpc"
|
||||
:profile/profile {:custom-bootnodes-enabled?
|
||||
{"mainnet_rpc" true}}}}))))
|
||||
(testing "is on a different network"
|
||||
(testing "it returns false when not enabled"
|
||||
(is (not (model/custom-bootnodes-in-use? {:db {:networks/current-network "goerli_rpc"}}))))
|
||||
(testing "it returns true when enabled"
|
||||
(is (not (model/custom-bootnodes-in-use?
|
||||
{:db {:networks/current-network "goerli_rpc"
|
||||
:profile/profile {:custom-bootnodes-enabled?
|
||||
{"mainnnet_rpc" true}}}}))))))
|
||||
|
||||
(deftest delete-bootnode
|
||||
(testing "non existing bootnode"
|
||||
(let [cofx {:db {:networks/current-network "mainnet_rpc"
|
||||
:profile/profile {:custom-bootnodes
|
||||
{"mainnet_rpc"
|
||||
{"a" {:id "a"
|
||||
:name "name"
|
||||
:address
|
||||
"enode://old-id:old-password@url:port"}}}
|
||||
:custom-bootnodes-enabled?
|
||||
{"mainnnet_rpc" true}}}}
|
||||
actual (model/delete cofx "b")]
|
||||
(testing "it does not removes the bootnode"
|
||||
(is (model/fetch actual "a")))))
|
||||
(testing "existing bootnode"
|
||||
(let [cofx {:db {:networks/current-network "mainnet_rpc"
|
||||
:profile/profile {:custom-bootnodes
|
||||
{"mainnet_rpc"
|
||||
{"a" {:id "a"
|
||||
:name "name"
|
||||
:address
|
||||
"enode://old-id:old-password@url:port"}}}
|
||||
:custom-bootnodes-enabled?
|
||||
{"mainnnet_rpc" true}}}}
|
||||
actual (model/delete cofx "a")]
|
||||
|
||||
(testing "it removes the bootnode"
|
||||
(is (not (model/fetch actual "a")))))))
|
||||
@@ -3,7 +3,7 @@
|
||||
[legacy.status-im.bottom-sheet.view :as bottom-sheet]
|
||||
[legacy.status-im.ui.screens.about-app.views :as about-app]
|
||||
[legacy.status-im.ui.screens.mobile-network-settings.view :as mobile-network-settings]
|
||||
[quo.theme :as theme]
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
(merge mobile-network-settings/offline-sheet)
|
||||
|
||||
(= view :learn-more)
|
||||
(merge about-app/learn-more))
|
||||
page-theme (:theme options)]
|
||||
(merge about-app/learn-more))]
|
||||
|
||||
[:f>
|
||||
(fn []
|
||||
@@ -32,7 +31,7 @@
|
||||
(rn/hw-back-add-listener dismiss-bottom-sheet-callback)
|
||||
(fn []
|
||||
(rn/hw-back-remove-listener dismiss-bottom-sheet-callback))))
|
||||
[theme/provider {:theme (or page-theme (theme/get-theme))}
|
||||
[quo.theme/provider (or (:theme options))
|
||||
[bottom-sheet/bottom-sheet opts
|
||||
(when content
|
||||
[content (when options options)])]])]))
|
||||
|
||||
@@ -3,12 +3,10 @@
|
||||
["eth-phishing-detect" :as eth-phishing-detect]
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.bottom-sheet.events :as bottom-sheet]
|
||||
[legacy.status-im.browser.eip3326 :as eip3326]
|
||||
[legacy.status-im.browser.permissions :as browser.permissions]
|
||||
[legacy.status-im.browser.webview-ref :as webview-ref]
|
||||
[legacy.status-im.ethereum.ens :as ens]
|
||||
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
[legacy.status-im.signing.core :as signing]
|
||||
[legacy.status-im.ui.components.list-selection :as list-selection]
|
||||
[legacy.status-im.utils.deprecated-types :as types]
|
||||
[legacy.status-im.utils.random :as random]
|
||||
@@ -393,64 +391,6 @@
|
||||
constants/web3-eth-sign constants/web3-keycard-sign-typed-data}
|
||||
method))
|
||||
|
||||
(rf/defn web3-send-async
|
||||
[cofx dapp-name {:keys [method params id] :as payload} message-id]
|
||||
(let [message? (web3-sign-message? method)
|
||||
dapps-address (get-in cofx [:db :profile/profile :dapps-address])
|
||||
typed? (and (not= constants/web3-personal-sign method)
|
||||
(not= constants/web3-eth-sign method))]
|
||||
(if (or message? (= constants/web3-send-transaction method))
|
||||
(let [[address data] (cond (and (= method constants/web3-keycard-sign-typed-data)
|
||||
(not (vector? params)))
|
||||
;; We don't use signer argument for keycard sign-typed-data
|
||||
["0x0" params]
|
||||
message? (normalize-sign-message-params params
|
||||
typed?)
|
||||
:else [nil nil])]
|
||||
(when (or (not message?) (and address data))
|
||||
(signing/sign cofx
|
||||
(merge
|
||||
(if message?
|
||||
{:message {:address address
|
||||
:data data
|
||||
:v4 (= constants/web3-sign-typed-data-v4 method)
|
||||
:typed? typed?
|
||||
:pinless? (= method constants/web3-keycard-sign-typed-data)
|
||||
:from dapps-address}}
|
||||
{:tx-obj (-> params
|
||||
first
|
||||
(update :from #(or % dapps-address))
|
||||
(dissoc :gasPrice))})
|
||||
{:on-result [:browser.dapp/transaction-on-result message-id id]
|
||||
:on-error [:browser.dapp/transaction-on-error message-id]}))))
|
||||
(cond
|
||||
(#{"eth_accounts" "eth_coinbase"} method)
|
||||
(send-to-bridge
|
||||
cofx
|
||||
{:type constants/web3-send-async-callback
|
||||
:messageId message-id
|
||||
:result {:jsonrpc "2.0"
|
||||
:id (int id)
|
||||
:result (if (= method "eth_coinbase") dapps-address [dapps-address])}})
|
||||
(= method "personal_ecRecover")
|
||||
{:signing.fx/recover-message {:params {:message (first params)
|
||||
:signature (second params)}
|
||||
:on-completed #(re-frame/dispatch
|
||||
[:browser.callback/call-rpc
|
||||
{:type constants/web3-send-async-callback
|
||||
:messageId message-id
|
||||
:result (types/json->clj %)}])}}
|
||||
(= method "wallet_switchEthereumChain")
|
||||
(eip3326/handle-switch-ethereum-chain cofx dapp-name id message-id (first params))
|
||||
|
||||
:else
|
||||
{:browser/call-rpc [payload
|
||||
#(re-frame/dispatch [:browser.callback/call-rpc
|
||||
{:type constants/web3-send-async-callback
|
||||
:messageId message-id
|
||||
:error %1
|
||||
:result %2}])]}))))
|
||||
|
||||
(rf/defn handle-no-permissions
|
||||
[cofx {:keys [method id]} message-id]
|
||||
(if (= method "eth_accounts")
|
||||
@@ -479,9 +419,8 @@
|
||||
|
||||
(rf/defn web3-send-async-read-only
|
||||
[{:keys [db] :as cofx} dapp-name {:keys [method] :as payload} message-id]
|
||||
(if (has-permissions? db dapp-name method)
|
||||
(handle-no-permissions cofx payload message-id)
|
||||
(web3-send-async cofx dapp-name payload message-id)))
|
||||
(when (has-permissions? db dapp-name method)
|
||||
(handle-no-permissions cofx payload message-id)))
|
||||
|
||||
(rf/defn handle-scanned-qr-code
|
||||
{:events [:browser.bridge.callback/qr-code-scanned]}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
;reference https://eips.ethereum.org/EIPS/eip-3085 EIP-3085: Wallet Add Ethereum Chain RPC Method
|
||||
;(`wallet_addEthereumChain`)
|
||||
(ns legacy.status-im.browser.eip3085
|
||||
(:require
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.constants :as constants]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn send-success-call-to-bridge
|
||||
{:events [:eip3085/send-success-call-to-bridge]}
|
||||
[_ id messageId]
|
||||
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
||||
:messageId messageId
|
||||
:result {:jsonrpc "2.0"
|
||||
:id (int id)
|
||||
:result nil}}})
|
||||
|
||||
(rf/defn allow-permission
|
||||
{:events [:eip3085.ui/dapp-permission-allowed]}
|
||||
[{:keys [db] :as cofx} message-id {:keys [new-networks id]}]
|
||||
{:db (assoc db :networks/networks new-networks)
|
||||
:json-rpc/call [{:method "settings_saveSetting"
|
||||
:params [:networks/networks (vals new-networks)]
|
||||
:on-success #(re-frame/dispatch [:eip3085/send-success-call-to-bridge cofx id
|
||||
message-id])
|
||||
:on-error #(log/error "failed to perform settings_saveSetting" %)}]
|
||||
:dispatch [:bottom-sheet/hide-old]})
|
||||
|
||||
(rf/defn deny-permission
|
||||
{:events [:eip3085.ui/dapp-permission-denied]}
|
||||
[_ message-id _]
|
||||
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
||||
:messageId message-id
|
||||
:error {:code 4001
|
||||
:message "User rejected the request."}}
|
||||
:dispatch [:bottom-sheet/hide-old]})
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
;reference https://eips.ethereum.org/EIPS/eip-3326 EIP-3326: Wallet Switch Ethereum Chain RPC Method
|
||||
;(`wallet_switchEthereumChain`)
|
||||
(ns legacy.status-im.browser.eip3326
|
||||
(:require
|
||||
[legacy.status-im.ui.screens.browser.eip3326.sheet :as sheet]
|
||||
[status-im.constants :as constants]
|
||||
[utils.ethereum.chain :as chain]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn deny-permission
|
||||
{:events [:eip3326.ui/dapp-permission-denied]}
|
||||
[{:keys [db] :as cofx} message-id _]
|
||||
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
||||
:messageId message-id
|
||||
:error {:code 4001
|
||||
:message "User rejected the request."}}
|
||||
:dispatch [:bottom-sheet/hide-old]})
|
||||
|
||||
(rf/defn handle-switch-ethereum-chain
|
||||
{:events [:eip3326/handle-switch-ethereum-chain]}
|
||||
[{:keys [db] :as cofx} dapp-name id message-id {:keys [chainId] :as params}]
|
||||
(let [target-chain-id (js/parseInt chainId 16)
|
||||
networks (vals (get-in db [:networks/networks]))
|
||||
exist-chain-ids (set (map chain/network->chain-id networks))
|
||||
current-chain-id (chain/chain-id db)]
|
||||
(if (exist-chain-ids target-chain-id)
|
||||
(if (= current-chain-id target-chain-id)
|
||||
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
||||
:messageId message-id
|
||||
:result {:jsonrpc "2.0"
|
||||
:id (int id)
|
||||
:result nil}}}
|
||||
(let [target-network (first (filter #(= (chain/network->chain-id %1) target-chain-id)
|
||||
networks))
|
||||
target-network-id (:id target-network)
|
||||
current-network (chain/current-network db)
|
||||
network-from (:name current-network)
|
||||
network-to (:name target-network)
|
||||
params (assoc params
|
||||
:target-network-id target-network-id
|
||||
:network-from network-from
|
||||
:network-to network-to)]
|
||||
{:dispatch [:bottom-sheet/show-sheet-old
|
||||
{:content (fn []
|
||||
[sheet/permissions-panel dapp-name message-id params])}]}))
|
||||
{:browser/send-to-bridge {:type constants/web3-send-async-callback
|
||||
:messageId message-id
|
||||
:error
|
||||
{:code 4902
|
||||
:message
|
||||
(str
|
||||
"Unrecognized chain ID: "
|
||||
target-chain-id
|
||||
". Try adding the chain using wallet_addEthereumChain first.")}}})))
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
[legacy.status-im.bottom-sheet.events :as bottom-sheet]
|
||||
legacy.status-im.communities.e2e
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.contexts.shell.activity-center.events :as activity-center]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
@@ -22,60 +23,10 @@
|
||||
{}
|
||||
requests))
|
||||
|
||||
(defn- fetch-community-id-input
|
||||
[{:keys [db]}]
|
||||
(:communities/community-id-input db))
|
||||
|
||||
(rf/defn handle-response
|
||||
[_ response-js]
|
||||
{:dispatch [:sanitize-messages-and-process-response response-js]})
|
||||
|
||||
(rf/defn invite-users
|
||||
{:events [::invite-people-confirmation-pressed]}
|
||||
[cofx user-pk contacts]
|
||||
(let [community-id (fetch-community-id-input cofx)
|
||||
pks (if (seq user-pk)
|
||||
(conj contacts user-pk)
|
||||
contacts)]
|
||||
(when (seq pks)
|
||||
{:json-rpc/call [{:method "wakuext_inviteUsersToCommunity"
|
||||
:params [{:communityId community-id
|
||||
:users pks}]
|
||||
:js-response true
|
||||
:on-success #(re-frame/dispatch [::people-invited %])
|
||||
:on-error #(do
|
||||
(log/error "failed to invite-user community" %)
|
||||
(re-frame/dispatch [::failed-to-invite-people %]))}]})))
|
||||
|
||||
(rf/defn share-community
|
||||
{:events [::share-community-confirmation-pressed]}
|
||||
[cofx user-pk contacts]
|
||||
(let [community-id (fetch-community-id-input cofx)
|
||||
pks (if (seq user-pk)
|
||||
(conj contacts user-pk)
|
||||
contacts)]
|
||||
(when (seq pks)
|
||||
{:json-rpc/call [{:method "wakuext_shareCommunity"
|
||||
:params [{:communityId community-id
|
||||
:users pks}]
|
||||
:js-response true
|
||||
:on-success #(re-frame/dispatch [::people-invited %])
|
||||
:on-error #(do
|
||||
(log/error "failed to invite-user community" %)
|
||||
(re-frame/dispatch [::failed-to-share-community %]))}]})))
|
||||
|
||||
(re-frame/reg-event-fx :communities/invite-people-pressed
|
||||
(fn [{:keys [db]} [id]]
|
||||
{:db (assoc db :communities/community-id-input id)
|
||||
:fx [[:dispatch [:hide-bottom-sheet]]
|
||||
[:dispatch [:open-modal :legacy-invite-people-community {:invite? true}]]]}))
|
||||
|
||||
(re-frame/reg-event-fx :communities/share-community-pressed
|
||||
(fn [{:keys [db]} [id]]
|
||||
{:db (assoc db :communities/community-id-input id)
|
||||
:fx [[:dispatch [:hide-bottom-sheet]]
|
||||
[:dispatch [:open-modal :legacy-invite-people-community {}]]]}))
|
||||
|
||||
(rf/defn people-invited
|
||||
{:events [::people-invited]}
|
||||
[cofx response-js]
|
||||
@@ -90,6 +41,14 @@
|
||||
[:sanitize-messages-and-process-response response-js]
|
||||
[:activity-center.notifications/fetch-unread-count]]}))
|
||||
|
||||
(rf/defn member-banned
|
||||
{:events [::member-banned]}
|
||||
[cofx response-js]
|
||||
(rf/merge cofx
|
||||
(bottom-sheet/hide-bottom-sheet-old)
|
||||
(handle-response response-js)
|
||||
(activity-center/notifications-fetch-unread-count)))
|
||||
|
||||
(rf/defn member-ban
|
||||
{:events [::member-ban]}
|
||||
[cofx community-id public-key]
|
||||
|
||||
@@ -125,6 +125,7 @@
|
||||
:profile-public-key (.-profile chat)
|
||||
:highlight (.-highlight chat)
|
||||
:active (.-active chat)
|
||||
:image (.-image chat)
|
||||
:members (types/js->clj (.-members chat))
|
||||
:hide-if-permissions-not-met (.-hideIfPermissionsNotMet chat)}
|
||||
rpc->type
|
||||
|
||||
@@ -2,18 +2,8 @@
|
||||
(:require
|
||||
[clojure.set :as set]
|
||||
[legacy.status-im.data-store.visibility-status-updates :as visibility-status-updates]
|
||||
[status-im.config :as config]
|
||||
[utils.ethereum.eip.eip55 :as eip55]))
|
||||
|
||||
(defn rpc->networks
|
||||
[networks]
|
||||
(reduce (fn [acc {:keys [id] :as network}]
|
||||
(assoc acc id network))
|
||||
{}
|
||||
(if (seq networks)
|
||||
networks
|
||||
config/default-networks)))
|
||||
|
||||
(defn rpc->visible-tokens
|
||||
[visible-tokens]
|
||||
(reduce-kv (fn [acc chain visible-tokens]
|
||||
@@ -28,25 +18,14 @@
|
||||
{}
|
||||
pinned-mailservers))
|
||||
|
||||
(defn rpc->custom-bootnodes
|
||||
[custom-bootnodes]
|
||||
(reduce-kv (fn [acc chain custom-bootnodes]
|
||||
(assoc acc (name chain) custom-bootnodes))
|
||||
{}
|
||||
custom-bootnodes))
|
||||
|
||||
(defn rpc->settings
|
||||
[settings]
|
||||
(-> settings
|
||||
(update :dapps-address eip55/address->checksum)
|
||||
(update :address eip55/address->checksum)
|
||||
(update :networks/networks rpc->networks)
|
||||
(update :networks/current-network #(if (seq %) % config/default-network))
|
||||
(update :wallet-legacy/visible-tokens rpc->visible-tokens)
|
||||
(update :pinned-mailservers rpc->pinned-mailservers)
|
||||
(update :link-previews-enabled-sites set)
|
||||
(update :custom-bootnodes rpc->custom-bootnodes)
|
||||
(update :custom-bootnodes-enabled? rpc->custom-bootnodes)
|
||||
(update :currency keyword)
|
||||
(visibility-status-updates/<-rpc-settings)
|
||||
(set/rename-keys {:compressedKey :compressed-key
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
(:require
|
||||
clojure.set
|
||||
legacy.status-im.backup.core
|
||||
legacy.status-im.bootnodes.core
|
||||
legacy.status-im.browser.core
|
||||
legacy.status-im.browser.permissions
|
||||
legacy.status-im.chat.models.loading
|
||||
@@ -13,7 +12,6 @@
|
||||
legacy.status-im.data-store.visibility-status-updates
|
||||
legacy.status-im.fleet.core
|
||||
legacy.status-im.group-chats.core
|
||||
[legacy.status-im.keycard.core :as keycard]
|
||||
legacy.status-im.log-level.core
|
||||
legacy.status-im.mailserver.constants
|
||||
[legacy.status-im.mailserver.core :as mailserver]
|
||||
@@ -191,15 +189,8 @@
|
||||
:db (assoc db :screens/was-focused-once? true)}
|
||||
|
||||
(not (get db :screens/was-focused-once?))
|
||||
{:db (assoc db :screens/was-focused-once? true)})
|
||||
#(case view-id
|
||||
:keycard-settings (keycard/settings-screen-did-load %)
|
||||
:reset-card (keycard/reset-card-screen-did-load %)
|
||||
:enter-pin-settings (keycard/enter-pin-screen-did-load %)
|
||||
:keycard-login-pin (keycard/login-pin-screen-did-load %)
|
||||
:keycard-authentication-method (keycard/authentication-method-screen-did-load %)
|
||||
:multiaccounts (keycard/multiaccounts-screen-did-load %)
|
||||
nil)))
|
||||
{:db (assoc db :screens/was-focused-once? true)})))
|
||||
|
||||
|
||||
;;TODO :replace by named events
|
||||
(rf/defn set-event
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
(ns legacy.status-im.keycard.backup-key
|
||||
(:require
|
||||
[legacy.status-im.ethereum.mnemonic :as mnemonic]
|
||||
[legacy.status-im.keycard.common :as common]
|
||||
[legacy.status-im.multiaccounts.recover.core :as multiaccounts.recover]
|
||||
[legacy.status-im.signing.core :as signing.core]
|
||||
[legacy.status-im.utils.utils :as utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn backup-card-pressed
|
||||
{:events [:keycard-settings.ui/backup-card-pressed]}
|
||||
[{:keys [db] :as cofx} backup-type]
|
||||
(log/debug "[keycard] start backup")
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :creating-backup?] backup-type))}
|
||||
(when (:profile/profile db)
|
||||
(navigation/navigate-to :my-profile nil))
|
||||
(navigation/navigate-to :seed-phrase nil)))
|
||||
|
||||
(rf/defn recovery-card-pressed
|
||||
{:events [:keycard-settings.ui/recovery-card-pressed]}
|
||||
[{:keys [db] :as cofx} show-warning]
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
;setting pin-retry-counter is a workaround for the way the PIN view
|
||||
;decides if it should accept PUK or PIN
|
||||
(assoc-in [:keycard :application-info :pin-retry-counter] 3)
|
||||
(assoc-in [:keycard :factory-reset-card?] true)
|
||||
(dissoc :popover/popover))
|
||||
:hide-popover nil}
|
||||
(signing.core/discard)
|
||||
(if show-warning
|
||||
(utils/show-confirmation
|
||||
{:title (i18n/label :t/keycard-recover-title)
|
||||
:content (i18n/label :t/keycard-recover-text)
|
||||
:confirm-button-text (i18n/label :t/yes)
|
||||
:cancel-button-text (i18n/label :t/no)
|
||||
:on-accept #(re-frame/dispatch [:keycard-settings.ui/backup-card-pressed
|
||||
:recovery-card])
|
||||
:on-cancel #()})
|
||||
(backup-card-pressed :recovery-card))))
|
||||
|
||||
(rf/defn start-keycard-backup
|
||||
{:events [::start-keycard-backup]}
|
||||
[{:keys [db] :as cofx}]
|
||||
{::multiaccounts.recover/import-multiaccount {:passphrase (-> db
|
||||
:profile/key-storage
|
||||
:seed-phrase
|
||||
mnemonic/sanitize-passphrase)
|
||||
:password nil
|
||||
:success-event ::create-backup-card}})
|
||||
|
||||
(rf/defn create-backup-card
|
||||
{:events [::create-backup-card]}
|
||||
[{:keys [db] :as cofx} root-data derived-data]
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(update :intro-wizard
|
||||
assoc
|
||||
:root-key root-data
|
||||
:derived derived-data
|
||||
:recovering? true
|
||||
:selected-storage-type :advanced)
|
||||
(assoc-in [:keycard :flow] :recovery)
|
||||
(update :profile/key-storage dissoc :seed-phrase))
|
||||
:dismiss-keyboard nil}
|
||||
(common/listen-to-hardware-back-button)
|
||||
(navigation/navigate-to :keycard-onboarding-intro nil)))
|
||||
@@ -1,565 +0,0 @@
|
||||
(ns legacy.status-im.keycard.card
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[keycard.keycard :as keycard]
|
||||
[keycard.real-keycard :as real-keycard]
|
||||
[legacy.status-im.keycard.simulated-keycard :as simulated-keycard]
|
||||
[legacy.status-im.node.core :as node]
|
||||
[native-module.core :as native-module]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.config :as config]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.transforms :as types]))
|
||||
|
||||
(defonce card
|
||||
(if config/keycard-test-menu-enabled?
|
||||
(simulated-keycard/SimulatedKeycard.)
|
||||
(real-keycard/RealKeycard.)))
|
||||
|
||||
(defn check-nfc-support
|
||||
[]
|
||||
(log/debug "[keycard] check-nfc-support")
|
||||
(keycard/check-nfc-support
|
||||
card
|
||||
{:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response] check-nfc-support")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/check-nfc-support-success response]))}))
|
||||
|
||||
(defn check-nfc-enabled
|
||||
[]
|
||||
(log/debug "[keycard] check-nfc-enabled")
|
||||
(keycard/check-nfc-enabled
|
||||
card
|
||||
{:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response] check-nfc-enabled")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/check-nfc-enabled-success response]))}))
|
||||
|
||||
(defn open-nfc-settings
|
||||
[]
|
||||
(log/debug "[keycard] open-nfc-settings")
|
||||
(keycard/open-nfc-settings card))
|
||||
|
||||
(defn remove-event-listener
|
||||
[event]
|
||||
(log/debug "[keycard] remove-event-listener")
|
||||
(keycard/remove-event-listener card event))
|
||||
|
||||
(defn on-card-disconnected
|
||||
[callback]
|
||||
(log/debug "[keycard] on-card-disconnected")
|
||||
(keycard/on-card-disconnected card callback))
|
||||
|
||||
(defn on-card-connected
|
||||
[callback]
|
||||
(log/debug "[keycard] on-card-connected")
|
||||
(keycard/on-card-connected card callback))
|
||||
|
||||
(defn remove-event-listeners
|
||||
[]
|
||||
(log/debug "[keycard] remove-event-listeners")
|
||||
(keycard/remove-event-listeners card))
|
||||
|
||||
(defn register-card-events
|
||||
[]
|
||||
(log/debug "[keycard] register-card-events")
|
||||
(keycard/register-card-events
|
||||
card
|
||||
{:on-card-connected
|
||||
#(re-frame/dispatch [:keycard.callback/on-card-connected])
|
||||
|
||||
:on-card-disconnected
|
||||
#(re-frame/dispatch [:keycard.callback/on-card-disconnected])
|
||||
|
||||
:on-nfc-user-cancelled
|
||||
#(re-frame/dispatch [:keycard.callback/on-nfc-user-cancelled])
|
||||
|
||||
:on-nfc-timeout
|
||||
#(re-frame/dispatch [:keycard.callback/on-nfc-timeout])
|
||||
|
||||
:on-nfc-enabled
|
||||
#(re-frame/dispatch [:keycard.callback/check-nfc-enabled-success true])
|
||||
|
||||
:on-nfc-disabled
|
||||
#(re-frame/dispatch [:keycard.callback/check-nfc-enabled-success false])}))
|
||||
|
||||
(defn- error-object->map
|
||||
[^js object]
|
||||
{:code (.-code object)
|
||||
:error (.-message object)})
|
||||
|
||||
(defn set-pairings
|
||||
[pairings]
|
||||
(log/debug "[keycard] open-nfc-settings")
|
||||
(keycard/set-pairings card {:pairings pairings}))
|
||||
|
||||
(defn get-application-info
|
||||
[{:keys [on-success] :as args}]
|
||||
(log/debug "[keycard] get-application-info")
|
||||
(keycard/get-application-info
|
||||
card
|
||||
(merge
|
||||
args
|
||||
{:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] get-application-info")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-get-application-info-success
|
||||
response on-success]))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/debug "[keycard response fail] get-application-info")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-get-application-info-error
|
||||
(error-object->map response)]))})))
|
||||
|
||||
(defn factory-reset
|
||||
[{:keys [on-success] :as args}]
|
||||
(log/debug "[keycard] factory-reset")
|
||||
(keycard/factory-reset
|
||||
card
|
||||
(merge
|
||||
args
|
||||
{:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] get-application-info")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-get-application-info-success
|
||||
response on-success]))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/debug "[keycard response fail] get-application-info")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-get-application-info-error
|
||||
(error-object->map response)]))})))
|
||||
|
||||
(defn install-applet
|
||||
[]
|
||||
(log/debug "[keycard] install-applet")
|
||||
(keycard/install-applet
|
||||
card
|
||||
{:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] install-applet")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-install-applet-success response]))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/debug "[keycard response fail] install-applet")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-install-applet-error
|
||||
(error-object->map response)]))}))
|
||||
|
||||
(defn init-card
|
||||
[pin]
|
||||
(log/debug "[keycard] init-card")
|
||||
(keycard/init-card
|
||||
card
|
||||
{:pin pin
|
||||
:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] init-card")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-init-card-success response]))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/debug "[keycard response fail] init-card")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-init-card-error
|
||||
(error-object->map response)]))}))
|
||||
|
||||
(defn install-applet-and-init-card
|
||||
[pin]
|
||||
(log/debug "[keycard] install-applet-and-init-card")
|
||||
(keycard/install-applet-and-init-card
|
||||
card
|
||||
{:pin pin
|
||||
:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] install-applet-and-init-card")
|
||||
#(re-frame/dispatch
|
||||
[:keycard.callback/on-install-applet-and-init-card-success
|
||||
response]))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/debug "[keycard response fail] install-applet-and-init-card")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-install-applet-and-init-card-error
|
||||
(error-object->map response)]))}))
|
||||
|
||||
(defn pair
|
||||
[args]
|
||||
(log/debug "[keycard] pair")
|
||||
(keycard/pair
|
||||
card
|
||||
(merge
|
||||
args
|
||||
{:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] pair")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-pair-success response]))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/debug "[keycard response fail] pair")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-pair-error (error-object->map response)]))})))
|
||||
|
||||
(defn generate-and-load-key
|
||||
[args]
|
||||
(log/debug "[keycard] generate-and-load-key")
|
||||
(keycard/generate-and-load-key
|
||||
card
|
||||
(merge
|
||||
args
|
||||
{:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] generate-and-load-key")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-generate-and-load-key-success response]))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/debug "[keycard response fail] generate-and-load-key")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-generate-and-load-key-error
|
||||
(error-object->map response)]))})))
|
||||
|
||||
(defn unblock-pin
|
||||
[args]
|
||||
(log/debug "[keycard] unblock-pin")
|
||||
(keycard/unblock-pin
|
||||
card
|
||||
(merge
|
||||
args
|
||||
{:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] unblock-pin")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-unblock-pin-success response]))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/debug "[keycard response fail] unblock-pin")
|
||||
(re-frame/dispatch [:keycard.callback/on-unblock-pin-error
|
||||
(error-object->map response)]))})))
|
||||
|
||||
(defn verify-pin
|
||||
[args]
|
||||
(log/debug "[keycard] verify-pin")
|
||||
(keycard/verify-pin
|
||||
card
|
||||
(merge
|
||||
args
|
||||
{:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] verify-pin")
|
||||
(re-frame/dispatch [:keycard.callback/on-verify-pin-success
|
||||
response]))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/debug "[keycard response fail] verify-pin")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-verify-pin-error
|
||||
(error-object->map response)]))})))
|
||||
|
||||
(defn change-pin
|
||||
[args]
|
||||
(log/debug "[keycard] change-pin")
|
||||
(keycard/change-pin
|
||||
card
|
||||
(merge
|
||||
args
|
||||
{:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] change-pin")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-change-pin-success response]))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/debug "[keycard response fail] change-pin")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-change-pin-error
|
||||
(error-object->map response)]))})))
|
||||
|
||||
(defn change-puk
|
||||
[args]
|
||||
(log/debug "[keycard] change-puk")
|
||||
(keycard/change-puk
|
||||
card
|
||||
(merge
|
||||
args
|
||||
{:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] change-puk")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-change-puk-success response]))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/debug "[keycard response fail] change-puk")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-change-pin-error
|
||||
(error-object->map response)]))})))
|
||||
|
||||
(defn change-pairing
|
||||
[args]
|
||||
(log/debug "[keycard] change-pairing")
|
||||
(keycard/change-pairing
|
||||
card
|
||||
(merge
|
||||
args
|
||||
{:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] change-pairing")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-change-pairing-success response]))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/debug "[keycard response fail] change-pairing")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-change-pin-error
|
||||
(error-object->map response)]))})))
|
||||
|
||||
(defn unpair
|
||||
[args]
|
||||
(log/debug "[keycard] unpair")
|
||||
(keycard/unpair
|
||||
card
|
||||
(merge
|
||||
args
|
||||
{:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] unpair")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-unpair-success response]))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/debug "[keycard response fail] unpair")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-unpair-error
|
||||
(error-object->map response)]))})))
|
||||
|
||||
(defn delete
|
||||
[]
|
||||
(log/debug "[keycard] delete")
|
||||
(keycard/delete
|
||||
card
|
||||
{:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] delete")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-delete-success response]))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/debug "[keycard response fail] delete")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-delete-error
|
||||
(error-object->map response)]))}))
|
||||
|
||||
(defn remove-key
|
||||
[args]
|
||||
(log/debug "[keycard] remove-key")
|
||||
(keycard/remove-key
|
||||
card
|
||||
(merge
|
||||
args
|
||||
{:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] remove-key")
|
||||
(re-frame/dispatch [:keycard.callback/on-remove-key-success
|
||||
response]))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/debug "[keycard response fail] remove-key")
|
||||
(re-frame/dispatch [:keycard.callback/on-remove-key-error
|
||||
(error-object->map response)]))})))
|
||||
|
||||
(defn remove-key-with-unpair
|
||||
[args]
|
||||
(log/debug "[keycard] remove-key-with-unpair")
|
||||
(keycard/remove-key-with-unpair
|
||||
card
|
||||
(merge
|
||||
args
|
||||
{:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] remove-key-with-unpair")
|
||||
(re-frame/dispatch [:keycard.callback/on-remove-key-success
|
||||
response]))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/debug "[keycard response fail] remove-key-with-unpair")
|
||||
(re-frame/dispatch [:keycard.callback/on-remove-key-error
|
||||
(error-object->map response)]))})))
|
||||
|
||||
(defn export-key
|
||||
[args]
|
||||
(log/debug "[keycard] export-key")
|
||||
(keycard/export-key
|
||||
card
|
||||
(merge
|
||||
args
|
||||
{:on-success
|
||||
(fn [_response]
|
||||
(log/debug "[keycard response succ] export-key")
|
||||
(js/alert "feature no longer supported"))
|
||||
:on-failure
|
||||
(fn [_response]
|
||||
(log/debug "[keycard response fail] export-key"))})))
|
||||
|
||||
(defn unpair-and-delete
|
||||
[args]
|
||||
(log/debug "[keycard] unpair-and-delete")
|
||||
(keycard/unpair
|
||||
card
|
||||
(merge
|
||||
args
|
||||
{:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] unpair-and-delete")
|
||||
(re-frame/dispatch [:keycard.callback/on-unpair-and-delete-success
|
||||
response]))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/debug "[keycard response fail] unpair-and-delete")
|
||||
(re-frame/dispatch [:keycard.callback/on-unpair-and-delete-error
|
||||
(error-object->map response)]))})))
|
||||
|
||||
(defn import-keys
|
||||
[{:keys [on-success] :as args}]
|
||||
(log/debug "[keycard] import-keys")
|
||||
(keycard/import-keys
|
||||
card
|
||||
(assoc
|
||||
args
|
||||
:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] import-keys")
|
||||
(re-frame/dispatch
|
||||
[(or on-success :keycard.callback/on-generate-and-load-key-success)
|
||||
response]))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/warn "[keycard response fail] import-keys"
|
||||
(error-object->map response))
|
||||
(re-frame/dispatch [:keycard.callback/on-get-keys-error
|
||||
(error-object->map response)])))))
|
||||
|
||||
(defn get-keys
|
||||
[{:keys [on-success] :as args}]
|
||||
(log/debug "[keycard] get-keys")
|
||||
(keycard/get-keys
|
||||
card
|
||||
(assoc
|
||||
args
|
||||
:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] get-keys")
|
||||
(re-frame/dispatch
|
||||
[(or on-success :keycard.callback/on-get-keys-success)
|
||||
response]))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/warn "[keycard response fail] get-keys"
|
||||
(error-object->map response))
|
||||
(re-frame/dispatch [:keycard.callback/on-get-keys-error
|
||||
(error-object->map response)])))))
|
||||
|
||||
(defn sign
|
||||
[{:keys [on-success on-failure] :as args}]
|
||||
(log/debug "[keycard] sign")
|
||||
(keycard/sign
|
||||
card
|
||||
(merge
|
||||
args
|
||||
{:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] sign")
|
||||
(if on-success
|
||||
(on-success response)
|
||||
(re-frame/dispatch [:keycard.callback/on-sign-success response])))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/debug "[keycard response fail] sign")
|
||||
(if on-failure
|
||||
(on-failure response)
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-sign-error
|
||||
(error-object->map response)])))})))
|
||||
|
||||
(defn install-cash-applet
|
||||
[]
|
||||
(log/debug "[keycard] install-cash-applet")
|
||||
(keycard/install-cash-applet
|
||||
card
|
||||
{:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] install-cash-applet")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-install-applet-success response]))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/debug "[keycard response fail] install-cash-applet")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-install-applet-error
|
||||
(error-object->map response)]))}))
|
||||
|
||||
(defn sign-typed-data
|
||||
[{card-hash :hash}]
|
||||
(log/debug "[keycard] sign-typed-data")
|
||||
(keycard/sign-typed-data
|
||||
card
|
||||
{:hash card-hash
|
||||
:on-success
|
||||
(fn [response]
|
||||
(log/debug "[keycard response succ] sign-typed-data")
|
||||
(re-frame/dispatch [:keycard.callback/on-sign-success
|
||||
response]))
|
||||
:on-failure
|
||||
(fn [response]
|
||||
(log/debug "[keycard response fail] sign-typed-data")
|
||||
(re-frame/dispatch
|
||||
[:keycard.callback/on-sign-error
|
||||
(error-object->map response)]))}))
|
||||
|
||||
(defn save-multiaccount-and-login
|
||||
[_])
|
||||
|
||||
(defn login
|
||||
[{:keys [key-uid multiaccount-data password] :as args}]
|
||||
(if config/keycard-test-menu-enabled?
|
||||
(native-module/login-with-config key-uid multiaccount-data password node/login-node-config)
|
||||
(native-module/login-with-keycard (assoc args :node-config {:ProcessBackedupMessages false}))))
|
||||
|
||||
(def account-password (native-module/sha3 "no password"))
|
||||
|
||||
(defn send-transaction-with-signature
|
||||
[{:keys [transaction signature on-completed]}]
|
||||
(if config/keycard-test-menu-enabled?
|
||||
(native-module/send-transaction transaction account-password on-completed)
|
||||
(native-module/send-transaction-with-signature transaction signature on-completed)))
|
||||
|
||||
(defn start-nfc
|
||||
[args]
|
||||
(keycard/start-nfc card args))
|
||||
|
||||
(defn stop-nfc
|
||||
[args]
|
||||
(keycard/stop-nfc card args))
|
||||
|
||||
(defn set-nfc-message
|
||||
[args]
|
||||
(keycard/set-nfc-message card args))
|
||||
|
||||
(defn delete-multiaccount-before-migration
|
||||
[{:keys [key-uid on-success on-error]}]
|
||||
(if config/keycard-test-menu-enabled?
|
||||
(on-success)
|
||||
(native-module/delete-multiaccount
|
||||
key-uid
|
||||
(fn [result]
|
||||
(let [{:keys [error]} (types/json->clj result)]
|
||||
(if-not (string/blank? error)
|
||||
(on-error error)
|
||||
(on-success)))))))
|
||||
@@ -1,216 +0,0 @@
|
||||
(ns legacy.status-im.keycard.change-pin
|
||||
(:require
|
||||
[legacy.status-im.keycard.common :as common]
|
||||
[legacy.status-im.keycard.onboarding :as onboarding]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(rf/defn change-credentials-pressed
|
||||
{:events [:keycard-settings.ui/change-credentials-pressed]}
|
||||
[{:keys [db] :as cofx} changing]
|
||||
(rf/merge cofx
|
||||
{:db
|
||||
(assoc-in db
|
||||
[:keycard :pin]
|
||||
{:enter-step :current
|
||||
:current []
|
||||
:puk []
|
||||
:original []
|
||||
:confirmation []
|
||||
:puk-original []
|
||||
:puk-confirmation []
|
||||
:status nil
|
||||
:error-label nil
|
||||
:on-verified (case changing
|
||||
:pin :keycard/proceed-to-change-pin
|
||||
:puk :keycard/proceed-to-change-puk
|
||||
:pairing :keycard/proceed-to-change-pairing)})}
|
||||
(common/navigate-to-enter-pin-screen)))
|
||||
|
||||
(rf/defn proceed-to-change-pin
|
||||
{:events [:keycard/proceed-to-change-pin]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :pin :enter-step] :original)
|
||||
(assoc-in [:keycard :pin :status] nil))}
|
||||
(navigation/navigate-replace :enter-pin-settings nil)))
|
||||
|
||||
(rf/defn proceed-to-change-puk
|
||||
{:events [:keycard/proceed-to-change-puk]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :pin :enter-step] :puk-original)
|
||||
(assoc-in [:keycard :pin :status] nil))}
|
||||
(navigation/navigate-replace :enter-pin-settings nil)))
|
||||
|
||||
(rf/defn proceed-to-change-pairing
|
||||
{:events [:keycard/proceed-to-change-pairing]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(navigation/navigate-replace cofx :change-pairing-code nil))
|
||||
|
||||
(rf/defn discard-pin-change
|
||||
{:events [::on-cancel]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
(common/clear-pin)
|
||||
(common/hide-connection-sheet)
|
||||
(if (get-in db [:keycard :pin :puk-restore?])
|
||||
(navigation/navigate-to :multiaccounts nil)
|
||||
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings]))))
|
||||
|
||||
(rf/defn change-pin
|
||||
{:events [:keycard/change-pin]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [setup-step (get-in db [:keycard :setup-step])]
|
||||
(log/debug "[keycard] change-pin"
|
||||
"setup-step"
|
||||
setup-step)
|
||||
(if (= setup-step :pin)
|
||||
(onboarding/load-preparing-screen cofx)
|
||||
(common/show-connection-sheet
|
||||
cofx
|
||||
{:sheet-options {:on-cancel [::on-cancel]}
|
||||
:on-card-connected :keycard/change-pin
|
||||
:handler
|
||||
(fn [{:keys [db] :as cofx}]
|
||||
(let [new-pin (common/vector->string
|
||||
(get-in db [:keycard :pin :original]))
|
||||
current-pin (common/vector->string
|
||||
(get-in db [:keycard :pin :current]))]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (assoc-in db [:keycard :pin :status] :verifying)
|
||||
|
||||
:keycard/change-pin
|
||||
{:new-pin new-pin
|
||||
:current-pin current-pin}})))}))))
|
||||
|
||||
(rf/defn change-puk
|
||||
{:events [:keycard/change-puk]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(common/show-connection-sheet
|
||||
cofx
|
||||
{:sheet-options {:on-cancel [::on-cancel]}
|
||||
:on-card-connected :keycard/change-puk
|
||||
:handler
|
||||
(fn [{:keys [db] :as cofx}]
|
||||
(let [puk (common/vector->string
|
||||
(get-in db [:keycard :pin :puk-original]))
|
||||
pin (common/vector->string
|
||||
(get-in db [:keycard :pin :current]))]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (assoc-in db [:keycard :pin :status] :verifying)
|
||||
:keycard/change-puk {:puk puk
|
||||
:pin pin}})))}))
|
||||
|
||||
(rf/defn change-pairing
|
||||
{:events [:keycard/change-pairing]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(common/show-connection-sheet
|
||||
cofx
|
||||
{:sheet-options {:on-cancel [::on-cancel]}
|
||||
:on-card-connected :keycard/change-pairing
|
||||
:handler
|
||||
(fn [{:keys [db] :as cofx}]
|
||||
(let [pairing (get-in db [:keycard :pin :pairing-code])
|
||||
pin (common/vector->string
|
||||
(get-in db [:keycard :pin :current]))]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (assoc-in db [:keycard :pin :status] :verifying)
|
||||
:keycard/change-pairing {:pairing pairing
|
||||
:pin pin}})))}))
|
||||
|
||||
(rf/defn change-pairing-code
|
||||
{:events [:keycard/change-pairing-code]}
|
||||
[{:keys [db] :as cofx} pairing]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (assoc-in db [:keycard :pin :pairing-code] (security/unmask pairing))}
|
||||
(change-pairing)))
|
||||
|
||||
(rf/defn on-change-pin-success
|
||||
{:events [:keycard.callback/on-change-pin-success]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [pin (get-in db [:keycard :pin :original])
|
||||
puk-restore? (get-in db [:keycard :pin :puk-restore?])]
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db
|
||||
[:keycard :pin]
|
||||
{:status nil
|
||||
:login pin
|
||||
:confirmation []
|
||||
:error-label nil})
|
||||
:effects.utils/show-popup {:title ""
|
||||
:content (i18n/label :t/pin-changed)}}
|
||||
(common/hide-connection-sheet)
|
||||
(if puk-restore?
|
||||
(navigation/navigate-to :multiaccounts nil)
|
||||
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings]))
|
||||
(when (:profile/login db)
|
||||
(common/get-keys-from-keycard)))))
|
||||
|
||||
(rf/defn on-change-puk-success
|
||||
{:events [:keycard.callback/on-change-puk-success]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db
|
||||
[:keycard :pin]
|
||||
{:status nil
|
||||
:puk-original []
|
||||
:puk-confirmation []
|
||||
:error-label nil})
|
||||
:effects.utils/show-popup {:title ""
|
||||
:content (i18n/label :t/puk-changed)}}
|
||||
(common/hide-connection-sheet)
|
||||
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings])))
|
||||
|
||||
(rf/defn on-change-pairing-success
|
||||
{:events [:keycard.callback/on-change-pairing-success]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db
|
||||
[:keycard :pin]
|
||||
{:status nil
|
||||
:pairing-code nil
|
||||
:error-label nil})
|
||||
:effects.utils/show-popup {:title ""
|
||||
:content (i18n/label :t/pairing-changed)}}
|
||||
(common/hide-connection-sheet)
|
||||
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings])))
|
||||
|
||||
(rf/defn on-change-pin-error
|
||||
{:events [:keycard.callback/on-change-pin-error]}
|
||||
[{:keys [db] :as cofx} error]
|
||||
(log/debug "[keycard] change pin error" error)
|
||||
(let [tag-was-lost? (common/tag-lost? (:error error))
|
||||
pin-retries (common/pin-retries (:error error))]
|
||||
(rf/merge
|
||||
cofx
|
||||
(if tag-was-lost?
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:keycard :pin :status] nil)}
|
||||
(common/set-on-card-connected :keycard/change-pin))
|
||||
(if-not (nil? pin-retries)
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries)
|
||||
(update-in [:keycard :pin]
|
||||
assoc
|
||||
:status :error
|
||||
:enter-step :current
|
||||
:puk []
|
||||
:current []
|
||||
:original []
|
||||
:confirmation []
|
||||
:sign []
|
||||
:error-label :t/pin-mismatch))}
|
||||
(when (zero? pin-retries) (common/frozen-keycard-popup))
|
||||
(navigation/navigate-to :enter-pin-settings nil))
|
||||
(common/show-wrong-keycard-alert))))))
|
||||
@@ -1,560 +0,0 @@
|
||||
(ns legacy.status-im.keycard.common
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.bottom-sheet.events :as bottom-sheet]
|
||||
[legacy.status-im.keycard.nfc :as nfc]
|
||||
[legacy.status-im.popover.core :as popover]
|
||||
[legacy.status-im.utils.deprecated-types :as types]
|
||||
[legacy.status-im.utils.keychain.core :as keychain]
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.platform :as platform]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.address :as address]
|
||||
[utils.datetime :as datetime]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def default-pin "000000")
|
||||
|
||||
(def pin-mismatch-error #"Unexpected error SW, 0x63C(\d+)|wrongPIN\(retryCounter: (\d+)\)")
|
||||
|
||||
(defn pin-retries
|
||||
[error]
|
||||
(when-let [matched-error (re-matches pin-mismatch-error error)]
|
||||
(js/parseInt (second (filter some? matched-error)))))
|
||||
|
||||
(rf/defn dispatch-event
|
||||
[_ event]
|
||||
{:dispatch-n [[event]]})
|
||||
|
||||
(defn vector->string
|
||||
"Converts numbers stored in vector into string,
|
||||
e.g. [1 2 3 4 5 6] -> \"123456\""
|
||||
[v]
|
||||
(apply str v))
|
||||
|
||||
(defn get-card-state
|
||||
[{:keys [has-master-key?
|
||||
applet-installed?
|
||||
initialized?
|
||||
free-pairing-slots
|
||||
paired?]}]
|
||||
(cond
|
||||
|
||||
(not applet-installed?)
|
||||
:blank
|
||||
|
||||
(not initialized?)
|
||||
:pre-init
|
||||
|
||||
(not has-master-key?)
|
||||
:init
|
||||
|
||||
has-master-key?
|
||||
:profile/profile
|
||||
|
||||
(and (not paired?)
|
||||
(zero? free-pairing-slots))
|
||||
:no-pairing-slots))
|
||||
|
||||
(defn tag-lost?
|
||||
[error]
|
||||
(or
|
||||
(= error "Tag was lost.")
|
||||
(= error "NFCError:100")
|
||||
(re-matches #".*NFCError:100.*" error)))
|
||||
|
||||
(defn find-multiaccount-by-keycard-instance-uid
|
||||
[db keycard-instance-uid]
|
||||
(when keycard-instance-uid
|
||||
(->> (:profile/profiles-overview db)
|
||||
vals
|
||||
(filter #(= keycard-instance-uid (:keycard-instance-uid %)))
|
||||
first)))
|
||||
|
||||
(defn find-multiaccount-by-key-uid
|
||||
[db key-uid]
|
||||
(when key-uid
|
||||
(->> (:profile/profiles-overview db)
|
||||
vals
|
||||
(filter #(= (address/normalized-hex key-uid) (:key-uid %)))
|
||||
first)))
|
||||
|
||||
(defn get-pairing
|
||||
([db]
|
||||
(get-pairing db (get-in db [:keycard :application-info :key-uid])))
|
||||
([db key-uid]
|
||||
(or
|
||||
(get-in db [:profile/profile :keycard-pairing])
|
||||
(get-in db [:keycard :secrets :pairing])
|
||||
(when key-uid
|
||||
(:keycard-pairing
|
||||
(find-multiaccount-by-key-uid db key-uid))))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/set-nfc-supported
|
||||
(fn [supported?]
|
||||
(nfc/set-nfc-supported? supported?)))
|
||||
|
||||
(rf/defn listen-to-hardware-back-button
|
||||
[{:keys [db]}]
|
||||
(when-not (get-in db [:keycard :back-button-listener])
|
||||
{:keycard/listen-to-hardware-back-button nil}))
|
||||
|
||||
(rf/defn remove-listener-to-hardware-back-button
|
||||
[{:keys [db]}]
|
||||
(when-let [listener (get-in db [:keycard :back-button-listener])]
|
||||
{:keycard/remove-listener-to-hardware-back-button listener}))
|
||||
|
||||
(rf/defn set-on-card-connected
|
||||
[{:keys [db]} on-connect]
|
||||
(log/debug "[keycard] set-on-card-connected" on-connect)
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :on-card-connected] on-connect)
|
||||
(assoc-in [:keycard :last-on-card-connected] nil))})
|
||||
|
||||
(rf/defn stash-on-card-connected
|
||||
[{:keys [db]}]
|
||||
(let [on-connect (get-in db [:keycard :on-card-connected])]
|
||||
(log/debug "[keycard] stash-on-card-connected" on-connect)
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :last-on-card-connected] on-connect)
|
||||
(assoc-in [:keycard :on-card-connected] nil))}))
|
||||
|
||||
(rf/defn restore-on-card-connected
|
||||
[{:keys [db]}]
|
||||
(let [on-connect (or
|
||||
(get-in db [:keycard :on-card-connected])
|
||||
(get-in db [:keycard :last-on-card-connected]))]
|
||||
(log/debug "[keycard] restore-on-card-connected" on-connect)
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :on-card-connected] on-connect)
|
||||
(assoc-in [:keycard :last-on-card-connect] nil))}))
|
||||
|
||||
(rf/defn clear-on-card-connected
|
||||
[{:keys [db]}]
|
||||
(log/debug "[keycard] clear-on-card-connected")
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :on-card-connected] nil)
|
||||
(assoc-in [:keycard :last-on-card-connected] nil))})
|
||||
|
||||
(rf/defn set-on-card-read
|
||||
[{:keys [db]} on-connect]
|
||||
(log/debug "[keycard] set-on-card-read" on-connect)
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :on-card-read] on-connect)
|
||||
(assoc-in [:keycard :last-on-card-read] nil))})
|
||||
|
||||
(rf/defn stash-on-card-read
|
||||
[{:keys [db]}]
|
||||
(let [on-connect (get-in db [:keycard :on-card-read])]
|
||||
(log/debug "[keycard] stash-on-card-read" on-connect)
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :last-on-card-read] on-connect)
|
||||
(assoc-in [:keycard :on-card-read] nil))}))
|
||||
|
||||
(rf/defn restore-on-card-read
|
||||
[{:keys [db]}]
|
||||
(let [on-connect (or
|
||||
(get-in db [:keycard :on-card-read])
|
||||
(get-in db [:keycard :last-on-card-read]))]
|
||||
(log/debug "[keycard] restore-on-card-read" on-connect)
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :on-card-read] on-connect)
|
||||
(assoc-in [:keycard :last-on-card-connect] nil))}))
|
||||
|
||||
(rf/defn clear-on-card-read
|
||||
[{:keys [db]}]
|
||||
(log/debug "[keycard] clear-on-card-read")
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :on-card-read] nil)
|
||||
(assoc-in [:keycard :last-on-card-read] nil))})
|
||||
|
||||
(rf/defn show-connection-sheet-component
|
||||
[{:keys [db] :as cofx}
|
||||
{:keys [on-card-connected on-card-read handler]
|
||||
{:keys [on-cancel]
|
||||
:or {on-cancel [::cancel-sheet-confirm]}}
|
||||
:sheet-options}]
|
||||
(assert (keyword? on-card-connected))
|
||||
(assert (fn? handler))
|
||||
(let [connected? (get-in db [:keycard :card-connected?])]
|
||||
(log/debug "[keycard] show-sheet-with-connection-check"
|
||||
"card-connected?"
|
||||
connected?)
|
||||
(rf/merge
|
||||
cofx
|
||||
(bottom-sheet/show-bottom-sheet-old
|
||||
{:view {:transparent platform/ios?
|
||||
:show-handle? false
|
||||
:backdrop-dismiss? false
|
||||
:disable-drag? true
|
||||
:back-button-cancel false}})
|
||||
(when on-card-read
|
||||
(set-on-card-read on-card-read))
|
||||
(set-on-card-connected on-card-connected)
|
||||
(when connected?
|
||||
(stash-on-card-connected))
|
||||
(when connected?
|
||||
handler))))
|
||||
|
||||
(rf/defn show-connection-sheet
|
||||
[{:keys [db] :as cofx} args]
|
||||
(let [nfc-running? (get-in db [:keycard :nfc-running?])]
|
||||
(log/debug "show connection; already running?" nfc-running?)
|
||||
(if nfc-running?
|
||||
(show-connection-sheet-component cofx args)
|
||||
{:keycard/start-nfc-and-show-connection-sheet args})))
|
||||
|
||||
(rf/defn on-nfc-ready-for-sheet
|
||||
{:events [:keycard.callback/show-connection-sheet]}
|
||||
[cofx args]
|
||||
(log/debug "on-nfc-ready-for-sheet")
|
||||
(show-connection-sheet-component cofx args))
|
||||
|
||||
(rf/defn hide-connection-sheet-component
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:keycard :card-read-in-progress?] false)}
|
||||
(restore-on-card-connected)
|
||||
(restore-on-card-read)
|
||||
(bottom-sheet/hide-bottom-sheet-old)))
|
||||
|
||||
(rf/defn hide-connection-sheet
|
||||
[cofx]
|
||||
(log/debug "hide-connection-sheet")
|
||||
{:keycard/stop-nfc-and-hide-connection-sheet nil})
|
||||
|
||||
(rf/defn on-nfc-ready-to-close-sheet
|
||||
{:events [:keycard.callback/hide-connection-sheet]}
|
||||
[cofx]
|
||||
(log/debug "on-nfc-ready-to-close-sheet")
|
||||
(hide-connection-sheet-component cofx))
|
||||
|
||||
(rf/defn clear-pin
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (assoc-in db
|
||||
[:keycard :pin]
|
||||
{:status nil
|
||||
:login (get-in db [:keycard :pin :original])
|
||||
:export-key []
|
||||
:sign []
|
||||
:puk []
|
||||
:current []
|
||||
:original []
|
||||
:confirmation []
|
||||
:error-label nil
|
||||
:on-verified (get-in db [:keycard :pin :on-verified])
|
||||
:on-verified-failure (get-in db [:keycard :pin :on-verified])})}))
|
||||
|
||||
(rf/defn cancel-sheet-confirm
|
||||
{:events [::cancel-sheet-confirm
|
||||
:keycard/back-button-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(when-not (get-in db [:keycard :card-connected?])
|
||||
(rf/merge cofx
|
||||
(hide-connection-sheet)
|
||||
(clear-pin))))
|
||||
|
||||
(rf/defn cancel-sheet
|
||||
{:events [::cancel-sheet]}
|
||||
[_]
|
||||
{:ui/show-confirmation {:title (i18n/label :t/keycard-cancel-setup-title)
|
||||
:content (i18n/label :t/keycard-cancel-setup-text)
|
||||
:confirm-button-text (i18n/label :t/yes)
|
||||
:cancel-button-text (i18n/label :t/no)
|
||||
:on-accept #(re-frame/dispatch [::cancel-sheet-confirm])
|
||||
:on-cancel #()}})
|
||||
|
||||
(rf/defn on-add-listener-to-hardware-back-button
|
||||
"Adds listener to hardware back button on Android.
|
||||
During keycard setup we show user a warning that setup will be cancelled
|
||||
when back button pressed. This prevents user from going back during setup
|
||||
flow as some of the actions changing keycard step could not be repeated."
|
||||
{:events [:keycard/add-listener-to-hardware-back-button]}
|
||||
[{:keys [db]} listener]
|
||||
{:db (assoc-in db [:keycard :back-button-listener] listener)})
|
||||
|
||||
(rf/defn show-wrong-keycard-alert
|
||||
[_]
|
||||
(log/debug "show-wrong-keycard-alert")
|
||||
{:effects.utils/show-popup {:title (i18n/label :t/wrong-card)
|
||||
:content (i18n/label :t/wrong-card-text)}})
|
||||
|
||||
(rf/defn unauthorized-operation
|
||||
[cofx]
|
||||
(rf/merge cofx
|
||||
{:effects.utils/show-popup {:title ""
|
||||
:content (i18n/label :t/keycard-unauthorized-operation)}}
|
||||
(clear-on-card-connected)
|
||||
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings])))
|
||||
|
||||
(rf/defn navigate-to-enter-pin-screen
|
||||
{:events [:keycard/navigate-to-enter-pin-screen]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:keycard :pin :current] [])}
|
||||
(navigation/navigate-to :enter-pin-settings nil)))
|
||||
|
||||
(defn- tag-lost-exception?
|
||||
[code error]
|
||||
(or
|
||||
(= code "android.nfc.TagLostException")
|
||||
(= error "Tag was lost.")
|
||||
(= error "NFCError:100")))
|
||||
|
||||
(rf/defn process-error
|
||||
[{:keys [db]} code error]
|
||||
(when-not (tag-lost-exception? code error)
|
||||
{:db (assoc-in db [:keycard :setup-step] :error)}))
|
||||
|
||||
(rf/defn get-keys-from-keycard
|
||||
[{:keys [db]}]
|
||||
(let [key-uid (get-in db [:profile/login :key-uid])
|
||||
pin (string/join (get-in db [:keycard :pin :login]))]
|
||||
(log/debug "[keycard] get-keys-from-keycard"
|
||||
", not empty pin:"
|
||||
(boolean (seq pin)))
|
||||
(when (seq pin)
|
||||
{:db (assoc-in db [:keycard :pin :status] :verifying)
|
||||
:keycard/get-keys {:pin pin}})))
|
||||
|
||||
(rf/defn on-get-keys-success
|
||||
{:events [:keycard.callback/on-get-keys-success]}
|
||||
[{:keys [db] :as cofx} data]
|
||||
(let [{:keys [key-uid encryption-public-key whisper-private-key]
|
||||
:as account-data}
|
||||
(js->clj data :keywordize-keys true)
|
||||
{:keys [name]} (get-in db [:profile/profiles-overview key-uid])
|
||||
key-uid (get-in db [:keycard :application-info :key-uid])
|
||||
multiaccount-data (types/clj->json {:name name
|
||||
:key-uid key-uid})
|
||||
save-keys? (get-in db [:profile/login :save-password?])]
|
||||
(rf/merge cofx
|
||||
{:db
|
||||
(-> db
|
||||
(assoc-in [:keycard :pin :status] nil)
|
||||
(assoc-in [:keycard :pin :login] [])
|
||||
(update-in [:keycard :application-info]
|
||||
assoc
|
||||
:puk-retry-counter 5
|
||||
:pin-retry-counter 3)
|
||||
(assoc-in [:keycard :profile/profile]
|
||||
(update account-data :whisper-public-key address/normalized-hex))
|
||||
(assoc-in [:keycard :flow] nil)
|
||||
(update :profile/login assoc
|
||||
:password encryption-public-key
|
||||
:key-uid key-uid
|
||||
:name name))
|
||||
|
||||
:keycard/login-with-keycard {:multiaccount-data multiaccount-data
|
||||
:password encryption-public-key
|
||||
:chat-key whisper-private-key
|
||||
:key-uid key-uid}}
|
||||
(when save-keys?
|
||||
(keychain/save-keycard-keys key-uid encryption-public-key whisper-private-key))
|
||||
(clear-on-card-connected)
|
||||
(clear-on-card-read)
|
||||
(hide-connection-sheet))))
|
||||
|
||||
(rf/defn blocked-or-frozen-keycard-popup
|
||||
[{:keys [db] :as cofx} card-status]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (assoc-in db [:keycard :pin :status] card-status)}
|
||||
(hide-connection-sheet)
|
||||
; do not try to display the popover if it is already open or
|
||||
; we are in the login interface (which has a different handling)
|
||||
(when-not (or (:profile/login db) (:popover/popover db))
|
||||
(popover/show-popover {:view card-status}))))
|
||||
|
||||
(rf/defn blocked-keycard-popup
|
||||
[cofx]
|
||||
(blocked-or-frozen-keycard-popup cofx :blocked-card))
|
||||
|
||||
(rf/defn frozen-keycard-popup
|
||||
[cofx]
|
||||
(blocked-or-frozen-keycard-popup cofx :frozen-card))
|
||||
|
||||
(rf/defn on-get-keys-error
|
||||
{:events [:keycard.callback/on-get-keys-error]}
|
||||
[{:keys [db] :as cofx} error]
|
||||
(log/debug "[keycard] get keys error: " error)
|
||||
(let [tag-was-lost? (tag-lost? (:error error))
|
||||
key-uid (get-in db [:keycard :application-info :key-uid])
|
||||
flow (get-in db [:keycard :flow])
|
||||
pin-retries-count (pin-retries (:error error))]
|
||||
(if tag-was-lost?
|
||||
{:db (assoc-in db [:keycard :pin :status] nil)}
|
||||
(if-not (nil? pin-retries-count)
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries-count)
|
||||
(update-in [:keycard :pin]
|
||||
assoc
|
||||
:status :error
|
||||
:login []
|
||||
:import-multiaccount []
|
||||
:error-label :t/pin-mismatch))}
|
||||
(hide-connection-sheet)
|
||||
(when (zero? pin-retries-count) (frozen-keycard-popup)))
|
||||
(show-wrong-keycard-alert)))))
|
||||
|
||||
(rf/defn factory-reset
|
||||
{:events [:keycard/factory-reset]}
|
||||
[{:keys [db]} on-card-read]
|
||||
(log/debug "[keycard] factory-reset")
|
||||
{:db (update db :keycard dissoc :factory-reset-card?)
|
||||
:keycard/factory-reset {:on-success on-card-read}})
|
||||
|
||||
;; Get application info
|
||||
|
||||
(rf/defn update-pairings
|
||||
[{:keys [db]} instance-uid pairing]
|
||||
(let [paired-on (datetime/timestamp)
|
||||
pairings (-> (get-in db [:keycard :pairings])
|
||||
(assoc instance-uid {:pairing pairing :paired-on paired-on}))]
|
||||
{:keycard/persist-pairings pairings
|
||||
:db (assoc-in db [:keycard :pairings] pairings)}))
|
||||
|
||||
(rf/defn get-application-info
|
||||
{:events [:keycard/get-application-info]}
|
||||
[{:keys [db]} on-card-read]
|
||||
(log/debug "[keycard] get-application-info")
|
||||
{:keycard/get-application-info {:on-success on-card-read}})
|
||||
|
||||
(rf/defn on-get-application-info-success
|
||||
{:events [:keycard.callback/on-get-application-info-success]}
|
||||
[{:keys [db] :as cofx} info on-success]
|
||||
(let [{:keys [pin-retry-counter puk-retry-counter instance-uid new-pairing]} info
|
||||
view-id (:view-id db)
|
||||
{:keys [on-card-read]} (:keycard db)
|
||||
on-success' (or on-success
|
||||
on-card-read)
|
||||
enter-step (get-in db
|
||||
[:keycard :pin
|
||||
:enter-step])]
|
||||
(log/debug "[keycard] on-get-application-info-success"
|
||||
"on-success" on-success'
|
||||
"pin-retry-counter" pin-retry-counter
|
||||
"puk-retry-counter" puk-retry-counter)
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :pin :enter-step] enter-step)
|
||||
(assoc-in [:keycard :application-info] info)
|
||||
(assoc-in [:keycard :application-info :applet-installed?] true)
|
||||
(assoc-in [:keycard :application-info-error] nil))}
|
||||
(stash-on-card-read)
|
||||
(when new-pairing
|
||||
(update-pairings instance-uid new-pairing))
|
||||
(when (and (zero? pin-retry-counter)
|
||||
(pos? puk-retry-counter)
|
||||
(not= enter-step :puk))
|
||||
(frozen-keycard-popup))
|
||||
(fn [{:keys [db] :as cofx}]
|
||||
(if (zero? puk-retry-counter)
|
||||
(blocked-keycard-popup cofx)
|
||||
(when on-success'
|
||||
(dispatch-event cofx on-success')))))))
|
||||
|
||||
(rf/defn on-get-application-info-error
|
||||
{:events [:keycard.callback/on-get-application-info-error]}
|
||||
[{:keys [db] :as cofx} error]
|
||||
(let [on-card-read (get-in db [:keycard :on-card-read])
|
||||
on-card-connected (get-in db [:keycard :on-card-connected])
|
||||
last-on-card-connected (get-in db [:keycard :last-on-card-connected])
|
||||
login? (= on-card-read :keycard/login-with-keycard)
|
||||
tag-was-lost? (tag-lost? (:error error))]
|
||||
(log/debug "[keycard] application info error"
|
||||
error
|
||||
on-card-connected
|
||||
last-on-card-connected)
|
||||
(when-not tag-was-lost?
|
||||
(if login?
|
||||
(rf/merge cofx
|
||||
(clear-on-card-read)
|
||||
(navigation/navigate-to :not-keycard nil))
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:keycard :application-info-error] error)}
|
||||
|
||||
(when (contains?
|
||||
#{last-on-card-connected on-card-connected}
|
||||
:keycard/prepare-to-sign)
|
||||
(show-wrong-keycard-alert))
|
||||
|
||||
(when on-card-read
|
||||
(dispatch-event on-card-read)))))))
|
||||
|
||||
(rf/defn on-card-connected
|
||||
{:events [::on-card-connected]}
|
||||
[{:keys [db] :as cofx} _]
|
||||
(let [instance-uid (get-in db [:keycard :application-info :instance-uid])
|
||||
key-uid (get-in db [:keycard :application-info :key-uid])
|
||||
should-read-instance-uid? (nil? instance-uid)
|
||||
on-card-connected (get-in db [:keycard :on-card-connected])
|
||||
on-card-read (cond
|
||||
should-read-instance-uid? :keycard/get-application-info
|
||||
:else (get-in db [:keycard :on-card-read]))]
|
||||
(log/debug "[keycard] on-card-connected" on-card-connected
|
||||
"on-card-read" on-card-read)
|
||||
(when on-card-connected
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :card-read-in-progress?] (boolean on-card-read)))}
|
||||
(when on-card-connected
|
||||
(dispatch-event on-card-connected))
|
||||
(stash-on-card-connected)
|
||||
(when (and on-card-read
|
||||
(nil? on-card-connected))
|
||||
(get-application-info on-card-read))))))
|
||||
|
||||
(rf/defn on-card-disconnected
|
||||
{:events [::on-card-disconnected]}
|
||||
[{:keys [db] :as cofx} _]
|
||||
(log/debug "[keycard] card disconnected")
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :card-read-in-progress?] false))}
|
||||
(restore-on-card-connected)
|
||||
(restore-on-card-read)))
|
||||
|
||||
(defn keycard-multiaccount?
|
||||
[db]
|
||||
(boolean (get-in db [:profile/profile :keycard-pairing])))
|
||||
|
||||
(rf/defn verify-pin
|
||||
{:events [:keycard/verify-pin]}
|
||||
[{:keys [db] :as cofx} {:keys [pin-step on-card-connected on-failure on-success]}]
|
||||
(let [on-success (or on-success
|
||||
(get-in db [:keycard :pin :on-verified]))
|
||||
on-failure (or on-failure
|
||||
(get-in db [:keycard :pin :on-verified-failure]))
|
||||
pin-step (or pin-step
|
||||
(get-in db [:keycard :pin :step]))]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (update-in db
|
||||
[:keycard :pin]
|
||||
assoc
|
||||
:step pin-step
|
||||
:on-verified on-success
|
||||
:on-verified-failure on-failure)}
|
||||
(show-connection-sheet
|
||||
{:on-card-connected (or on-card-connected :keycard/verify-pin)
|
||||
:handler
|
||||
(fn [{:keys [db] :as cofx}]
|
||||
(let [pin (vector->string (get-in db [:keycard :pin pin-step]))]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (assoc-in db [:keycard :pin :status] :verifying)
|
||||
:keycard/verify-pin {:pin pin}})))}))))
|
||||
|
||||
(rf/defn navigete-to-keycard-settings
|
||||
{:events [::navigate-to-keycard-settings]}
|
||||
[cofx]
|
||||
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings]))
|
||||
@@ -1,43 +0,0 @@
|
||||
(ns legacy.status-im.keycard.common-test
|
||||
(:require
|
||||
[cljs.test :refer-macros [deftest is testing]]
|
||||
[legacy.status-im.keycard.common :as common]))
|
||||
|
||||
(deftest test-show-connection-sheet
|
||||
(testing "the card is not connected yet"
|
||||
(let [db {:keycard {:card-connected? false}}
|
||||
res (common/show-connection-sheet-component
|
||||
{:db db}
|
||||
{:on-card-connected :do-something
|
||||
:handler (fn [{:keys [db]}]
|
||||
{:db (assoc db :some-key :some-value)})})]
|
||||
(is (= :do-something
|
||||
(get-in res [:db :keycard :on-card-connected])))
|
||||
(is (nil? (get-in res [:db :some-key])))
|
||||
(is (true? (get-in res [:db :bottom-sheet/show?])))))
|
||||
(testing "the card is connected before the interaction"
|
||||
(let [db {:keycard {:card-connected? true}}
|
||||
res (common/show-connection-sheet-component
|
||||
{:db db}
|
||||
{:on-card-connected :do-something
|
||||
:handler (fn [{:keys [db]}]
|
||||
{:db (assoc db :some-key :some-value)})})]
|
||||
(is (nil? (get-in res [:db :keycard :on-card-connected])))
|
||||
(is (= :do-something
|
||||
(get-in res [:db :keycard :last-on-card-connected])))
|
||||
(is (= :some-value (get-in res [:db :some-key])))
|
||||
(is (true? (get-in res [:db :bottom-sheet/show?])))))
|
||||
(testing "on-card-connected is not specified"
|
||||
(is
|
||||
(thrown?
|
||||
js/Error
|
||||
(common/show-connection-sheet-component
|
||||
{:db {}}
|
||||
{:handler (fn [_])}))))
|
||||
(testing "handler is not specified"
|
||||
(is
|
||||
(thrown?
|
||||
js/Error
|
||||
(common/show-connection-sheet-component
|
||||
{:db {}}
|
||||
{:on-card-connected :do-something})))))
|
||||
@@ -1,688 +0,0 @@
|
||||
(ns legacy.status-im.keycard.core
|
||||
(:require
|
||||
legacy.status-im.keycard.backup-key
|
||||
[legacy.status-im.keycard.card :as card]
|
||||
[legacy.status-im.keycard.change-pin :as change-pin]
|
||||
[legacy.status-im.keycard.common :as common]
|
||||
legacy.status-im.keycard.delete-key
|
||||
legacy.status-im.keycard.export-key
|
||||
[legacy.status-im.keycard.login :as login]
|
||||
[legacy.status-im.keycard.mnemonic :as mnemonic]
|
||||
[legacy.status-im.keycard.onboarding :as onboarding]
|
||||
[legacy.status-im.keycard.recovery :as recovery]
|
||||
[legacy.status-im.keycard.sign :as sign]
|
||||
legacy.status-im.keycard.unpair
|
||||
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
[re-frame.db]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.datetime :as datetime]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn show-keycard-has-multiaccount-alert
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:keycard :setup-step] nil)
|
||||
:effects.utils/show-confirmation {:title nil
|
||||
:content (i18n/label
|
||||
:t/keycard-has-multiaccount-on-it)
|
||||
:cancel-button-text ""
|
||||
:confirm-button-text :t/okay}}))
|
||||
|
||||
(rf/defn load-pin-screen
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :setup-step] :pin)
|
||||
(assoc-in [:keycard :pin]
|
||||
{:enter-step :original
|
||||
:original []
|
||||
:confirmation []}))}
|
||||
(navigation/navigate-to :keycard-onboarding-pin nil)))
|
||||
|
||||
(rf/defn load-recovery-pin-screen
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :pin]
|
||||
{:enter-step :import-multiaccount
|
||||
:import-multiaccount []
|
||||
:current []}))}
|
||||
(common/listen-to-hardware-back-button)
|
||||
(navigation/navigate-replace :keycard-recovery-pin nil)))
|
||||
|
||||
(rf/defn load-pairing
|
||||
[{:keys [db]}]
|
||||
(let [instance-uid (get-in db [:keycard :application-info :instance-uid])
|
||||
pairing-data (or (get-in db [:keycard :pairings (keyword instance-uid)])
|
||||
(get-in db [:keycard :pairings instance-uid]))]
|
||||
{:db (update-in db [:keycard :secrets] merge pairing-data)}))
|
||||
|
||||
(rf/defn proceed-setup-with-initialized-card
|
||||
[{:keys [db] :as cofx} flow instance-uid paired?]
|
||||
(log/debug "[keycard] proceed-setup-with-initialized-card"
|
||||
"instance-uid"
|
||||
instance-uid)
|
||||
(if (= flow :import)
|
||||
(navigation/navigate-to cofx :keycard-recovery-no-key nil)
|
||||
(if paired?
|
||||
(rf/merge cofx
|
||||
(common/listen-to-hardware-back-button)
|
||||
(when (= flow :create)
|
||||
(mnemonic/set-mnemonic))
|
||||
(when (= flow :recovery)
|
||||
(onboarding/proceed-with-generating-key)))
|
||||
(if (get-in db [:keycard :secrets :password])
|
||||
(onboarding/load-pairing-screen cofx)
|
||||
(recovery/load-pair-screen cofx)))))
|
||||
|
||||
(rf/defn navigate-to-keycard-settings
|
||||
{:events [:profile.ui/keycard-settings-button-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :pin :on-verified] nil)
|
||||
(assoc-in [:keycard :setup-step] nil))}
|
||||
(common/clear-on-card-connected)
|
||||
(navigation/navigate-to :keycard-settings nil)))
|
||||
|
||||
(rf/defn password-option-pressed
|
||||
{:eevents [:keycard.ui/password-option-pressed]}
|
||||
[{:keys [db]}]
|
||||
(when (= (get-in db [:keycard :flow]) :create)
|
||||
#())) ;;TODO with v1 flow
|
||||
|
||||
(rf/defn settings-screen-did-load
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :pin :on-verified] nil)
|
||||
(assoc-in [:keycard :setup-step] nil))}
|
||||
(common/clear-on-card-connected)))
|
||||
|
||||
(defn reset-card-screen-did-load
|
||||
[{:keys [db]}]
|
||||
{:db (assoc-in db [:keycard :reset-card :disabled?] false)})
|
||||
|
||||
(defn enter-pin-screen-did-load
|
||||
[{:keys [db]}]
|
||||
(let [enter-step (get-in db [:keycard :pin :enter-step])]
|
||||
{:db (assoc-in db [:keycard :pin enter-step] [])}))
|
||||
|
||||
(defn login-pin-screen-did-load
|
||||
[{:keys [db]}]
|
||||
(let [enter-step (get-in db [:keycard :pin :enter-step])]
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :pin enter-step] [])
|
||||
(dissoc :intro-wizard :recovered-account?))}))
|
||||
|
||||
(defn multiaccounts-screen-did-load
|
||||
[{:keys [db]}]
|
||||
{:db (assoc-in db [:keycard :setup-step] nil)})
|
||||
|
||||
(defn authentication-method-screen-did-load
|
||||
[{:keys [db]}]
|
||||
{:db (assoc-in db [:keycard :setup-step] nil)})
|
||||
|
||||
(rf/defn set-nfc-supported
|
||||
{:events [:keycard.callback/check-nfc-support-success]}
|
||||
[_ supported?]
|
||||
{:keycard/set-nfc-supported supported?})
|
||||
|
||||
;; TODO: Should be listener and replace the view in bottom sheet to avoid this
|
||||
(rf/defn on-check-nfc-enabled-success
|
||||
{:events [:keycard.callback/check-nfc-enabled-success]}
|
||||
[{:keys [db]} nfc-enabled?]
|
||||
(log/debug "[keycard] check-nfc-enabled-success"
|
||||
"nfc-enabled?"
|
||||
nfc-enabled?)
|
||||
{:db (assoc-in db [:keycard :nfc-enabled?] nfc-enabled?)})
|
||||
|
||||
(defn- proceed-to-pin-confirmation
|
||||
[fx]
|
||||
(assoc-in fx [:db :keycard :pin :enter-step] :confirmation))
|
||||
|
||||
(defn- proceed-to-change-puk-confirmation
|
||||
[fx]
|
||||
(assoc-in fx [:db :keycard :pin :enter-step] :puk-confirmation))
|
||||
|
||||
(defn- proceed-to-pin-reset-confirmation
|
||||
[fx]
|
||||
(-> fx
|
||||
(update-in [:db :keycard :pin] dissoc :reset-confirmation)
|
||||
(assoc-in [:db :keycard :pin :enter-step] :reset-confirmation)))
|
||||
|
||||
(defn- proceed-to-puk-confirmation
|
||||
[fx]
|
||||
(assoc-in fx [:db :keycard :pin :enter-step] :puk))
|
||||
|
||||
(rf/defn on-unblock-pin-success
|
||||
{:events [:keycard.callback/on-unblock-pin-success]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [reset-pin (get-in db [:keycard :pin :reset])]
|
||||
(rf/merge cofx
|
||||
{:db
|
||||
(-> db
|
||||
(update-in [:keycard :application-info]
|
||||
assoc
|
||||
:puk-retry-counter 5
|
||||
:pin-retry-counter 3)
|
||||
(update-in [:keycard :pin]
|
||||
assoc
|
||||
:status :after-unblocking
|
||||
:enter-step :login
|
||||
:login reset-pin
|
||||
:confirmation []
|
||||
:puk []
|
||||
:puk-restore? true
|
||||
:error-label nil))}
|
||||
(common/hide-connection-sheet)
|
||||
(common/clear-on-card-connected)
|
||||
(common/clear-on-card-read))))
|
||||
|
||||
(rf/defn on-unblock-pin-error
|
||||
{:events [:keycard.callback/on-unblock-pin-error]}
|
||||
[{:keys [db] :as cofx} error]
|
||||
(let [tag-was-lost? (common/tag-lost? (:error error))
|
||||
puk-retries (common/pin-retries (:error error))]
|
||||
(log/debug "[keycard] unblock pin error" error)
|
||||
(when-not tag-was-lost?
|
||||
(rf/merge cofx
|
||||
{:db
|
||||
(-> db
|
||||
(assoc-in [:keycard :application-info :puk-retry-counter] puk-retries)
|
||||
(update-in [:keycard :pin]
|
||||
merge
|
||||
{:status (if (zero? puk-retries) :blocked-card :error)
|
||||
:error-label :t/puk-mismatch
|
||||
:enter-step :puk
|
||||
:puk []}))}
|
||||
|
||||
(common/hide-connection-sheet)))))
|
||||
|
||||
(rf/defn clear-on-verify-handlers
|
||||
[{:keys [db]}]
|
||||
{:db (update-in db
|
||||
[:keycard :pin]
|
||||
dissoc
|
||||
:on-verified-failure
|
||||
:on-verified)})
|
||||
|
||||
(rf/defn on-verify-pin-success
|
||||
{:events [:keycard.callback/on-verify-pin-success]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [on-verified (get-in db [:keycard :pin :on-verified])]
|
||||
(log/debug "[hardwaller] success pin verification. on-verified" on-verified)
|
||||
(rf/merge cofx
|
||||
{:db (update-in db
|
||||
[:keycard :pin]
|
||||
merge
|
||||
{:status nil
|
||||
:error-label nil})}
|
||||
(common/clear-on-card-connected)
|
||||
(common/clear-on-card-read)
|
||||
;; TODO(Ferossgp): Each pin input should handle this event on it's own,
|
||||
;; now for simplicity do not hide bottom sheet when generating key
|
||||
;; and exporting key but should be refactored.
|
||||
(when-not (contains? #{:keycard/generate-and-load-key
|
||||
:wallet-legacy.accounts/generate-new-keycard-account
|
||||
:keycard/remove-key-with-unpair
|
||||
:keycard/unpair-and-delete}
|
||||
on-verified)
|
||||
(common/hide-connection-sheet))
|
||||
(when-not (contains? #{:keycard/unpair
|
||||
:keycard/generate-and-load-key
|
||||
:keycard/remove-key-with-unpair
|
||||
:keycard/unpair-and-delete
|
||||
:wallet-legacy.accounts/generate-new-keycard-account}
|
||||
on-verified)
|
||||
(common/get-application-info nil))
|
||||
(when on-verified
|
||||
(common/dispatch-event on-verified))
|
||||
(clear-on-verify-handlers))))
|
||||
|
||||
(rf/defn on-verify-pin-error
|
||||
{:events [:keycard.callback/on-verify-pin-error]}
|
||||
[{:keys [db] :as cofx} error]
|
||||
(let [tag-was-lost? (common/tag-lost? (:error error))
|
||||
setup? (boolean (get-in db [:keycard :setup-step]))
|
||||
on-verified-failure (get-in db [:keycard :pin :on-verified-failure])
|
||||
exporting? (get-in db [:keycard :on-export-success])
|
||||
pin-retries (common/pin-retries (:error error))]
|
||||
(log/debug "[keycard] verify pin error" error)
|
||||
(when-not tag-was-lost?
|
||||
(if-not (nil? pin-retries)
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries)
|
||||
(update-in [:keycard :pin]
|
||||
assoc
|
||||
:status :error
|
||||
:enter-step :current
|
||||
:puk []
|
||||
:current []
|
||||
:original []
|
||||
:confirmation []
|
||||
:sign []
|
||||
:error-label :t/pin-mismatch))}
|
||||
(common/hide-connection-sheet)
|
||||
(when (and (not setup?)
|
||||
(not on-verified-failure))
|
||||
(when exporting?
|
||||
(navigation/navigate-back)))
|
||||
;(navigation/navigate-to :enter-pin-settings nil)))
|
||||
(when (zero? pin-retries) (common/frozen-keycard-popup))
|
||||
(when on-verified-failure
|
||||
(fn [_]
|
||||
{:utils/dispatch-later
|
||||
[{:dispatch [on-verified-failure]
|
||||
:ms 200}]}))
|
||||
#_(clear-on-verify-handlers))
|
||||
|
||||
(rf/merge cofx
|
||||
(common/hide-connection-sheet)
|
||||
(common/show-wrong-keycard-alert)
|
||||
(clear-on-verify-handlers))))))
|
||||
|
||||
(rf/defn unblock-pin
|
||||
{:events [:keycard/unblock-pin]}
|
||||
[cofx]
|
||||
(common/show-connection-sheet
|
||||
cofx
|
||||
{:on-card-connected :keycard/unblock-pin
|
||||
:handler
|
||||
(fn [{:keys [db]}]
|
||||
(let [puk (common/vector->string (get-in db [:keycard :pin :puk]))
|
||||
pin (common/vector->string (get-in db [:keycard :pin :reset]))
|
||||
key-uid (get-in db [:keycard :application-info :key-uid])]
|
||||
{:db (assoc-in db [:keycard :pin :status] :verifying)
|
||||
:keycard/unblock-pin
|
||||
{:puk puk
|
||||
:new-pin pin}}))}))
|
||||
|
||||
(def pin-code-length 6)
|
||||
(def puk-code-length 12)
|
||||
|
||||
(rf/defn handle-pin-input
|
||||
[{:keys [db]} enter-step]
|
||||
(let [numbers-entered (count (get-in db [:keycard :pin enter-step]))]
|
||||
(when (or (= numbers-entered pin-code-length)
|
||||
(= numbers-entered puk-code-length))
|
||||
{:dispatch [:keycard/process-pin-input]})))
|
||||
|
||||
(rf/defn update-pin
|
||||
{:events [:keycard.ui/pin-numpad-button-pressed]}
|
||||
[{:keys [db] :as cofx} number enter-step]
|
||||
(log/debug "update-pin" enter-step)
|
||||
(let [numbers-entered (count (get-in db [:keycard :pin enter-step]))
|
||||
need-update? (if (or (= enter-step :puk)
|
||||
(= enter-step :puk-original)
|
||||
(= enter-step :puk-confirmation))
|
||||
(< numbers-entered puk-code-length)
|
||||
(< numbers-entered pin-code-length))]
|
||||
(rf/merge cofx
|
||||
{:db (cond-> (-> db
|
||||
(assoc-in [:keycard :pin :enter-step] enter-step)
|
||||
(assoc-in [:keycard :pin :status] nil))
|
||||
need-update? (update-in [:keycard :pin enter-step] (fnil conj []) number))}
|
||||
(when need-update?
|
||||
(handle-pin-input enter-step)))))
|
||||
|
||||
(defn- pin-enter-error
|
||||
[fx error-label]
|
||||
(update-in fx
|
||||
[:db :keycard :pin]
|
||||
merge
|
||||
{:status :error
|
||||
:error-label error-label
|
||||
:enter-step :original
|
||||
:original []
|
||||
:confirmation []}))
|
||||
|
||||
(defn- puk-enter-error
|
||||
[fx error-label]
|
||||
(update-in fx
|
||||
[:db :keycard :pin]
|
||||
merge
|
||||
{:status :error
|
||||
:error-label error-label
|
||||
:enter-step :puk-original
|
||||
:puk-original []
|
||||
:puk-confirmation []}))
|
||||
|
||||
(defn- pin-reset-error
|
||||
[fx error-label]
|
||||
(update-in fx
|
||||
[:db :keycard :pin]
|
||||
merge
|
||||
{:status :error
|
||||
:error-label error-label
|
||||
:enter-step :reset
|
||||
:reset []
|
||||
:reset-confirmation []}))
|
||||
|
||||
; PIN enter steps:
|
||||
; login - PIN is used to login
|
||||
; sign - PIN for transaction sign
|
||||
; current - current PIN to perform actions which require PIN auth
|
||||
; original - new PIN when user changes it or creates new one
|
||||
; confirmation - confirmation for new PIN
|
||||
(rf/defn process-pin-input
|
||||
{:events [:keycard/process-pin-input]}
|
||||
[{:keys [db]}]
|
||||
(let [enter-step (get-in db [:keycard :pin :enter-step])
|
||||
pin (get-in db [:keycard :pin enter-step])
|
||||
numbers-entered (count pin)]
|
||||
(log/debug "[keycard] process-pin-input"
|
||||
"enter-step" enter-step
|
||||
"numbers-entered" numbers-entered)
|
||||
(cond-> {:db (assoc-in db [:keycard :pin :status] nil)}
|
||||
|
||||
(and (= enter-step :login)
|
||||
(= 6 numbers-entered))
|
||||
(login/proceed-to-login)
|
||||
|
||||
(and (= enter-step :original)
|
||||
(= pin-code-length numbers-entered))
|
||||
(proceed-to-pin-confirmation)
|
||||
|
||||
(and (= enter-step :original)
|
||||
(= pin-code-length numbers-entered)
|
||||
(= common/default-pin (common/vector->string pin)))
|
||||
(pin-enter-error :t/cannot-use-default-pin)
|
||||
|
||||
(and (= enter-step :import-multiaccount)
|
||||
(= pin-code-length numbers-entered))
|
||||
(recovery/load-recovering-key-screen)
|
||||
|
||||
(and (= enter-step :current)
|
||||
(= pin-code-length numbers-entered))
|
||||
(common/verify-pin {:pin-step :current})
|
||||
|
||||
(and (= enter-step :sign)
|
||||
(= pin-code-length numbers-entered))
|
||||
(sign/prepare-to-sign)
|
||||
|
||||
(and (= enter-step :puk)
|
||||
(= puk-code-length numbers-entered))
|
||||
(unblock-pin)
|
||||
|
||||
(and (= enter-step :confirmation)
|
||||
(= (get-in db [:keycard :pin :original])
|
||||
(get-in db [:keycard :pin :confirmation])))
|
||||
(change-pin/change-pin)
|
||||
|
||||
(and (= enter-step :confirmation)
|
||||
(= pin-code-length numbers-entered)
|
||||
(not= (get-in db [:keycard :pin :original])
|
||||
(get-in db [:keycard :pin :confirmation])))
|
||||
(pin-enter-error :t/pin-mismatch)
|
||||
|
||||
(and (= enter-step :puk-original)
|
||||
(= puk-code-length numbers-entered))
|
||||
(proceed-to-change-puk-confirmation)
|
||||
|
||||
(and (= enter-step :puk-confirmation)
|
||||
(= (get-in db [:keycard :pin :puk-original])
|
||||
(get-in db [:keycard :pin :puk-confirmation])))
|
||||
(change-pin/change-puk)
|
||||
|
||||
(and (= enter-step :puk-confirmation)
|
||||
(= puk-code-length numbers-entered)
|
||||
(not= (get-in db [:keycard :pin :puk-original])
|
||||
(get-in db [:keycard :pin :puk-confirmation])))
|
||||
(puk-enter-error :t/puk-mismatch)
|
||||
|
||||
(= enter-step :reset)
|
||||
(proceed-to-pin-reset-confirmation)
|
||||
|
||||
(and (= enter-step :reset-confirmation)
|
||||
(= (get-in db [:keycard :pin :reset])
|
||||
(get-in db [:keycard :pin :reset-confirmation])))
|
||||
(proceed-to-puk-confirmation)
|
||||
|
||||
(and (= enter-step :reset-confirmation)
|
||||
(= pin-code-length numbers-entered)
|
||||
(not= (get-in db [:keycard :pin :reset])
|
||||
(get-in db [:keycard :pin :reset-confirmation])))
|
||||
(pin-reset-error :t/pin-mismatch))))
|
||||
|
||||
(rf/defn set-multiaccount-pairing
|
||||
[cofx _ pairing paired-on]
|
||||
(rf/merge cofx
|
||||
(multiaccounts.update/multiaccount-update
|
||||
:keycard-pairing
|
||||
pairing
|
||||
{})
|
||||
(multiaccounts.update/multiaccount-update
|
||||
:keycard-paired-on
|
||||
paired-on
|
||||
{})))
|
||||
|
||||
(rf/defn on-retrieve-pairings-success
|
||||
{:events [:keycard.callback/on-retrieve-pairings-success]}
|
||||
[{:keys [db]} pairings]
|
||||
(card/set-pairings pairings)
|
||||
{:db (assoc-in db [:keycard :pairings] pairings)})
|
||||
|
||||
;; When pairing to device has completed, we need to persist pairing data to
|
||||
;; local storage. That's needed to ensure that during keycard setup
|
||||
;; keycard won't run out of pairings slots, ie. we don't pair the same
|
||||
;; card to the same device more than one time. Also, this allows the user to proceed
|
||||
;; with setup and skip the pairing step if the pairing was already done during a previous
|
||||
;; unfinished setup.
|
||||
|
||||
(rf/defn on-pair-success
|
||||
{:events [:keycard.callback/on-pair-success]}
|
||||
[{:keys [db] :as cofx} pairing]
|
||||
(let [setup-step (get-in db [:keycard :setup-step])
|
||||
flow (get-in db [:keycard :flow])
|
||||
instance-uid (get-in db [:keycard :application-info :instance-uid])
|
||||
multiaccount (common/find-multiaccount-by-keycard-instance-uid db instance-uid)
|
||||
paired-on (datetime/timestamp)
|
||||
pairings (-> (get-in db [:keycard :pairings])
|
||||
(dissoc (keyword instance-uid))
|
||||
(assoc instance-uid {:pairing pairing :paired-on paired-on}))
|
||||
next-step (if (= setup-step :pair)
|
||||
:begin
|
||||
:card-ready)]
|
||||
(rf/merge cofx
|
||||
{:keycard/persist-pairings pairings
|
||||
:db (-> db
|
||||
(assoc-in [:keycard :pairings] pairings)
|
||||
(assoc-in [:keycard :application-info :paired?] true)
|
||||
(assoc-in [:keycard :setup-step] next-step)
|
||||
(assoc-in [:keycard :secrets :pairing] pairing)
|
||||
(assoc-in [:keycard :secrets :paired-on] paired-on))}
|
||||
(when-not (and (= flow :recovery) (= next-step :card-ready))
|
||||
(common/hide-connection-sheet))
|
||||
(when multiaccount
|
||||
(set-multiaccount-pairing multiaccount pairing paired-on))
|
||||
(when (= flow :login)
|
||||
(navigation/navigate-to :multiaccounts nil))
|
||||
(when (= flow :recovery)
|
||||
(onboarding/proceed-with-generating-key))
|
||||
(when (= flow :import)
|
||||
(load-recovery-pin-screen))
|
||||
;; TODO: If card is already initialized need to confirm pin only then go to mnenmonic
|
||||
;; https://github.com/status-im/status-mobile/issues/9451
|
||||
(when (= flow :create)
|
||||
(mnemonic/set-mnemonic)))))
|
||||
|
||||
(rf/defn on-pair-error
|
||||
{:events [:keycard.callback/on-pair-error]}
|
||||
[{:keys [db] :as cofx} {:keys [error code]}]
|
||||
(log/debug "[keycard] pair error: " error)
|
||||
(let [setup-step (get-in db [:keycard :setup-step])
|
||||
tag-was-lost? (common/tag-lost? error)
|
||||
flow (get-in db [:keycard :flow])]
|
||||
(log/debug "[keycard] on-pair-error" setup-step "flow:" flow)
|
||||
(when-not tag-was-lost?
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:keycard :setup-error] (i18n/label :t/invalid-pairing-password))}
|
||||
(common/set-on-card-connected (if (= setup-step :pairing)
|
||||
:keycard/load-pairing-screen
|
||||
:keycard/pair))
|
||||
(common/hide-connection-sheet)
|
||||
(when (= flow :import)
|
||||
(navigation/navigate-to :keycard-recovery-pair nil))
|
||||
(when (not= setup-step :enter-pair-code)
|
||||
(common/process-error code error))))))
|
||||
|
||||
(rf/defn set-setup-step
|
||||
[{:keys [db]} card-state]
|
||||
{:db (assoc-in db
|
||||
[:keycard :setup-step]
|
||||
(case card-state
|
||||
:not-paired :pair
|
||||
:no-pairing-slots :no-slots
|
||||
:init :card-ready
|
||||
:profile/profile :import-multiaccount
|
||||
:begin))})
|
||||
|
||||
(rf/defn show-no-keycard-applet-alert
|
||||
[_]
|
||||
{:effects.utils/show-confirmation {:title (i18n/label :t/no-keycard-applet-on-card)
|
||||
:content (i18n/label
|
||||
:t/keycard-applet-install-instructions)
|
||||
:cancel-button-text ""
|
||||
:confirm-button-text :t/okay}})
|
||||
|
||||
;; NOTE: Maybe replaced by multiple events based on on flow to make it easier to maintain.
|
||||
;; Because there are many execution paths it is harder to follow all possible states.
|
||||
(rf/defn check-card-state
|
||||
{:events [:keycard/check-card-state]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [app-info (get-in db [:keycard :application-info])
|
||||
flow (get-in db [:keycard :flow])
|
||||
{:keys [instance-uid key-uid paired?]} app-info
|
||||
card-state (common/get-card-state app-info)]
|
||||
(log/debug "[keycard] check-card-state"
|
||||
"card-state" card-state
|
||||
"flow" flow)
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:keycard :card-state] card-state)}
|
||||
(set-setup-step card-state)
|
||||
|
||||
(when paired?
|
||||
(load-pairing))
|
||||
|
||||
(if (and flow
|
||||
(= card-state :init))
|
||||
(proceed-setup-with-initialized-card flow instance-uid paired?)
|
||||
(common/hide-connection-sheet))
|
||||
|
||||
(when (= card-state :pre-init)
|
||||
(if (= flow :import)
|
||||
(navigation/navigate-to :keycard-recovery-no-key nil)
|
||||
(fn [cofx]
|
||||
(rf/merge
|
||||
cofx
|
||||
(common/clear-on-card-read)
|
||||
(load-pin-screen)))))
|
||||
|
||||
(when (and (= card-state :profile/profile)
|
||||
(= flow :import))
|
||||
(if (common/find-multiaccount-by-key-uid db key-uid)
|
||||
;; reimplement
|
||||
;;(multiaccounts.recover/show-existing-multiaccount-alert key-uid)
|
||||
(if paired?
|
||||
(load-recovery-pin-screen)
|
||||
(recovery/load-pair-screen))))
|
||||
|
||||
(when (= card-state :blank)
|
||||
(if (= flow :import)
|
||||
(navigation/navigate-to :keycard-recovery-no-key nil)
|
||||
(show-no-keycard-applet-alert)))
|
||||
|
||||
(when (and (= card-state :profile/profile)
|
||||
(#{:create :recovery} flow))
|
||||
(show-keycard-has-multiaccount-alert)))))
|
||||
|
||||
(rf/defn on-card-connected
|
||||
{:events [:keycard.callback/on-card-connected]}
|
||||
[{:keys [db]} _]
|
||||
(log/debug "[keycard] card globally connected")
|
||||
{:db (assoc-in db [:keycard :card-connected?] true)})
|
||||
|
||||
(rf/defn on-card-disconnected
|
||||
{:events [:keycard.callback/on-card-disconnected]}
|
||||
[{:keys [db]} _]
|
||||
(log/debug "[keycard] card disconnected")
|
||||
{:db (assoc-in db [:keycard :card-connected?] false)})
|
||||
|
||||
(rf/defn on-nfc-user-cancelled
|
||||
{:events [:keycard.callback/on-nfc-user-cancelled]}
|
||||
[{:keys [db]} _]
|
||||
(log/debug "[keycard] nfc user cancelled")
|
||||
{:dispatch [:signing.ui/cancel-is-pressed]})
|
||||
|
||||
(rf/defn on-nfc-timeout
|
||||
{:events [:keycard.callback/on-nfc-timeout]}
|
||||
[{:keys [db]} _]
|
||||
(log/debug "[keycard] nfc timeout")
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :nfc-running?] false)
|
||||
(assoc-in [:keycard :card-connected?] false))
|
||||
:dispatch-later [{:ms 500 :dispatch [:keycard.ui/start-nfc]}]})
|
||||
|
||||
(rf/defn on-register-card-events
|
||||
{:events [:keycard.callback/on-register-card-events]}
|
||||
[{:keys [db]} listeners]
|
||||
{:db (update-in db [:keycard :listeners] merge listeners)})
|
||||
|
||||
(rf/defn ui-recovery-phrase-cancel-pressed
|
||||
{:events [:keycard.ui/recovery-phrase-cancel-pressed]}
|
||||
[{:keys [db]}]
|
||||
{:db (assoc-in db [:keycard :setup-step] :recovery-phrase)})
|
||||
|
||||
(rf/defn ui-pin-numpad-delete-button-pressed
|
||||
{:events [:keycard.ui/pin-numpad-delete-button-pressed]}
|
||||
[{:keys [db]} step]
|
||||
(when-not (empty? (get-in db [:keycard :pin step]))
|
||||
{:db (update-in db [:keycard :pin step] pop)}))
|
||||
|
||||
(rf/defn start-nfc
|
||||
{:events [:keycard.ui/start-nfc]}
|
||||
[cofx]
|
||||
{:keycard/start-nfc nil})
|
||||
|
||||
(rf/defn stop-nfc
|
||||
{:events [:keycard.ui/stop-nfc]}
|
||||
[cofx]
|
||||
{:keycard/stop-nfc nil
|
||||
:keycard.callback/on-card-disconnected nil})
|
||||
|
||||
(rf/defn start-nfc-success
|
||||
{:events [:keycard.callback/start-nfc-success]}
|
||||
[{:keys [db]} _]
|
||||
(log/debug "[keycard] nfc started success")
|
||||
{:db (assoc-in db [:keycard :nfc-running?] true)})
|
||||
|
||||
(rf/defn start-nfc-failure
|
||||
{:events [:keycard.callback/start-nfc-failure]}
|
||||
[{:keys [db]} _]
|
||||
(log/debug "[keycard] nfc failed starting")) ;; leave current value on :nfc-running
|
||||
|
||||
(rf/defn stop-nfc-success
|
||||
{:events [:keycard.callback/stop-nfc-success]}
|
||||
[{:keys [db]} _]
|
||||
(log/debug "[keycard] nfc stopped success")
|
||||
(log/debug "[keycard] setting card-connected? and nfc-running? to false")
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :nfc-running?] false)
|
||||
(assoc-in [:keycard :card-connected?] false))})
|
||||
|
||||
(rf/defn stop-nfc-failure
|
||||
{:events [:keycard.callback/stop-nfc-failure]}
|
||||
[{:keys [db]} _]
|
||||
(log/debug "[keycard] nfc failed stopping")) ;; leave current value on :nfc-running
|
||||
|
||||
(rf/defn init
|
||||
{:events [:keycard/init]}
|
||||
[_]
|
||||
{:keycard/register-card-events nil
|
||||
:keycard/check-nfc-support nil
|
||||
:keycard/check-nfc-enabled nil
|
||||
:keycard/retrieve-pairings nil})
|
||||
@@ -1,77 +0,0 @@
|
||||
(ns legacy.status-im.keycard.core-test)
|
||||
|
||||
;;TODO re-enable after fixing keycard flow
|
||||
#_(deftest process-pin-input
|
||||
(testing "start entering PIN"
|
||||
(is (= {:db {:keycard {:pin {:original [1]
|
||||
:confirmation []
|
||||
:status nil
|
||||
:enter-step :original}}}}
|
||||
(keycard/process-pin-input {:db {:keycard {:pin {:original [1]
|
||||
:confirmation []
|
||||
:enter-step :original}}}}))))
|
||||
(testing "first 6 numbers entered"
|
||||
(is (= {:db {:keycard {:pin {:original [1 2 3 4 5 6]
|
||||
:confirmation []
|
||||
:status nil
|
||||
:enter-step :confirmation}}}}
|
||||
(keycard/process-pin-input {:db {:keycard {:pin {:original [1 2 3 4 5 6]
|
||||
:confirmation []
|
||||
:enter-step :original}}}}))))
|
||||
(testing "confirmation entered"
|
||||
(is (= {:db {:keycard {:pin {:original [1 2 3 4 5 6]
|
||||
:confirmation [1 2 3 4 5 6]
|
||||
:current [1 1 1 1 1 1]
|
||||
:enter-step :confirmation
|
||||
:status :verifying}
|
||||
:card-connected? true}}
|
||||
:keycard/change-pin {:new-pin "123456"
|
||||
:current-pin "111111"
|
||||
:pairing nil}}
|
||||
(keycard/process-pin-input {:db {:keycard {:pin {:original [1 2 3 4 5 6]
|
||||
:confirmation [1 2 3 4 5 6]
|
||||
:current [1 1 1 1 1 1]
|
||||
:enter-step :confirmation}
|
||||
:card-connected? true}}}))))
|
||||
|
||||
(testing "confirmation doesn't match"
|
||||
(is (= {:db {:keycard {:pin {:original []
|
||||
:confirmation []
|
||||
:enter-step :original
|
||||
:error-label :t/pin-mismatch
|
||||
:status :error}}}}
|
||||
(keycard/process-pin-input {:db {:keycard {:pin {:original [1 2 3 4 5 6]
|
||||
:confirmation [1 2 3 4 5 7]
|
||||
:enter-step :confirmation}}}})))))
|
||||
|
||||
#_(deftest on-generate-and-load-key-success
|
||||
(is
|
||||
(=
|
||||
(select-keys
|
||||
(get-in
|
||||
(keycard/on-generate-and-load-key-success
|
||||
{:random-guid-generator (constantly "")
|
||||
:signing-phrase ""
|
||||
:status ""
|
||||
:db {}}
|
||||
#js
|
||||
{"whisper-private-key" "f342f3ef17ce86abfa92b912b3a108a4546cfc687fd8e0f02fedf87a60ee4c0f"
|
||||
"whisper-public-key"
|
||||
"04de2e21f1642ebee03b9aa4bf1936066124cc89967eaf269544c9b90c539fd5c980166a897d06dd4d3732b38116239f63c89395a8d73eac72881fab802010cb56"
|
||||
"encryption-public-key"
|
||||
"04f2a432677a1b7c4f1bb22078135821d1d10fce23422297b5c808a545f2b61cdba38ee7394762172fc6ff5e9e28db7535e555efe2812905ffd4e0c25e82a98ae8"
|
||||
"whisper-address" "87df2285f90b71221fab6267b7cb37532fedbb1f"
|
||||
"wallet-address" "7e92236392a850980d00d0cd2a4b92886bd7fe7b"})
|
||||
[:db :keycard :profile/profile])
|
||||
[:whisper-private-key
|
||||
:whisper-public-key
|
||||
:encryption-public-key
|
||||
:wallet-address
|
||||
:whisper-address]))
|
||||
{:whisper-private-key "f342f3ef17ce86abfa92b912b3a108a4546cfc687fd8e0f02fedf87a60ee4c0f"
|
||||
:whisper-public-key
|
||||
"0x04de2e21f1642ebee03b9aa4bf1936066124cc89967eaf269544c9b90c539fd5c980166a897d06dd4d3732b38116239f63c89395a8d73eac72881fab802010cb56"
|
||||
:encryption-public-key
|
||||
"04f2a432677a1b7c4f1bb22078135821d1d10fce23422297b5c808a545f2b61cdba38ee7394762172fc6ff5e9e28db7535e555efe2812905ffd4e0c25e82a98ae8"
|
||||
:whisper-address "87df2285f90b71221fab6267b7cb37532fedbb1f"
|
||||
:wallet-address "7e92236392a850980d00d0cd2a4b92886bd7fe7b"}))
|
||||
@@ -1,47 +0,0 @@
|
||||
(ns legacy.status-im.keycard.delete-key
|
||||
(:require
|
||||
[legacy.status-im.keycard.common :as common]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn reset-card-pressed
|
||||
{:events [:keycard-settings.ui/reset-card-pressed]}
|
||||
[cofx]
|
||||
(navigation/navigate-to cofx :reset-card nil))
|
||||
|
||||
(rf/defn delete-card
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [key-uid (get-in db [:keycard :application-info :key-uid])
|
||||
multiaccount-key-uid (get-in db [:profile/profile :key-uid])]
|
||||
(if (and key-uid
|
||||
(= key-uid multiaccount-key-uid))
|
||||
{:keycard/delete nil}
|
||||
(common/unauthorized-operation cofx))))
|
||||
|
||||
(rf/defn navigate-to-reset-card-screen
|
||||
{:events [:keycard/navigate-to-reset-card-screen]}
|
||||
[cofx]
|
||||
(navigation/navigate-to cofx :reset-card nil))
|
||||
|
||||
(rf/defn reset-card-next-button-pressed
|
||||
{:events [:keycard-settings.ui/reset-card-next-button-pressed]}
|
||||
[{:keys [db]}]
|
||||
{:db (assoc-in db [:keycard :reset-card :disabled?] true)
|
||||
:dispatch [:keycard/proceed-to-reset-card false]})
|
||||
|
||||
(rf/defn proceed-to-reset-card
|
||||
{:events [:keycard/proceed-to-reset-card]}
|
||||
[{:keys [db] :as cofx} keep-keys-on-keycard?]
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db
|
||||
[:keycard :pin]
|
||||
{:enter-step :current
|
||||
:current []
|
||||
:puk []
|
||||
:status nil
|
||||
:error-label nil
|
||||
:on-verified (if keep-keys-on-keycard?
|
||||
:keycard/unpair-and-delete
|
||||
:keycard/remove-key-with-unpair)})}
|
||||
(common/set-on-card-connected :keycard/navigate-to-enter-pin-screen)
|
||||
(common/navigate-to-enter-pin-screen)))
|
||||
@@ -1,13 +0,0 @@
|
||||
(ns legacy.status-im.keycard.export-key
|
||||
(:require
|
||||
[legacy.status-im.keycard.common :as common]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn on-export-key-success
|
||||
{:events [:keycard.callback/on-export-key-success]}
|
||||
[{:keys [db] :as cofx} pubkey]
|
||||
(let [callback-fn (get-in db [:keycard :on-export-success])]
|
||||
(rf/merge cofx
|
||||
{:dispatch (callback-fn pubkey)}
|
||||
(common/clear-pin)
|
||||
(common/hide-connection-sheet))))
|
||||
@@ -1,208 +0,0 @@
|
||||
(ns legacy.status-im.keycard.fx
|
||||
(:require
|
||||
["@react-native-async-storage/async-storage" :default AsyncStorage]
|
||||
["react-native" :refer (BackHandler)]
|
||||
[legacy.status-im.keycard.card :as card]
|
||||
[legacy.status-im.utils.deprecated-types :as types]
|
||||
[re-frame.core :as re-frame]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/start-nfc
|
||||
(fn []
|
||||
(log/debug "fx start-nfc")
|
||||
(card/start-nfc
|
||||
{:on-success #(re-frame/dispatch [:keycard.callback/start-nfc-success])
|
||||
:on-failure #(re-frame/dispatch [:keycard.callback/start-nfc-failure])})))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/stop-nfc
|
||||
(fn []
|
||||
(log/debug "fx stop-nfc")
|
||||
(card/stop-nfc
|
||||
{:on-success #(re-frame/dispatch [:keycard.callback/stop-nfc-success])
|
||||
:on-failure #(re-frame/dispatch [:keycard.callback/stop-nfc-failure])})))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/set-nfc-message
|
||||
card/set-nfc-message)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/start-nfc-and-show-connection-sheet
|
||||
(fn [args]
|
||||
(log/debug "fx start-nfc-and-show-connection-sheet")
|
||||
(card/start-nfc
|
||||
{:on-success
|
||||
(fn []
|
||||
(log/debug "nfc started successfully. next: show-connection-sheet")
|
||||
(re-frame/dispatch [:keycard.callback/start-nfc-success])
|
||||
(re-frame/dispatch [:keycard.callback/show-connection-sheet args]))
|
||||
:on-failure
|
||||
(fn []
|
||||
(log/debug "nfc failed star starting. not calling show-connection-sheet")
|
||||
(re-frame/dispatch [:keycard.callback/start-nfc-failure]))})))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/stop-nfc-and-hide-connection-sheet
|
||||
(fn []
|
||||
(log/debug "fx stop-nfc-and-hide-connection-sheet")
|
||||
(card/stop-nfc
|
||||
{:on-success
|
||||
(fn []
|
||||
(re-frame/dispatch [:keycard.callback/stop-nfc-success])
|
||||
(re-frame/dispatch [:keycard.callback/hide-connection-sheet]))
|
||||
:on-failure
|
||||
(fn []
|
||||
(re-frame/dispatch [:keycard.callback/stop-nfc-failure]))})))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/get-application-info
|
||||
card/get-application-info)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/factory-reset
|
||||
card/factory-reset)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/check-nfc-support
|
||||
card/check-nfc-support)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/check-nfc-enabled
|
||||
card/check-nfc-enabled)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/open-nfc-settings
|
||||
card/open-nfc-settings)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/install-applet-and-init-card
|
||||
card/install-applet-and-init-card)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/init-card
|
||||
card/init-card)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/register-card-events
|
||||
card/register-card-events)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/remove-event-listeners
|
||||
card/remove-event-listeners)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/pair
|
||||
card/pair)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/generate-and-load-key
|
||||
card/generate-and-load-key)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/unblock-pin
|
||||
card/unblock-pin)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/verify-pin
|
||||
card/verify-pin)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/change-pin
|
||||
card/change-pin)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/change-puk
|
||||
card/change-puk)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/change-pairing
|
||||
card/change-pairing)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/unpair
|
||||
card/unpair)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/delete
|
||||
card/delete)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/remove-key
|
||||
card/remove-key)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/remove-key-with-unpair
|
||||
card/remove-key-with-unpair)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/export-key
|
||||
card/export-key)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/unpair-and-delete
|
||||
card/unpair-and-delete)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/import-keys
|
||||
card/import-keys)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/get-keys
|
||||
card/get-keys)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/sign
|
||||
card/sign)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/sign-typed-data
|
||||
card/sign-typed-data)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/login-with-keycard
|
||||
card/login)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:send-transaction-with-signature
|
||||
card/send-transaction-with-signature)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/persist-pairings
|
||||
(fn [pairings]
|
||||
(.. AsyncStorage
|
||||
(setItem "status-keycard-pairings" (types/serialize pairings)))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/retrieve-pairings
|
||||
(fn []
|
||||
(.. AsyncStorage
|
||||
(getItem "status-keycard-pairings")
|
||||
(then #(re-frame/dispatch [:keycard.callback/on-retrieve-pairings-success
|
||||
(types/deserialize %)])))))
|
||||
|
||||
;; TODO: Should act differently on different views
|
||||
(re-frame/reg-fx
|
||||
:keycard/listen-to-hardware-back-button
|
||||
;;NOTE: not done in view because effect should happen under different conditions and is not
|
||||
;;dependent on particular screen to be loaded. An fx is easier to re-use and test.
|
||||
(fn []
|
||||
(re-frame/dispatch [:keycard/add-listener-to-hardware-back-button
|
||||
(.addEventListener BackHandler
|
||||
"hardwareBackPress"
|
||||
(fn []
|
||||
(re-frame/dispatch [:keycard/back-button-pressed])
|
||||
true))])))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/remove-listener-to-hardware-back-button
|
||||
(fn [^js listener]
|
||||
(.remove listener)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/save-multiaccount-and-login
|
||||
card/save-multiaccount-and-login)
|
||||
|
||||
(re-frame/reg-fx
|
||||
:keycard/delete-multiaccount-before-migration
|
||||
card/delete-multiaccount-before-migration)
|
||||
@@ -1,182 +0,0 @@
|
||||
(ns legacy.status-im.keycard.login
|
||||
(:require
|
||||
[legacy.status-im.bottom-sheet.events :as bottom-sheet]
|
||||
[legacy.status-im.keycard.common :as common]
|
||||
legacy.status-im.keycard.fx
|
||||
[legacy.status-im.keycard.onboarding :as onboarding]
|
||||
[legacy.status-im.keycard.recovery :as recovery]
|
||||
[legacy.status-im.signing.core :as signing.core]
|
||||
[legacy.status-im.utils.deprecated-types :as types]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.address :as address]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn login-got-it-pressed
|
||||
{:events [:keycard.login.pin.ui/got-it-pressed
|
||||
:keycard.login.pin.ui/cancel-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db db}
|
||||
(navigation/pop-to-root :screen/profile.profiles)))
|
||||
|
||||
(rf/defn login-pin-more-icon-pressed
|
||||
{:events [:keycard.login.pin.ui/more-icon-pressed]}
|
||||
[cofx]
|
||||
(bottom-sheet/hide-bottom-sheet-old cofx))
|
||||
|
||||
(rf/defn login-create-key-pressed
|
||||
{:events [:keycard.login.ui/create-new-key-pressed]}
|
||||
[cofx]
|
||||
(rf/merge cofx
|
||||
(bottom-sheet/hide-bottom-sheet-old)
|
||||
(onboarding/start-onboarding-flow)))
|
||||
|
||||
(rf/defn login-add-key-pressed
|
||||
{:events [:keycard.login.ui/add-key-pressed]}
|
||||
[cofx]
|
||||
(recovery/start-import-flow cofx))
|
||||
|
||||
(rf/defn login-remember-me-changed
|
||||
{:events [:keycard.login.ui/remember-me-changed]}
|
||||
[{:keys [db] :as cofx} value]
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:keycard :remember-me?] value)}))
|
||||
|
||||
(rf/defn login-pair-card-pressed
|
||||
{:events [:keycard.login.ui/pair-card-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(log/debug "[keycard] load-pair-card-pressed")
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:keycard :flow] :login)}
|
||||
(navigation/navigate-to :keycard-recovery-pair nil)))
|
||||
|
||||
(rf/defn reset-pin
|
||||
{:events [::reset-pin]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge
|
||||
cofx
|
||||
(signing.core/discard)
|
||||
(fn [{:keys [db]}]
|
||||
{:db (-> db
|
||||
(dissoc :popover/popover)
|
||||
(update-in [:keycard :pin]
|
||||
dissoc
|
||||
:reset
|
||||
:puk)
|
||||
(update-in [:keycard :pin]
|
||||
assoc
|
||||
:enter-step :reset
|
||||
:error nil
|
||||
:status nil))
|
||||
:hide-popover nil})
|
||||
(when (:profile/profile db)
|
||||
(navigation/navigate-to :my-profile nil))
|
||||
(when-not (:profile/login db)
|
||||
(if (:popover/popover db)
|
||||
(navigation/navigate-replace :keycard-pin nil)
|
||||
(navigation/navigate-to :keycard-pin nil)))))
|
||||
|
||||
(rf/defn dismiss-frozen-keycard-popover
|
||||
{:events [::frozen-keycard-popover-dismissed]}
|
||||
[{:keys [db]}]
|
||||
{:db (-> db
|
||||
(dissoc :popover/popover)
|
||||
(update :keycard dissoc :setup-step))
|
||||
:hide-popover nil})
|
||||
|
||||
(rf/defn login-with-keycard
|
||||
{:events [:keycard/login-with-keycard]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [{:keys [:pin-retry-counter :puk-retry-counter]
|
||||
:as application-info}
|
||||
(get-in db [:keycard :application-info])
|
||||
|
||||
key-uid (get-in db [:keycard :application-info :key-uid])
|
||||
paired? (get-in db [:keycard :application-info :paired?])
|
||||
multiaccount (get-in db
|
||||
[:profile/profiles-overview (get-in db [:profile/login :key-uid])])
|
||||
multiaccount-key-uid (get multiaccount :key-uid)
|
||||
multiaccount-mismatch? (or (nil? multiaccount)
|
||||
(not= multiaccount-key-uid key-uid))]
|
||||
(log/debug "[keycard] login-with-keycard"
|
||||
"empty application info" (empty? application-info)
|
||||
"no key-uid" (empty? key-uid)
|
||||
"multiaccount-mismatch?" multiaccount-mismatch?
|
||||
"no pairing" paired?)
|
||||
(cond
|
||||
(empty? application-info)
|
||||
(rf/merge cofx
|
||||
(common/hide-connection-sheet)
|
||||
(navigation/navigate-to :not-keycard nil))
|
||||
|
||||
(empty? key-uid)
|
||||
(rf/merge cofx
|
||||
(common/hide-connection-sheet)
|
||||
(navigation/navigate-to :keycard-blank nil))
|
||||
|
||||
multiaccount-mismatch?
|
||||
(rf/merge cofx
|
||||
(common/hide-connection-sheet)
|
||||
(navigation/navigate-to :keycard-wrong nil))
|
||||
|
||||
(not paired?)
|
||||
(rf/merge cofx
|
||||
(common/hide-connection-sheet)
|
||||
(navigation/navigate-to :keycard-unpaired nil))
|
||||
|
||||
(and (zero? pin-retry-counter)
|
||||
(or (nil? puk-retry-counter)
|
||||
(pos? puk-retry-counter)))
|
||||
nil
|
||||
|
||||
:else
|
||||
(common/get-keys-from-keycard cofx))))
|
||||
|
||||
(rf/defn proceed-to-login
|
||||
{:events [::login-after-reset]}
|
||||
[cofx]
|
||||
(log/debug "[keycard] proceed-to-login")
|
||||
(common/show-connection-sheet
|
||||
cofx
|
||||
{:sheet-options {:on-cancel [::common/cancel-sheet-confirm]}
|
||||
:on-card-connected :keycard/get-application-info
|
||||
:on-card-read :keycard/login-with-keycard
|
||||
:handler (common/get-application-info :keycard/login-with-keycard)}))
|
||||
|
||||
(rf/defn on-keycard-keychain-keys
|
||||
{:events [:multiaccounts.login.callback/get-keycard-keys-success]}
|
||||
[{:keys [db] :as cofx} key-uid [encryption-public-key whisper-private-key :as creds]]
|
||||
(if (nil? creds)
|
||||
(navigation/set-stack-root cofx
|
||||
:multiaccounts-stack
|
||||
[:multiaccounts
|
||||
:keycard-login-pin])
|
||||
(let [{:keys [name]} (get-in db [:profile/profiles-overview key-uid])
|
||||
multiaccount-data (types/clj->json {:name name
|
||||
:key-uid key-uid})
|
||||
account-data {:key-uid key-uid
|
||||
:encryption-public-key encryption-public-key
|
||||
:whisper-private-key whisper-private-key}]
|
||||
{:db
|
||||
(-> db
|
||||
(assoc-in [:keycard :pin :status] nil)
|
||||
(assoc-in [:keycard :pin :login] [])
|
||||
(assoc-in [:keycard :profile/profile]
|
||||
(update account-data :whisper-public-key address/normalized-hex))
|
||||
(assoc-in [:keycard :flow] nil)
|
||||
(update :profile/login assoc
|
||||
:password encryption-public-key
|
||||
:key-uid key-uid
|
||||
:name name
|
||||
:save-password? true))
|
||||
:keycard/login-with-keycard
|
||||
{:multiaccount-data multiaccount-data
|
||||
:key-uid key-uid
|
||||
:password encryption-public-key
|
||||
:chat-key whisper-private-key}})))
|
||||
|
||||
(rf/defn on-login-success
|
||||
{:events [:keycard.login.callback/login-success]}
|
||||
[_ result]
|
||||
(log/debug "loginWithKeycard success: " result))
|
||||
@@ -1,37 +0,0 @@
|
||||
(ns legacy.status-im.keycard.mnemonic
|
||||
(:require
|
||||
[legacy.status-im.keycard.common :as common]
|
||||
legacy.status-im.keycard.fx
|
||||
[status-im.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn set-mnemonic
|
||||
[{:keys [db] :as cofx}]
|
||||
(log/debug "[keycard] set-mnemonic")
|
||||
(let [selected-id (get-in db [:intro-wizard :selected-id])
|
||||
mnemonic (reduce
|
||||
(fn [_ {:keys [id mnemonic]}]
|
||||
(when (= selected-id id)
|
||||
(reduced mnemonic)))
|
||||
nil
|
||||
(get-in db [:intro-wizard :multiaccounts]))]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :setup-step] :recovery-phrase)
|
||||
(assoc-in [:keycard :secrets :mnemonic] mnemonic))}
|
||||
(common/clear-on-card-connected)
|
||||
(common/hide-connection-sheet)
|
||||
(navigation/navigate-replace :keycard-onboarding-recovery-phrase nil))))
|
||||
|
||||
(rf/defn load-loading-keys-screen
|
||||
{:events [:keycard.ui/recovery-phrase-confirm-pressed
|
||||
:keycard/load-loading-keys-screen]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (assoc-in db [:keycard :setup-step] :loading-keys)}
|
||||
(common/show-connection-sheet
|
||||
{:on-card-connected :keycard/load-loading-keys-screen
|
||||
:handler (common/dispatch-event :keycard/generate-and-load-key)})))
|
||||
@@ -1,11 +0,0 @@
|
||||
(ns legacy.status-im.keycard.nfc)
|
||||
|
||||
(def is-nfc-supported? (atom nil))
|
||||
|
||||
(defn set-nfc-supported?
|
||||
[supported?]
|
||||
(reset! is-nfc-supported? supported?))
|
||||
|
||||
(defn nfc-supported?
|
||||
[]
|
||||
@is-nfc-supported?)
|
||||
@@ -1,335 +0,0 @@
|
||||
(ns legacy.status-im.keycard.onboarding
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.keycard.common :as common]
|
||||
legacy.status-im.keycard.fx
|
||||
[legacy.status-im.keycard.mnemonic :as mnemonic]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.utils.utils :as utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn begin-setup-button-pressed
|
||||
{:keys [:keycard.ui/begin-setup-button-pressed]}
|
||||
[{:keys [db]}]
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :setup-step] :pin)
|
||||
(assoc-in [:keycard :pin :enter-step] :original)
|
||||
(assoc-in [:keycard :pin :original] [])
|
||||
(assoc-in [:keycard :pin :confirmation] []))})
|
||||
|
||||
(rf/defn start-installation
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [card-state (get-in db [:keycard :card-state])
|
||||
pin (common/vector->string (get-in db [:keycard :pin :original]))]
|
||||
(log/debug "start-installation: card-state" card-state)
|
||||
(case card-state
|
||||
|
||||
:pre-init
|
||||
{:keycard/init-card pin}
|
||||
|
||||
(do
|
||||
(log/debug (str "Cannot start keycard installation from state: " card-state))
|
||||
(rf/merge cofx
|
||||
{:effects.utils/show-popup {:title (i18n/label :t/error)
|
||||
:content (i18n/label :t/something-went-wrong)}}
|
||||
(navigation/navigate-to :keycard-authentication-method nil))))))
|
||||
|
||||
(rf/defn load-preparing-screen
|
||||
{:events [:keycard/load-preparing-screen]}
|
||||
[cofx]
|
||||
(common/show-connection-sheet
|
||||
cofx
|
||||
{:sheet-options {:on-cancel [::cancel-pressed]}
|
||||
:on-card-connected :keycard/load-preparing-screen
|
||||
:handler start-installation}))
|
||||
|
||||
(rf/defn load-pairing-screen
|
||||
{:events [:keycard/load-pairing-screen
|
||||
:keycard.onboarding.puk-code.ui/confirm-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (assoc-in db [:keycard :setup-step] :pairing)}
|
||||
(common/show-connection-sheet
|
||||
{:sheet-options {:on-cancel [::cancel-pressed]}
|
||||
:on-card-connected :keycard/load-pairing-screen
|
||||
:handler (common/dispatch-event :keycard/pair)})))
|
||||
|
||||
(rf/defn puk-code-next-pressed
|
||||
{:events [:keycard.onboarding.puk-code.ui/next-pressed]}
|
||||
[_]
|
||||
{:ui/show-confirmation {:title (i18n/label :t/secret-keys-confirmation-title)
|
||||
:content (i18n/label :t/secret-keys-confirmation-text)
|
||||
:confirm-button-text (i18n/label :t/yes)
|
||||
:cancel-button-text (i18n/label :t/cancel)
|
||||
:on-accept #(re-frame/dispatch
|
||||
[:keycard.onboarding.puk-code.ui/confirm-pressed])
|
||||
:on-cancel #()}})
|
||||
|
||||
(rf/defn load-finishing-screen
|
||||
{:events [:keycard.onboarding.recovery-phrase-confirm-word2.ui/next-pressed
|
||||
:keycard/load-finishing-screen]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (assoc-in db [:keycard :setup-step] :loading-keys)}
|
||||
(common/show-connection-sheet
|
||||
{:sheet-options {:on-cancel [::cancel-pressed]}
|
||||
:on-card-connected :keycard/load-finishing-screen
|
||||
:handler (common/dispatch-event :keycard/generate-and-load-key)})))
|
||||
|
||||
(rf/defn recovery-phrase-learn-more-pressed
|
||||
{:events [:keycard.onboarding.recovery-phrase.ui/learn-more-pressed]}
|
||||
[_]
|
||||
(.openURL ^js react/linking constants/keycard-integration-link))
|
||||
|
||||
(rf/defn recovery-phrase-next-pressed
|
||||
{:events [:keycard.onboarding.recovery-phrase.ui/next-pressed
|
||||
:keycard.ui/recovery-phrase-next-button-pressed]}
|
||||
[_]
|
||||
{:ui/show-confirmation {:title (i18n/label :t/keycard-recovery-phrase-confirmation-title)
|
||||
:content (i18n/label :t/keycard-recovery-phrase-confirmation-text)
|
||||
:confirm-button-text (i18n/label :t/yes)
|
||||
:cancel-button-text (i18n/label :t/cancel)
|
||||
:on-accept #(re-frame/dispatch
|
||||
[:keycard.onboarding.recovery-phrase.ui/confirm-pressed])
|
||||
:on-cancel #()}})
|
||||
|
||||
(rf/defn recovery-phrase-start-confirmation
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [mnemonic (get-in db [:keycard :secrets :mnemonic])
|
||||
[word1 word2] (shuffle (map-indexed vector (clojure.string/split mnemonic #" ")))
|
||||
word1 (zipmap [:idx :word] word1)
|
||||
word2 (zipmap [:idx :word] word2)]
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :setup-step] :recovery-phrase-confirm-word1)
|
||||
(assoc-in [:keycard :recovery-phrase :step] :word1)
|
||||
(assoc-in [:keycard :recovery-phrase :confirm-error] nil)
|
||||
(assoc-in [:keycard :recovery-phrase :input-word] nil)
|
||||
(assoc-in [:keycard :recovery-phrase :word1] word1)
|
||||
(assoc-in [:keycard :recovery-phrase :word2] word2))}
|
||||
(common/remove-listener-to-hardware-back-button))))
|
||||
|
||||
(rf/defn recovery-phrase-confirm-pressed
|
||||
{:events [:keycard.onboarding.recovery-phrase.ui/confirm-pressed]}
|
||||
[cofx]
|
||||
(rf/merge cofx
|
||||
(recovery-phrase-start-confirmation)
|
||||
(navigation/navigate-to :keycard-onboarding-recovery-phrase-confirm-word1 nil)))
|
||||
|
||||
(rf/defn recovery-phrase-next-word
|
||||
[{:keys [db]}]
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :recovery-phrase :step] :word2)
|
||||
(assoc-in [:keycard :recovery-phrase :confirm-error] nil)
|
||||
(assoc-in [:keycard :recovery-phrase :input-word] nil)
|
||||
(assoc-in [:keycard :setup-step] :recovery-phrase-confirm-word2))})
|
||||
|
||||
(rf/defn proceed-with-generating-key
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [pin (get-in db
|
||||
[:keycard :secrets :pin]
|
||||
(common/vector->string (get-in db [:keycard :pin :current])))]
|
||||
(if (empty? pin)
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :pin]
|
||||
{:enter-step :current
|
||||
:on-verified :keycard/generate-and-load-key
|
||||
:current []})
|
||||
(assoc-in [:keycard :setup-step] :loading-keys))}
|
||||
(navigation/navigate-to :keycard-onboarding-pin nil))
|
||||
(load-finishing-screen cofx))))
|
||||
|
||||
(rf/defn recovery-phrase-confirm-word-next-pressed
|
||||
{:events [:keycard.onboarding.recovery-phrase-confirm-word.ui/next-pressed
|
||||
:keycard.onboarding.recovery-phrase-confirm-word.ui/input-submitted]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [step (get-in db [:keycard :recovery-phrase :step])
|
||||
input-word (get-in db [:keycard :recovery-phrase :input-word])
|
||||
{:keys [word]} (get-in db [:keycard :recovery-phrase step])]
|
||||
(if (= word input-word)
|
||||
(if (= (:view-id db) :keycard-onboarding-recovery-phrase-confirm-word1)
|
||||
(rf/merge cofx
|
||||
(recovery-phrase-next-word)
|
||||
(navigation/navigate-replace :keycard-onboarding-recovery-phrase-confirm-word2 nil))
|
||||
(proceed-with-generating-key cofx))
|
||||
{:db (assoc-in db [:keycard :recovery-phrase :confirm-error] (i18n/label :t/wrong-word))})))
|
||||
|
||||
(rf/defn recovery-phrase-confirm-word-input-changed
|
||||
{:events [:keycard.onboarding.recovery-phrase-confirm-word.ui/input-changed]}
|
||||
[{:keys [db]} input]
|
||||
{:db (assoc-in db [:keycard :recovery-phrase :input-word] input)})
|
||||
|
||||
(rf/defn pair-code-input-changed
|
||||
{:events [:keycard.onboarding.pair.ui/input-changed]}
|
||||
[{:keys [db]} input]
|
||||
{:db (assoc-in db [:keycard :secrets :password] input)})
|
||||
|
||||
(rf/defn keycard-option-pressed
|
||||
{:events [:onboarding.ui/keycard-option-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [flow (get-in db [:keycard :flow])]
|
||||
(rf/merge cofx
|
||||
{:keycard/check-nfc-enabled nil}
|
||||
(if (= flow :import)
|
||||
(navigation/navigate-to :keycard-recovery-intro nil)
|
||||
(do
|
||||
(common/listen-to-hardware-back-button)
|
||||
(navigation/navigate-to :keycard-onboarding-intro nil))))))
|
||||
|
||||
(rf/defn start-onboarding-flow
|
||||
{:events [:keycard/start-onboarding-flow]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:keycard :flow] :create)
|
||||
:keycard/check-nfc-enabled nil}
|
||||
(common/listen-to-hardware-back-button)
|
||||
(navigation/navigate-to :keycard-onboarding-intro nil)))
|
||||
|
||||
(rf/defn open-nfc-settings-pressed
|
||||
{:events [:keycard.onboarding.nfc-on/open-nfc-settings-pressed]}
|
||||
[_]
|
||||
{:keycard/open-nfc-settings nil})
|
||||
|
||||
(defn- show-recover-confirmation
|
||||
[]
|
||||
{:ui/show-confirmation {:title (i18n/label :t/are-you-sure?)
|
||||
:content (i18n/label :t/are-you-sure-description)
|
||||
:confirm-button-text (clojure.string/upper-case (i18n/label :t/yes))
|
||||
:cancel-button-text (i18n/label :t/see-it-again)
|
||||
:on-accept #(re-frame/dispatch
|
||||
[:keycard.ui/recovery-phrase-confirm-pressed])
|
||||
:on-cancel #(re-frame/dispatch
|
||||
[:keycard.ui/recovery-phrase-cancel-pressed])}})
|
||||
|
||||
(rf/defn recovery-phrase-confirm-word
|
||||
{:events [:keycard.ui/recovery-phrase-confirm-word-next-button-pressed]}
|
||||
[{:keys [db]}]
|
||||
(let [step (get-in db [:keycard :recovery-phrase :step])
|
||||
input-word (get-in db [:keycard :recovery-phrase :input-word])
|
||||
{:keys [word]} (get-in db [:keycard :recovery-phrase step])]
|
||||
(if (= word input-word)
|
||||
(if (= step :word1)
|
||||
(recovery-phrase-next-word db)
|
||||
(show-recover-confirmation))
|
||||
{:db (assoc-in db [:keycard :recovery-phrase :confirm-error] (i18n/label :t/wrong-word))})))
|
||||
|
||||
(rf/defn recovery-phrase-next-button-pressed
|
||||
[{:keys [db] :as cofx}]
|
||||
(if (= (get-in db [:keycard :flow]) :create)
|
||||
(recovery-phrase-start-confirmation cofx)
|
||||
(let [mnemonic (get-in db [:multiaccounts/recover :passphrase])]
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:keycard :secrets :mnemonic] mnemonic)}
|
||||
(mnemonic/load-loading-keys-screen)))))
|
||||
|
||||
(rf/defn on-install-applet-and-init-card-success
|
||||
{:events [:keycard.callback/on-install-applet-and-init-card-success
|
||||
:keycard.callback/on-init-card-success]}
|
||||
[{:keys [db] :as cofx} secrets]
|
||||
(let [secrets' (js->clj secrets :keywordize-keys true)]
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :card-state] :init)
|
||||
(assoc-in [:keycard :setup-step] :secret-keys)
|
||||
(update-in [:keycard :secrets] merge secrets'))}
|
||||
(common/show-connection-sheet
|
||||
{:on-card-connected :keycard/get-application-info
|
||||
:on-card-read :keycard/check-card-state
|
||||
:handler (common/get-application-info :keycard/check-card-state)}))))
|
||||
|
||||
(rf/defn on-install-applet-and-init-card-error
|
||||
{:events [:keycard.callback/on-install-applet-and-init-card-error
|
||||
:keycard.callback/on-init-card-error]}
|
||||
[{:keys [db] :as cofx} {:keys [code error]}]
|
||||
(log/debug "[keycard] install applet and init card error: " error)
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:keycard :setup-error] error)}
|
||||
(common/set-on-card-connected :keycard/load-preparing-screen)
|
||||
(common/process-error code error)))
|
||||
|
||||
(rf/defn generate-and-load-key
|
||||
{:events [:keycard/generate-and-load-key]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [{:keys [pin]}
|
||||
(get-in db [:keycard :secrets])
|
||||
|
||||
{:keys [selected-id multiaccounts]}
|
||||
(:intro-wizard db)
|
||||
|
||||
multiaccount (or (->> multiaccounts
|
||||
(filter #(= (:id %) selected-id))
|
||||
first)
|
||||
(assoc (get-in db [:intro-wizard :root-key])
|
||||
:derived
|
||||
(get-in db [:intro-wizard :derived])))
|
||||
recovery-mnemonic (get-in db [:intro-wizard :passphrase])
|
||||
mnemonic (or (:mnemonic multiaccount)
|
||||
recovery-mnemonic)
|
||||
pin' (or pin
|
||||
(common/vector->string (get-in db
|
||||
[:keycard :pin
|
||||
:current])))]
|
||||
{:keycard/generate-and-load-key
|
||||
{:mnemonic mnemonic
|
||||
:pin pin'
|
||||
:key-uid (:key-uid multiaccount)
|
||||
:delete-multiaccount? (get-in db [:keycard :delete-account?])}}))
|
||||
|
||||
(rf/defn factory-reset-card-toggle
|
||||
{:events [:keycard.onboarding.intro.ui/factory-reset-card-toggle]}
|
||||
[{:keys [db] :as cofx} checked?]
|
||||
{:db (assoc-in db [:keycard :factory-reset-card?] checked?)})
|
||||
|
||||
(rf/defn begin-setup-pressed
|
||||
{:events [:keycard.onboarding.intro.ui/begin-setup-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (-> db
|
||||
(update :keycard
|
||||
dissoc
|
||||
:secrets
|
||||
:card-state :multiaccount-wallet-address
|
||||
:multiaccount-whisper-public-key :application-info)
|
||||
(assoc-in [:keycard :setup-step] :begin)
|
||||
(assoc-in [:keycard :pin :on-verified] nil))}
|
||||
(if (get-in db [:keycard :factory-reset-card?])
|
||||
(utils/show-confirmation {:title (i18n/label :t/keycard-factory-reset-title)
|
||||
:content (i18n/label :t/keycard-factory-reset-text)
|
||||
:confirm-button-text (i18n/label :t/yes)
|
||||
:cancel-button-text (i18n/label :t/no)
|
||||
:on-accept #(re-frame/dispatch [::factory-reset])
|
||||
:on-cancel #(re-frame/dispatch [::factory-reset-cancel])})
|
||||
(common/show-connection-sheet
|
||||
{:on-card-connected :keycard/get-application-info
|
||||
:on-card-read :keycard/check-card-state
|
||||
:handler (common/get-application-info :keycard/check-card-state)}))))
|
||||
|
||||
(rf/defn factory-reset
|
||||
{:events [::factory-reset]}
|
||||
[cofx]
|
||||
(common/show-connection-sheet
|
||||
cofx
|
||||
{:on-card-connected :keycard/factory-reset
|
||||
:on-card-read :keycard/check-card-state
|
||||
:handler (common/factory-reset :keycard/check-card-state)}))
|
||||
|
||||
(rf/defn factory-reset-cancel
|
||||
{:events [::factory-reset-cancel]}
|
||||
[{:keys [db] :as cofx}]
|
||||
{:db (update db :keycard dissoc :factory-reset-card?)})
|
||||
|
||||
(rf/defn cancel-pressed
|
||||
{:events [::cancel-pressed]}
|
||||
[cofx]
|
||||
(rf/merge cofx
|
||||
(navigation/navigate-back)
|
||||
(common/cancel-sheet-confirm)))
|
||||
@@ -1,355 +0,0 @@
|
||||
(ns legacy.status-im.keycard.recovery
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.bottom-sheet.events :as bottom-sheet]
|
||||
[legacy.status-im.keycard.common :as common]
|
||||
legacy.status-im.keycard.fx
|
||||
[legacy.status-im.multiaccounts.create.core :as multiaccounts.create]
|
||||
[legacy.status-im.multiaccounts.model :as multiaccounts.model]
|
||||
[legacy.status-im.popover.core :as popover]
|
||||
[legacy.status-im.utils.deprecated-types :as types]
|
||||
[native-module.core :as native-module]
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.platform :as platform]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.address :as address]
|
||||
[utils.datetime :as datetime]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(rf/defn pair*
|
||||
[_ password]
|
||||
{:keycard/pair {:password password}})
|
||||
|
||||
(rf/defn pair
|
||||
{:events [:keycard/pair]}
|
||||
[cofx]
|
||||
(let [{:keys [password]} (get-in cofx [:db :keycard :secrets])]
|
||||
(common/show-connection-sheet
|
||||
cofx
|
||||
{:on-card-connected :keycard/pair
|
||||
:handler (pair* password)})))
|
||||
|
||||
(rf/defn pair-code-next-button-pressed
|
||||
{:events [:keycard.onboarding.pair.ui/input-submitted
|
||||
:keycard.ui/pair-code-next-button-pressed
|
||||
:keycard.onboarding.pair.ui/next-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [pairing (get-in db [:keycard :secrets :pairing])
|
||||
paired-on (get-in db [:keycard :secrets :paired-on] (datetime/timestamp))]
|
||||
(rf/merge cofx
|
||||
(if pairing
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :setup-step] :import-multiaccount)
|
||||
(assoc-in [:keycard :secrets :paired-on] paired-on))}
|
||||
(pair)))))
|
||||
|
||||
(rf/defn load-pair-screen
|
||||
[{:keys [db] :as cofx}]
|
||||
(log/debug "[keycard] load-pair-screen")
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :setup-step] :pair))
|
||||
:dispatch [:bottom-sheet/hide-old]}
|
||||
(common/listen-to-hardware-back-button)
|
||||
(navigation/navigate-to :keycard-recovery-pair nil)))
|
||||
|
||||
(rf/defn keycard-storage-selected-for-recovery
|
||||
{:events [:recovery.ui/keycard-storage-selected]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:keycard :flow] :recovery)}
|
||||
(navigation/navigate-to :keycard-recovery-enter-mnemonic nil)))
|
||||
|
||||
(rf/defn start-import-flow
|
||||
{:events [::recover-with-keycard-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db
|
||||
(-> db
|
||||
(assoc-in [:keycard :flow] :import)
|
||||
(assoc :recovered-account? true))
|
||||
:keycard/check-nfc-enabled nil}
|
||||
(bottom-sheet/hide-bottom-sheet-old)
|
||||
(navigation/navigate-to-within-stack [:keycard-recovery-intro
|
||||
:screen/onboarding.new-to-status])))
|
||||
|
||||
(rf/defn access-key-pressed
|
||||
{:events [:multiaccounts.recover.ui/recover-multiaccount-button-pressed]}
|
||||
[_]
|
||||
{:dispatch [:bottom-sheet/show-sheet-old :recover-sheet]})
|
||||
|
||||
(rf/defn recovery-keycard-selected
|
||||
{:events [:recovery.ui/keycard-option-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:keycard :flow] :recovery)
|
||||
:keycard/check-nfc-enabled nil}
|
||||
(common/listen-to-hardware-back-button)
|
||||
(navigation/navigate-to :keycard-onboarding-intro nil)))
|
||||
|
||||
(rf/defn cancel-pressed
|
||||
{:events [::cancel-pressed]}
|
||||
[cofx]
|
||||
(rf/merge cofx
|
||||
(common/cancel-sheet-confirm)
|
||||
(navigation/navigate-back)))
|
||||
|
||||
(rf/defn begin-setup-pressed
|
||||
{:events [:keycard.recovery.intro.ui/begin-recovery-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (-> db
|
||||
(update :keycard
|
||||
dissoc
|
||||
:secrets
|
||||
:card-state :multiaccount-wallet-address
|
||||
:multiaccount-whisper-public-key
|
||||
:application-info)
|
||||
(assoc-in [:keycard :setup-step] :begin)
|
||||
(assoc-in [:keycard :pin :on-verified] nil))}
|
||||
(common/show-connection-sheet
|
||||
{:on-card-connected :keycard/get-application-info
|
||||
:on-card-read :keycard/check-card-state
|
||||
:sheet-options {:on-cancel [::cancel-pressed]}
|
||||
:handler (common/get-application-info :keycard/check-card-state)})))
|
||||
|
||||
(rf/defn recovery-success-finish-pressed
|
||||
{:events [:keycard.recovery.success/finish-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (update db
|
||||
:keycard dissoc
|
||||
:multiaccount-wallet-address
|
||||
:multiaccount-whisper-public-key)}
|
||||
(navigation/navigate-to (if platform/android?
|
||||
:notifications-settings
|
||||
:screen/onboarding.welcome)
|
||||
nil)))
|
||||
|
||||
(rf/defn intro-wizard
|
||||
{:events [:multiaccounts.create.ui/intro-wizard]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [accs (get db :profile/profiles-overview)]
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(update :keycard dissoc :flow)
|
||||
(dissoc :restored-account?))}
|
||||
(if (pos? (count accs))
|
||||
(navigation/navigate-to :get-your-keys nil)
|
||||
(navigation/set-stack-root :onboarding [:get-your-keys])))))
|
||||
|
||||
(rf/defn recovery-no-key
|
||||
{:events [:keycard.recovery.no-key.ui/generate-key-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:keycard :flow] :create)
|
||||
:keycard/check-nfc-enabled nil}
|
||||
(intro-wizard)))
|
||||
|
||||
;; NOTE: currently non functional, keycard needs to be reimplemented
|
||||
(rf/defn create-keycard-multiaccount
|
||||
{:events [::create-keycard-multiaccount]
|
||||
:interceptors [(re-frame/inject-cofx :random-guid-generator)
|
||||
(re-frame/inject-cofx ::multiaccounts.create/get-signing-phrase)]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [{{:keys [secrets flow] :profile/keys [profile]} :keycard} db
|
||||
{:keys [address
|
||||
name
|
||||
public-key
|
||||
whisper-public-key
|
||||
wallet-public-key
|
||||
wallet-root-public-key
|
||||
whisper-address
|
||||
wallet-address
|
||||
wallet-root-address
|
||||
whisper-private-key
|
||||
encryption-public-key
|
||||
instance-uid
|
||||
key-uid
|
||||
recovered]}
|
||||
profile
|
||||
{:keys [pairing paired-on]} secrets
|
||||
{:keys [name]}
|
||||
(if (nil? name)
|
||||
;; name might have been generated during recovery via passphrase
|
||||
(get-in db [:intro-wizard :derived constants/path-whisper-keyword])
|
||||
{:name name})]
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :setup-step] nil)
|
||||
(dissoc :intro-wizard))})))
|
||||
|
||||
(rf/defn return-to-keycard-login
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(update-in [:keycard :pin]
|
||||
assoc
|
||||
:enter-step :login
|
||||
:status nil
|
||||
:login [])
|
||||
(update :keycard dissoc :application-info))}
|
||||
(navigation/set-stack-root :multiaccounts-stack
|
||||
[:multiaccounts
|
||||
:keycard-login-pin])))
|
||||
|
||||
(rf/defn on-backup-success
|
||||
[{:keys [db] :as cofx} backup-type]
|
||||
(rf/merge cofx
|
||||
{:effects.utils/show-popup {:title (i18n/label (if (= backup-type :recovery-card)
|
||||
:t/keycard-access-reset
|
||||
:t/keycard-backup-success-title))
|
||||
:content (i18n/label (if (= backup-type :recovery-card)
|
||||
:t/keycard-can-use-with-new-passcode
|
||||
:t/keycard-backup-success-body))}}
|
||||
(cond
|
||||
(multiaccounts.model/logged-in? db)
|
||||
(navigation/set-stack-root :profile-stack [:my-profile :keycard-settings])
|
||||
|
||||
(:profile/login db)
|
||||
(return-to-keycard-login)
|
||||
|
||||
:else
|
||||
(navigation/set-stack-root :onboarding [:get-your-keys]))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::finish-migration
|
||||
(fn [[account settings password encryption-pass login-params]]
|
||||
(native-module/convert-to-keycard-account
|
||||
account
|
||||
settings
|
||||
password
|
||||
encryption-pass
|
||||
#(let [{:keys [error]} (types/json->clj %)]
|
||||
(if (string/blank? error)
|
||||
(native-module/login-with-keycard
|
||||
(assoc login-params :node-config {:ProcessBackedupMessages true}))
|
||||
(throw
|
||||
(js/Error.
|
||||
"Please shake the phone to report this error and restart the app. Migration failed unexpectedly.")))))))
|
||||
|
||||
(rf/defn migrate-account
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [pairing (get-in db [:keycard :secrets :pairing])
|
||||
paired-on (get-in db [:keycard :secrets :paired-on])
|
||||
instance-uid (get-in db [:keycard :profile/profile :instance-uid])
|
||||
account (-> db
|
||||
:profile/login
|
||||
(assoc :keycard-pairing pairing)
|
||||
(assoc :save-password? false))
|
||||
key-uid (-> account :key-uid)
|
||||
settings {:keycard-instance-uid instance-uid
|
||||
:keycard-paired-on paired-on
|
||||
:keycard-pairing pairing}
|
||||
password (native-module/sha3 (security/safe-unmask-data (get-in db
|
||||
[:keycard
|
||||
:migration-password])))
|
||||
encryption-pass (get-in db [:keycard :profile/profile :encryption-public-key])
|
||||
login-params {:key-uid key-uid
|
||||
:multiaccount-data (types/clj->json account)
|
||||
:password encryption-pass
|
||||
:chat-key (get-in db
|
||||
[:keycard :profile/profile :whisper-private-key])}]
|
||||
{:db (-> db
|
||||
(assoc-in [:profile/profiles-overview key-uid :keycard-pairing] pairing)
|
||||
(assoc :profile/login account)
|
||||
(assoc :auth-method "none")
|
||||
(update :keycard dissoc :flow :migration-password)
|
||||
(dissoc :recovered-account?))
|
||||
::finish-migration [account settings password encryption-pass login-params]}))
|
||||
|
||||
(rf/defn delete-multiaccount
|
||||
[{:keys [db]}]
|
||||
(let [key-uid (get-in db [:profile/login :key-uid])]
|
||||
{:keycard/delete-multiaccount-before-migration
|
||||
{:key-uid key-uid
|
||||
:on-error #(re-frame/dispatch [::delete-multiaccount-error %])
|
||||
:on-success #(re-frame/dispatch [::create-keycard-multiaccount])}}))
|
||||
|
||||
(rf/defn handle-delete-multiaccount-error
|
||||
{:events [::delete-multiaccount-error]}
|
||||
[cofx _]
|
||||
(popover/show-popover cofx {:view :transfer-multiaccount-unknown-error}))
|
||||
|
||||
(rf/defn on-generate-and-load-key-success
|
||||
{:events [:keycard.callback/on-generate-and-load-key-success]
|
||||
:interceptors [(re-frame/inject-cofx :random-guid-generator)
|
||||
(re-frame/inject-cofx ::multiaccounts.create/get-signing-phrase)]}
|
||||
[{:keys [db random-guid-generator] :as cofx} data]
|
||||
(let [account-data (js->clj data :keywordize-keys true)
|
||||
backup? (get-in db [:keycard :creating-backup?])
|
||||
migration? (get-in db [:keycard :converting-account?])]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (-> db
|
||||
(assoc-in
|
||||
[:keycard :profile/profile]
|
||||
(-> account-data
|
||||
(update :address address/normalized-hex)
|
||||
(update :whisper-address address/normalized-hex)
|
||||
(update :wallet-address address/normalized-hex)
|
||||
(update :wallet-root-address address/normalized-hex)
|
||||
(update :public-key address/normalized-hex)
|
||||
(update :whisper-public-key address/normalized-hex)
|
||||
(update :wallet-public-key address/normalized-hex)
|
||||
(update :wallet-root-public-key address/normalized-hex)
|
||||
(update :instance-uid #(get-in db [:keycard :profile/profile :instance-uid] %))))
|
||||
(assoc-in [:keycard :multiaccount-wallet-address] (:wallet-address account-data))
|
||||
(assoc-in [:keycard :multiaccount-whisper-public-key] (:whisper-public-key account-data))
|
||||
(assoc-in [:keycard :pin :status] nil)
|
||||
(assoc-in [:keycard :application-info :key-uid]
|
||||
(address/normalized-hex (:key-uid account-data)))
|
||||
(update :keycard dissoc :recovery-phrase :creating-backup? :converting-account?)
|
||||
(update-in [:keycard :secrets] dissoc :pin :puk :password :mnemonic)
|
||||
(assoc :multiaccounts/new-installation-id (random-guid-generator)))}
|
||||
(common/remove-listener-to-hardware-back-button)
|
||||
(common/hide-connection-sheet)
|
||||
(cond backup? (on-backup-success backup?)
|
||||
migration? (migrate-account)
|
||||
|
||||
(get-in db [:keycard :delete-account?])
|
||||
(delete-multiaccount)
|
||||
|
||||
:else (create-keycard-multiaccount)))))
|
||||
|
||||
(rf/defn on-generate-and-load-key-error
|
||||
{:events [:keycard.callback/on-generate-and-load-key-error]}
|
||||
[{:keys [db] :as cofx} {:keys [error code]}]
|
||||
(log/debug "[keycard] generate and load key error: " error)
|
||||
(when-not (common/tag-lost? error)
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:keycard :setup-error] error)}
|
||||
(common/set-on-card-connected :keycard/load-loading-keys-screen)
|
||||
(common/process-error code error))))
|
||||
|
||||
(rf/defn import-multiaccount
|
||||
{:events [:keycard/import-multiaccount]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [{:keys [pairing]} (get-in db [:keycard :secrets])
|
||||
instance-uid (get-in db [:keycard :application-info :instance-uid])
|
||||
key-uid (get-in db [:keycard :application-info :key-uid])
|
||||
pairing' (or pairing (common/get-pairing db key-uid))
|
||||
pin (common/vector->string (get-in db [:keycard :pin :import-multiaccount]))]
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :profile/profile :instance-uid] instance-uid)
|
||||
(assoc-in [:keycard :pin :status] :verifying)
|
||||
(assoc-in [:keycard :secrets]
|
||||
{:pairing pairing'
|
||||
:paired-on (datetime/timestamp)}))
|
||||
:keycard/import-keys
|
||||
{:pin pin
|
||||
:on-success :keycard.callback/on-generate-and-load-key-success}})))
|
||||
|
||||
(rf/defn load-recovering-key-screen
|
||||
{:events [:keycard/load-recovering-key-screen]}
|
||||
[cofx]
|
||||
(common/show-connection-sheet
|
||||
cofx
|
||||
{:on-card-connected :keycard/load-recovering-key-screen
|
||||
:handler (common/dispatch-event :keycard/import-multiaccount)}))
|
||||
@@ -1,196 +0,0 @@
|
||||
(ns legacy.status-im.keycard.sign
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.keycard.common :as common]
|
||||
[legacy.status-im.utils.deprecated-types :as types]
|
||||
[re-frame.core :as re-frame]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.address :as address]
|
||||
[utils.ethereum.chain :as chain]
|
||||
[utils.money :as money]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn sign
|
||||
{:events [:keycard/sign]}
|
||||
[{:keys [db] :as cofx} hash on-success]
|
||||
(let [card-connected? (get-in db [:keycard :card-connected?])
|
||||
key-uid (get-in db [:profile/profile :key-uid])
|
||||
keycard-key-uid (get-in db [:keycard :application-info :key-uid])
|
||||
keycard-pin-retries (get-in db [:keycard :application-info :pin-retry-counter])
|
||||
keycard-match? (= key-uid keycard-key-uid)
|
||||
hash (or hash (get-in db [:keycard :hash]))
|
||||
data (get-in db [:keycard :data])
|
||||
typed? (get-in db [:keycard :typed?])
|
||||
pin (common/vector->string (get-in db [:keycard :pin :sign]))
|
||||
from (or (get-in db [:signing/tx :from :address])
|
||||
(get-in db [:signing/tx :message :from]))
|
||||
path (reduce
|
||||
(fn [_ {:keys [address path]}]
|
||||
(when (address/address= from address)
|
||||
(reduced path)))
|
||||
nil
|
||||
(:profile/wallet-accounts db))]
|
||||
(cond
|
||||
(not keycard-match?)
|
||||
(common/show-wrong-keycard-alert cofx)
|
||||
|
||||
(not card-connected?)
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:signing/sign :keycard-step] :signing)}
|
||||
(common/set-on-card-connected :keycard/sign))
|
||||
|
||||
(pos? keycard-pin-retries) ; if 0, get-application-info will have already closed the
|
||||
; connection sheet and opened the frozen card popup
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :card-read-in-progress?] true)
|
||||
(assoc-in [:keycard :pin :status] :verifying))
|
||||
:keycard/sign {:hash (address/naked-address hash)
|
||||
:data data
|
||||
:typed? typed? ; this parameter is for e2e
|
||||
:on-success on-success
|
||||
:pin pin
|
||||
:path path}})))
|
||||
|
||||
(defn normalize-signature
|
||||
[signature]
|
||||
(-> signature
|
||||
(string/replace-first #"00$" "1b")
|
||||
(string/replace-first #"01$" "1c")
|
||||
address/normalized-hex))
|
||||
|
||||
(rf/defn sign-message
|
||||
{:events [:keycard/sign-message]}
|
||||
[cofx params result]
|
||||
(let [{:keys [result error]} (types/json->clj result)
|
||||
on-success #(re-frame/dispatch [:keycard/on-sign-message-success params
|
||||
(normalize-signature %)])
|
||||
hash (address/naked-address result)]
|
||||
(sign cofx hash on-success)))
|
||||
|
||||
(rf/defn on-sign-message-success
|
||||
{:events [:keycard/on-sign-message-success]}
|
||||
[{:keys [db] :as cofx} {:keys [tx-hash message-id chat-id value contract]} signature]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:dispatch
|
||||
(if message-id
|
||||
[:sign/send-accept-transaction-message message-id tx-hash signature]
|
||||
[:sign/send-transaction-message chat-id value contract tx-hash signature])
|
||||
:signing/show-transaction-result nil
|
||||
:db (-> db
|
||||
(assoc-in [:keycard :pin :sign] [])
|
||||
(assoc-in [:keycard :pin :status] nil))}
|
||||
(common/clear-on-card-connected)
|
||||
(common/get-application-info nil)
|
||||
(common/hide-connection-sheet)))
|
||||
|
||||
(rf/defn sign-typed-data
|
||||
{:events [:keycard/sign-typed-data]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [card-connected? (get-in db [:keycard :card-connected?])
|
||||
hash (get-in db [:keycard :hash])]
|
||||
(if card-connected?
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :card-read-in-progress?] true)
|
||||
(assoc-in [:signing/sign :keycard-step] :signing))
|
||||
:keycard/sign-typed-data {:hash (address/naked-address hash)}}
|
||||
(rf/merge cofx
|
||||
(common/set-on-card-connected :keycard/sign-typed-data)
|
||||
{:db (assoc-in db [:signing/sign :keycard-step] :signing)}))))
|
||||
|
||||
(rf/defn fetch-currency-token-on-success
|
||||
{:events [:keycard/fetch-currency-token-on-success]}
|
||||
[{:keys [db]} {:keys [decimals symbol]}]
|
||||
{:db (-> db
|
||||
(assoc-in [:signing/sign :formatted-data :message :formatted-currency] symbol)
|
||||
(update-in [:signing/sign :formatted-data :message]
|
||||
#(assoc %
|
||||
:formatted-amount
|
||||
(.dividedBy ^js (money/bignumber (:amount %))
|
||||
(money/bignumber (money/from-decimal decimals))))))})
|
||||
|
||||
(rf/defn store-hash-and-sign-typed
|
||||
{:events [:keycard/store-hash-and-sign-typed]}
|
||||
[{:keys [db] :as cofx} result]
|
||||
(let [{:keys [result]} (types/json->clj result)
|
||||
message (get-in db [:signing/sign :formatted-data :message])
|
||||
currency-contract (:currency message)]
|
||||
(when currency-contract
|
||||
{:json-rpc/call [{:method "wallet_discoverToken"
|
||||
:params [(chain/chain-id db) currency-contract]
|
||||
:on-success #(re-frame/dispatch [:keycard/fetch-currency-token-on-success
|
||||
%])}]})
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:keycard :hash] result)}
|
||||
sign-typed-data)))
|
||||
|
||||
(rf/defn prepare-to-sign
|
||||
{:events [:keycard/prepare-to-sign]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(common/show-connection-sheet
|
||||
cofx
|
||||
{:on-card-connected :keycard/prepare-to-sign
|
||||
:handler (common/get-application-info :keycard/sign)}))
|
||||
|
||||
(rf/defn sign-message-completed
|
||||
[_ signature]
|
||||
{:dispatch
|
||||
[:signing/sign-message-completed signature]})
|
||||
|
||||
(rf/defn send-transaction-with-signature
|
||||
[_ data]
|
||||
{:send-transaction-with-signature data})
|
||||
|
||||
(rf/defn on-sign-success
|
||||
{:events [:keycard.callback/on-sign-success]}
|
||||
[{:keys [db] :as cofx} signature]
|
||||
(log/debug "[keycard] sign success: " signature)
|
||||
(let [signature-json (types/clj->json {:result (normalize-signature signature)})
|
||||
transaction (get-in db [:keycard :transaction])
|
||||
tx-obj (select-keys transaction
|
||||
[:from :to :value :gas :gasPrice :command? :chat-id :message-id])
|
||||
command? (:command? transaction)]
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :hash] nil)
|
||||
(assoc-in [:keycard :transaction] nil))}
|
||||
(when-not command?
|
||||
(fn [{:keys [db] :as cofx}]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :pin :sign] [])
|
||||
(assoc-in [:keycard :pin :status] nil))}
|
||||
(common/clear-on-card-connected)
|
||||
(common/get-application-info nil)
|
||||
(common/hide-connection-sheet))))
|
||||
(if transaction
|
||||
(send-transaction-with-signature
|
||||
{:transaction (types/clj->json transaction)
|
||||
:signature signature
|
||||
:on-completed #(re-frame/dispatch [:signing/transaction-completed % tx-obj])})
|
||||
(sign-message-completed signature-json)))))
|
||||
|
||||
(rf/defn on-sign-error
|
||||
{:events [:keycard.callback/on-sign-error]}
|
||||
[{:keys [db] :as cofx} error]
|
||||
(log/debug "[keycard] sign error: " error)
|
||||
(let [tag-was-lost? (common/tag-lost? (:error error))
|
||||
pin-retries (common/pin-retries (:error error))]
|
||||
(when-not tag-was-lost?
|
||||
(if (not (nil? pin-retries))
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries)
|
||||
(update-in [:keycard :pin]
|
||||
assoc
|
||||
:status :error
|
||||
:sign []
|
||||
:error-label :t/pin-mismatch)
|
||||
(assoc-in [:signing/sign :keycard-step] :pin))}
|
||||
(common/hide-connection-sheet)
|
||||
(when (zero? pin-retries) (common/frozen-keycard-popup)))
|
||||
|
||||
(rf/merge cofx
|
||||
(common/hide-connection-sheet)
|
||||
(common/show-wrong-keycard-alert))))))
|
||||
@@ -1,588 +0,0 @@
|
||||
(ns legacy.status-im.keycard.simulated-keycard
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[keycard.keycard :as keycard]
|
||||
[legacy.status-im.multiaccounts.create.core :as multiaccounts.create]
|
||||
[legacy.status-im.utils.deprecated-types :as types]
|
||||
[native-module.core :as native-module]
|
||||
re-frame.db
|
||||
[status-im.constants :as constants]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.address :as address]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as re-frame]))
|
||||
|
||||
(def kk1-password "000000")
|
||||
(def default-pin "111111")
|
||||
(def default-puk "000000000000")
|
||||
(def account-password (native-module/sha3 "no password"))
|
||||
|
||||
(def initial-state
|
||||
{:card-connected? false
|
||||
:application-info {:initialized? false}})
|
||||
|
||||
(defonce state (atom initial-state))
|
||||
|
||||
(defn connect-card
|
||||
[]
|
||||
(swap! state assoc :card-connected? true)
|
||||
(doseq [callback (vals (get @state :on-card-connected))]
|
||||
(callback)))
|
||||
|
||||
(defn connect-selected-card
|
||||
[]
|
||||
(swap! state assoc
|
||||
:application-info
|
||||
{:free-pairing-slots 5
|
||||
:app-version "3.0"
|
||||
:secure-channel-pub-key
|
||||
"04c3071768912a515c00aeab7ceb8a5bfda91d036f4a4e60b7944cee3ca7fb67b6d118e8df1e2480b87fd636c6615253245bbbc93a6a407f155f2c58f76c96ef0e"
|
||||
:instance-uid "1b360b10a9a68b7d494e8f059059f118"
|
||||
:paired? true
|
||||
:has-master-key? true
|
||||
:initialized? true
|
||||
:pin-retry-counter 3
|
||||
:puk-retry-counter 5
|
||||
:key-uid (get-in @re-frame.db/app-db [:profile/login :key-uid])})
|
||||
(swap! state assoc :pin default-pin :puk default-puk :password kk1-password)
|
||||
(connect-card))
|
||||
|
||||
(def initialization (atom false))
|
||||
|
||||
(defn connect-pairing-card
|
||||
[]
|
||||
(reset! initialization false)
|
||||
(swap! state assoc
|
||||
:application-info
|
||||
{:free-pairing-slots 5
|
||||
:app-version "3.0"
|
||||
:secure-channel-pub-key
|
||||
"04c3071768912a515c00aeab7ceb8a5bfda91d036f4a4e60b7944cee3ca7fb67b6d118e8df1e2480b87fd636c6615253245bbbc93a6a407f155f2c58f76c96ef0e"
|
||||
:instance-uid "1b360b10a9a68b7d494e8f059059f118"
|
||||
:paired? false
|
||||
:has-master-key? true
|
||||
:initialized? true
|
||||
:pin-retry-counter 3
|
||||
:puk-retry-counter 5
|
||||
:key-uid "0x16839e8b1b8a395acb18100c7e2b161701c225adf31eefa02114099b4d81a30b"})
|
||||
(swap! state assoc :pin default-pin :puk default-puk :password kk1-password)
|
||||
(connect-card))
|
||||
|
||||
(defn disconnect-card
|
||||
[]
|
||||
(swap! state assoc :card-connected? false)
|
||||
(doseq [callback (vals (get @state :on-card-disconnected))]
|
||||
(callback)))
|
||||
|
||||
(defn reset-state
|
||||
[]
|
||||
(swap! state assoc :application-info {:initialized? false}))
|
||||
|
||||
(defn- later
|
||||
[f]
|
||||
(when f (js/setTimeout f 500)))
|
||||
|
||||
(defn pin-error
|
||||
[]
|
||||
#js
|
||||
{:code "EUNSPECIFIED"
|
||||
:message (str "Unexpected error SW, 0x63C" (get-in @state [:application-info :pin-retry-counter]))})
|
||||
|
||||
(defn puk-error
|
||||
[]
|
||||
#js
|
||||
{:code "EUNSPECIFIED"
|
||||
:message (str "Unexpected error SW, 0x63C" (get-in @state [:application-info :puk-retry-counter]))})
|
||||
|
||||
(defn with-pin
|
||||
[pin on-failure on-valid]
|
||||
(cond
|
||||
(= (get-in @state [:application-info :pin-retry-counter]) 0)
|
||||
(later #(on-failure (pin-error)))
|
||||
|
||||
(= pin (get @state :pin))
|
||||
(do
|
||||
(swap! state update
|
||||
:application-info assoc
|
||||
:pin-retry-counter 3
|
||||
:puk-retry-counter 5)
|
||||
(later on-valid))
|
||||
|
||||
:else
|
||||
(do
|
||||
(swap! state update-in
|
||||
[:application-info :pin-retry-counter]
|
||||
(fnil dec 3))
|
||||
(later #(on-failure (pin-error))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn start-nfc
|
||||
[{:keys [on-success]}]
|
||||
(when (get @state :card-connected?) (connect-card))
|
||||
(later #(on-success true)))
|
||||
|
||||
(defn stop-nfc
|
||||
[{:keys [on-success]}]
|
||||
(later #(on-success true)))
|
||||
|
||||
(defn set-nfc-message
|
||||
[{:keys [on-success]}]
|
||||
(later #(on-success true)))
|
||||
|
||||
(defn check-nfc-support
|
||||
[{:keys [on-success]}]
|
||||
(later #(on-success true)))
|
||||
|
||||
(defn check-nfc-enabled
|
||||
[{:keys [on-success]}]
|
||||
(later #(on-success true)))
|
||||
|
||||
(defn open-nfc-settings [])
|
||||
|
||||
(defn on-card-connected
|
||||
[callback]
|
||||
(let [id (random-uuid)]
|
||||
(swap! state update :on-card-connected assoc id callback)
|
||||
id))
|
||||
|
||||
(defn on-card-disconnected
|
||||
[callback]
|
||||
(let [id (random-uuid)]
|
||||
(swap! state update :on-card-disconnected assoc id callback)
|
||||
id))
|
||||
|
||||
(defn register-card-events
|
||||
[args]
|
||||
(log/debug "register-card-events")
|
||||
(on-card-connected (:on-card-connected args))
|
||||
(on-card-disconnected (:on-card-disconnected args)))
|
||||
|
||||
(defn set-pairings
|
||||
[args]
|
||||
(log/warn "set-pairings not implemented" args))
|
||||
|
||||
(defn remove-event-listener
|
||||
[id]
|
||||
(log/debug "remove-event-listener")
|
||||
(swap! state update :on-card-connected dissoc id)
|
||||
(swap! state update :on-card-disconnected dissoc id))
|
||||
|
||||
(defn remove-event-listeners
|
||||
[]
|
||||
(log/debug "remove-event-listeners")
|
||||
(swap! state dissoc :on-card-connected)
|
||||
(swap! state dissoc :on-card-disconnected))
|
||||
|
||||
(defn get-application-info
|
||||
[{:keys [on-success]}]
|
||||
(log/debug "get-application-info")
|
||||
(later #(on-success (get @state :application-info))))
|
||||
|
||||
(defn factory-reset
|
||||
[args]
|
||||
(log/debug "factory-reset")
|
||||
(reset-state)
|
||||
(get-application-info args))
|
||||
|
||||
(defn install-applet [_])
|
||||
(defn install-cash-applet [_])
|
||||
|
||||
(defn init-card
|
||||
[{:keys [pin on-success]}]
|
||||
(reset! initialization true)
|
||||
(swap! state assoc
|
||||
:application-info
|
||||
{:free-pairing-slots 5
|
||||
:app-version "3.0"
|
||||
:secure-channel-pub-key
|
||||
"04c3071768912a515c00aeab7ceb8a5bfda91d036f4a4e60b7944cee3ca7fb67b6d118e8df1e2480b87fd636c6615253245bbbc93a6a407f155f2c58f76c96ef0e"
|
||||
:key-uid ""
|
||||
:instance-uid "1b360b10a9a68b7d494e8f059059f118"
|
||||
:paired? false
|
||||
:has-master-key? false
|
||||
:pin-retry-counter 3
|
||||
:puk-retry-counter 5
|
||||
:initialized? true})
|
||||
(swap! state assoc :pin pin :puk default-puk :password kk1-password)
|
||||
(later
|
||||
#(on-success {:password kk1-password
|
||||
:puk default-puk
|
||||
:pin pin})))
|
||||
|
||||
(defn install-applet-and-init-card [_])
|
||||
|
||||
(def derived-acc (atom nil))
|
||||
|
||||
(defn multiaccount->keys
|
||||
[data]
|
||||
(let [{:keys [selected-id multiaccounts root-key derived]}
|
||||
data
|
||||
|
||||
{:keys [id address public-key derived key-uid]}
|
||||
(or (->> multiaccounts
|
||||
(filter #(= (:id %) selected-id))
|
||||
first)
|
||||
(assoc root-key :derived derived))
|
||||
|
||||
whisper (get derived constants/path-whisper-keyword)
|
||||
wallet (get derived constants/path-default-wallet-keyword)
|
||||
wallet-root (get derived constants/path-wallet-root-keyword)
|
||||
password account-password
|
||||
response {:key-uid key-uid
|
||||
:encryption-public-key password
|
||||
:address address
|
||||
:whisper-public-key (:public-key whisper)
|
||||
:instance-uid "1b360b10a9a68b7d494e8f059059f118"
|
||||
:wallet-root-public-key (:public-key wallet-root)
|
||||
:wallet-root-address (:address wallet-root)
|
||||
:whisper-address (:address whisper)
|
||||
:public-key public-key
|
||||
:whisper-private-key "34bc7d0c258c4f2ac1dac4fd6c55c9478bac1f4a9d8b9f1152c8551ab7187b43"
|
||||
:wallet-address (:address wallet)
|
||||
:wallet-public-key (:public-key wallet)}]
|
||||
[id response]))
|
||||
|
||||
(defn pair
|
||||
[{:keys [password on-success]}]
|
||||
(when (and (not @initialization)
|
||||
(not @derived-acc))
|
||||
(native-module/multiaccount-import-mnemonic
|
||||
"night fortune spider version version armed amused winner matter tonight cave flag"
|
||||
nil
|
||||
(fn [result]
|
||||
(let [{:keys [id] :as root-data}
|
||||
(multiaccounts.create/normalize-multiaccount-data-keys
|
||||
(types/json->clj result))]
|
||||
(native-module.core/multiaccount-derive-addresses
|
||||
id
|
||||
[constants/path-wallet-root
|
||||
constants/path-eip1581
|
||||
constants/path-whisper
|
||||
constants/path-default-wallet]
|
||||
(fn [result]
|
||||
(let [derived-data (multiaccounts.create/normalize-derived-data-keys
|
||||
(types/json->clj result))]
|
||||
(reset! derived-acc
|
||||
{:root-key root-data
|
||||
:derived derived-data}))))))))
|
||||
(when (= password (get @state :password))
|
||||
(swap! state assoc-in [:application-info :paired?] true)
|
||||
(later #(on-success (str (rand-int 10000000))))))
|
||||
|
||||
(defn generate-and-load-key
|
||||
[{:keys [pin on-success key-uid delete-multiaccount?]}]
|
||||
(when (= pin (get @state :pin))
|
||||
(let [[id response] (multiaccount->keys
|
||||
(:intro-wizard @re-frame.db/app-db))]
|
||||
(log/debug "[simulated kk] generate-and-load-key response" response)
|
||||
(swap! state assoc-in
|
||||
[:application-info :key-uid]
|
||||
(:key-uid response))
|
||||
(let [deletion-wrapper
|
||||
(if delete-multiaccount?
|
||||
(fn [on-deletion-success]
|
||||
(js/alert "OH SHEET")
|
||||
(native-module/delete-multiaccount
|
||||
key-uid
|
||||
(fn [result]
|
||||
(let [{:keys [error]} (types/json->clj result)]
|
||||
(if-not (string/blank? error)
|
||||
(log/error error)
|
||||
(on-deletion-success))))))
|
||||
(fn [cb] (cb)))]
|
||||
(deletion-wrapper
|
||||
(fn []
|
||||
(native-module/multiaccount-store-derived
|
||||
id
|
||||
(:key-uid response)
|
||||
[constants/path-wallet-root
|
||||
constants/path-eip1581
|
||||
constants/path-whisper
|
||||
constants/path-default-wallet]
|
||||
account-password
|
||||
#(on-success response))))))))
|
||||
|
||||
(defn unblock-pin
|
||||
[{:keys [puk new-pin on-success on-failure]}]
|
||||
(cond
|
||||
(= (get-in @state [:application-info :puk-retry-counter]) 0)
|
||||
(later #(on-failure (puk-error)))
|
||||
|
||||
(= puk (get @state :puk))
|
||||
(do
|
||||
(swap! state update
|
||||
:application-info assoc
|
||||
:pin-retry-counter 3
|
||||
:puk-retry-counter 5)
|
||||
(swap! state assoc :pin new-pin)
|
||||
(later #(on-success true)))
|
||||
|
||||
:else
|
||||
(do
|
||||
(swap! state update-in
|
||||
[:application-info :puk-retry-counter]
|
||||
(fnil dec 5))
|
||||
(later
|
||||
#(on-failure (puk-error))))))
|
||||
|
||||
(defn verify-pin
|
||||
[{:keys [pin on-success on-failure]}]
|
||||
(with-pin pin on-failure #(on-success 3)))
|
||||
|
||||
(defn change-pin
|
||||
[{:keys [current-pin new-pin on-success on-failure]}]
|
||||
(with-pin current-pin
|
||||
on-failure
|
||||
(fn []
|
||||
(swap! state assoc :pin new-pin)
|
||||
(on-success))))
|
||||
|
||||
(defn change-puk
|
||||
[{:keys [pin puk on-success on-failure]}]
|
||||
(with-pin pin
|
||||
on-failure
|
||||
(fn []
|
||||
(swap! state assoc :puk puk)
|
||||
(on-success))))
|
||||
|
||||
(defn change-pairing
|
||||
[{:keys [pin pairing on-success on-failure]}]
|
||||
(with-pin pin
|
||||
on-failure
|
||||
(fn []
|
||||
(swap! state assoc :password pairing)
|
||||
(on-success))))
|
||||
|
||||
(defn unpair
|
||||
[args]
|
||||
(log/warn "unpair not implemented" args))
|
||||
(defn delete
|
||||
[args]
|
||||
(log/warn "delete not implemented" args))
|
||||
(defn remove-key
|
||||
[args]
|
||||
(log/warn "remove-key not implemented" args))
|
||||
(defn remove-key-with-unpair
|
||||
[args]
|
||||
(log/warn "remove-key-with-unpair not implemented" args))
|
||||
|
||||
(defn normalize-path
|
||||
[path]
|
||||
(if (string/starts-with? path "m/")
|
||||
(str constants/path-wallet-root
|
||||
"/"
|
||||
(last (string/split path "/")))
|
||||
path))
|
||||
|
||||
(defn export-key
|
||||
[{:keys [pin on-success on-failure]}]
|
||||
(with-pin
|
||||
pin
|
||||
on-failure
|
||||
#(let [{:keys [key-uid wallet-root-address]}
|
||||
(get @re-frame.db/app-db :profile/profile)
|
||||
accounts (get @re-frame.db/app-db :profile/wallet-accounts)
|
||||
hashed-password account-password
|
||||
path-num (inc (get-in @re-frame.db/app-db
|
||||
[:profile/profile :latest-derived-path]))
|
||||
path (str "m/" path-num)]
|
||||
(native-module/multiaccount-load-account
|
||||
wallet-root-address
|
||||
hashed-password
|
||||
(fn [value]
|
||||
(let [{:keys [id error]} (types/json->clj value)]
|
||||
(if error
|
||||
(re-frame/dispatch [::new-account-error :password-error error])
|
||||
(native-module/multiaccount-derive-addresses
|
||||
id
|
||||
[path]
|
||||
(fn [derived]
|
||||
(let [derived-address (get-in (types/json->clj derived) [(keyword path) :address])]
|
||||
(if (some (fn [a] (= derived-address (get a :address))) accounts)
|
||||
(re-frame/dispatch [::new-account-error :account-error
|
||||
(i18n/label :t/account-exists-title)])
|
||||
(native-module/multiaccount-store-derived
|
||||
id
|
||||
key-uid
|
||||
[path]
|
||||
hashed-password
|
||||
(fn [result]
|
||||
(let [{:keys [error] :as result} (types/json->clj result)
|
||||
{:keys [publicKey]} (get result (keyword path))]
|
||||
(if error
|
||||
(on-failure error)
|
||||
(on-success publicKey))))))))))))))))
|
||||
|
||||
(defn unpair-and-delete [_])
|
||||
|
||||
(defn get-keys
|
||||
[{:keys [on-success on-failure pin]}]
|
||||
(with-pin pin
|
||||
on-failure
|
||||
(if @derived-acc
|
||||
(let [[id account-keys] (multiaccount->keys @derived-acc)]
|
||||
(swap! state assoc-in
|
||||
[:application-info :key-uid]
|
||||
(:key-uid account-keys))
|
||||
(native-module/multiaccount-store-derived
|
||||
id
|
||||
(:key-uid account-keys)
|
||||
[constants/path-wallet-root
|
||||
constants/path-eip1581
|
||||
constants/path-whisper
|
||||
constants/path-default-wallet]
|
||||
account-password
|
||||
#(on-success account-keys)))
|
||||
#(on-success
|
||||
{:key-uid (get-in @state [:application-info :key-uid])
|
||||
:instance-uid (get-in @state [:application-info :instance-uid])
|
||||
:encryption-public-key account-password}))))
|
||||
|
||||
(def import-keys get-keys)
|
||||
|
||||
(defn sign
|
||||
[{:keys [pin data path typed? on-success on-failure] :as card}]
|
||||
(with-pin pin
|
||||
on-failure
|
||||
#(let [address
|
||||
(if path
|
||||
(reduce
|
||||
(fn [_ {:keys [address] :as acc}]
|
||||
(when (= path (:path acc))
|
||||
(reduced address)))
|
||||
nil
|
||||
(:profile/wallet-accounts @re-frame.db/app-db))
|
||||
(-> (:profile/wallet-accounts @re-frame.db/app-db)
|
||||
first
|
||||
:address))
|
||||
password account-password]
|
||||
(if-not typed?
|
||||
(let [params (types/clj->json
|
||||
{:account address
|
||||
:password password
|
||||
:data (or data (str "0x" (:hash card)))})]
|
||||
(native-module/sign-message
|
||||
params
|
||||
(fn [res]
|
||||
(let [signature (-> res
|
||||
types/json->clj
|
||||
:result
|
||||
address/normalized-hex)]
|
||||
(on-success signature)))))
|
||||
(native-module/sign-typed-data
|
||||
data
|
||||
address
|
||||
password
|
||||
(fn [res]
|
||||
(let [signature (-> res
|
||||
types/json->clj
|
||||
:result
|
||||
address/normalized-hex)]
|
||||
(on-success signature))))))))
|
||||
|
||||
(defn sign-typed-data
|
||||
[args]
|
||||
(log/warn "sign-typed-data not implemented" args))
|
||||
|
||||
(defrecord SimulatedKeycard []
|
||||
keycard/Keycard
|
||||
(keycard/start-nfc [_this args]
|
||||
(log/debug "simulated card start-nfc")
|
||||
(start-nfc args))
|
||||
(keycard/stop-nfc [_this args]
|
||||
(log/debug "simulated card stop-nfc")
|
||||
(stop-nfc args))
|
||||
(keycard/set-nfc-message [_this args]
|
||||
(log/debug "simulated card set-nfc-message")
|
||||
(set-nfc-message args))
|
||||
(keycard/check-nfc-support [_this args]
|
||||
(log/debug "simulated card check-nfc-support")
|
||||
(check-nfc-support args))
|
||||
(keycard/check-nfc-enabled [_this args]
|
||||
(log/debug "simulated card check-nfc-enabled")
|
||||
(check-nfc-enabled args))
|
||||
(keycard/open-nfc-settings [_this]
|
||||
(log/debug "simulated card open-nfc-setting")
|
||||
(open-nfc-settings))
|
||||
(keycard/register-card-events [_this args]
|
||||
(log/debug "simulated card register-card-event")
|
||||
(register-card-events args))
|
||||
(keycard/set-pairings [_this args]
|
||||
(log/debug "simulated card set-pairings")
|
||||
(set-pairings args))
|
||||
(keycard/on-card-connected [_this callback]
|
||||
(log/debug "simulated card on-card-connected")
|
||||
(on-card-connected callback))
|
||||
(keycard/on-card-disconnected [_this callback]
|
||||
(log/debug "simulated card on-card-disconnected")
|
||||
(on-card-disconnected callback))
|
||||
(keycard/remove-event-listener [_this event]
|
||||
(log/debug "simulated card remove-event-listener")
|
||||
(remove-event-listener event))
|
||||
(keycard/remove-event-listeners [_this]
|
||||
(log/debug "simulated card remove-event-listener")
|
||||
(remove-event-listeners))
|
||||
(keycard/get-application-info [_this args]
|
||||
(log/debug "simulated card get-application-info")
|
||||
(get-application-info args))
|
||||
(keycard/factory-reset [_this args]
|
||||
(log/debug "simulated card factory-reset")
|
||||
(factory-reset args))
|
||||
(keycard/install-applet [_this args]
|
||||
(log/debug "simulated card install-applet")
|
||||
(install-applet args))
|
||||
(keycard/init-card [_this args]
|
||||
(log/debug "simulated card init-card")
|
||||
(init-card args))
|
||||
(keycard/install-applet-and-init-card [_this args]
|
||||
(log/debug "simulated card install-applet-and-init-card")
|
||||
(install-applet-and-init-card args))
|
||||
(keycard/pair [_this args]
|
||||
(log/debug "simulated card pair")
|
||||
(pair args))
|
||||
(keycard/generate-and-load-key [_this args]
|
||||
(log/debug "simulated card generate-and-load-key")
|
||||
(generate-and-load-key args))
|
||||
(keycard/unblock-pin [_this args]
|
||||
(log/debug "simulated card unblock-pin")
|
||||
(unblock-pin args))
|
||||
(keycard/verify-pin [_this args]
|
||||
(log/debug "simulated card verify-pin")
|
||||
(verify-pin args))
|
||||
(keycard/change-pin [_this args]
|
||||
(log/debug "simulated card change-pin")
|
||||
(change-pin args))
|
||||
(keycard/change-puk [_this args]
|
||||
(log/debug "simulated card change-puk")
|
||||
(change-puk args))
|
||||
(keycard/change-pairing [_this args]
|
||||
(log/debug "simulated card change-pairing")
|
||||
(change-pairing args))
|
||||
(keycard/unpair [_this args]
|
||||
(log/debug "simulated card unpair")
|
||||
(unpair args))
|
||||
(keycard/delete [_this args]
|
||||
(log/debug "simulated card delete")
|
||||
(delete args))
|
||||
(keycard/remove-key [_this args]
|
||||
(log/debug "simulated card remove-key")
|
||||
(remove-key args))
|
||||
(keycard/remove-key-with-unpair [_this args]
|
||||
(log/debug "simulated card remove-key-with-unpair")
|
||||
(remove-key-with-unpair args))
|
||||
(keycard/export-key [_this args]
|
||||
(log/debug "simulated card export-key")
|
||||
(export-key args))
|
||||
(keycard/unpair-and-delete [_this args]
|
||||
(log/debug "simulated card unpair-and-delete")
|
||||
(unpair-and-delete args))
|
||||
(keycard/import-keys [_this args]
|
||||
(log/debug "simulated card import-keys")
|
||||
(import-keys args))
|
||||
(keycard/get-keys [_this args]
|
||||
(log/debug "simulated card get-keys")
|
||||
(get-keys args))
|
||||
(keycard/sign [_this args]
|
||||
(log/debug "simulated card sign")
|
||||
(sign args)))
|
||||
@@ -1,32 +0,0 @@
|
||||
(ns legacy.status-im.keycard.test-menu
|
||||
(:require
|
||||
[legacy.status-im.keycard.simulated-keycard :as simulated-keycard]
|
||||
[legacy.status-im.ui.components.react :as react]))
|
||||
|
||||
(defn button
|
||||
[label accessibility-label handler]
|
||||
[react/view
|
||||
{:style {:width 20
|
||||
:height 30
|
||||
:justify-content :center
|
||||
:align-items :center}}
|
||||
[react/text
|
||||
{:on-press handler
|
||||
:style {:font-size 8}
|
||||
:accessibility-label accessibility-label}
|
||||
label]])
|
||||
|
||||
(defn test-menu
|
||||
[]
|
||||
[react/view
|
||||
{:style {:position :absolute
|
||||
:top 70
|
||||
:right 0
|
||||
:width 50
|
||||
:justify-content :center
|
||||
:align-items :center}}
|
||||
[button "conn" :connect-card simulated-keycard/connect-card]
|
||||
[button "conn sell" :connect-selected-card simulated-keycard/connect-selected-card]
|
||||
[button "pair" :connect-pairing-card simulated-keycard/connect-pairing-card]
|
||||
[button "disc" :disconnect-card simulated-keycard/disconnect-card]
|
||||
[button "res" :keycard-reset-state simulated-keycard/reset-state]])
|
||||
@@ -1,187 +0,0 @@
|
||||
(ns legacy.status-im.keycard.unpair
|
||||
(:require
|
||||
[legacy.status-im.keycard.common :as common]
|
||||
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/defn unpair-card-pressed
|
||||
{:events [:keycard-settings.ui/unpair-card-pressed]}
|
||||
[_]
|
||||
{:ui/show-confirmation {:title (i18n/label :t/unpair-card)
|
||||
:content (i18n/label :t/unpair-card-confirmation)
|
||||
:confirm-button-text (i18n/label :t/yes)
|
||||
:cancel-button-text (i18n/label :t/no)
|
||||
:on-accept #(re-frame/dispatch
|
||||
[:keycard-settings.ui/unpair-card-confirmed])
|
||||
:on-cancel #()}})
|
||||
|
||||
(rf/defn unpair-card-confirmed
|
||||
{:events [:keycard-settings.ui/unpair-card-confirmed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db
|
||||
[:keycard :pin]
|
||||
{:enter-step :current
|
||||
:current []
|
||||
:puk []
|
||||
:status nil
|
||||
:error-label nil
|
||||
:on-verified :keycard/unpair})}
|
||||
(common/navigate-to-enter-pin-screen)))
|
||||
|
||||
(rf/defn unpair
|
||||
{:events [:keycard/unpair]}
|
||||
[{:keys [db]}]
|
||||
(let [pin (common/vector->string (get-in db [:keycard :pin :current]))]
|
||||
{:keycard/unpair {:pin pin}}))
|
||||
|
||||
(rf/defn unpair-and-delete
|
||||
{:events [:keycard/unpair-and-delete]}
|
||||
[cofx]
|
||||
(common/show-connection-sheet
|
||||
cofx
|
||||
{:on-card-connected :keycard/unpair-and-delete
|
||||
:handler
|
||||
(fn [{:keys [db]}]
|
||||
(let [pin (common/vector->string (get-in db [:keycard :pin :current]))]
|
||||
{:keycard/unpair-and-delete
|
||||
{:pin pin}}))}))
|
||||
|
||||
(rf/defn remove-pairing-from-multiaccount
|
||||
[cofx {:keys [remove-instance-uid?]}]
|
||||
(rf/merge cofx
|
||||
(multiaccounts.update/multiaccount-update
|
||||
:keycard-pairing
|
||||
nil
|
||||
{})
|
||||
(multiaccounts.update/multiaccount-update
|
||||
:keycard-paired-on
|
||||
nil
|
||||
{})
|
||||
(when remove-instance-uid?
|
||||
(multiaccounts.update/multiaccount-update
|
||||
:keycard-instance-uid
|
||||
nil
|
||||
{}))))
|
||||
|
||||
(rf/defn on-unpair-success
|
||||
{:events [:keycard.callback/on-unpair-success]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [instance-uid (get-in db [:keycard :application-info :instance-uid])
|
||||
pairings (get-in db [:keycard :pairings])]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :secrets] nil)
|
||||
(update-in [:keycard :pairings] dissoc (keyword instance-uid))
|
||||
(assoc-in [:keycard :pin]
|
||||
{:status nil
|
||||
:error-label nil
|
||||
:on-verified nil}))
|
||||
:keycard/persist-pairings (dissoc pairings (keyword instance-uid))
|
||||
:effects.utils/show-popup {:title ""
|
||||
:content (i18n/label :t/card-unpaired)}}
|
||||
(common/clear-on-card-connected)
|
||||
(remove-pairing-from-multiaccount nil)
|
||||
(navigation/navigate-to :keycard-settings nil))))
|
||||
|
||||
(rf/defn on-unpair-error
|
||||
{:events [:keycard.callback/on-unpair-error]}
|
||||
[{:keys [db] :as cofx} error]
|
||||
(log/debug "[keycard] unpair error" error)
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db
|
||||
[:keycard :pin]
|
||||
{:status nil
|
||||
:error-label nil
|
||||
:on-verified nil})
|
||||
:keycard/get-application-info nil
|
||||
:effects.utils/show-popup {:title ""
|
||||
:content (i18n/label :t/something-went-wrong)}}
|
||||
(common/clear-on-card-connected)
|
||||
(navigation/navigate-to :keycard-settings nil)))
|
||||
|
||||
(rf/defn remove-key-with-unpair
|
||||
{:events [:keycard/remove-key-with-unpair]}
|
||||
[cofx]
|
||||
(common/show-connection-sheet
|
||||
cofx
|
||||
{:on-card-connected :keycard/remove-key-with-unpair
|
||||
:handler
|
||||
(fn [{:keys [db]}]
|
||||
(let [pin (common/vector->string (get-in db [:keycard :pin :current]))]
|
||||
{:keycard/remove-key-with-unpair
|
||||
{:pin pin}}))}))
|
||||
|
||||
(defn handle-account-removal
|
||||
[{:keys [db] :as cofx} keys-removed-from-card?]
|
||||
(let [key-uid (get-in db [:profile/profile :key-uid])
|
||||
instance-uid (get-in db [:keycard :application-info :instance-uid])
|
||||
pairings (get-in db [:keycard :pairings])]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (-> db
|
||||
(update :profile/profiles-overview dissoc key-uid)
|
||||
(assoc-in [:keycard :secrets] nil)
|
||||
(update-in [:keycard :pairings]
|
||||
dissoc
|
||||
(keyword instance-uid))
|
||||
(update-in [:keycard :pairings] dissoc instance-uid)
|
||||
(assoc-in [:keycard :whisper-public-key] nil)
|
||||
(assoc-in [:keycard :wallet-address] nil)
|
||||
(assoc-in [:keycard :application-info] nil)
|
||||
(assoc-in [:keycard :pin]
|
||||
{:status nil
|
||||
:error-label nil
|
||||
:on-verified nil}))
|
||||
:keycard/persist-pairings (dissoc pairings (keyword instance-uid))
|
||||
:effects.utils/show-popup {:title (i18n/label (if keys-removed-from-card?
|
||||
:t/profile-deleted-title
|
||||
:t/database-reset-title))
|
||||
:content (i18n/label (if keys-removed-from-card?
|
||||
:t/profile-deleted-keycard
|
||||
:t/database-reset-content))
|
||||
:on-dismiss #(re-frame/dispatch [:logout])}}
|
||||
;;should be reimplemented :key-storage/delete-profile {:key-uid key-uid
|
||||
;;:on-success #(log/debug "[keycard] remove account ok")
|
||||
;; :on-error #(log/warn "[keycard] remove account: " %)}
|
||||
(common/clear-on-card-connected)
|
||||
(common/hide-connection-sheet))))
|
||||
|
||||
(rf/defn on-remove-key-success
|
||||
{:events [:keycard.callback/on-remove-key-success]}
|
||||
[cofx]
|
||||
(handle-account-removal cofx true))
|
||||
|
||||
(rf/defn on-remove-key-error
|
||||
{:events [:keycard.callback/on-remove-key-error]}
|
||||
[{:keys [db] :as cofx} error]
|
||||
(log/debug "[keycard] remove key error" error)
|
||||
(let [tag-was-lost? (common/tag-lost? (:error error))]
|
||||
(rf/merge cofx
|
||||
(if tag-was-lost?
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:keycard :pin :status] nil)}
|
||||
(common/set-on-card-connected :keycard/remove-key-with-unpair))
|
||||
(common/show-wrong-keycard-alert)))))
|
||||
|
||||
(rf/defn on-unpair-and-delete-success
|
||||
{:events [:keycard.callback/on-unpair-and-delete-success]}
|
||||
[cofx]
|
||||
(handle-account-removal cofx false))
|
||||
|
||||
(rf/defn on-unpair-and-delete-error
|
||||
{:events [:keycard.callback/on-unpair-and-delete-error]}
|
||||
[{:keys [db] :as cofx} error]
|
||||
(log/debug "[keycard] unpair and delete error" error)
|
||||
(let [tag-was-lost? (common/tag-lost? (:error error))]
|
||||
(rf/merge cofx
|
||||
(if tag-was-lost?
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:keycard :pin :status] nil)}
|
||||
(common/set-on-card-connected :keycard/unpair-and-delete))
|
||||
(common/show-wrong-keycard-alert)))))
|
||||
@@ -5,16 +5,6 @@
|
||||
[react-native.platform :as platform]
|
||||
[status-im.config :as config]))
|
||||
|
||||
(defn- add-custom-bootnodes
|
||||
[config network all-bootnodes]
|
||||
(let [bootnodes (as-> all-bootnodes $
|
||||
(get $ network)
|
||||
(vals $)
|
||||
(map :address $))]
|
||||
(if (seq bootnodes)
|
||||
(assoc-in config [:ClusterConfig :BootNodes] bootnodes)
|
||||
config)))
|
||||
|
||||
(defn- add-log-level
|
||||
[config log-level]
|
||||
(if (empty? log-level)
|
||||
@@ -124,10 +114,8 @@
|
||||
waku-nodes (get config/waku-nodes-config fleet-key)
|
||||
rendezvous-nodes (pick-nodes 3 (vals (:rendezvous current-fleet)))
|
||||
{:keys [installation-id log-level
|
||||
waku-bloom-filter-mode
|
||||
custom-bootnodes custom-bootnodes-enabled?]}
|
||||
profile
|
||||
use-custom-bootnodes (get custom-bootnodes-enabled? current-network)]
|
||||
waku-bloom-filter-mode]}
|
||||
profile]
|
||||
(cond-> (get-in networks [current-network :config])
|
||||
:always
|
||||
(get-base-node-config)
|
||||
@@ -144,8 +132,6 @@
|
||||
(if wakuv2-enabled
|
||||
waku-nodes
|
||||
[])
|
||||
:BootNodes
|
||||
(if wakuv2-enabled [] (pick-nodes 4 (vals (:boot current-fleet))))
|
||||
:TrustedMailServers
|
||||
(if wakuv2-enabled [] (pick-nodes 6 (vals (:mail current-fleet))))
|
||||
:StaticNodes
|
||||
@@ -185,11 +171,6 @@
|
||||
:RequireTopics (get-topics current-network)
|
||||
:StatusAccountsConfig {:Enabled true})
|
||||
|
||||
(and
|
||||
config/bootnodes-settings-enabled?
|
||||
use-custom-bootnodes)
|
||||
(add-custom-bootnodes current-network custom-bootnodes)
|
||||
|
||||
:always
|
||||
(add-log-level log-level))))
|
||||
|
||||
|
||||
@@ -1,650 +0,0 @@
|
||||
(ns legacy.status-im.signing.core
|
||||
(:require
|
||||
[clojure.set :as set]
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.ethereum.tokens :as tokens]
|
||||
[legacy.status-im.keycard.card :as keycard.card]
|
||||
[legacy.status-im.keycard.common :as keycard.common]
|
||||
[legacy.status-im.signing.eip1559 :as eip1559]
|
||||
[legacy.status-im.signing.keycard :as signing.keycard]
|
||||
[legacy.status-im.utils.deprecated-types :as types]
|
||||
[legacy.status-im.utils.hex :as utils.hex]
|
||||
[legacy.status-im.utils.utils :as utils]
|
||||
[native-module.core :as native-module]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.common.json-rpc.events :as json-rpc]
|
||||
[status-im.constants :as constants]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.address :as address]
|
||||
[utils.ethereum.chain :as chain]
|
||||
[utils.ethereum.eip.eip55 :as eip55]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.money :as money]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:signing/send-transaction-fx
|
||||
(fn [{:keys [tx-obj hashed-password cb]}]
|
||||
(native-module/send-transaction (types/clj->json tx-obj)
|
||||
hashed-password
|
||||
cb)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:signing/show-transaction-error
|
||||
(fn [message]
|
||||
(utils/show-popup (i18n/label :t/transaction-failed) message)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:signing/show-transaction-result
|
||||
(fn []
|
||||
(utils/show-popup (i18n/label :t/transaction-sent) (i18n/label :t/transaction-description))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:signing.fx/sign-message
|
||||
(fn [{:keys [params on-completed]}]
|
||||
(native-module/sign-message (types/clj->json params)
|
||||
on-completed)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:signing.fx/recover-message
|
||||
(fn [{:keys [params on-completed]}]
|
||||
(native-module/recover-message (types/clj->json params)
|
||||
on-completed)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:signing.fx/sign-typed-data
|
||||
(fn [{:keys [v4 data account on-completed hashed-password]}]
|
||||
(if v4
|
||||
(native-module/sign-typed-data-v4 data account hashed-password on-completed)
|
||||
(native-module/sign-typed-data data account hashed-password on-completed))))
|
||||
|
||||
(defn get-contact
|
||||
[db to]
|
||||
(let [to (utils.hex/normalize-hex to)]
|
||||
(or
|
||||
(get-in db [:contacts/contacts to])
|
||||
{:address (address/normalized-hex to)})))
|
||||
|
||||
(rf/defn change-password
|
||||
{:events [:signing.ui/password-is-changed]}
|
||||
[{db :db} password]
|
||||
(let [unmasked-pass (security/safe-unmask-data password)]
|
||||
{:db (update db
|
||||
:signing/sign assoc
|
||||
:password password
|
||||
:error nil
|
||||
:enabled? (and unmasked-pass (> (count unmasked-pass) 5)))}))
|
||||
|
||||
(rf/defn sign-message
|
||||
[{{:signing/keys [sign tx] :as db} :db}]
|
||||
(let [{{:keys [data typed? from v4]} :message} tx
|
||||
{:keys [in-progress? password]} sign
|
||||
from from
|
||||
hashed-password (native-module/sha3 (security/safe-unmask-data
|
||||
password))]
|
||||
(when-not in-progress?
|
||||
(merge
|
||||
{:db (update db :signing/sign assoc :error nil :in-progress? true)}
|
||||
(if typed?
|
||||
{:signing.fx/sign-typed-data {:v4 v4
|
||||
:data data
|
||||
:account from
|
||||
:hashed-password hashed-password
|
||||
:on-completed #(re-frame/dispatch
|
||||
[:signing/sign-message-completed %])}}
|
||||
{:signing.fx/sign-message {:params {:data data
|
||||
:password hashed-password
|
||||
:account from}
|
||||
:on-completed #(re-frame/dispatch [:signing/sign-message-completed
|
||||
%])}})))))
|
||||
|
||||
(rf/defn send-transaction
|
||||
{:events [:signing.ui/sign-is-pressed]}
|
||||
[{{:signing/keys [sign tx] :ens/keys [registration] :as db} :db :as cofx}]
|
||||
(let [{:keys [in-progress? password]} sign
|
||||
{:keys [tx-obj gas gasPrice maxPriorityFeePerGas
|
||||
maxFeePerGas message nonce]} tx
|
||||
hashed-password (native-module/sha3 (security/safe-unmask-data
|
||||
password))
|
||||
{:keys [action username custom-domain?]} registration
|
||||
{:keys [public-key]} (:profile/profile db)
|
||||
chain-id (chain/chain-id db)]
|
||||
(if message
|
||||
(sign-message cofx)
|
||||
(let [tx-obj-to-send (merge tx-obj
|
||||
(when gas
|
||||
{:gas (str "0x" (native-module/number-to-hex gas))})
|
||||
(when gasPrice
|
||||
{:gasPrice (str "0x" (native-module/number-to-hex gasPrice))})
|
||||
(when nonce
|
||||
{:nonce (str "0x" (native-module/number-to-hex nonce))})
|
||||
(when maxPriorityFeePerGas
|
||||
{:maxPriorityFeePerGas (str "0x"
|
||||
(native-module/number-to-hex
|
||||
(js/parseInt maxPriorityFeePerGas)))})
|
||||
(when maxFeePerGas
|
||||
{:maxFeePerGas (str "0x"
|
||||
(native-module/number-to-hex
|
||||
(js/parseInt maxFeePerGas)))}))
|
||||
cb #(re-frame/dispatch
|
||||
[:signing/transaction-completed %
|
||||
tx-obj-to-send hashed-password])
|
||||
watch-ens-tx-fn #(re-frame/dispatch
|
||||
[:transactions/watch-transaction
|
||||
%
|
||||
{:trigger-fn
|
||||
(fn [_ {:keys [hash type]}]
|
||||
(and (= hash %)
|
||||
(contains? #{:outbound :failed} type)))
|
||||
:on-trigger
|
||||
(fn [{:keys [type]}]
|
||||
(case type
|
||||
:outbound (do (rf/dispatch [:ens/clear-registration %])
|
||||
(rf/dispatch [:ens/save-username custom-domain?
|
||||
username false]))
|
||||
|
||||
:failed (rf/dispatch [:ens/update-ens-tx-state :failure username
|
||||
custom-domain? %])
|
||||
nil))}])]
|
||||
(when-not in-progress?
|
||||
(cond-> {:db (update db :signing/sign assoc :error nil :in-progress? true)}
|
||||
(nil? action) (assoc :signing/send-transaction-fx
|
||||
{:tx-obj tx-obj-to-send
|
||||
:hashed-password hashed-password
|
||||
:cb cb})
|
||||
(= action constants/ens-action-type-register) (assoc :json-rpc/call
|
||||
[{:method "ens_register"
|
||||
:params [chain-id tx-obj-to-send
|
||||
hashed-password username
|
||||
public-key]
|
||||
:on-success
|
||||
#(do
|
||||
(cb (types/clj->json
|
||||
{:result %}))
|
||||
(watch-ens-tx-fn %))
|
||||
:on-error #(cb (types/clj->json
|
||||
{:error %}))}])
|
||||
(= action
|
||||
constants/ens-action-type-set-pub-key) (assoc :json-rpc/call
|
||||
[{:method "ens_setPubKey"
|
||||
:params [chain-id tx-obj-to-send
|
||||
hashed-password username
|
||||
public-key]
|
||||
:on-success #(do (cb (types/clj->json
|
||||
{:result %}))
|
||||
(watch-ens-tx-fn %))
|
||||
:on-error #(cb (types/clj->json
|
||||
{:error
|
||||
%}))}])))))))
|
||||
|
||||
(rf/defn prepare-unconfirmed-transaction
|
||||
[{:keys [db now]} new-tx-hash
|
||||
{:keys [value gasPrice maxFeePerGas maxPriorityFeePerGas gas data to from hash]} symbol amount]
|
||||
(let [token (tokens/symbol->token (:wallet-legacy/all-tokens db) symbol)
|
||||
from (eip55/address->checksum from)
|
||||
;;if there is a hash in the tx object that means we resending transaction
|
||||
old-tx-hash hash
|
||||
gas-price (money/to-fixed (money/bignumber gasPrice))
|
||||
gas-limit (money/to-fixed (money/bignumber gas))
|
||||
tx {:timestamp now
|
||||
:to to
|
||||
:from from
|
||||
:type :pending
|
||||
:hash new-tx-hash
|
||||
:data data
|
||||
:token token
|
||||
:symbol symbol
|
||||
:value (if token
|
||||
(money/to-fixed (money/unit->token amount (:decimals token)))
|
||||
(money/to-fixed (money/bignumber value)))
|
||||
:gas-price gas-price
|
||||
:fee-cap maxFeePerGas
|
||||
:tip-cap maxPriorityFeePerGas
|
||||
:gas-limit gas-limit}]
|
||||
(log/info "[signing] prepare-unconfirmed-transaction" tx)
|
||||
{:db (-> db
|
||||
;;remove old transaction, because we replace it with the new one
|
||||
(update-in [:wallet-legacy :accounts from :transactions] dissoc old-tx-hash)
|
||||
(assoc-in [:wallet-legacy :accounts from :transactions new-tx-hash] tx))}))
|
||||
|
||||
(defn get-method-type
|
||||
[data]
|
||||
(cond
|
||||
(string/starts-with? data constants/method-id-transfer)
|
||||
:transfer
|
||||
(string/starts-with? data constants/method-id-approve)
|
||||
:approve
|
||||
(string/starts-with? data constants/method-id-approve-and-call)
|
||||
:approve-and-call))
|
||||
|
||||
(defn get-transfer-token
|
||||
[db to data]
|
||||
(let [{:keys [decimals] :as token} (tokens/address->token (:wallet-legacy/all-tokens db) to)]
|
||||
(when (and token data (string? data))
|
||||
(when-let [type (get-method-type data)]
|
||||
(let [[address value _] (native-module/decode-parameters
|
||||
(str "0x" (subs data 10))
|
||||
(if (= type :approve-and-call)
|
||||
["address" "uint256" "bytes"]
|
||||
["address" "uint256"]))]
|
||||
(when (and address value)
|
||||
{:to address
|
||||
:contact (get-contact db address)
|
||||
:contract to
|
||||
:approve? (not= type :transfer)
|
||||
:value value
|
||||
:amount (money/to-fixed (money/token->unit value decimals))
|
||||
:token token
|
||||
:symbol (:symbol token)}))))))
|
||||
|
||||
(defn parse-tx-obj
|
||||
[db {:keys [from to value data cancel?] :as tx}]
|
||||
(merge {:from {:address from}
|
||||
:cancel? cancel?
|
||||
:hash (:hash tx)}
|
||||
(if (nil? to)
|
||||
{:contact {:name (i18n/label :t/new-contract)}}
|
||||
(let [eth-value (when value (money/bignumber value))
|
||||
eth-amount (when eth-value (money/to-fixed (money/wei->ether eth-value)))
|
||||
token (get-transfer-token db to data)]
|
||||
(cond
|
||||
(and eth-amount (or (not (.equals ^js (money/bignumber 0) ^js eth-amount)) (nil? data)))
|
||||
{:to to
|
||||
:contact (get-contact db to)
|
||||
:symbol :ETH
|
||||
:value value
|
||||
:amount (str eth-amount)
|
||||
:token (tokens/asset-for (:wallet-legacy/all-tokens db)
|
||||
(chain/get-current-network db)
|
||||
:ETH)}
|
||||
(not (nil? token))
|
||||
token
|
||||
:else
|
||||
{:to to
|
||||
:contact {:address (address/normalized-hex to)}})))))
|
||||
|
||||
(defn prepare-tx
|
||||
[db {{:keys [data gas gasPrice maxFeePerGas maxPriorityFeePerGas] :as tx-obj} :tx-obj :as tx}]
|
||||
(merge
|
||||
tx
|
||||
(parse-tx-obj db tx-obj)
|
||||
{:data data
|
||||
:gas (when gas (money/bignumber gas))
|
||||
:gasPrice (when gasPrice (money/bignumber gasPrice))
|
||||
:maxFeePerGas (when maxFeePerGas
|
||||
(money/bignumber maxFeePerGas))
|
||||
:maxPriorityFeePerGas (when maxPriorityFeePerGas
|
||||
(money/bignumber maxPriorityFeePerGas))}))
|
||||
|
||||
(defn hex-to-utf8
|
||||
[s]
|
||||
(let [utf8 (native-module/hex-to-utf8 s)]
|
||||
(if (empty? utf8)
|
||||
nil
|
||||
utf8)))
|
||||
|
||||
(defn hex->text
|
||||
"Converts a hexstring to UTF8 text."
|
||||
[data]
|
||||
(or (hex-to-utf8 data) data))
|
||||
|
||||
(rf/defn show-sign
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [{:signing/keys [queue]} db
|
||||
{{:keys [gas gasPrice maxFeePerGas] :as tx-obj} :tx-obj
|
||||
{:keys [data typed? pinless?] :as message} :message
|
||||
:as tx}
|
||||
(last queue)
|
||||
keycard-multiaccount? (boolean (get-in db [:profile/profile :keycard-pairing]))
|
||||
wallet-set-up-passed? (get-in db [:profile/profile :wallet-set-up-passed?])]
|
||||
(if message
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (assoc db
|
||||
:signing/queue (drop-last queue)
|
||||
:signing/tx tx
|
||||
:signing/sign {:type (cond pinless? :pinless
|
||||
keycard-multiaccount? :keycard
|
||||
:else :password)
|
||||
:formatted-data (if typed?
|
||||
(types/js->pretty-json
|
||||
(types/json->js data))
|
||||
(hex->text data))
|
||||
:keycard-step (when pinless? :connect)})
|
||||
:show-signing-sheet nil}
|
||||
#(when-not wallet-set-up-passed?
|
||||
{:dispatch-later [{:dispatch [:show-popover {:view :signing-phrase}] :ms 200}]})
|
||||
(when pinless?
|
||||
(keycard.card/start-nfc {:on-success #(re-frame/dispatch [:keycard.callback/start-nfc-success])
|
||||
:on-failure #(re-frame/dispatch
|
||||
[:keycard.callback/start-nfc-failure])})
|
||||
(signing.keycard/hash-message
|
||||
{:data data
|
||||
:typed? true
|
||||
:on-completed #(re-frame/dispatch [:keycard/store-hash-and-sign-typed %])})))
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (assoc db
|
||||
:signing/queue (drop-last queue)
|
||||
:signing/tx (prepare-tx db tx))
|
||||
:show-signing-sheet nil
|
||||
:dismiss-keyboard nil}
|
||||
#(when-not wallet-set-up-passed?
|
||||
{:dispatch-later [{:dispatch [:show-popover {:view :signing-phrase}] :ms 200}]})
|
||||
|
||||
#(when-not gas
|
||||
{:db (assoc-in (:db %) [:signing/edit-fee :gas-loading?] true)
|
||||
:signing/update-estimated-gas {:obj (-> tx-obj
|
||||
(dissoc :gasPrice)
|
||||
(update :maxFeePerGas
|
||||
(fn [fee]
|
||||
(some-> fee
|
||||
money/bignumber
|
||||
(money/mul 2)
|
||||
money/to-hex))))
|
||||
:success-event :signing/update-estimated-gas-success
|
||||
:error-event :signing/update-estimated-gas-error}})
|
||||
(fn [cofx]
|
||||
{:db (assoc-in (:db cofx) [:signing/edit-fee :gas-price-loading?] true)
|
||||
:signing/update-gas-price
|
||||
{:success-callback #(re-frame/dispatch
|
||||
[:wallet-legacy.send/update-gas-price-success :signing/tx % tx-obj])
|
||||
:error-callback #(re-frame/dispatch [:signing/update-gas-price-error %])
|
||||
:network-id (get-in (chain/current-network db)
|
||||
[:config :NetworkId])}})))))
|
||||
|
||||
(rf/defn check-queue
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [{:signing/keys [tx queue]} db]
|
||||
(when (and (not tx) (seq queue))
|
||||
(show-sign cofx))))
|
||||
|
||||
(rf/defn send-transaction-message
|
||||
{:events [:sign/send-transaction-message]}
|
||||
[cofx chat-id value contract transaction-hash signature]
|
||||
{:json-rpc/call [{:method "wakuext_sendTransaction"
|
||||
;; We make sure `value` is serialized as string, and not as an integer or
|
||||
;; big-int
|
||||
:params [chat-id (str value) contract transaction-hash
|
||||
(or (:result (types/json->clj signature))
|
||||
(address/normalized-hex signature))]
|
||||
:js-response true
|
||||
:on-success
|
||||
#(re-frame/dispatch [:transport/message-sent %])}]})
|
||||
|
||||
(rf/defn send-accept-request-transaction-message
|
||||
{:events [:sign/send-accept-transaction-message]}
|
||||
[cofx message-id transaction-hash signature]
|
||||
{:json-rpc/call [{:method "wakuext_acceptRequestTransaction"
|
||||
:params [transaction-hash message-id
|
||||
(or (:result (types/json->clj signature))
|
||||
(address/normalized-hex signature))]
|
||||
:js-response true
|
||||
:on-success
|
||||
#(re-frame/dispatch [:transport/message-sent %])}]})
|
||||
|
||||
(rf/defn transaction-result
|
||||
[{:keys [db] :as cofx} result tx-obj]
|
||||
(let [{:keys [on-result symbol amount from]} (get db :signing/tx)]
|
||||
(rf/merge cofx
|
||||
{:db (dissoc db :signing/tx :signing/sign)
|
||||
:signing/show-transaction-result nil}
|
||||
(prepare-unconfirmed-transaction result tx-obj symbol amount)
|
||||
(check-queue)
|
||||
#(when on-result
|
||||
{:dispatch (conj on-result result)}))))
|
||||
|
||||
(rf/defn command-transaction-result
|
||||
[{:keys [db] :as cofx} transaction-hash hashed-password
|
||||
{:keys [message-id chat-id from] :as tx-obj}]
|
||||
(let [{:keys [on-result symbol amount contract value]} (get db :signing/tx)
|
||||
data (str (get-in db [:profile/profile :public-key])
|
||||
(subs transaction-hash 2))]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (dissoc db :signing/tx :signing/sign)}
|
||||
(if (keycard.common/keycard-multiaccount? db)
|
||||
(signing.keycard/hash-message
|
||||
{:data data
|
||||
:on-completed
|
||||
(fn [hash]
|
||||
(re-frame/dispatch
|
||||
[:keycard/sign-message
|
||||
{:tx-hash transaction-hash
|
||||
:message-id message-id
|
||||
:chat-id chat-id
|
||||
:value value
|
||||
:contract contract
|
||||
:data data}
|
||||
hash]))})
|
||||
(fn [_]
|
||||
{:signing.fx/sign-message
|
||||
{:params {:data data
|
||||
:password hashed-password
|
||||
:account from}
|
||||
:on-completed
|
||||
(fn [res]
|
||||
(re-frame/dispatch
|
||||
(if message-id
|
||||
[:sign/send-accept-transaction-message message-id transaction-hash res]
|
||||
[:sign/send-transaction-message
|
||||
chat-id value contract transaction-hash res])))}
|
||||
:signing/show-transaction-result nil}))
|
||||
(prepare-unconfirmed-transaction transaction-hash tx-obj symbol amount)
|
||||
(check-queue)
|
||||
#(when on-result
|
||||
{:dispatch (conj on-result transaction-hash)}))))
|
||||
|
||||
(rf/defn transaction-error
|
||||
[{:keys [db]} {:keys [code message]}]
|
||||
(let [on-error (get-in db [:signing/tx :on-error])]
|
||||
(if (= code constants/send-transaction-err-decrypt)
|
||||
;;wrong password
|
||||
{:db (assoc-in db [:signing/sign :error] (i18n/label :t/wrong-password))}
|
||||
(merge {:db (dissoc db :signing/tx :signing/sign)
|
||||
:signing/show-transaction-error message}
|
||||
(when on-error
|
||||
{:dispatch (conj on-error message)})))))
|
||||
|
||||
(rf/defn dissoc-signing-db-entries-and-check-queue
|
||||
{:events [:signing/dissoc-entries-and-check-queue]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(rf/merge cofx
|
||||
{:db (dissoc db :signing/tx :signing/sign)}
|
||||
check-queue))
|
||||
|
||||
(rf/defn sign-message-completed
|
||||
{:events [:signing/sign-message-completed]}
|
||||
[{:keys [db] :as cofx} result]
|
||||
(let [{:keys [result error]} (types/json->clj result)
|
||||
on-result (get-in db [:signing/tx :on-result])]
|
||||
(if error
|
||||
{:db (update db
|
||||
:signing/sign
|
||||
assoc
|
||||
:error (if (= 5 (:code error))
|
||||
(i18n/label :t/wrong-password)
|
||||
(:message error))
|
||||
:in-progress? false)}
|
||||
(rf/merge cofx
|
||||
(when-not (= (-> db :signing/sign :type) :pinless)
|
||||
(dissoc-signing-db-entries-and-check-queue))
|
||||
#(when (= (-> db :signing/sign :type) :pinless)
|
||||
{:dispatch-later [{:ms 3000
|
||||
:dispatch [:signing/dissoc-entries-and-check-queue]}]})
|
||||
#(when on-result
|
||||
{:dispatch (conj on-result result)})))))
|
||||
|
||||
(rf/defn transaction-completed
|
||||
{:events [:signing/transaction-completed]
|
||||
:interceptors [(re-frame/inject-cofx :random-id-generator)]}
|
||||
[cofx response tx-obj hashed-password]
|
||||
(log/info "transaction-completed" "tx-obj" tx-obj "response" response)
|
||||
(let [cofx-in-progress-false (assoc-in cofx [:db :signing/sign :in-progress?] false)
|
||||
{:keys [result error]} (types/json->clj response)]
|
||||
(if error
|
||||
(transaction-error cofx-in-progress-false error)
|
||||
(if (:command? tx-obj)
|
||||
(command-transaction-result cofx-in-progress-false result hashed-password tx-obj)
|
||||
(transaction-result cofx-in-progress-false result tx-obj)))))
|
||||
|
||||
(rf/defn discard
|
||||
"Discrad transaction signing"
|
||||
{:events [:signing.ui/cancel-is-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [{:keys [on-error]} (get-in db [:signing/tx])]
|
||||
(rf/merge cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :pin :status] nil)
|
||||
(dissoc :signing/tx :signing/sign))
|
||||
:hide-signing-sheet nil}
|
||||
(check-queue)
|
||||
(keycard.common/hide-connection-sheet)
|
||||
(keycard.common/clear-pin)
|
||||
#(when on-error
|
||||
{:dispatch (conj on-error "transaction was cancelled by user")}))))
|
||||
|
||||
(defn normalize-tx-obj
|
||||
[_db tx]
|
||||
(update-in tx [:tx-obj :from] #(eip55/address->checksum %)))
|
||||
|
||||
(rf/defn sign
|
||||
"Signing transaction or message, shows signing sheet
|
||||
tx
|
||||
{:tx-obj - transaction object to send https://github.com/ethereum/wiki/wiki/JavaScript-API#parameters-25
|
||||
:message {:address :data :typed? } - message data to sign
|
||||
:on-result - re-frame event vector
|
||||
:on-error - re-frame event vector}"
|
||||
{:events [:signing.ui/sign]}
|
||||
[{:keys [db] :as cofx} tx]
|
||||
(rf/merge cofx
|
||||
{:db (update db :signing/queue conj (normalize-tx-obj db tx))}
|
||||
(check-queue)))
|
||||
|
||||
(rf/defn sign-transaction-button-clicked-from-chat
|
||||
{:events [:wallet-legacy.ui/sign-transaction-button-clicked-from-chat]}
|
||||
[{:keys [db] :as cofx} {:keys [to amount from token]}]
|
||||
(let [{:keys [symbol address]} token
|
||||
amount-hex (str "0x" (native-module/number-to-hex amount))
|
||||
to-norm (address/normalized-hex (if (string? to) to (:address to)))
|
||||
from-address (:address from)
|
||||
identity (:current-chat-id db)
|
||||
db (dissoc db :wallet-legacy/prepare-transaction :signing/edit-fee)]
|
||||
(if to-norm
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db db}
|
||||
(sign {:tx-obj (if (= symbol :ETH)
|
||||
{:to to-norm
|
||||
:from from-address
|
||||
:chat-id identity
|
||||
:command? true
|
||||
:value amount-hex}
|
||||
{:to (address/normalized-hex address)
|
||||
:from from-address
|
||||
:chat-id identity
|
||||
:command? true
|
||||
:data (native-module/encode-transfer to-norm amount-hex)})}))
|
||||
{:db db
|
||||
:json-rpc/call
|
||||
[{:method "wakuext_requestAddressForTransaction"
|
||||
:params [(:current-chat-id db)
|
||||
from-address
|
||||
amount
|
||||
(when-not (= symbol :ETH)
|
||||
address)]
|
||||
:js-response true
|
||||
:on-success #(re-frame/dispatch [:transport/message-sent %])}]})))
|
||||
|
||||
(rf/defn sign-transaction-button-clicked-from-request
|
||||
{:events [:wallet-legacy.ui/sign-transaction-button-clicked-from-request]}
|
||||
[{:keys [db] :as cofx} {:keys [amount from token]}]
|
||||
(let [{:keys [request-parameters chat-id]} (:wallet-legacy/prepare-transaction db)
|
||||
{:keys [symbol address]} token
|
||||
amount-hex (str "0x" (native-module/number-to-hex amount))
|
||||
to-norm (:address request-parameters)
|
||||
from-address (:address from)]
|
||||
(rf/merge cofx
|
||||
{:db (dissoc db :wallet-legacy/prepare-transaction :signing/edit-fee)}
|
||||
(fn [cofx]
|
||||
(sign
|
||||
cofx
|
||||
{:tx-obj (if (= symbol :ETH)
|
||||
{:to to-norm
|
||||
:from from-address
|
||||
:message-id (:id request-parameters)
|
||||
:chat-id chat-id
|
||||
:command? true
|
||||
:value amount-hex}
|
||||
{:to (address/normalized-hex address)
|
||||
:from from-address
|
||||
:command? true
|
||||
:message-id (:id request-parameters)
|
||||
:chat-id chat-id
|
||||
:data (native-module/encode-transfer to-norm amount-hex)})})))))
|
||||
|
||||
(rf/defn sign-transaction-button-clicked
|
||||
{:events [:wallet-legacy.ui/sign-transaction-button-clicked]}
|
||||
[{:keys [db] :as cofx} {:keys [to amount from token gas gasPrice maxFeePerGas maxPriorityFeePerGas]}]
|
||||
(let [{:keys [symbol address]} token
|
||||
amount-hex (str "0x" (native-module/number-to-hex amount))
|
||||
to-norm (address/normalized-hex (if (string? to) to (:address to)))
|
||||
from-address (:address from)]
|
||||
(rf/merge cofx
|
||||
{:db (dissoc db :wallet-legacy/prepare-transaction :signing/edit-fee)}
|
||||
(sign
|
||||
{:tx-obj (merge (if (eip1559/sync-enabled?)
|
||||
{:from from-address
|
||||
:gas gas
|
||||
;; per eip1559
|
||||
:maxFeePerGas maxFeePerGas
|
||||
:maxPriorityFeePerGas maxPriorityFeePerGas}
|
||||
{:from from-address
|
||||
;;gas and gasPrice from qr (eip681)
|
||||
:gas gas
|
||||
:gasPrice gasPrice})
|
||||
(if (= symbol :ETH)
|
||||
{:to to-norm
|
||||
:value amount-hex}
|
||||
{:to (address/normalized-hex address)
|
||||
:data (native-module/encode-transfer to-norm amount-hex)}))}))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:signing/get-transaction-by-hash-fx
|
||||
(fn [[tx-hash handler]]
|
||||
(json-rpc/call
|
||||
{:method "eth_getTransactionByHash"
|
||||
:params [tx-hash]
|
||||
:on-success handler})))
|
||||
|
||||
(rf/defn cancel-transaction-pressed
|
||||
{:events [:signing.ui/cancel-transaction-pressed]}
|
||||
[_ hash]
|
||||
{:signing/get-transaction-by-hash-fx [hash #(re-frame/dispatch [:signing/cancel-transaction %])]})
|
||||
|
||||
(rf/defn increase-gas-pressed
|
||||
{:events [:signing.ui/increase-gas-pressed]}
|
||||
[_ hash]
|
||||
{:signing/get-transaction-by-hash-fx [hash #(re-frame/dispatch [:signing/increase-gas %])]})
|
||||
|
||||
(rf/defn cancel-transaction
|
||||
{:events [:signing/cancel-transaction]}
|
||||
[cofx {:keys [from nonce hash]}]
|
||||
(when (and from nonce hash)
|
||||
(sign cofx
|
||||
{:tx-obj {:from from
|
||||
:to from
|
||||
:nonce nonce
|
||||
:value "0x0"
|
||||
:cancel? true
|
||||
:hash hash}})))
|
||||
|
||||
(rf/defn increase-gas
|
||||
{:events [:signing/increase-gas]}
|
||||
[cofx {:keys [from nonce] :as tx}]
|
||||
(when (and from nonce)
|
||||
(sign cofx
|
||||
{:tx-obj (-> tx
|
||||
(select-keys [:from :to :value :input :gas :nonce :hash])
|
||||
(set/rename-keys {:input :data}))})))
|
||||
@@ -1,64 +0,0 @@
|
||||
(ns legacy.status-im.signing.core-test
|
||||
(:require
|
||||
[cljs.test :refer-macros [deftest is testing]]
|
||||
[legacy.status-im.signing.core :as signing]
|
||||
[native-module.core :as native-module]))
|
||||
|
||||
(deftest signing-test
|
||||
(testing "showing sheet"
|
||||
(let [to "0x2f88d65f3cb52605a54a833ae118fb1363acccd2"
|
||||
contract "0xc55cf4b03948d7ebc8b9e8bad92643703811d162"
|
||||
amount1-hex (str "0x" (native-module/number-to-hex "10000000000000000000"))
|
||||
amount2-hex (str "0x" (native-module/number-to-hex "100000000000000000000"))
|
||||
data (native-module/encode-transfer to amount2-hex)
|
||||
first-tx {:tx-obj {:to to
|
||||
:from nil
|
||||
:value amount1-hex}}
|
||||
second-tx {:tx-obj {:to contract
|
||||
:from nil
|
||||
:data data}}
|
||||
sign-first (signing/sign {:db {}} first-tx)
|
||||
sign-second (signing/sign sign-first second-tx)]
|
||||
(testing "after fist transaction"
|
||||
(testing "signing in progress"
|
||||
(is (get-in sign-first [:db :signing/tx])))
|
||||
(testing "qieue is empty"
|
||||
(is (= (get-in sign-first [:db :signing/queue]) '())))
|
||||
(testing "first tx object is parsed"
|
||||
(is (= (dissoc (get-in sign-first [:db :signing/tx]) :token :hash :cancel?)
|
||||
(merge first-tx
|
||||
{:from {:address nil}
|
||||
:gas nil
|
||||
:gasPrice nil
|
||||
:maxFeePerGas nil
|
||||
:maxPriorityFeePerGas nil
|
||||
:data nil
|
||||
:to to
|
||||
:contact {:address to}
|
||||
:symbol :ETH
|
||||
:value "0x8ac7230489e80000"
|
||||
:amount "10"})))))
|
||||
(testing "after second transaction"
|
||||
(testing "signing still in progress"
|
||||
(is (get-in sign-second [:db :signing/tx])))
|
||||
(testing "queue is not empty, second tx in queue"
|
||||
(is (= (get-in sign-second [:db :signing/queue]) (list second-tx))))
|
||||
(testing "check queue does nothing"
|
||||
(is (not (signing/check-queue sign-second))))
|
||||
(let [first-discarded (signing/check-queue (update sign-second :db dissoc :signing/tx))]
|
||||
(testing "after first transaction discarded"
|
||||
(testing "signing still in progress"
|
||||
(is (get-in first-discarded [:db :signing/tx])))
|
||||
(testing "qieue is empty"
|
||||
(is (= (get-in first-discarded [:db :signing/queue]) '())))
|
||||
(testing "second tx object is parsed"
|
||||
(is (= (dissoc (get-in first-discarded [:db :signing/tx]) :token :hash :cancel?)
|
||||
(merge second-tx
|
||||
{:from {:address nil}
|
||||
:gas nil
|
||||
:gasPrice nil
|
||||
:maxFeePerGas nil
|
||||
:maxPriorityFeePerGas nil
|
||||
:data data
|
||||
:to contract
|
||||
:contact {:address contract}}))))))))))
|
||||
@@ -1,55 +0,0 @@
|
||||
(ns legacy.status-im.signing.eip1559
|
||||
(:require
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.common.json-rpc.events :as json-rpc]))
|
||||
|
||||
(defonce london-activated? (atom false))
|
||||
|
||||
(defn london-is-definitely-activated
|
||||
[network-id]
|
||||
(contains? #{"1" "3"} network-id))
|
||||
|
||||
(defn on-block
|
||||
[callback header]
|
||||
(let [activated? (contains? header :baseFeePerGas)]
|
||||
(reset! london-activated? activated?)
|
||||
(callback activated?)))
|
||||
|
||||
(defn check-activation
|
||||
[callback]
|
||||
(json-rpc/call
|
||||
{:method "eth_getBlockByNumber"
|
||||
:params ["latest" false]
|
||||
:on-success (partial on-block callback)
|
||||
:on-error #(callback nil)}))
|
||||
|
||||
(defn sync-enabled? [] @london-activated?)
|
||||
|
||||
(defn enabled?
|
||||
([] @london-activated?)
|
||||
([network-id enabled-callback disabled-callback]
|
||||
(let [definitely-activated? (london-is-definitely-activated network-id)
|
||||
enabled-callback (or enabled-callback #())
|
||||
disabled-callback (or disabled-callback #())]
|
||||
(cond
|
||||
definitely-activated?
|
||||
(do
|
||||
(reset! london-activated? true)
|
||||
(enabled-callback))
|
||||
|
||||
(not definitely-activated?)
|
||||
(check-activation
|
||||
(fn [activated?]
|
||||
(if activated?
|
||||
(enabled-callback)
|
||||
(disabled-callback))))
|
||||
|
||||
:else
|
||||
(do
|
||||
(reset! london-activated? false)
|
||||
(disabled-callback))))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:check-eip1559-activation
|
||||
(fn [network-id]
|
||||
(enabled? network-id nil nil)))
|
||||
@@ -1,430 +0,0 @@
|
||||
(ns legacy.status-im.signing.gas
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.bottom-sheet.events :as bottom-sheet]
|
||||
[legacy.status-im.popover.core :as popover]
|
||||
[legacy.status-im.signing.eip1559 :as eip1559]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.common.json-rpc.events :as json-rpc]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.ethereum.chain :as chain]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.money :as money]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def min-gas-price-wei ^js (money/bignumber 1))
|
||||
|
||||
(def min-gas-units ^js (money/bignumber 21000))
|
||||
|
||||
(defmulti get-error-label-key (fn [type _] type))
|
||||
|
||||
(defmethod get-error-label-key :gasPrice
|
||||
[_ value]
|
||||
(cond
|
||||
(not value) :t/invalid-number
|
||||
(.lt ^js (money/->wei :gwei value) min-gas-price-wei) :t/wallet-send-min-wei
|
||||
(-> (money/->wei :gwei value) .decimalPlaces pos?) :t/invalid-number))
|
||||
|
||||
(defmethod get-error-label-key :gas
|
||||
[_ ^js value]
|
||||
(cond
|
||||
(not value) :t/invalid-number
|
||||
(.lt value min-gas-units) :t/wallet-send-min-units
|
||||
(-> value .decimalPlaces pos?) :t/invalid-number))
|
||||
|
||||
(defmethod get-error-label-key :default
|
||||
[_ value]
|
||||
(when (or (not value)
|
||||
(<= value 0))
|
||||
:t/invalid-number))
|
||||
|
||||
(defn calculate-max-fee
|
||||
[^js gas ^js gasPrice]
|
||||
(if (and gas gasPrice)
|
||||
(money/to-fixed (money/wei->ether (.times gas gasPrice)))
|
||||
"0"))
|
||||
|
||||
(defn edit-max-fee
|
||||
[edit]
|
||||
(let [gasPrice (get-in edit [:gasPrice :value-number])
|
||||
gas (get-in edit [:gas :value-number])]
|
||||
(assoc edit :max-fee (calculate-max-fee gas gasPrice))))
|
||||
|
||||
(defn build-edit
|
||||
"Takes the previous edit, either :gas or :gas-price and a value as string.
|
||||
Wei for gas, and gwei for gas price.
|
||||
Validates them and sets max fee"
|
||||
[edit-value k value]
|
||||
(let [^js bn-value (money/bignumber value)
|
||||
error-label-key (get-error-label-key k bn-value)
|
||||
data (if error-label-key
|
||||
{:value value
|
||||
:max-fee 0
|
||||
:error (i18n/label error-label-key)}
|
||||
{:value value
|
||||
:value-number (if (= :gasPrice k)
|
||||
(money/->wei :gwei bn-value)
|
||||
bn-value)})]
|
||||
(-> edit-value
|
||||
(assoc k data)
|
||||
edit-max-fee)))
|
||||
|
||||
;; TODO(rasom): this number is almost arbitrary, I was able to sent txs with
|
||||
;; 0.2 gwei tip, so it should be revisited lately
|
||||
(def minimum-priority-fee-gwei
|
||||
(money/bignumber 0.3))
|
||||
|
||||
(defn get-suggested-tip
|
||||
[latest-priority-fee]
|
||||
(money/bignumber latest-priority-fee))
|
||||
|
||||
(defn get-minimum-priority-fee
|
||||
[latest-priority-fee]
|
||||
(let [latest-priority-fee-bn (money/bignumber latest-priority-fee)
|
||||
suggested-tip-gwei (money/wei->gwei (get-suggested-tip latest-priority-fee-bn))]
|
||||
(if (money/greater-than minimum-priority-fee-gwei suggested-tip-gwei)
|
||||
(money/div suggested-tip-gwei 2)
|
||||
minimum-priority-fee-gwei)))
|
||||
|
||||
(defn get-suggestions-range
|
||||
[latest-priority-fee]
|
||||
(let [current-minimum-fee (get-minimum-priority-fee latest-priority-fee)]
|
||||
[(if (money/greater-than minimum-priority-fee-gwei current-minimum-fee)
|
||||
current-minimum-fee
|
||||
minimum-priority-fee-gwei)
|
||||
(money/wei->gwei (money/bignumber latest-priority-fee))]))
|
||||
|
||||
(def average-priority-fee
|
||||
(money/wei->gwei (money/->wei :gwei 1.5)))
|
||||
|
||||
(defn validate-max-fee
|
||||
[db]
|
||||
(let [{:keys [maxFeePerGas maxPriorityFeePerGas]} (get db :signing/edit-fee)
|
||||
latest-base-fee (money/wei->gwei
|
||||
(money/bignumber
|
||||
(get db :wallet-legacy/current-base-fee)))
|
||||
fee-error (cond
|
||||
(or (:error maxFeePerGas)
|
||||
(:error maxPriorityFeePerGas))
|
||||
nil
|
||||
|
||||
(money/greater-than latest-base-fee
|
||||
(:value-number maxFeePerGas))
|
||||
{:label (i18n/label :t/below-base-fee)
|
||||
:severity :error})]
|
||||
(if fee-error
|
||||
(assoc-in db [:signing/edit-fee :maxFeePerGas :fee-error] fee-error)
|
||||
(update-in db [:signing/edit-fee :maxFeePerGas] dissoc :fee-error))))
|
||||
|
||||
(defn validate-max-priority-fee
|
||||
[db]
|
||||
(let [{:keys [maxPriorityFeePerGas]} (get db :signing/edit-fee)
|
||||
latest-priority-fee (get db :wallet-legacy/current-priority-fee)
|
||||
fee-error (cond
|
||||
(:error maxPriorityFeePerGas)
|
||||
nil
|
||||
|
||||
(money/greater-than (get-minimum-priority-fee
|
||||
(money/div
|
||||
(money/wei->gwei (money/bignumber
|
||||
latest-priority-fee))
|
||||
2))
|
||||
(:value-number maxPriorityFeePerGas))
|
||||
{:label (i18n/label :t/low-tip)
|
||||
:severity :error}
|
||||
|
||||
#_(money/greater-than average-priority-fee
|
||||
(:value-number maxPriorityFeePerGas))
|
||||
#_{:label (i18n/label :t/lower-than-average-tip)
|
||||
:severity :error})]
|
||||
(if fee-error
|
||||
(assoc-in db [:signing/edit-fee :maxPriorityFeePerGas :fee-error] fee-error)
|
||||
(update-in db [:signing/edit-fee :maxPriorityFeePerGas] dissoc :fee-error))))
|
||||
|
||||
(defn validate-eip1559-fees
|
||||
[db]
|
||||
(if (eip1559/sync-enabled?)
|
||||
(reduce
|
||||
(fn [acc f]
|
||||
(f acc))
|
||||
db
|
||||
[validate-max-fee
|
||||
validate-max-priority-fee])
|
||||
db))
|
||||
|
||||
(rf/defn edit-value
|
||||
{:events [:signing.edit-fee.ui/edit-value]}
|
||||
[{:keys [db]} key value]
|
||||
{:db (-> db
|
||||
(assoc-in [:signing/edit-fee :selected-fee-option] :custom)
|
||||
(update :signing/edit-fee build-edit key value)
|
||||
validate-eip1559-fees)})
|
||||
|
||||
(defn get-fee-options
|
||||
[tip slow normal fast]
|
||||
(let [tip-bn (money/bignumber tip)
|
||||
normal-bn (money/bignumber normal)
|
||||
slow-bn (money/bignumber slow)
|
||||
fast-bn (money/bignumber fast)]
|
||||
{:normal
|
||||
{:base-fee normal-bn
|
||||
:tip tip-bn
|
||||
:fee (money/add normal-bn tip-bn)}
|
||||
:slow
|
||||
{:base-fee slow-bn
|
||||
:tip tip-bn
|
||||
:fee (money/add slow-bn tip-bn)}
|
||||
:fast
|
||||
{:base-fee fast-bn
|
||||
:tip tip-bn
|
||||
:fee (money/add fast-bn tip-bn)}}))
|
||||
|
||||
(rf/defn set-fee-option
|
||||
{:events [:signing.edit-fee.ui/set-option]}
|
||||
[{:keys [db] :as cofx} option]
|
||||
(let [tip (get db :wallet-legacy/current-priority-fee)
|
||||
slow (get db :wallet-legacy/slow-base-fee)
|
||||
normal (get db :wallet-legacy/normal-base-fee)
|
||||
fast (get db :wallet-legacy/fast-base-fee)
|
||||
{:keys [fee tip]} (get (get-fee-options tip slow normal fast) option)]
|
||||
{:db (-> db
|
||||
(assoc-in [:signing/edit-fee :selected-fee-option] option)
|
||||
(update :signing/edit-fee
|
||||
build-edit
|
||||
:maxFeePerGas (money/wei->gwei fee))
|
||||
(update :signing/edit-fee
|
||||
build-edit
|
||||
:maxPriorityFeePerGas (money/wei->gwei tip)))}))
|
||||
|
||||
(rf/defn set-priority-fee
|
||||
{:events [:signing.edit-fee.ui/set-priority-fee]}
|
||||
[{:keys [db]} value]
|
||||
(let [{:keys [maxFeePerGas maxPriorityFeePerGas]}
|
||||
(get db :signing/edit-fee)
|
||||
latest-base-fee (get db :wallet-legacy/current-base-fee)
|
||||
max-fee-value (:value-number maxFeePerGas)
|
||||
max-priority-fee-value (:value-number maxPriorityFeePerGas)
|
||||
new-value (money/bignumber value)
|
||||
fee-without-tip (money/sub max-fee-value max-priority-fee-value)
|
||||
base-fee (money/wei->gwei (money/bignumber latest-base-fee))
|
||||
new-max-fee-value
|
||||
(money/to-fixed
|
||||
(if (money/greater-than base-fee fee-without-tip)
|
||||
(money/add new-value base-fee)
|
||||
(money/add new-value fee-without-tip)))]
|
||||
{:db (-> db
|
||||
(update :signing/edit-fee build-edit :maxPriorityFeePerGas value)
|
||||
(update :signing/edit-fee build-edit :maxFeePerGas new-max-fee-value)
|
||||
validate-eip1559-fees)}))
|
||||
|
||||
(rf/defn update-estimated-gas-success
|
||||
{:events [:signing/update-estimated-gas-success]}
|
||||
[{db :db} gas]
|
||||
(when (contains? db :signing/tx)
|
||||
{:db (-> db
|
||||
(assoc-in [:signing/tx :gas] gas)
|
||||
(assoc-in [:signing/edit-fee :gas-loading?] false))}))
|
||||
|
||||
(rf/defn update-gas-price-success
|
||||
{:events [:signing/update-gas-price-success]}
|
||||
[{db :db} price]
|
||||
(if (eip1559/sync-enabled?)
|
||||
(let [{:keys [normal-base-fee max-priority-fee]} price
|
||||
max-priority-fee-bn (money/with-precision (get-suggested-tip
|
||||
max-priority-fee)
|
||||
0)]
|
||||
{:db (-> db
|
||||
(assoc-in [:signing/tx :maxFeePerGas]
|
||||
(money/to-hex (money/add max-priority-fee-bn
|
||||
(money/bignumber normal-base-fee))))
|
||||
(assoc-in [:signing/tx :maxPriorityFeePerGas]
|
||||
(money/to-hex max-priority-fee-bn))
|
||||
(assoc-in [:signing/edit-fee :gas-price-loading?] false))})
|
||||
{:db (-> db
|
||||
(assoc-in [:signing/tx :gasPrice] price)
|
||||
(assoc-in [:signing/edit-fee :gas-price-loading?] false))}))
|
||||
|
||||
(rf/defn update-estimated-gas-error
|
||||
{:events [:signing/update-estimated-gas-error]}
|
||||
[{db :db} {:keys [message]}]
|
||||
(log/warn "signing/update-estimated-gas-error" message)
|
||||
{:db (-> db
|
||||
(assoc-in [:signing/edit-fee :gas-loading?] false)
|
||||
(assoc-in [:signing/tx :gas-error-message] message))})
|
||||
|
||||
(rf/defn update-gas-price-error
|
||||
{:events [:signing/update-gas-price-error]}
|
||||
[{db :db}]
|
||||
{:db (assoc-in db [:signing/edit-fee :gas-price-loading?] false)})
|
||||
|
||||
(rf/defn open-fee-sheet
|
||||
{:events [:signing.ui/open-fee-sheet]}
|
||||
[{{:signing/keys [tx] :as db} :db :as cofx} sheet-opts]
|
||||
(let [{:keys [gas gasPrice maxFeePerGas maxPriorityFeePerGas]} tx
|
||||
max-fee (money/to-fixed (money/wei->gwei
|
||||
maxFeePerGas))
|
||||
max-priority-fee (money/to-fixed (money/wei->gwei
|
||||
maxPriorityFeePerGas))
|
||||
edit-fee (reduce
|
||||
(partial apply build-edit)
|
||||
{:selected-fee-option
|
||||
(get-in db
|
||||
[:signing/edit-fee
|
||||
:selected-fee-option])}
|
||||
{:gas (money/to-fixed gas)
|
||||
:gasPrice (money/to-fixed
|
||||
(money/wei->gwei gasPrice))
|
||||
:maxFeePerGas max-fee
|
||||
:maxPriorityFeePerGas
|
||||
max-priority-fee})]
|
||||
(rf/merge cofx
|
||||
{:db (assoc db :signing/edit-fee edit-fee)}
|
||||
(bottom-sheet/show-bottom-sheet-old {:view sheet-opts}))))
|
||||
|
||||
(rf/defn submit-fee
|
||||
{:events [:signing.edit-fee.ui/submit]}
|
||||
[{{:signing/keys [edit-fee] :as db} :db :as cofx} force?]
|
||||
(let [{:keys [gas gasPrice maxFeePerGas maxPriorityFeePerGas]} edit-fee
|
||||
errors?
|
||||
(keep
|
||||
(fn [[k {:keys [fee-error]}]]
|
||||
(when (= :error (:severity fee-error))
|
||||
[k fee-error]))
|
||||
edit-fee)]
|
||||
(if (and (seq errors?)
|
||||
(not force?))
|
||||
(popover/show-popover cofx {:view :fees-warning})
|
||||
(rf/merge cofx
|
||||
{:db (update db
|
||||
:signing/tx assoc
|
||||
:gas (:value-number gas)
|
||||
:gasPrice (:value-number gasPrice)
|
||||
:maxFeePerGas (money/->wei :gwei (:value-number maxFeePerGas))
|
||||
:maxPriorityFeePerGas (money/->wei :gwei
|
||||
(:value-number maxPriorityFeePerGas)))}
|
||||
(bottom-sheet/hide-bottom-sheet-old)))))
|
||||
|
||||
(rf/defn submit-nonce
|
||||
{:events [:signing.nonce/submit]}
|
||||
[{db :db :as cofx} nonce]
|
||||
(rf/merge cofx
|
||||
{:db (assoc-in db [:signing/tx :nonce] (if (string/blank? nonce) nil nonce))}
|
||||
(bottom-sheet/hide-bottom-sheet-old)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:signing/update-gas-price
|
||||
(fn [{:keys [success-callback error-callback network-id] :as params}]
|
||||
(eip1559/enabled?
|
||||
network-id
|
||||
(fn []
|
||||
(json-rpc/call
|
||||
{:method "eth_feeHistory"
|
||||
;; NOTE(rasom): We don't need `reward` atm but if the last parameter is
|
||||
;; `nil` request fails on some chains (particularly on xDai).
|
||||
:params [101 "latest" [100]]
|
||||
:on-success #(re-frame/dispatch [::header-fetched
|
||||
(assoc params :fee-history %)])}))
|
||||
(fn []
|
||||
(json-rpc/call
|
||||
{:method "eth_gasPrice"
|
||||
:on-success #(success-callback (money/bignumber %))
|
||||
:on-error (or error-callback #(log/warn "eth_gasPrice error" %))})))))
|
||||
|
||||
(def london-block-gas-limit (money/bignumber 30000000))
|
||||
|
||||
(defn calc-percentiles
|
||||
[v ps]
|
||||
(let [sorted-v (sort-by
|
||||
identity
|
||||
(fn [a b]
|
||||
(utils.money/greater-than b a))
|
||||
v)]
|
||||
(reduce
|
||||
(fn [acc p]
|
||||
(assoc acc p (nth sorted-v p)))
|
||||
{}
|
||||
ps)))
|
||||
|
||||
;; It is very unlikely to be that small on mainnet, but on testnets current base
|
||||
;; fee might be very small and using this value might slow transaction
|
||||
(def minimum-base-fee (money/->wei :gwei (money/bignumber 1)))
|
||||
|
||||
(defn recommended-base-fee
|
||||
[current perc20]
|
||||
(let [fee
|
||||
(cond (money/greater-than-or-equals current perc20)
|
||||
current
|
||||
|
||||
(money/greater-than perc20 current)
|
||||
perc20)]
|
||||
(if (money/greater-than minimum-base-fee fee)
|
||||
minimum-base-fee
|
||||
fee)))
|
||||
|
||||
(defn slow-base-fee [_ perc10] perc10)
|
||||
|
||||
(defn fast-base-fee
|
||||
[current]
|
||||
(let [fee (money/mul current 2)]
|
||||
(if (money/greater-than minimum-base-fee fee)
|
||||
(money/mul minimum-base-fee 2)
|
||||
fee)))
|
||||
|
||||
(defn check-base-fee
|
||||
[{:keys [baseFeePerGas testnet?]}]
|
||||
(let [all-base-fees (mapv money/bignumber baseFeePerGas)
|
||||
next-base-fee (peek all-base-fees)
|
||||
previous-fees (subvec all-base-fees 0 101)
|
||||
current-base-fee (peek previous-fees)
|
||||
percentiles (calc-percentiles previous-fees [10 20 80])]
|
||||
{:normal-base-fee (money/to-hex
|
||||
(if testnet?
|
||||
(fast-base-fee next-base-fee)
|
||||
(recommended-base-fee
|
||||
next-base-fee
|
||||
(get percentiles 20))))
|
||||
:slow-base-fee (money/to-hex
|
||||
(slow-base-fee
|
||||
next-base-fee
|
||||
(get percentiles 10)))
|
||||
:fast-base-fee (money/to-hex (fast-base-fee next-base-fee))
|
||||
:current-base-fee (money/to-hex current-base-fee)}))
|
||||
|
||||
(defn max-priority-fee-hex
|
||||
[gas-price base-fee]
|
||||
(money/to-hex
|
||||
(money/sub (money/bignumber gas-price)
|
||||
(money/bignumber base-fee))))
|
||||
|
||||
(rf/defn header-fetched
|
||||
{:events [::header-fetched]}
|
||||
[{{:networks/keys [current-network networks]} :db}
|
||||
{:keys [error-callback success-callback fee-history] :as params}]
|
||||
{:json-rpc/call
|
||||
[;; NOTE(rasom): eth_maxPriorityFeePerGas is not supported by some networks
|
||||
;; so it is more reliable to calculate maxPriorityFeePerGas using the value
|
||||
;; returned by eth_gasPrice and current base fee.
|
||||
{:method "eth_gasPrice"
|
||||
:on-success #(success-callback
|
||||
(let [{:keys [current-base-fee] :as base-fees}
|
||||
(check-base-fee
|
||||
(assoc fee-history
|
||||
:testnet?
|
||||
(chain/testnet?
|
||||
(get-in networks [current-network :config :NetworkId]))))]
|
||||
(merge {:max-priority-fee
|
||||
(max-priority-fee-hex (money/bignumber %) current-base-fee)}
|
||||
base-fees)))
|
||||
:on-error (if error-callback
|
||||
#(error-callback %)
|
||||
#(log/error "Can't fetch header" %))}]})
|
||||
|
||||
(re-frame/reg-fx
|
||||
:signing/update-estimated-gas
|
||||
(fn [{:keys [obj success-event error-event]}]
|
||||
(json-rpc/call
|
||||
{:method "eth_estimateGas"
|
||||
:params [obj]
|
||||
:on-success #(re-frame/dispatch [success-event
|
||||
(money/bignumber (if (= (int %) 21000) % (int (* % 1.2))))])
|
||||
:on-error #(re-frame/dispatch [error-event %])})))
|
||||
@@ -1,39 +0,0 @@
|
||||
(ns legacy.status-im.signing.gas-test
|
||||
(:require
|
||||
[cljs.test :refer-macros [deftest is testing]]
|
||||
[legacy.status-im.signing.gas :as signing.gas]))
|
||||
|
||||
(deftest build-edit-test
|
||||
(testing "an invalid edit"
|
||||
(let [actual (-> {}
|
||||
(signing.gas/build-edit :gas "invalid")
|
||||
(signing.gas/build-edit :gasPrice "0.00000000001"))]
|
||||
(testing "it marks gasPrice as invalid"
|
||||
(is (get-in actual [:gasPrice :error])))
|
||||
(testing "it does not change value"
|
||||
(is (= "0.00000000001" (get-in actual [:gasPrice :value]))))
|
||||
(testing "it marks gas as invalid"
|
||||
(is (get-in actual [:gas :error])))
|
||||
(testing "it does not change gas value"
|
||||
(is (= "invalid" (get-in actual [:gas :value]))))
|
||||
(testing "it sets max-fee to 0"
|
||||
(is (= "0" (:max-fee actual))))))
|
||||
(testing "gas price in wei should be round"
|
||||
(let [actual (-> {}
|
||||
(signing.gas/build-edit :gas "21000")
|
||||
(signing.gas/build-edit :gasPrice "0.0000000023"))]
|
||||
(is (get-in actual [:gasPrice :error]))))
|
||||
(testing "an valid edit"
|
||||
(let [actual (-> {}
|
||||
(signing.gas/build-edit :gas "21000")
|
||||
(signing.gas/build-edit :gasPrice "10"))]
|
||||
(testing "it does not mark gas-price as invalid"
|
||||
(is (not (get-in actual [:gasPrice :error]))))
|
||||
(testing "it sets the value in number for gas-price, in gwei"
|
||||
(is (= "10000000000" (str (get-in actual [:gasPrice :value-number])))))
|
||||
(testing "it does not mark gas as invalid"
|
||||
(is (not (get-in actual [:gas :error]))))
|
||||
(testing "it sets the value in number for gasi"
|
||||
(is (= "21000" (str (get-in actual [:gas :value-number])))))
|
||||
(testing "it calculates max-fee"
|
||||
(is (= "0.00021" (:max-fee actual)))))))
|
||||
@@ -1,120 +0,0 @@
|
||||
(ns legacy.status-im.signing.keycard
|
||||
(:require
|
||||
[legacy.status-im.utils.deprecated-types :as types]
|
||||
[native-module.core :as native-module]
|
||||
[re-frame.core :as re-frame]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::hash-transaction
|
||||
(fn [{:keys [transaction on-completed]}]
|
||||
(native-module/hash-transaction (types/clj->json transaction) on-completed)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::hash-message
|
||||
(fn [{:keys [message on-completed]}]
|
||||
(native-module/hash-message message on-completed)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::hash-typed-data
|
||||
(fn [{:keys [v4 data on-completed]}]
|
||||
(if v4
|
||||
(native-module/hash-typed-data-v4 data on-completed)
|
||||
(native-module/hash-typed-data data on-completed))))
|
||||
|
||||
(defn prepare-transaction
|
||||
[{:keys [gas gasPrice data nonce tx-obj] :as params}]
|
||||
(let [{:keys [from to value chat-id message-id command? maxPriorityFeePerGas maxFeePerGas]} tx-obj
|
||||
maxPriorityFeePerGas (or maxPriorityFeePerGas (get params :maxPriorityFeePerGas))
|
||||
maxFeePerGas (or maxFeePerGas (get params :maxFeePerGas))]
|
||||
(cond-> {:from from
|
||||
:to to
|
||||
:value value
|
||||
:chat-id chat-id
|
||||
:message-id message-id
|
||||
:command? command?}
|
||||
maxPriorityFeePerGas
|
||||
(assoc :maxPriorityFeePerGas
|
||||
(str "0x"
|
||||
(native-module/number-to-hex
|
||||
(js/parseInt maxPriorityFeePerGas))))
|
||||
maxFeePerGas
|
||||
(assoc :maxFeePerGas
|
||||
(str "0x"
|
||||
(native-module/number-to-hex
|
||||
(js/parseInt maxFeePerGas))))
|
||||
gas
|
||||
(assoc :gas (str "0x" (native-module/number-to-hex gas)))
|
||||
gasPrice
|
||||
(assoc :gasPrice (str "0x" (native-module/number-to-hex gasPrice)))
|
||||
data
|
||||
(assoc :data data)
|
||||
nonce
|
||||
(assoc :nonce nonce))))
|
||||
|
||||
(rf/defn hash-message
|
||||
[_ {:keys [v4 data typed? on-completed]}]
|
||||
(if typed?
|
||||
{::hash-typed-data
|
||||
{:data data
|
||||
:v4 v4
|
||||
:on-completed
|
||||
(or on-completed
|
||||
#(re-frame/dispatch
|
||||
[:signing.keycard.callback/hash-message-completed
|
||||
data typed? %]))}}
|
||||
{::hash-message
|
||||
{:message data
|
||||
:on-completed
|
||||
(or on-completed
|
||||
#(re-frame/dispatch
|
||||
[:signing.keycard.callback/hash-message-completed
|
||||
data typed? %]))}}))
|
||||
|
||||
(rf/defn hash-message-completed
|
||||
{:events [:signing.keycard.callback/hash-message-completed]}
|
||||
[{:keys [db]} data typed? result]
|
||||
(let [{:keys [result error]} (types/json->clj result)]
|
||||
(if error
|
||||
{:dispatch [:signing.ui/cancel-is-pressed]
|
||||
:effects.utils/show-popup {:title (i18n/label :t/sign-request-failed)
|
||||
:content (:message error)}}
|
||||
{:db (update db
|
||||
:keycard assoc
|
||||
:hash result
|
||||
:typed? typed?
|
||||
:data data)})))
|
||||
|
||||
(rf/defn hash-transaction
|
||||
[{:keys [db]}]
|
||||
(let [tx (prepare-transaction (:signing/tx db))]
|
||||
(log/debug "hash-transaction" tx)
|
||||
{::hash-transaction
|
||||
{:transaction tx
|
||||
:on-completed #(re-frame/dispatch
|
||||
[:signing.keycard.callback/hash-transaction-completed tx %])}}))
|
||||
|
||||
(rf/defn hash-transaction-completed
|
||||
{:events [:signing.keycard.callback/hash-transaction-completed]}
|
||||
[{:keys [db]} original-tx result]
|
||||
(let [{:keys [transaction hash]} (:result (types/json->clj result))]
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :transaction]
|
||||
(merge original-tx transaction))
|
||||
(assoc-in [:keycard :hash] hash))}))
|
||||
|
||||
(rf/defn sign-with-keycard
|
||||
{:events [:signing.ui/sign-with-keycard-pressed]}
|
||||
[{:keys [db] :as cofx}]
|
||||
(let [{:keys [message maxPriorityFeePerGas maxFeePerGas]} (get db :signing/tx)]
|
||||
(rf/merge
|
||||
cofx
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :pin :enter-step] :sign)
|
||||
(assoc-in [:signing/sign :type] :keycard)
|
||||
(assoc-in [:signing/sign :keycard-step] :pin))}
|
||||
#(if message
|
||||
(hash-message % message)
|
||||
(hash-transaction %)))))
|
||||
@@ -38,22 +38,6 @@
|
||||
:params []
|
||||
:on-success [:stickers/stickers-recent-success]})))
|
||||
|
||||
(rf/defn load-packs
|
||||
{:events [:stickers/load-packs]}
|
||||
[{:keys [db]}]
|
||||
{:json-rpc/call [{:method "stickers_market"
|
||||
:params [(chain/chain-id db)]
|
||||
:on-success #(re-frame/dispatch [:stickers/stickers-market-success %])}
|
||||
{:method "stickers_installed"
|
||||
:params []
|
||||
:on-success #(re-frame/dispatch [:stickers/stickers-installed-success %])}
|
||||
{:method "stickers_pending"
|
||||
:params []
|
||||
:on-success #(re-frame/dispatch [:stickers/stickers-pending-success %])}
|
||||
{:method "stickers_recent"
|
||||
:params []
|
||||
:on-success #(re-frame/dispatch [:stickers/stickers-recent-success %])}]})
|
||||
|
||||
(rf/defn pending-pack
|
||||
{:events [:stickers/pending-pack]}
|
||||
[{db :db} id]
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
(ns legacy.status-im.subs.bootnodes
|
||||
(:require
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:custom-bootnodes/enabled?
|
||||
:<- [:profile/profile]
|
||||
:<- [:networks/current-network]
|
||||
(fn [[{:keys [custom-bootnodes-enabled?]} current-network]]
|
||||
(get custom-bootnodes-enabled? current-network)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:custom-bootnodes/network-bootnodes
|
||||
:<- [:profile/profile]
|
||||
:<- [:networks/current-network]
|
||||
(fn [[multiaccount current-network]]
|
||||
(get-in multiaccount [:custom-bootnodes current-network])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:get-manage-bootnode
|
||||
:<- [:bootnodes/manage]
|
||||
(fn [manage]
|
||||
manage))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wakuv2-nodes/validation-errors
|
||||
:<- [:wakuv2-nodes/manage]
|
||||
(fn [manage]
|
||||
(set (keep
|
||||
(fn [[k {:keys [error]}]]
|
||||
(when error k))
|
||||
manage))))
|
||||
@@ -1,210 +0,0 @@
|
||||
(ns legacy.status-im.subs.keycard
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.keycard.common :as common]
|
||||
[re-frame.core :as re-frame]
|
||||
[utils.address :as address]
|
||||
[utils.datetime :as datetime]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard/nfc-enabled?
|
||||
(fn [db]
|
||||
(get-in db [:keycard :nfc-enabled?])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard/card-read-in-progress?
|
||||
(fn [db]
|
||||
(get-in db [:keycard :card-read-in-progress?] false)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-setup-step
|
||||
(fn [db]
|
||||
(get-in db [:keycard :setup-step])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-card-state
|
||||
(fn [db]
|
||||
(get-in db [:keycard :card-state])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-flow
|
||||
(fn [db]
|
||||
(get-in db [:keycard :flow])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-flow-steps
|
||||
(fn [db]
|
||||
(case (get-in db [:keycard :flow])
|
||||
:recovery "2"
|
||||
"3")))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-pair-code
|
||||
(fn [db]
|
||||
(get-in db [:keycard :secrets :password])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-recovery-phrase-word
|
||||
(fn [db]
|
||||
(get-in db
|
||||
[:keycard
|
||||
:recovery-phrase
|
||||
(get-in db [:keycard :recovery-phrase :step])])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-recovery-phrase-input-word
|
||||
(fn [db]
|
||||
(get-in db [:keycard :recovery-phrase :input-word])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-recovery-phrase-confirm-error
|
||||
(fn [db]
|
||||
(get-in db [:keycard :recovery-phrase :confirm-error])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-recovery-phrase-step
|
||||
(fn [db]
|
||||
(get-in db [:keycard :recovery-phrase :step])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-secrets
|
||||
(fn [db]
|
||||
(get-in db [:keycard :secrets])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-puk-code
|
||||
(fn [db]
|
||||
(->> (get-in db [:keycard :secrets :puk])
|
||||
(partition 4)
|
||||
(map string/join)
|
||||
(string/join " "))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-setup-error
|
||||
(fn [db]
|
||||
(get-in db [:keycard :setup-error])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-mnemonic
|
||||
(fn [db]
|
||||
(map-indexed vector
|
||||
(partition 3
|
||||
(map-indexed vector
|
||||
(string/split
|
||||
(get-in db [:keycard :secrets :mnemonic])
|
||||
#" "))))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-application-info
|
||||
(fn [db]
|
||||
(get-in db [:keycard :application-info])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-application-info-error
|
||||
(fn [db]
|
||||
(get-in db [:keycard :application-info-error])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-multiaccount
|
||||
(fn [db]
|
||||
(get-in db [:keycard :profile/profile])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-multiaccount-wallet-address
|
||||
(fn [db]
|
||||
(str "0x" (get-in db [:keycard :multiaccount-wallet-address]))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-multiaccount-whisper-public-key
|
||||
(fn [db]
|
||||
(address/normalized-hex (get-in db [:keycard :multiaccount-whisper-public-key]))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-paired-on
|
||||
(fn [db]
|
||||
(some-> (get-in db [:profile/profile :keycard-paired-on])
|
||||
(datetime/timestamp->year-month-day-date))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-multiaccount-pairing
|
||||
(fn [db]
|
||||
(get-in db [:profile/profile :keycard-pairing])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard/pin-retry-counter
|
||||
(fn [db]
|
||||
(get-in db [:keycard :application-info :pin-retry-counter])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard/puk-retry-counter
|
||||
(fn [db]
|
||||
(get-in db [:keycard :application-info :puk-retry-counter])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard/retry-counter
|
||||
:<- [:keycard/pin-retry-counter]
|
||||
:<- [:keycard/puk-retry-counter]
|
||||
(fn [[pin puk]]
|
||||
(if (zero? pin) puk pin)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-reset-card-disabled?
|
||||
(fn [db]
|
||||
(get-in db [:keycard :reset-card :disabled?] false)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard-multiaccount?
|
||||
common/keycard-multiaccount?)
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard/original-pin
|
||||
(fn [db]
|
||||
(get-in db [:keycard :pin :original])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard/login-pin
|
||||
(fn [db]
|
||||
(get-in db [:keycard :pin :login])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard/pin-confirmation
|
||||
(fn [db]
|
||||
(get-in db [:keycard :pin :confirmation])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard/pin-enter-step
|
||||
(fn [db]
|
||||
(get-in db [:keycard :pin :enter-step])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard/pin-operation
|
||||
(fn [db]
|
||||
(get-in db [:keycard :pin :operation])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard/pin-data
|
||||
(fn [db]
|
||||
(get-in db [:keycard :pin])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard/pin
|
||||
:<- [:keycard/pin-data]
|
||||
:<- [:keycard/pin-enter-step]
|
||||
(fn [[pin-data step]]
|
||||
(get pin-data step)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard/pin-status
|
||||
(fn [db]
|
||||
(get-in db [:keycard :pin :status])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard/pin-error-label
|
||||
(fn [db]
|
||||
(get-in db [:keycard :pin :error-label])))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:keycard/frozen-card?
|
||||
(fn [db]
|
||||
(and (common/keycard-multiaccount? db)
|
||||
(zero? (get-in db [:keycard :application-info :pin-retry-counter])))))
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns legacy.status-im.subs.mailservers
|
||||
(:require
|
||||
[legacy.status-im.fleet.core :as fleet]
|
||||
[legacy.status-im.mailserver.core :as mailserver]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
@@ -24,12 +23,6 @@
|
||||
(fn [state]
|
||||
(#{:error :disconnected} state)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:chats/fetching-gap-in-progress?
|
||||
:<- [:mailserver/fetching-gaps-in-progress]
|
||||
(fn [gaps [_ ids _]]
|
||||
(seq (select-keys gaps ids))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:mailserver/fetching?
|
||||
:<- [:mailserver/state]
|
||||
@@ -58,11 +51,6 @@
|
||||
(= (get-in mailserver [:id :value])
|
||||
current-mailserver-id)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:mailserver/use-status-nodes?
|
||||
(fn [db _]
|
||||
(boolean (mailserver/fetch-use-mailservers? db))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:mailserver.edit/validation-errors
|
||||
:<- [:mailserver.edit/mailserver]
|
||||
@@ -72,15 +60,6 @@
|
||||
(when error k))
|
||||
mailserver))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:mailserver/connected?
|
||||
:<- [:mailserver/state]
|
||||
:<- [:disconnected?]
|
||||
(fn [[mail-state disconnected?]]
|
||||
(let [mailserver-connected? (= :connected mail-state)]
|
||||
(and mailserver-connected?
|
||||
(not disconnected?)))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:mailserver/preferred-id
|
||||
:<- [:profile/profile]
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
(ns legacy.status-im.subs.root
|
||||
(:require
|
||||
legacy.status-im.subs.bootnodes
|
||||
legacy.status-im.subs.browser
|
||||
legacy.status-im.subs.ens
|
||||
legacy.status-im.subs.keycard
|
||||
legacy.status-im.subs.mailservers
|
||||
legacy.status-im.subs.stickers
|
||||
[re-frame.core :as re-frame]))
|
||||
@@ -23,10 +21,6 @@
|
||||
(reg-root-key-sub :peers-summary :peers-summary)
|
||||
(reg-root-key-sub :web3-node-version :web3-node-version)
|
||||
|
||||
;;keycard
|
||||
(reg-root-key-sub :keycard :keycard)
|
||||
(reg-root-key-sub :keycard/banner-hidden :keycard/banner-hidden)
|
||||
|
||||
;;bottom sheet old
|
||||
(reg-root-key-sub :bottom-sheet/show? :bottom-sheet/show?)
|
||||
(reg-root-key-sub :bottom-sheet/view :bottom-sheet/view)
|
||||
|
||||
@@ -3,12 +3,6 @@
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.constants :as constants]))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:stickers/installed-packs
|
||||
:<- [:stickers/packs]
|
||||
(fn [packs]
|
||||
(filter #(= (:status %) constants/sticker-pack-status-installed) (vals packs))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:stickers/all-packs
|
||||
:<- [:stickers/packs]
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
[legacy.status-im.ui.screens.profile.visibility-status.utils :as visibility-status-utils]
|
||||
[quo.components.avatars.user-avatar.style :as user-avatar.style]
|
||||
[quo.core :as quo]
|
||||
[quo.theme :as theme]
|
||||
[quo.theme]
|
||||
[re-frame.core :as re-frame.core]
|
||||
[react-native.core :as rn]
|
||||
[status-im.contexts.profile.utils :as profile.utils]
|
||||
@@ -52,7 +52,8 @@
|
||||
|
||||
(defn profile-photo-plus-dot-view
|
||||
[{:keys [public-key full-name customization-color photo-container photo-path community?]}]
|
||||
(let [photo-container (if (nil? photo-container)
|
||||
(let [theme @(re-frame.core/subscribe [:theme])
|
||||
photo-container (if (nil? photo-container)
|
||||
styles/container-chat-list
|
||||
photo-container)
|
||||
size (:width photo-container)
|
||||
@@ -71,8 +72,7 @@
|
||||
{:size size
|
||||
:full-name full-name
|
||||
:font-size (get text-style :font-size)
|
||||
:background-color (user-avatar.style/customization-color customization-color
|
||||
(theme/get-theme))
|
||||
:background-color (user-avatar.style/customization-color customization-color theme)
|
||||
:indicator-size 0
|
||||
:indicator-border 0
|
||||
:indicator-color "#000000"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
(:require
|
||||
[legacy.status-im.ui.components.core :as quo]
|
||||
[quo.foundations.colors :as quo.colors]
|
||||
[quo.theme]
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.safe-area :as safe-area]))
|
||||
|
||||
@@ -32,7 +33,8 @@
|
||||
:or {border-bottom? true
|
||||
new-ui? false}
|
||||
:as props}]
|
||||
(let [navigation (if (= navigation :none)
|
||||
(let [theme (quo.theme/use-theme)
|
||||
navigation (if (= navigation :none)
|
||||
nil
|
||||
[(default-navigation modal? navigation)])]
|
||||
[quo/header
|
||||
@@ -47,4 +49,5 @@
|
||||
{:right-accessories right-accessories})
|
||||
(when new-ui?
|
||||
{:background (quo.colors/theme-colors quo.colors/neutral-5
|
||||
quo.colors/neutral-95)}))]))
|
||||
quo.colors/neutral-95
|
||||
theme)}))]))
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.bootnodes-settings.edit-bootnode.styles
|
||||
(:require
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.utils.styles :as styles]))
|
||||
|
||||
(def edit-bootnode-view
|
||||
{:flex 1
|
||||
:margin-horizontal 16
|
||||
:margin-vertical 15})
|
||||
|
||||
(def button-container
|
||||
{:margin-top 8
|
||||
:margin-bottom 16
|
||||
:margin-horizontal 16})
|
||||
|
||||
(styles/def button
|
||||
{:height 52
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:border-radius 8
|
||||
:ios {:opacity 0.9}})
|
||||
|
||||
(def button-label
|
||||
{:color colors/white-persist
|
||||
:font-size 17})
|
||||
|
||||
(def delete-button
|
||||
(assoc button
|
||||
:background-color
|
||||
colors/red))
|
||||
@@ -1,76 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.bootnodes-settings.edit-bootnode.views
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.qr-scanner.core :as qr-scanner]
|
||||
[legacy.status-im.ui.components.core :as quo]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.components.toolbar :as toolbar]
|
||||
[legacy.status-im.ui.components.topbar :as topbar]
|
||||
[legacy.status-im.ui.screens.bootnodes-settings.edit-bootnode.styles :as styles]
|
||||
[re-frame.core :as re-frame]
|
||||
[utils.i18n :as i18n])
|
||||
(:require-macros [legacy.status-im.utils.views :as views]))
|
||||
|
||||
(defn delete-button
|
||||
[id]
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:bootnodes.ui/delete-pressed id])}
|
||||
[react/view styles/button-container
|
||||
[react/view
|
||||
{:style styles/delete-button
|
||||
:accessibility-label :bootnode-delete-button}
|
||||
[react/text {:style styles/button-label}
|
||||
(i18n/label :t/delete)]]]])
|
||||
|
||||
(views/defview edit-bootnode
|
||||
[]
|
||||
(views/letsubs [manage-bootnode [:get-manage-bootnode]
|
||||
validation-errors [:wakuv2-nodes/validation-errors]]
|
||||
(let [url (get-in manage-bootnode [:url :value])
|
||||
id (get-in manage-bootnode [:id :value])
|
||||
name (get-in manage-bootnode [:name :value])
|
||||
is-valid? (empty? validation-errors)
|
||||
invalid-url? (contains? validation-errors :url)]
|
||||
[react/keyboard-avoiding-view
|
||||
{:style {:flex 1}
|
||||
:ignore-offset true}
|
||||
[topbar/topbar {:title (i18n/label (if id :t/bootnode-details :t/add-bootnode))}]
|
||||
[react/scroll-view {:keyboard-should-persist-taps :handled}
|
||||
[react/view styles/edit-bootnode-view
|
||||
[react/view {:padding-vertical 8}
|
||||
[quo/text-input
|
||||
{:label (i18n/label :t/name)
|
||||
:placeholder (i18n/label :t/specify-name)
|
||||
:accessibility-label :bootnode-name
|
||||
:default-value name
|
||||
:on-change-text #(re-frame/dispatch [:bootnodes.ui/input-changed :name %])
|
||||
:auto-focus true}]]
|
||||
[react/view
|
||||
{:flex 1
|
||||
:padding-vertical 8}
|
||||
[quo/text-input
|
||||
(merge
|
||||
{:label (i18n/label :t/bootnode-address)
|
||||
:placeholder (i18n/label :t/bootnode-format)
|
||||
:accessibility-label :bootnode-address
|
||||
:default-value url
|
||||
:show-cancel false
|
||||
:on-change-text #(re-frame/dispatch [:bootnodes.ui/input-changed :url %])
|
||||
:error (when (and (not (string/blank? url)) invalid-url?)
|
||||
(i18n/label :t/invalid-format
|
||||
{:format (i18n/label :t/bootnode-format)}))
|
||||
:bottom-value 0
|
||||
:after {:icon :main-icons/qr
|
||||
:on-press #(re-frame/dispatch
|
||||
[::qr-scanner/scan-code
|
||||
{:title (i18n/label :t/add-bootnode)
|
||||
:handler :bootnodes.callback/qr-code-scanned}])}})]]
|
||||
(when id
|
||||
[delete-button id])]]
|
||||
[toolbar/toolbar
|
||||
{:right
|
||||
[quo/button
|
||||
{:type :secondary
|
||||
:after :main-icon/next
|
||||
:disabled (not is-valid?)
|
||||
:on-press #(re-frame/dispatch [:bootnodes.ui/save-pressed])}
|
||||
(i18n/label :t/save)]}]])))
|
||||
@@ -1,23 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.bootnodes-settings.styles
|
||||
(:require
|
||||
[legacy.status-im.utils.styles :as styles]))
|
||||
|
||||
(def wrapper
|
||||
{:flex 1})
|
||||
|
||||
(def bootnode-item-inner
|
||||
{:padding-horizontal 16})
|
||||
|
||||
(styles/def bootnode-item
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:padding-horizontal 16
|
||||
:ios {:height 64}
|
||||
:android {:height 56}})
|
||||
|
||||
(def bootnode-item-name-text
|
||||
{:font-size 17})
|
||||
|
||||
(def switch-container
|
||||
{:height 50
|
||||
:padding-left 15})
|
||||
@@ -1,47 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.bootnodes-settings.views
|
||||
(:require-macros [legacy.status-im.utils.views :as views])
|
||||
(:require
|
||||
[legacy.status-im.ui.components.list.views :as list]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.components.topbar :as topbar]
|
||||
[legacy.status-im.ui.screens.bootnodes-settings.styles :as styles]
|
||||
[legacy.status-im.ui.screens.profile.components.views :as profile.components]
|
||||
[re-frame.core :as re-frame]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn navigate-to-add-bootnode
|
||||
[id]
|
||||
(re-frame/dispatch [:bootnodes.ui/add-bootnode-pressed id]))
|
||||
|
||||
(defn render-row
|
||||
[{:keys [name id]}]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(navigate-to-add-bootnode id)
|
||||
:accessibility-label :bootnode-item}
|
||||
[react/view styles/bootnode-item
|
||||
[react/view styles/bootnode-item-inner
|
||||
[react/text {:style styles/bootnode-item-name-text}
|
||||
name]]]])
|
||||
|
||||
(views/defview bootnodes-settings
|
||||
[]
|
||||
(views/letsubs [bootnodes-enabled [:custom-bootnodes/enabled?]
|
||||
bootnodes [:custom-bootnodes/network-bootnodes]]
|
||||
[:<>
|
||||
[topbar/topbar
|
||||
{:title (i18n/label :t/bootnodes-settings)
|
||||
:right-accessories
|
||||
[{:icon :main-icons/add
|
||||
:accessibility-label :add-bootnode
|
||||
:on-press #(navigate-to-add-bootnode nil)}]}]
|
||||
[react/view styles/switch-container
|
||||
[profile.components/settings-switch-item
|
||||
{:label-kw :t/bootnodes-enabled
|
||||
:value bootnodes-enabled
|
||||
:action-fn #(re-frame/dispatch [:bootnodes.ui/custom-bootnodes-switch-toggled %])}]]
|
||||
[react/view styles/wrapper
|
||||
[list/flat-list
|
||||
{:data (vals bootnodes)
|
||||
:default-separator? false
|
||||
:key-fn :id
|
||||
:render-fn render-row}]]]))
|
||||
@@ -2,10 +2,8 @@
|
||||
(:require
|
||||
[legacy.status-im.ui.components.chat-icon.screen :as chat-icon.screen]
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.copyable-text :as copyable-text]
|
||||
[legacy.status-im.ui.components.core :as quo]
|
||||
[legacy.status-im.ui.components.icons.icons :as icons]
|
||||
[legacy.status-im.ui.components.list.item :as list.item]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.screens.browser.styles :as styles]
|
||||
[re-frame.core :as re-frame]
|
||||
@@ -13,7 +11,7 @@
|
||||
(:require-macros [legacy.status-im.utils.views :as views]))
|
||||
|
||||
(views/defview permissions-panel
|
||||
[dapp-name message-id params]
|
||||
[_dapp-name message-id params]
|
||||
(views/letsubs [{:keys [dapp? dapp]} [:get-current-browser]]
|
||||
[react/view {}
|
||||
[react/view styles/permissions-panel-icons-container
|
||||
@@ -37,35 +35,6 @@
|
||||
[react/view styles/dot]]
|
||||
[react/view styles/permissions-panel-wallet-icon-container
|
||||
[icons/icon :main-icons/wallet {:color colors/white}]]]
|
||||
[react/text {:style styles/permissions-panel-title-label :number-of-lines 2}
|
||||
(str "\"" dapp-name "\" Allow this site to add a network?")]
|
||||
[react/text {:style styles/permissions-panel-description-label :number-of-lines 4}
|
||||
"This will allow this network to be used within Status.Status does not verify custom networks.Learn about scams and network security risks."]
|
||||
[react/scroll-view
|
||||
[copyable-text/copyable-text-view
|
||||
{:copied-text (:name (:new-network params))}
|
||||
[list.item/list-item
|
||||
{:size :small
|
||||
:accessibility-label :network-name
|
||||
:title "Network Name"
|
||||
:accessory :text
|
||||
:accessory-text (:name (:new-network params))}]]
|
||||
[copyable-text/copyable-text-view
|
||||
{:copied-text (get-in params [:new-network :config :UpstreamConfig :URL])}
|
||||
[list.item/list-item
|
||||
{:size :small
|
||||
:accessibility-label :network-url
|
||||
:title "Network URL"
|
||||
:accessory :text
|
||||
:accessory-text (get-in params [:new-network :config :UpstreamConfig :URL])}]]
|
||||
[copyable-text/copyable-text-view
|
||||
{:copied-text (str (get-in params [:new-network :config :NetworkId]))}
|
||||
[list.item/list-item
|
||||
{:size :small
|
||||
:accessibility-label :network-id
|
||||
:title "Chain ID"
|
||||
:accessory :text
|
||||
:accessory-text (str (get-in params [:new-network :config :NetworkId]))}]]]
|
||||
[react/view
|
||||
{:style {:flex-direction :row
|
||||
:justify-content :center
|
||||
|
||||
@@ -10,9 +10,7 @@
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.utils.utils :as utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.constants :as constants]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.url :as url]))
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn hide-sheet-and-dispatch
|
||||
[event]
|
||||
@@ -40,13 +38,10 @@
|
||||
:on-press #(hide-sheet-and-dispatch [:browser/revoke-dapp-permissions host])}]]))
|
||||
|
||||
(defn browser-options
|
||||
[url account empty-tab name]
|
||||
[url _account empty-tab name]
|
||||
(fn []
|
||||
(let [bookmarks @(re-frame/subscribe [:bookmarks/active])
|
||||
permissions @(re-frame/subscribe [:dapps/permissions])
|
||||
fav? (get bookmarks url)
|
||||
connected? (some #{constants/dapp-permission-web3}
|
||||
(get-in permissions [(url/url-host url) :permissions]))]
|
||||
(let [bookmarks @(re-frame/subscribe [:bookmarks/active])
|
||||
fav? (get bookmarks url)]
|
||||
[react/view {:flex 1}
|
||||
[quo/button
|
||||
{:style {:align-self :flex-end
|
||||
@@ -86,21 +81,4 @@
|
||||
#(browser/share-link url)
|
||||
200))}]
|
||||
[react/view {:style {:height 1 :background-color (colors/alpha colors/black 0.1)}}]])
|
||||
(if connected?
|
||||
[list.item/list-item
|
||||
{:icon [chat-icon/custom-icon-view-list (:name account) (:color account)]
|
||||
:title (:name account)
|
||||
:subtitle (i18n/label :t/connected)
|
||||
:accessibility-label :connected-account
|
||||
:chevron true
|
||||
:on-press #(hide-sheet-and-dispatch
|
||||
[:bottom-sheet/show-sheet-old
|
||||
{:content (wallet-connection (url/url-host url) account)}])}]
|
||||
[list.item/list-item
|
||||
{:theme :accent
|
||||
:title (i18n/label :t/connect-wallet)
|
||||
:accessibility-label :connect-account
|
||||
:icon :main-icons/wallet
|
||||
:on-press #(hide-sheet-and-dispatch
|
||||
[:browser/bridge-message-received
|
||||
"{\"type\":\"api-request\",\"permission\":\"web3\"}"])}])])))
|
||||
])))
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
(:require
|
||||
[legacy.status-im.browser.core :as browser]
|
||||
[legacy.status-im.browser.webview-ref :as webview-ref]
|
||||
[legacy.status-im.qr-scanner.core :as qr-scanner]
|
||||
[legacy.status-im.ui.components.chat-icon.screen :as chat-icon]
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.connectivity.view :as connectivity]
|
||||
@@ -105,9 +104,7 @@
|
||||
(if empty-tab
|
||||
[react/touchable-highlight
|
||||
{:accessibility-label :universal-qr-scanner
|
||||
:on-press #(re-frame/dispatch
|
||||
[::qr-scanner/scan-code
|
||||
{:handler ::qr-scanner/on-scan-success}])}
|
||||
:on-press #(re-frame/dispatch [:open-modal :shell-qr-reader])}
|
||||
[icons/icon :main-icons/qr {:color colors/black}]]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(re-frame/dispatch
|
||||
|
||||
@@ -46,22 +46,22 @@
|
||||
:color colors/gray})
|
||||
|
||||
(defn message-default-style
|
||||
[]
|
||||
[theme]
|
||||
{:font-family "Inter-Regular"
|
||||
:color (quo.colors/theme-colors quo.colors/neutral-100 quo.colors/white)
|
||||
:color (quo.colors/theme-colors quo.colors/neutral-100 quo.colors/white theme)
|
||||
:font-size 15
|
||||
:line-height 21.75
|
||||
:letter-spacing -0.135})
|
||||
|
||||
;; Markdown styles
|
||||
(defn default-text-style
|
||||
[]
|
||||
[theme]
|
||||
{:max-font-size-multiplier react/max-font-size-multiplier
|
||||
:style (message-default-style)})
|
||||
:style (message-default-style theme)})
|
||||
|
||||
(defn system-text-style
|
||||
[]
|
||||
(update (default-text-style)
|
||||
[theme]
|
||||
(update (default-text-style theme)
|
||||
:style assoc
|
||||
:color colors/gray
|
||||
:line-height 20
|
||||
@@ -70,65 +70,65 @@
|
||||
:font-weight "400"))
|
||||
|
||||
(defn text-style
|
||||
[content-type in-popover?]
|
||||
[content-type in-popover? theme]
|
||||
(merge
|
||||
(when in-popover? {:number-of-lines 2})
|
||||
(cond
|
||||
(= content-type constants/content-type-system-text) (system-text-style)
|
||||
(= content-type constants/content-type-system-pinned-message) (system-text-style)
|
||||
:else (default-text-style))))
|
||||
(= content-type constants/content-type-system-text) (system-text-style theme)
|
||||
(= content-type constants/content-type-system-pinned-message) (system-text-style theme)
|
||||
:else (default-text-style theme))))
|
||||
|
||||
(defn emph-text-style
|
||||
[]
|
||||
(update (default-text-style)
|
||||
[theme]
|
||||
(update (default-text-style theme)
|
||||
:style
|
||||
assoc
|
||||
:font-style :italic))
|
||||
|
||||
(defn emph-style
|
||||
[]
|
||||
(emph-text-style))
|
||||
[theme]
|
||||
(emph-text-style theme))
|
||||
|
||||
(defn strong-text-style
|
||||
[]
|
||||
(update (default-text-style)
|
||||
[theme]
|
||||
(update (default-text-style theme)
|
||||
:style
|
||||
assoc
|
||||
:font-weight "700"))
|
||||
|
||||
(defn outgoing-strong-text-style
|
||||
[]
|
||||
(update (strong-text-style)
|
||||
[theme]
|
||||
(update (strong-text-style theme)
|
||||
:style
|
||||
assoc
|
||||
:color colors/white-persist))
|
||||
|
||||
(defn strong-style
|
||||
[]
|
||||
(outgoing-strong-text-style)
|
||||
(strong-text-style))
|
||||
[theme]
|
||||
(outgoing-strong-text-style theme)
|
||||
(strong-text-style theme))
|
||||
|
||||
(defn strong-emph-style
|
||||
[]
|
||||
(update (strong-style)
|
||||
[theme]
|
||||
(update (strong-style theme)
|
||||
:style
|
||||
assoc
|
||||
:font-style :italic))
|
||||
|
||||
(defn strikethrough-style
|
||||
[]
|
||||
(cond-> (update (default-text-style)
|
||||
[theme]
|
||||
(cond-> (update (default-text-style theme)
|
||||
:style
|
||||
assoc
|
||||
:text-decoration-line :line-through)))
|
||||
|
||||
(defn edited-style
|
||||
[]
|
||||
[theme]
|
||||
(cond->
|
||||
(update (default-text-style)
|
||||
(update (default-text-style theme)
|
||||
:style
|
||||
assoc
|
||||
:color (quo.colors/theme-colors quo.colors/neutral-40 quo.colors/neutral-50)
|
||||
:color (quo.colors/theme-colors quo.colors/neutral-40 quo.colors/neutral-50 theme)
|
||||
:font-size 13
|
||||
:line-height 18.2
|
||||
:letter-spacing (typography/tracking 13))))
|
||||
@@ -149,8 +149,8 @@
|
||||
(default-blockquote-style))
|
||||
|
||||
(defn default-blockquote-text-style
|
||||
[]
|
||||
(update (default-text-style)
|
||||
[theme]
|
||||
(update (default-text-style theme)
|
||||
:style
|
||||
assoc
|
||||
:line-height 19
|
||||
@@ -158,16 +158,16 @@
|
||||
:color colors/black-transparent-50))
|
||||
|
||||
(defn outgoing-blockquote-text-style
|
||||
[]
|
||||
(update (default-blockquote-text-style)
|
||||
[theme]
|
||||
(update (default-blockquote-text-style theme)
|
||||
:style
|
||||
assoc
|
||||
:color colors/white-transparent-70-persist))
|
||||
|
||||
(defn blockquote-text-style
|
||||
[]
|
||||
(outgoing-blockquote-text-style)
|
||||
(default-blockquote-text-style))
|
||||
[theme]
|
||||
(outgoing-blockquote-text-style theme)
|
||||
(default-blockquote-text-style theme))
|
||||
|
||||
(defn community-verified
|
||||
[]
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.foundations.typography :as typography]
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.chat.messenger.messages.delete-message-for-me.events]
|
||||
@@ -26,7 +27,7 @@
|
||||
|
||||
(defn render-inline
|
||||
[_message-text content-type acc {:keys [type literal destination]}
|
||||
community-id]
|
||||
community-id theme]
|
||||
(case type
|
||||
""
|
||||
(conj acc literal)
|
||||
@@ -35,24 +36,25 @@
|
||||
(conj acc [rn/text literal])
|
||||
|
||||
"emph"
|
||||
(conj acc [rn/text (style/emph-style) literal])
|
||||
(conj acc [rn/text (style/emph-style theme) literal])
|
||||
|
||||
"strong"
|
||||
(conj acc [rn/text (style/strong-style) literal])
|
||||
(conj acc [rn/text (style/strong-style theme) literal])
|
||||
|
||||
"strong-emph"
|
||||
(conj acc [quo/text (style/strong-emph-style) literal])
|
||||
(conj acc [quo/text (style/strong-emph-style theme) literal])
|
||||
|
||||
"del"
|
||||
(conj acc [rn/text (style/strikethrough-style) literal])
|
||||
(conj acc [rn/text (style/strikethrough-style theme) literal])
|
||||
|
||||
"link"
|
||||
(conj acc
|
||||
[rn/text
|
||||
{:style {:color (colors/theme-colors colors/primary-50 colors/primary-60)
|
||||
:text-decoration-line :underline}
|
||||
:on-press #(rf/dispatch [:browser.ui/message-link-pressed destination])}
|
||||
destination])
|
||||
(conj
|
||||
acc
|
||||
[rn/text
|
||||
{:style {:color (colors/theme-colors colors/primary-50 colors/primary-60 theme)
|
||||
:text-decoration-line :underline}
|
||||
:on-press #(rf/dispatch [:browser.ui/message-link-pressed destination])}
|
||||
destination])
|
||||
|
||||
"mention"
|
||||
(conj
|
||||
@@ -66,17 +68,18 @@
|
||||
#(rf/dispatch [:chat.ui/show-profile literal]))}
|
||||
[mention-element literal]]])
|
||||
"status-tag"
|
||||
(conj acc
|
||||
[rn/text
|
||||
(when community-id
|
||||
{:style {:color (colors/theme-colors colors/primary-50 colors/primary-60)
|
||||
:text-decoration-line :underline}
|
||||
:on-press #(rf/dispatch [:communities/status-tag-pressed community-id literal])})
|
||||
"#"
|
||||
literal])
|
||||
(conj
|
||||
acc
|
||||
[rn/text
|
||||
(when community-id
|
||||
{:style {:color (colors/theme-colors colors/primary-50 colors/primary-60 theme)
|
||||
:text-decoration-line :underline}
|
||||
:on-press #(rf/dispatch [:communities/status-tag-pressed community-id literal])})
|
||||
"#"
|
||||
literal])
|
||||
|
||||
"edited"
|
||||
(conj acc [rn/text (style/edited-style) (str " (" (i18n/label :t/edited) ")")])
|
||||
(conj acc [rn/text (style/edited-style theme) (str " (" (i18n/label :t/edited) ")")])
|
||||
|
||||
(conj acc literal)))
|
||||
|
||||
@@ -84,7 +87,7 @@
|
||||
(defn render-block
|
||||
[{:keys [content content-type edited-at in-popover?]} acc
|
||||
{:keys [type ^js literal children]}
|
||||
community-id]
|
||||
community-id theme]
|
||||
|
||||
(case type
|
||||
|
||||
@@ -96,8 +99,9 @@
|
||||
content-type
|
||||
acc
|
||||
e
|
||||
community-id))
|
||||
[rn/text (style/text-style content-type in-popover?)]
|
||||
community-id
|
||||
theme))
|
||||
[rn/text (style/text-style content-type in-popover? theme)]
|
||||
(conj
|
||||
children
|
||||
(when edited-at
|
||||
@@ -106,7 +110,7 @@
|
||||
"blockquote"
|
||||
(conj acc
|
||||
[rn/view (style/blockquote-style)
|
||||
[rn/text (style/blockquote-text-style)
|
||||
[rn/text (style/blockquote-text-style theme)
|
||||
(.substring literal 0 (.-length literal))]])
|
||||
|
||||
"codeblock"
|
||||
@@ -119,12 +123,14 @@
|
||||
(defn render-parsed-text
|
||||
[{:keys [content chat-id]
|
||||
:as message-data}]
|
||||
(let [community-id (rf/sub [:community-id-by-chat-id chat-id])]
|
||||
(let [community-id (rf/sub [:community-id-by-chat-id chat-id])
|
||||
theme (quo.theme/use-theme)]
|
||||
(reduce (fn [acc e]
|
||||
(render-block message-data
|
||||
acc
|
||||
e
|
||||
community-id))
|
||||
community-id
|
||||
theme))
|
||||
[:<>]
|
||||
(:parsed-text content))))
|
||||
|
||||
@@ -137,12 +143,13 @@
|
||||
;; STATUS ? whats that ?
|
||||
(defmethod ->message constants/content-type-status
|
||||
[{:keys [content content-type]}]
|
||||
[rn/view style/status-container
|
||||
[rn/text {:style (style/status-text)}
|
||||
(reduce
|
||||
(fn [acc e] (render-inline (:text content) content-type acc e nil))
|
||||
[rn/text {:style (style/status-text)}]
|
||||
(-> content :parsed-text peek :children))]])
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[rn/view style/status-container
|
||||
[rn/text {:style (style/status-text)}
|
||||
(reduce
|
||||
(fn [acc e] (render-inline (:text content) content-type acc e nil theme))
|
||||
[rn/text {:style (style/status-text)}]
|
||||
(-> content :parsed-text peek :children))]]))
|
||||
|
||||
(defn contact-request-status-pending
|
||||
[]
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
(ns legacy.status-im.ui.screens.communities.invite
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.communities.core :as communities]
|
||||
[legacy.status-im.ui.components.chat-icon.screen :as chat-icon.screen]
|
||||
[legacy.status-im.ui.components.core :as quo]
|
||||
[legacy.status-im.ui.components.list.item :as list.item]
|
||||
[legacy.status-im.ui.components.toolbar :as toolbar]
|
||||
[legacy.status-im.ui.components.topbar :as topbar]
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.constants :as constants]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -49,18 +48,35 @@
|
||||
contacts-selected (reagent/atom #{})
|
||||
{:keys [invite?]} (rf/sub [:get-screen-params])]
|
||||
(fn []
|
||||
(let [contacts-data (rf/sub [:contacts/active])
|
||||
{:keys [permissions
|
||||
can-manage-users?]}
|
||||
(let [theme (quo.theme/use-theme)
|
||||
contacts-data (rf/sub [:contacts/active])
|
||||
{community-id :id
|
||||
:keys [permissions
|
||||
can-manage-users?]}
|
||||
(rf/sub [:communities/edited-community])
|
||||
selected @contacts-selected
|
||||
selected-contacts-count (count selected)
|
||||
contacts (map (fn [{:keys [public-key] :as contact}]
|
||||
(assoc contact :active (contains? selected public-key)))
|
||||
contacts-data)
|
||||
;; no-membership communities can only be shared
|
||||
can-invite? (and can-manage-users?
|
||||
invite?
|
||||
(not= (:access permissions) constants/community-no-membership-access))]
|
||||
(not= (:access permissions) constants/community-no-membership-access))
|
||||
on-press-share-community (rn/use-callback
|
||||
(fn []
|
||||
(rf/dispatch [:communities/share-community-confirmation-pressed
|
||||
selected community-id])
|
||||
(rf/dispatch [:navigate-back])
|
||||
(rf/dispatch [:toasts/upsert
|
||||
{:type :positive
|
||||
:theme theme
|
||||
:text (if (= 1 selected-contacts-count)
|
||||
(i18n/label :t/one-user-was-invited)
|
||||
(i18n/label
|
||||
:t/n-users-were-invited
|
||||
{:count selected-contacts-count}))}]))
|
||||
[community-id selected selected-contacts-count theme])]
|
||||
[:<>
|
||||
[topbar/topbar
|
||||
{:title (i18n/label (if can-invite?
|
||||
@@ -81,11 +97,8 @@
|
||||
:center
|
||||
[quo/button
|
||||
{:disabled (and (string/blank? @user-pk)
|
||||
(zero? (count selected)))
|
||||
(zero? selected-contacts-count))
|
||||
:accessibility-label :share-community-link
|
||||
:type :secondary
|
||||
:on-press #(debounce/throttle-and-dispatch
|
||||
[::communities/share-community-confirmation-pressed @user-pk
|
||||
selected]
|
||||
3000)}
|
||||
:on-press on-press-share-community}
|
||||
(i18n/label (if can-invite? :t/invite :t/share))]}]]))))
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.screens.profile.user.views :as profile.user]
|
||||
[legacy.status-im.ui.screens.reset-password.views :as reset-password.views]
|
||||
[legacy.status-im.ui.screens.signing.sheets :as signing-sheets]
|
||||
[legacy.status-im.ui.screens.signing.views :as signing]
|
||||
[re-frame.core :as re-frame]
|
||||
[react-native.platform :as platform]
|
||||
[reagent.core :as reagent]))
|
||||
@@ -132,15 +130,9 @@
|
||||
(= :share-chat-key view)
|
||||
[profile.user/share-chat-key]
|
||||
|
||||
(= :transaction-data view)
|
||||
[signing/transaction-data]
|
||||
|
||||
(= :password-reset-popover view)
|
||||
[reset-password.views/reset-password-popover]
|
||||
|
||||
(= :fees-warning view)
|
||||
[signing-sheets/fees-warning]
|
||||
|
||||
:else
|
||||
[view])]]]])))})))
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns legacy.status-im.ui.screens.privacy-and-security-settings.delete-profile
|
||||
(:require
|
||||
legacy.status-im.keycard.delete-key
|
||||
[legacy.status-im.ui.components.chat-icon.screen :as chat-icon.screen]
|
||||
[legacy.status-im.ui.components.core :as quo]
|
||||
[legacy.status-im.ui.components.list.item :as list.item]
|
||||
@@ -23,18 +22,12 @@
|
||||
[::delete-profile/delete-profile @password])
|
||||
(reset! password nil)))
|
||||
|
||||
(defn on-delete-keycard-profile
|
||||
[keep-keys-on-keycard?]
|
||||
#(re-frame/dispatch
|
||||
[:keycard/proceed-to-reset-card keep-keys-on-keycard?]))
|
||||
|
||||
(defn delete-profile
|
||||
[]
|
||||
(let [password (reagent/atom nil)
|
||||
text-input-ref (atom nil)]
|
||||
(fn []
|
||||
(let [profile @(re-frame/subscribe [:profile/profile])
|
||||
keycard? @(re-frame/subscribe [:keycard-multiaccount?])
|
||||
error @(re-frame/subscribe [:delete-profile/error])
|
||||
keep-keys-on-keycard? @(re-frame/subscribe
|
||||
[:delete-profile/keep-keys-on-keycard?])]
|
||||
@@ -50,55 +43,29 @@
|
||||
[list.item/list-item
|
||||
{:title (profile.utils/displayed-name profile)
|
||||
:icon [chat-icon.screen/contact-icon-contacts-tab profile]}]
|
||||
(when keycard?
|
||||
[react/view
|
||||
[quo/list-header (i18n/label :t/actions)]
|
||||
[list.item/list-item
|
||||
{:title (i18n/label :t/delete-keys-keycard)
|
||||
:accessory :checkbox
|
||||
:active (not keep-keys-on-keycard?)
|
||||
:on-press #(re-frame/dispatch [::delete-profile/keep-keys-on-keycard
|
||||
(not keep-keys-on-keycard?)])}]
|
||||
[list.item/list-item
|
||||
{:title (i18n/label :t/unpair-keycard)
|
||||
:subtitle (i18n/label :t/unpair-keycard-warning)
|
||||
:subtitle-max-lines 4
|
||||
:disabled true
|
||||
:active true
|
||||
:accessory :checkbox}]
|
||||
[list.item/list-item
|
||||
{:title (i18n/label :t/reset-database)
|
||||
:subtitle (i18n/label :t/reset-database-warning-keycard)
|
||||
:subtitle-max-lines 4
|
||||
:disabled true
|
||||
:active true
|
||||
:accessory :checkbox}]])
|
||||
(when-not keycard?
|
||||
[quo/text
|
||||
{:style {:margin-horizontal 24}
|
||||
:align :center
|
||||
:color :negative}
|
||||
(i18n/label :t/delete-profile-warning)])
|
||||
(when-not keycard?
|
||||
[quo/text-input
|
||||
{:style {:margin-horizontal 36
|
||||
:margin-top 36}
|
||||
:show-cancel false
|
||||
:secure-text-entry true
|
||||
:return-key-type :next
|
||||
:on-submit-editing nil
|
||||
:auto-focus true
|
||||
:on-change-text #(reset! password (security/mask-data %))
|
||||
:bottom-value 36
|
||||
:get-ref #(reset! text-input-ref %)
|
||||
:error (when (and error (not @password))
|
||||
(if (= :wrong-password error)
|
||||
(i18n/label :t/wrong-password)
|
||||
(str error)))}])]
|
||||
[quo/text
|
||||
{:style {:margin-horizontal 24}
|
||||
:align :center
|
||||
:color :negative}
|
||||
(i18n/label :t/delete-profile-warning)]
|
||||
[quo/text-input
|
||||
{:style {:margin-horizontal 36
|
||||
:margin-top 36}
|
||||
:show-cancel false
|
||||
:secure-text-entry true
|
||||
:return-key-type :next
|
||||
:on-submit-editing nil
|
||||
:auto-focus true
|
||||
:on-change-text #(reset! password (security/mask-data %))
|
||||
:bottom-value 36
|
||||
:get-ref #(reset! text-input-ref %)
|
||||
:error (when (and error (not @password))
|
||||
(if (= :wrong-password error)
|
||||
(i18n/label :t/wrong-password)
|
||||
(str error)))}]]
|
||||
[react/view {:style {:align-items :center}}
|
||||
(when-not keycard?
|
||||
[quo/separator])
|
||||
(when (and keycard? (not keep-keys-on-keycard?))
|
||||
[quo/separator]
|
||||
(when (not keep-keys-on-keycard?)
|
||||
[quo/text
|
||||
{:style {:margin-horizontal 24 :margin-bottom 16}
|
||||
:align :center
|
||||
@@ -107,10 +74,8 @@
|
||||
[react/view
|
||||
{:style {:margin-vertical 8}}
|
||||
[quo/button
|
||||
{:on-press (if keycard?
|
||||
(on-delete-keycard-profile keep-keys-on-keycard?)
|
||||
(on-delete-profile password))
|
||||
{:on-press (on-delete-profile password)
|
||||
:theme :negative
|
||||
:accessibility-label :delete-profile-confirm
|
||||
:disabled (and (not keycard?) ((complement valid-password?) @password))}
|
||||
:disabled ((complement valid-password?) @password)}
|
||||
(i18n/label :t/delete-profile)]]]]))))
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
profile-pictures-visibility]}
|
||||
[:profile/profile]
|
||||
has-picture [:profile/has-picture]
|
||||
keycard? [:keycard-multiaccount?]
|
||||
profile-pictures-show-to [:multiaccount/profile-pictures-show-to]]
|
||||
[react/scroll-view {:padding-vertical 8}
|
||||
[quo/list-header (i18n/label :t/security)]
|
||||
@@ -92,16 +91,15 @@
|
||||
:t/anyone))
|
||||
:on-press #(re-frame/dispatch [:navigate-to :messages-from-contacts-only])
|
||||
:accessibility-label :accept-new-chats-from}]
|
||||
(when (not keycard?)
|
||||
[list.item/list-item
|
||||
{:size :small
|
||||
:title (i18n/label :t/reset-password)
|
||||
:chevron true
|
||||
:accessory :text
|
||||
:on-press #(do
|
||||
(re-frame/dispatch [::reset-password/clear-form-vals])
|
||||
(re-frame/dispatch [:navigate-to :reset-password]))
|
||||
:accessibility-label :reset-password}])
|
||||
[list.item/list-item
|
||||
{:size :small
|
||||
:title (i18n/label :t/reset-password)
|
||||
:chevron true
|
||||
:accessory :text
|
||||
:on-press #(do
|
||||
(re-frame/dispatch [::reset-password/clear-form-vals])
|
||||
(re-frame/dispatch [:navigate-to :reset-password]))
|
||||
:accessibility-label :reset-password}]
|
||||
(when platform/android?
|
||||
[list.item/list-item
|
||||
{:size :small
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
[legacy.status-im.ui.components.topbar :as topbar]
|
||||
[legacy.status-im.ui.screens.profile.components.sheets :as sheets]
|
||||
[quo.components.avatars.user-avatar.style :as user-avatar.style]
|
||||
[quo.theme :as theme]
|
||||
[quo.theme]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.constants :as constants]
|
||||
@@ -184,6 +184,7 @@
|
||||
:as profile} @(re-frame/subscribe [:contacts/current-contact])
|
||||
muted? @(re-frame/subscribe [:chats/muted public-key])
|
||||
customization-color (or customization-color :primary)
|
||||
theme @(re-frame/subscribe [:theme])
|
||||
on-share #(re-frame/dispatch [:show-popover
|
||||
(merge
|
||||
{:view :share-chat-key
|
||||
@@ -205,8 +206,7 @@
|
||||
{:on-press on-share
|
||||
:bottom-separator false
|
||||
:title (profile.utils/displayed-name profile)
|
||||
:color (user-avatar.style/customization-color customization-color
|
||||
(theme/get-theme))
|
||||
:color (user-avatar.style/customization-color customization-color theme)
|
||||
:photo (profile.utils/photo profile)
|
||||
:monospace (not ens-verified)
|
||||
:subtitle secondary-name
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
[legacy.status-im.ui.screens.profile.visibility-status.views :as visibility-status]
|
||||
[legacy.status-im.utils.utils :as utils]
|
||||
[quo.components.avatars.user-avatar.style :as user-avatar.style]
|
||||
[quo.theme :as theme]
|
||||
[quo.theme]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.qr-codes.view :as qr-codes]
|
||||
@@ -73,8 +73,7 @@
|
||||
(defn content
|
||||
[]
|
||||
(let [{:keys [preferred-name
|
||||
mnemonic
|
||||
keycard-pairing]}
|
||||
mnemonic]}
|
||||
@(re-frame/subscribe [:profile/profile])
|
||||
active-contacts-count @(re-frame/subscribe [:contacts/active-count])
|
||||
chain @(re-frame/subscribe [:chain-keyword])
|
||||
@@ -155,13 +154,6 @@
|
||||
:accessibility-label :sync-settings-button
|
||||
:chevron true
|
||||
:on-press #(re-frame/dispatch [:open-modal :sync-settings])}]
|
||||
(when keycard-pairing
|
||||
[list.item/list-item
|
||||
{:icon :main-icons/keycard
|
||||
:title (i18n/label :t/keycard)
|
||||
:accessibility-label :keycard-button
|
||||
:chevron true
|
||||
:on-press #(re-frame/dispatch [:open-modal :keycard-settings])}])
|
||||
[list.item/list-item
|
||||
{:icon :main-icons/settings-advanced
|
||||
:title (i18n/label :t/advanced)
|
||||
@@ -208,6 +200,7 @@
|
||||
@(re-frame/subscribe [:profile/profile-with-image])
|
||||
customization-color (or (:color @(re-frame/subscribe [:onboarding/profile]))
|
||||
@(re-frame/subscribe [:profile/customization-color key-uid]))
|
||||
theme @(re-frame/subscribe [:theme])
|
||||
on-share #(re-frame/dispatch [:show-popover
|
||||
{:view :share-chat-key
|
||||
:address (or compressed-key
|
||||
@@ -229,7 +222,7 @@
|
||||
{:content (edit/bottom-sheet
|
||||
has-picture)}])
|
||||
:color (user-avatar.style/customization-color customization-color
|
||||
(theme/get-theme))
|
||||
theme)
|
||||
:title (profile.utils/displayed-name profile)
|
||||
:photo (profile.utils/photo profile)
|
||||
:monospace (not ens-verified)
|
||||
|
||||
@@ -17,14 +17,14 @@
|
||||
:padding-right 12})
|
||||
|
||||
(defn visibility-status-dot
|
||||
[{:keys [color size new-ui?]}]
|
||||
[{:keys [color size new-ui?]} theme]
|
||||
(if new-ui?
|
||||
{:background-color color
|
||||
:width size
|
||||
:height size
|
||||
:border-radius (/ size 2)
|
||||
:border-width 3.5
|
||||
:border-color (quo.colors/theme-colors quo.colors/white quo.colors/neutral-90)}
|
||||
:border-color (quo.colors/theme-colors quo.colors/white quo.colors/neutral-90 theme)}
|
||||
{:background-color color
|
||||
:width size
|
||||
:height size
|
||||
@@ -33,10 +33,11 @@
|
||||
:border-color colors/white}))
|
||||
|
||||
(defn visibility-status-profile-dot
|
||||
[{:keys [color size border-width margin-left new-ui?]}]
|
||||
[{:keys [color size border-width margin-left new-ui?]} theme]
|
||||
(merge (visibility-status-dot {:color color
|
||||
:size size
|
||||
:new-ui? new-ui?})
|
||||
:new-ui? new-ui?}
|
||||
theme)
|
||||
{:margin-right 6
|
||||
:margin-left margin-left
|
||||
:border-width border-width}))
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.screens.profile.visibility-status.styles :as styles]
|
||||
[quo.foundations.colors :as quo.colors]
|
||||
[quo.theme]
|
||||
[status-im.constants :as constants]
|
||||
[utils.datetime :as datetime]
|
||||
[utils.i18n :as i18n]
|
||||
@@ -90,13 +91,15 @@
|
||||
(defn icon-visibility-status-dot
|
||||
[public-key container-size]
|
||||
(let [status (rf/sub [:visibility-status-updates/visibility-status-update public-key])
|
||||
theme (quo.theme/use-theme)
|
||||
size (icon-dot-size container-size)
|
||||
margin -2
|
||||
dot-color (icon-dot-color status)
|
||||
new-ui? true]
|
||||
(merge (styles/visibility-status-dot {:color dot-color
|
||||
:size size
|
||||
:new-ui? new-ui?})
|
||||
:new-ui? new-ui?}
|
||||
theme)
|
||||
{:bottom margin
|
||||
:right margin
|
||||
:position :absolute
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
(dispatch-popover page-y))))
|
||||
|
||||
(defn profile-visibility-status-dot
|
||||
[status-type color]
|
||||
[status-type color theme]
|
||||
(let [automatic? (= status-type
|
||||
constants/visibility-status-automatic)
|
||||
[border-width margin-left size] (if automatic? [1 -10 12] [0 6 10])
|
||||
@@ -50,14 +50,16 @@
|
||||
:size size
|
||||
:border-width border-width
|
||||
:margin-left 6
|
||||
:new-ui? new-ui?})}])
|
||||
:new-ui? new-ui?}
|
||||
theme)}])
|
||||
[rn/view
|
||||
{:style (styles/visibility-status-profile-dot
|
||||
{:color color
|
||||
:size size
|
||||
:border-width border-width
|
||||
:margin-left margin-left
|
||||
:new-ui? new-ui?})}]]))
|
||||
:new-ui? new-ui?}
|
||||
theme)}]]))
|
||||
|
||||
(defn visibility-status-button
|
||||
[on-press props]
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
[legacy.status-im.ui.screens.advanced-settings.views :as advanced-settings]
|
||||
[legacy.status-im.ui.screens.appearance.views :as appearance]
|
||||
[legacy.status-im.ui.screens.backup-settings.view :as backup-settings]
|
||||
[legacy.status-im.ui.screens.bootnodes-settings.edit-bootnode.views :as edit-bootnode]
|
||||
[legacy.status-im.ui.screens.bootnodes-settings.views :as bootnodes-settings]
|
||||
[legacy.status-im.ui.screens.browser.bookmarks.views :as bookmarks]
|
||||
[legacy.status-im.ui.screens.bug-report :as bug-report]
|
||||
[legacy.status-im.ui.screens.communities.invite :as communities.invite]
|
||||
@@ -44,7 +42,6 @@
|
||||
[legacy.status-im.ui.screens.sync-settings.views :as sync-settings]
|
||||
[legacy.status-im.ui.screens.wakuv2-settings.edit-node.views :as edit-wakuv2-node]
|
||||
[legacy.status-im.ui.screens.wakuv2-settings.views :as wakuv2-settings]
|
||||
[status-im.contexts.chat.group-details.view :as group-details]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn topbar-options
|
||||
@@ -69,10 +66,6 @@
|
||||
:component progress/progress}
|
||||
|
||||
;;CHAT
|
||||
{:name :group-chat-profile
|
||||
;;TODO animated-header
|
||||
:options {:insets {:top? true}}
|
||||
:component group-details/group-details}
|
||||
{:name :group-chat-invite
|
||||
;;TODO parameter in the event
|
||||
:options {:insets {:top? true}}
|
||||
@@ -141,18 +134,10 @@
|
||||
;;TODO dynamic title
|
||||
:options {:insets {:top? true}}
|
||||
:component edit-wakuv2-node/edit-node}
|
||||
{:name :bootnodes-settings
|
||||
;;TODO dynamic title
|
||||
:options {:insets {:top? true}}
|
||||
:component bootnodes-settings/bootnodes-settings}
|
||||
{:name :installations
|
||||
:options {:topBar (topbar-options (i18n/label :t/devices))
|
||||
:insets {:top? true}}
|
||||
:component pairing/installations}
|
||||
{:name :edit-bootnode
|
||||
;;TODO dynamic title
|
||||
:options {:insets {:top? true}}
|
||||
:component edit-bootnode/edit-bootnode}
|
||||
{:name :offline-messaging-settings
|
||||
;;TODO dynamic title
|
||||
:options {:insets {:top? true}}
|
||||
|
||||
@@ -1,437 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.signing.sheets
|
||||
(:require-macros [legacy.status-im.utils.views :as views])
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.signing.gas :as gas]
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.core :as quo]
|
||||
[legacy.status-im.ui.components.icons.icons :as icons]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.money :as money]))
|
||||
|
||||
(views/defview fee-bottom-sheet
|
||||
[fee-display-symbol]
|
||||
(views/letsubs [{gas-edit :gas gas-price-edit :gasPrice max-fee :max-fee} [:signing/edit-fee]]
|
||||
[react/view
|
||||
[react/view {:style {:margin-horizontal 16 :margin-top 8}}
|
||||
[react/text {:style {:typography :title-bold}} (i18n/label :t/network-fee)]
|
||||
[react/view
|
||||
{:style {:flex-direction :row
|
||||
:margin-top 8
|
||||
:align-items :flex-end}}
|
||||
[react/view {:flex 1}
|
||||
[quo/text-input
|
||||
{:on-change-text #(re-frame/dispatch [:signing.edit-fee.ui/edit-value :gas %])
|
||||
:label (i18n/label :t/gas-limit)
|
||||
:bottom-value 0
|
||||
:error (:error gas-edit)
|
||||
:default-value (:value gas-edit)
|
||||
:keyboard-type :numeric
|
||||
:auto-capitalize :none
|
||||
:placeholder "0"
|
||||
:show-cancel false
|
||||
:auto-focus false}]]
|
||||
[react/view
|
||||
{:flex 1
|
||||
:padding-left 16}
|
||||
[quo/text-input
|
||||
{:label (i18n/label :t/gas-price)
|
||||
:on-change-text #(re-frame/dispatch [:signing.edit-fee.ui/edit-value :gasPrice %])
|
||||
:bottom-value 0
|
||||
:error (:error gas-price-edit)
|
||||
:default-value (:value gas-price-edit)
|
||||
:keyboard-type :numeric
|
||||
:auto-capitalize :none
|
||||
:placeholder "0.000"
|
||||
:show-cancel false
|
||||
:auto-focus false}]]
|
||||
[react/view
|
||||
{:padding-left 8
|
||||
:padding-bottom 12}
|
||||
[react/text (i18n/label :t/gwei)]]]
|
||||
|
||||
[react/view {:margin-vertical 16 :align-items :center}
|
||||
[react/text {:style {:color colors/gray}} (i18n/label :t/wallet-transaction-total-fee)]
|
||||
[react/view {:height 8}]
|
||||
[react/nested-text {:style {:font-size 17}}
|
||||
max-fee " "
|
||||
[{:style {:color colors/gray}} fee-display-symbol]]]]
|
||||
[react/view {:height 1 :background-color colors/gray-lighter}]
|
||||
[react/view
|
||||
{:margin-horizontal 16
|
||||
:align-items :center
|
||||
:justify-content :space-between
|
||||
:flex-direction :row
|
||||
:margin-top 6}
|
||||
[quo/button
|
||||
{:type :secondary
|
||||
:on-press #(re-frame/dispatch [:bottom-sheet/hide-old])}
|
||||
(i18n/label :t/cancel)]
|
||||
[quo/button
|
||||
{:type :secondary
|
||||
:on-press #(re-frame/dispatch [:signing.edit-fee.ui/submit])
|
||||
:disabled (or (:error gas-edit) (:error gas-price-edit))}
|
||||
(i18n/label :t/update)]]]))
|
||||
|
||||
(declare fee-bottom-sheet-eip1559)
|
||||
|
||||
(defn fee-bottom-sheet-eip1559-custom
|
||||
[_ #_fee-display-symbol]
|
||||
(let [{gas-edit :gas
|
||||
max-fee-per-gas-edit :maxFeePerGas
|
||||
max-priority-fee-per-gas-edit :maxPriorityFeePerGas}
|
||||
@(re-frame/subscribe [:signing/edit-fee])
|
||||
error? (some :error
|
||||
[gas-edit
|
||||
max-fee-per-gas-edit
|
||||
max-priority-fee-per-gas-edit])
|
||||
base-fee @(re-frame/subscribe [:wallet-legacy/current-base-fee])
|
||||
[fee-currency fiat-currency price]
|
||||
@(re-frame/subscribe [:signing/currencies])
|
||||
fee-eth
|
||||
(if (and (:value-number gas-edit)
|
||||
(:value-number max-fee-per-gas-edit))
|
||||
(money/mul
|
||||
(money/wei->ether
|
||||
(money/->wei :gwei (:value-number max-fee-per-gas-edit)))
|
||||
(:value-number gas-edit))
|
||||
(money/bignumber 0))]
|
||||
[:<>
|
||||
[react/view {:style {:margin-horizontal 16 :margin-top 8}}
|
||||
[react/text {:style {:typography :title-bold}} (i18n/label :t/max-priority-fee)]
|
||||
[react/text
|
||||
{:style {:color (colors/get-color :text-02)
|
||||
:margin-top 12}}
|
||||
(i18n/label :t/miners-higher-fee)]
|
||||
[react/view
|
||||
{:style {:margin-top 12
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :space-between}}
|
||||
[quo/text (i18n/label :t/current-base-fee)]
|
||||
[quo/text
|
||||
(money/to-fixed (money/wei-> :gwei base-fee))
|
||||
" "
|
||||
(i18n/label :t/gwei)]]]
|
||||
[react/view
|
||||
{:margin-vertical 12
|
||||
:margin-horizontal 16
|
||||
:height 1
|
||||
:background-color colors/gray-lighter}]
|
||||
[react/view
|
||||
{:margin-horizontal 16
|
||||
:margin-top 4
|
||||
:margin-bottom 26}
|
||||
[quo/text-input
|
||||
{:label (i18n/label :t/gas-amount-limit)
|
||||
:accessibility-label :gas-amount-limit
|
||||
:error (:error gas-edit)
|
||||
:default-value (:value gas-edit)
|
||||
:on-change-text #(re-frame/dispatch [:signing.edit-fee.ui/edit-value :gas %])
|
||||
:show-cancel false}]]
|
||||
[react/view
|
||||
{:margin-horizontal 16
|
||||
:margin-top 4
|
||||
:margin-bottom 26}
|
||||
[quo/text-input
|
||||
{:label (i18n/label :t/per-gas-tip-limit)
|
||||
:accessibility-label :per-gas-tip-limit
|
||||
:error (or (:error max-priority-fee-per-gas-edit)
|
||||
(get-in max-priority-fee-per-gas-edit [:fee-error :label]))
|
||||
:default-value (str (:value max-priority-fee-per-gas-edit))
|
||||
:on-change-text #(re-frame/dispatch [:signing.edit-fee.ui/edit-value :maxPriorityFeePerGas
|
||||
%])
|
||||
:show-cancel false
|
||||
:after {:component [quo/text
|
||||
{:style {:color (colors/get-color :text-02)}}
|
||||
(i18n/label :t/gwei)]}}]]
|
||||
[react/view
|
||||
{:margin-horizontal 16
|
||||
:margin-top 4
|
||||
:margin-bottom 12}
|
||||
[quo/text-input
|
||||
{:label (i18n/label :t/per-gas-price-limit)
|
||||
:accessibility-label :per-gas-price-limit
|
||||
:error (or (:error max-fee-per-gas-edit)
|
||||
(get-in max-fee-per-gas-edit [:fee-error :label]))
|
||||
:default-value (str (:value max-fee-per-gas-edit))
|
||||
:on-change-text #(re-frame/dispatch [:signing.edit-fee.ui/edit-value :maxFeePerGas %])
|
||||
:show-cancel false
|
||||
:after {:component [quo/text
|
||||
{:style {:color (colors/get-color :text-02)}}
|
||||
(i18n/label :t/gwei)]}}]]
|
||||
[react/view
|
||||
{:margin-vertical 12
|
||||
:height 1
|
||||
:background-color colors/gray-lighter}]
|
||||
[react/view
|
||||
{:style {:margin-top 4
|
||||
:margin-horizontal 16
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :space-between}}
|
||||
[quo/text (i18n/label :t/maximum-fee) ":"]
|
||||
[react/view
|
||||
{:style {:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :flex-end}}
|
||||
[quo/text
|
||||
{:style {:margin-right 6
|
||||
:color (colors/get-color :text-02)}}
|
||||
(str (money/to-fixed fee-eth 6) " " fee-currency)]
|
||||
[quo/text
|
||||
(money/to-fixed (money/mul fee-eth (money/bignumber (or price 0))) 2)
|
||||
" "
|
||||
fiat-currency]]]
|
||||
[react/text
|
||||
{:style {:color (colors/get-color :text-02)
|
||||
:margin 16}}
|
||||
(i18n/label :t/fee-explanation)]
|
||||
[react/view
|
||||
{:style {:margin-left 12
|
||||
:margin-right 16
|
||||
:margin-bottom 20
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :space-between}}
|
||||
[quo/button
|
||||
{:type :secondary
|
||||
:accessibility-label :see-fee-suggestions
|
||||
;;:on-press
|
||||
#_(re-frame/dispatch
|
||||
[:bottom-sheet/show-sheet-old
|
||||
{:content (fn []
|
||||
[fee-bottom-sheet-eip1559 fee-display-symbol])
|
||||
:content-height 270}])}
|
||||
"" #_(i18n/label :t/see-suggestions)]
|
||||
[quo/button
|
||||
{:type :primary
|
||||
:accessibility-label :save-fees
|
||||
:disabled error?
|
||||
:on-press #(re-frame/dispatch [:signing.edit-fee.ui/submit])
|
||||
:theme :accent}
|
||||
(i18n/label :t/save)]]]))
|
||||
|
||||
(defn fee-bottom-sheet-eip1559
|
||||
[fee-display-symbol]
|
||||
(let [{priority-fee-edit :maxPriorityFeePerGas
|
||||
option :selected-fee-option
|
||||
fee-edit :maxFeePerGas}
|
||||
@(re-frame/subscribe [:signing/edit-fee])
|
||||
{:keys [normal fast slow]}
|
||||
@(re-frame/subscribe [:signing/priority-fee-suggestions-range])]
|
||||
[react/view
|
||||
[react/view {:style {:margin-horizontal 16 :margin-top 8}}
|
||||
[react/text {:style {:typography :title-bold}} (i18n/label :t/fee-options)]
|
||||
[react/text
|
||||
{:style {:margin-top 12}
|
||||
:accessibility-label :slow-fee
|
||||
:on-press #(re-frame/dispatch [:signing.edit-fee.ui/set-option :slow])}
|
||||
(string/join
|
||||
" "
|
||||
[(str (i18n/label :t/slow) ":")
|
||||
(str (:base-fee slow) " gwei")
|
||||
(str (:tip slow) " gwei")
|
||||
(when (= :slow option)
|
||||
"<- selected")])]
|
||||
[react/text
|
||||
{:style {:margin-top 12}
|
||||
:accessibility-label :normal-fee
|
||||
:on-press #(re-frame/dispatch [:signing.edit-fee.ui/set-option :normal])}
|
||||
(string/join
|
||||
" "
|
||||
[(str (i18n/label :t/normal) ":")
|
||||
(str (:base-fee normal) " gwei")
|
||||
(str (:tip normal) " gwei")
|
||||
(when (or (nil? option)
|
||||
(= :normal option))
|
||||
"<- selected")])]
|
||||
[react/text
|
||||
{:style {:margin-top 12}
|
||||
:accessibility-label :fast-fee
|
||||
:on-press #(re-frame/dispatch [:signing.edit-fee.ui/set-option :fast])}
|
||||
(string/join
|
||||
" "
|
||||
[(str (i18n/label :t/fast) ":")
|
||||
(str (:base-fee fast) " gwei")
|
||||
(str (:tip fast) " gwei")
|
||||
(when (= :fast option)
|
||||
"<- selected")])]
|
||||
(when (= :custom option)
|
||||
[react/text {:style {:margin-top 12}}
|
||||
(string/join
|
||||
" "
|
||||
[(str (i18n/label :t/custom) ":")
|
||||
(str (-> fee-edit
|
||||
:value-number
|
||||
(money/to-fixed 2))
|
||||
" gwei")
|
||||
(str (-> priority-fee-edit
|
||||
:value-number
|
||||
(money/to-fixed 2))
|
||||
" gwei")
|
||||
(when (= :custom option)
|
||||
"<- selected")])])]
|
||||
[react/view
|
||||
{:style {:margin-left 12
|
||||
:margin-right 16
|
||||
:margin-top 38}
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :space-between}
|
||||
[quo/button
|
||||
{:type :secondary
|
||||
:accessibility-label :set-custom-fee
|
||||
:on-press #(re-frame/dispatch
|
||||
[:bottom-sheet/show-sheet-old
|
||||
{:content (fn []
|
||||
[fee-bottom-sheet-eip1559-custom fee-display-symbol])
|
||||
:content-height 270}])}
|
||||
(i18n/label :t/set-custom-fee)]
|
||||
[quo/button
|
||||
{:type :primary
|
||||
:accessibility-label :save-custom-fee
|
||||
:theme :accent
|
||||
:on-press #(re-frame/dispatch [:signing.edit-fee.ui/submit])}
|
||||
(i18n/label :t/save)]]]))
|
||||
|
||||
(defn gwei
|
||||
[amount]
|
||||
(str (money/to-fixed amount 2)
|
||||
" "
|
||||
(i18n/label :t/gwei)))
|
||||
|
||||
(defn fees-warning
|
||||
[]
|
||||
(let [base-fee @(re-frame/subscribe [:wallet-legacy/current-base-fee])
|
||||
base-fee-gwei (money/wei-> :gwei (money/bignumber base-fee))
|
||||
priority-fee @(re-frame/subscribe [:wallet-legacy/current-priority-fee])
|
||||
priority-fee-gwei (money/wei-> :gwei (money/bignumber priority-fee))
|
||||
{priority-fee-edit :maxPriorityFeePerGas
|
||||
fee-edit :maxFeePerGas}
|
||||
@(re-frame/subscribe [:signing/edit-fee])]
|
||||
[react/view
|
||||
[react/view
|
||||
{:margin-top 24
|
||||
:margin-horizontal 24
|
||||
:margin-bottom 32
|
||||
:align-items :center}
|
||||
[react/view
|
||||
{:background-color colors/blue-light
|
||||
:width 32
|
||||
:height 32
|
||||
:border-radius 16
|
||||
:align-items :center
|
||||
:justify-content :center}
|
||||
[icons/icon :main-icons/warning {:color colors/black}]]
|
||||
[react/text
|
||||
{:style {:typography :title-bold
|
||||
:margin-top 16
|
||||
:margin-bottom 8}}
|
||||
(i18n/label :t/are-you-sure)]
|
||||
[react/text
|
||||
{:style {:color colors/gray
|
||||
:text-align :center
|
||||
:margin-horizontal 24}}
|
||||
(i18n/label :t/bad-fees-description)]]
|
||||
[react/view
|
||||
{:style {:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:margin-horizontal 32}}
|
||||
[react/text (i18n/label :t/current-base-fee)]
|
||||
[react/text (gwei base-fee-gwei)]]
|
||||
[react/view
|
||||
{:style {:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:margin-horizontal 32}}
|
||||
[react/text (i18n/label :t/current-minimum-tip)]
|
||||
[react/text (gwei (gas/get-minimum-priority-fee priority-fee))]]
|
||||
;;TODO(rasom): we can uncomment it once it will be clear which value can be
|
||||
;;used as "average" here
|
||||
#_[react/view
|
||||
{:style {:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:margin-horizontal 32}}
|
||||
[react/text (i18n/label :t/current-average-tip)]
|
||||
[react/text (gwei (money/to-fixed priority-fee-gwei 2))]]
|
||||
[react/view
|
||||
{:margin-vertical 16
|
||||
:height 1
|
||||
:background-color colors/gray-lighter}]
|
||||
[react/view
|
||||
{:style {:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:margin-horizontal 32
|
||||
:color :red}}
|
||||
[react/text {:style {:color (colors/get-color :negative-01)}}
|
||||
(i18n/label :t/your-tip-limit)]
|
||||
[react/text {:style {:color (colors/get-color :negative-01)}}
|
||||
(gwei (:value-number priority-fee-edit))]]
|
||||
[react/view
|
||||
{:style {:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:margin-horizontal 32}}
|
||||
[react/text {:style {:color (colors/get-color :negative-01)}}
|
||||
(i18n/label :t/your-price-limit)]
|
||||
[react/text {:style {:color (colors/get-color :negative-01)}}
|
||||
(gwei (:value-number fee-edit))]]
|
||||
[react/view
|
||||
{:style
|
||||
{:background-color colors/gray-lighter
|
||||
:padding-horizontal 32
|
||||
:padding-vertical 16
|
||||
:margin-vertical 16}}
|
||||
[react/view
|
||||
{:style {:flex-direction :row
|
||||
:justify-content :space-between}}
|
||||
[react/text (i18n/label :t/suggested-min-tip)]
|
||||
[react/text (gwei priority-fee-gwei)]]
|
||||
[react/view
|
||||
{:style {:flex-direction :row
|
||||
:justify-content :space-between}}
|
||||
[react/text (i18n/label :t/suggested-price-limit)]
|
||||
[react/text (gwei (money/add base-fee-gwei priority-fee-gwei))]]]
|
||||
[react/view
|
||||
{:style {:align-items :center
|
||||
:justify-content :center
|
||||
:margin-top 8}}
|
||||
[quo/button
|
||||
{:type :primary
|
||||
:on-press #(re-frame/dispatch [:hide-popover])}
|
||||
(i18n/label :t/change-tip)]]
|
||||
[react/view
|
||||
{:style {:align-items :center
|
||||
:justify-content :center
|
||||
:margin-top 8
|
||||
:margin-bottom 16}}
|
||||
[quo/button
|
||||
{:type :secondary
|
||||
:on-press #(do (re-frame/dispatch [:hide-popover])
|
||||
(re-frame/dispatch [:signing.edit-fee.ui/submit true]))}
|
||||
(i18n/label :t/continue-anyway)]]]))
|
||||
|
||||
(defn advanced
|
||||
[]
|
||||
(let [nonce (reagent/atom nil)
|
||||
default-nonce (:nonce @(re-frame/subscribe [:signing/tx]))]
|
||||
(fn []
|
||||
[react/view {:padding 20}
|
||||
[quo/text-input
|
||||
{:label (i18n/label :t/nonce)
|
||||
:accessibility-label :nonce
|
||||
:keyboard-type :numeric
|
||||
:default-value default-nonce
|
||||
:on-change-text #(reset! nonce %)
|
||||
:show-cancel false
|
||||
:auto-focus true
|
||||
:container-style {:margin-bottom 20}}]
|
||||
[react/view {:align-items :flex-end}
|
||||
[quo/button
|
||||
{:type :primary
|
||||
:accessibility-label :save-nonce
|
||||
:theme :accent
|
||||
:on-press #(re-frame/dispatch [:signing.nonce/submit @nonce])}
|
||||
(i18n/label :t/save)]]])))
|
||||
@@ -1,65 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.signing.styles
|
||||
(:require
|
||||
[legacy.status-im.ui.components.colors :as colors]))
|
||||
|
||||
(def header
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :space-between
|
||||
:padding-top 16
|
||||
:padding-left 16
|
||||
:margin-bottom 11})
|
||||
|
||||
(def message-header
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :space-between
|
||||
:padding-top 20
|
||||
:padding-left 16
|
||||
:padding-right 24
|
||||
:margin-bottom 19})
|
||||
|
||||
(defn message
|
||||
[]
|
||||
{:background-color colors/white
|
||||
:border-top-right-radius 16
|
||||
:border-top-left-radius 16
|
||||
:padding-bottom 40})
|
||||
|
||||
(def message-border
|
||||
{:margin-horizontal 24
|
||||
:max-height 96
|
||||
:min-height 35
|
||||
:flex 1
|
||||
:border-radius 8
|
||||
:border-color colors/black-transparent
|
||||
:border-width 1
|
||||
:padding 8})
|
||||
|
||||
(defn sheet
|
||||
[]
|
||||
{:background-color colors/white
|
||||
:border-top-right-radius 16
|
||||
:border-top-left-radius 16
|
||||
:padding-bottom 40})
|
||||
|
||||
(defn sign-with-keycard-button
|
||||
[disabled?]
|
||||
{:background-color (if (colors/dark?) "#27D8B9" colors/black-light)
|
||||
:padding-top 2
|
||||
:border-radius 8
|
||||
:width 182
|
||||
:height 44
|
||||
:flex-direction :row
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:opacity (if disabled? 0.1 1)
|
||||
:padding-horizontal 12})
|
||||
|
||||
(defn sign-with-keycard-button-text
|
||||
[disabled?]
|
||||
{:padding-right 2
|
||||
:padding-left 16
|
||||
:color (if disabled? colors/black colors/white-persist)
|
||||
:padding-horizontal 16
|
||||
:padding-vertical 10})
|
||||
@@ -1,386 +0,0 @@
|
||||
(ns legacy.status-im.ui.screens.signing.views
|
||||
(:require-macros [legacy.status-im.utils.views :as views])
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.react-native.resources :as resources]
|
||||
[legacy.status-im.signing.eip1559 :as eip1559]
|
||||
[legacy.status-im.ui.components.bottom-panel.views :as bottom-panel]
|
||||
[legacy.status-im.ui.components.chat-icon.screen :as chat-icon]
|
||||
[legacy.status-im.ui.components.colors :as colors]
|
||||
[legacy.status-im.ui.components.copyable-text :as copyable-text]
|
||||
[legacy.status-im.ui.components.core :as quo]
|
||||
[legacy.status-im.ui.components.icons.icons :as icons]
|
||||
[legacy.status-im.ui.components.list.item :as list.item]
|
||||
[legacy.status-im.ui.components.react :as react]
|
||||
[legacy.status-im.ui.screens.signing.sheets :as sheets]
|
||||
[legacy.status-im.ui.screens.signing.styles :as styles]
|
||||
[legacy.status-im.utils.deprecated-types :as types]
|
||||
[legacy.status-im.utils.utils :as utils]
|
||||
[re-frame.core :as re-frame]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.contexts.profile.utils :as profile.utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(defn separator
|
||||
[]
|
||||
[react/view {:height 1 :background-color colors/gray-lighter}])
|
||||
|
||||
(defn contact-item
|
||||
[title {:keys [address] :as profile}]
|
||||
[copyable-text/copyable-text-view
|
||||
{:copied-text address}
|
||||
[list.item/list-item
|
||||
{:title title
|
||||
:title-prefix-width 45
|
||||
:size :small
|
||||
:accessory :text
|
||||
:accessory-text [quo/text
|
||||
{:ellipsize-mode :middle
|
||||
:number-of-lines 1
|
||||
:monospace true}
|
||||
(profile.utils/displayed-name profile)]}]])
|
||||
|
||||
(defn token-item
|
||||
[{:keys [icon color] :as token} display-symbol]
|
||||
(when token
|
||||
[react/view
|
||||
[list.item/list-item
|
||||
{:size :small
|
||||
:title (i18n/label :t/wallet-asset)
|
||||
:accessory [react/view {:flex-direction :row}
|
||||
[quo/text
|
||||
{:color :secondary
|
||||
:style {:margin-right 8}}
|
||||
display-symbol]
|
||||
(if icon
|
||||
[react/view]
|
||||
[chat-icon/custom-icon-view-list (:name token) color 32])]}]
|
||||
[separator]]))
|
||||
|
||||
(defn header
|
||||
[{:keys [in-progress?] :as sign}
|
||||
{:keys [contact amount approve? cancel?] :as tx}
|
||||
display-symbol fee fee-display-symbol]
|
||||
[react/view styles/header
|
||||
(when sign
|
||||
[react/touchable-highlight
|
||||
(when-not in-progress? {:on-press #(re-frame/dispatch [:set :signing/sign nil])})
|
||||
[react/view {:padding-right 16}
|
||||
[icons/icon :main-icons/back]]])
|
||||
[react/view {:flex 1}
|
||||
(if amount
|
||||
[react/text {:style {:typography :title-bold}}
|
||||
(str (cond approve?
|
||||
(i18n/label :t/authorize)
|
||||
cancel?
|
||||
(i18n/label :t/cancelling)
|
||||
:else
|
||||
(i18n/label :t/sending))
|
||||
(if cancel?
|
||||
(str " " (utils/get-shortened-address (:hash tx)))
|
||||
(str " " amount " " display-symbol)))]
|
||||
[react/text {:style {:typography :title-bold}} (i18n/label :t/contract-interaction)])
|
||||
(if sign
|
||||
[react/nested-text
|
||||
{:style {:color colors/gray}
|
||||
:ellipsize-mode :middle
|
||||
:number-of-lines 1} (i18n/label :t/to-capitalized) " "
|
||||
[{:style {:color colors/black}} (profile.utils/displayed-name contact)]]
|
||||
[react/text {:style {:margin-top 6 :color colors/gray}}
|
||||
(str fee " " fee-display-symbol " " (string/lower-case (i18n/label :t/network-fee)))])]
|
||||
[react/view {:padding-horizontal 24}
|
||||
[quo/button
|
||||
(merge {:type :secondary}
|
||||
(when-not in-progress? {:on-press #(re-frame/dispatch [:signing.ui/cancel-is-pressed])}))
|
||||
(i18n/label :t/cancel)]]])
|
||||
|
||||
(defn sign-with-keycard-button
|
||||
[amount-error gas-error]
|
||||
(let [disabled? (or amount-error gas-error)]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(when-not disabled?
|
||||
(re-frame/dispatch [:signing.ui/sign-with-keycard-pressed]))}
|
||||
[react/view (styles/sign-with-keycard-button disabled?)
|
||||
[react/text {:style (styles/sign-with-keycard-button-text disabled?)}
|
||||
(i18n/label :t/sign-with)]
|
||||
[react/view {:padding-right 16}
|
||||
[react/image
|
||||
{:source (resources/get-image :keycard-logo)
|
||||
:style (merge {:width 64
|
||||
:margin-bottom 7
|
||||
:height 26}
|
||||
(when (colors/dark?)
|
||||
{:tint-color colors/white-persist}))}]]]]))
|
||||
|
||||
(defn- signing-phrase-view
|
||||
[phrase]
|
||||
[react/view {:align-items :center}
|
||||
[react/text {:style {:color colors/gray :padding-bottom 8}} (i18n/label :t/signing-phrase)]
|
||||
[react/text phrase]])
|
||||
|
||||
(defn- keycard-view
|
||||
[_ phrase]
|
||||
[react/view
|
||||
[signing-phrase-view phrase]
|
||||
[react/view {:align-items :center :margin-top 16 :margin-bottom 40}
|
||||
[sign-with-keycard-button nil nil]]])
|
||||
|
||||
(defn- transaction-data-item
|
||||
[data]
|
||||
(let [text (types/clj->pretty-json data 2)]
|
||||
[react/view
|
||||
[react/text
|
||||
{:style {:font-size 17
|
||||
:line-height 20
|
||||
:margin-bottom 24}}
|
||||
text]]))
|
||||
|
||||
(views/defview transaction-data
|
||||
[]
|
||||
(views/letsubs
|
||||
[{:keys [formatted-data]} [:signing/sign]]
|
||||
[react/view {:style {:flex 1}}
|
||||
[react/view
|
||||
{:style {:margin-horizontal 24
|
||||
:margin-top 24}}
|
||||
[react/text
|
||||
{:style {:font-size 17
|
||||
:font-weight "700"}}
|
||||
(i18n/label :t/transaction-data)]]
|
||||
[react/scroll-view
|
||||
{:style {:flex 1
|
||||
:margin-horizontal 8
|
||||
:padding-horizontal 16
|
||||
:padding-vertical 10
|
||||
:margin-vertical 14}}
|
||||
[transaction-data-item formatted-data]]
|
||||
[separator]
|
||||
[react/view
|
||||
{:style {:margin-horizontal 8
|
||||
:margin-vertical 16}}
|
||||
[quo/button {:on-press #(re-frame/dispatch [:hide-popover])}
|
||||
(i18n/label :t/close)]]]))
|
||||
|
||||
(views/defview password-view
|
||||
[{:keys [type error in-progress? enabled?] :as sign}]
|
||||
(views/letsubs [phrase [:signing/phrase]]
|
||||
(case type
|
||||
:password
|
||||
[react/view {:padding-top 8 :padding-bottom 8}
|
||||
[signing-phrase-view phrase]
|
||||
[react/view
|
||||
{:padding-horizontal 16
|
||||
:padding-vertical 12}
|
||||
[quo/text-input
|
||||
{:secure-text-entry true
|
||||
:placeholder (i18n/label :t/enter-password)
|
||||
:on-change-text #(re-frame/dispatch [:signing.ui/password-is-changed
|
||||
(security/mask-data %)])
|
||||
:accessibility-label :enter-password-input
|
||||
:auto-capitalize :none
|
||||
:editable (not in-progress?)
|
||||
:error error
|
||||
:show-cancel false}]]
|
||||
[react/view {:align-items :center :height 60}
|
||||
(if in-progress?
|
||||
[react/activity-indicator
|
||||
{:animating true
|
||||
:size :large}]
|
||||
[quo/button
|
||||
{:on-press #(re-frame/dispatch [:signing.ui/sign-is-pressed])
|
||||
:disabled (not enabled?)}
|
||||
(i18n/label :t/transactions-sign)])]]
|
||||
:keycard
|
||||
[keycard-view sign phrase]
|
||||
[react/view])))
|
||||
|
||||
(views/defview message-sheet
|
||||
[]
|
||||
(views/letsubs [{:keys [formatted-data] :as sign} [:signing/sign-message]]
|
||||
[react/view (styles/message)
|
||||
[react/view styles/message-header
|
||||
[react/text {:style {:typography :title-bold}} (i18n/label :t/signing-a-message)]
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:signing.ui/cancel-is-pressed])}
|
||||
[react/view {:padding 6}
|
||||
[react/text {:style {:color colors/blue}} (i18n/label :t/cancel)]]]]
|
||||
[separator]
|
||||
[react/view {:padding-top 16 :flex 1}
|
||||
[react/view styles/message-border
|
||||
[react/scroll-view
|
||||
[react/text (or formatted-data "")]]]
|
||||
[password-view sign]]]))
|
||||
|
||||
(defn error-item
|
||||
[]
|
||||
(fn [title show-error]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(swap! show-error not)
|
||||
:underlay-color (:interactive-02 @colors/theme)}
|
||||
[react/view
|
||||
{:style {:align-items :center
|
||||
:flex-direction :row}}
|
||||
[react/text {:style {:color colors/red :margin-right 8}}
|
||||
(i18n/label title)]
|
||||
[icons/icon :warning {:color colors/red}]]]))
|
||||
|
||||
(defn amount-item
|
||||
[]
|
||||
(let [show-error (reagent/atom false)]
|
||||
(fn [prices wallet-currency amount amount-error display-symbol fee-display-symbol prices-loading?]
|
||||
(let [converted-value (* amount
|
||||
(get-in prices
|
||||
[(keyword display-symbol) (keyword (:code wallet-currency))]))]
|
||||
[list.item/list-item
|
||||
{:size :small
|
||||
:title (if amount-error
|
||||
[error-item :t/send-request-amount show-error]
|
||||
(i18n/label :t/send-request-amount))
|
||||
:error (when (and amount-error @show-error) amount-error)
|
||||
:animated false
|
||||
:accessory [react/view {:style {:flex-direction :row}}
|
||||
[react/nested-text {:style {:color colors/gray}}
|
||||
[{:style {:color colors/black}} (utils/format-decimals amount 6)]
|
||||
" "
|
||||
(or display-symbol fee-display-symbol)
|
||||
" • "]
|
||||
(if prices-loading?
|
||||
[react/small-loading-indicator]
|
||||
[react/text {:style {:color colors/black}}
|
||||
(i18n/format-currency converted-value (:code wallet-currency))])
|
||||
[react/text {:style {:color colors/gray}} (str " " (:code wallet-currency))]]}]))))
|
||||
|
||||
(views/defview fee-item
|
||||
[prices wallet-currency fee-display-symbol fee
|
||||
insufficient-balance? gas-error gas-error-state prices-loading?]
|
||||
(views/letsubs [{:keys [gas-price-loading? gas-loading?]} [:signing/edit-fee]
|
||||
show-error (reagent/atom false)]
|
||||
(let [converted-fee-value (* fee
|
||||
(get-in prices
|
||||
[(keyword fee-display-symbol)
|
||||
(keyword (:code wallet-currency))]))]
|
||||
[list.item/list-item
|
||||
{:size :small
|
||||
:title (if (and (not (or gas-price-loading? gas-loading?)) gas-error)
|
||||
[error-item :t/network-fee show-error]
|
||||
(i18n/label :t/network-fee))
|
||||
:error (when (and (not (or gas-price-loading? gas-loading?)) gas-error @show-error)
|
||||
gas-error)
|
||||
:disabled (or insufficient-balance? gas-price-loading? gas-loading?)
|
||||
:chevron (not insufficient-balance?)
|
||||
:animated false
|
||||
:accessory (when-not insufficient-balance?
|
||||
(if (or gas-price-loading? gas-loading?)
|
||||
[react/small-loading-indicator]
|
||||
(if (= :gas-isnt-set gas-error-state)
|
||||
[react/text
|
||||
{:style {:color colors/blue}
|
||||
:accessibility-label :custom-gas-fee}
|
||||
(i18n/label :t/set-custom-fee)]
|
||||
[react/view
|
||||
{:style {:flex-direction :row}
|
||||
:accessibility-label :custom-gas-fee}
|
||||
[react/nested-text {:style {:color colors/gray}}
|
||||
[{:style {:color colors/black}} (utils/format-decimals fee 6)]
|
||||
" "
|
||||
fee-display-symbol
|
||||
" • "]
|
||||
(if prices-loading?
|
||||
[react/small-loading-indicator]
|
||||
[react/text {:style {:color colors/black}}
|
||||
(i18n/format-currency converted-fee-value (:code wallet-currency))])
|
||||
[react/text {:style {:color colors/gray}}
|
||||
(str " " (:code wallet-currency))]])))
|
||||
:on-press #(re-frame/dispatch
|
||||
[:signing.ui/open-fee-sheet
|
||||
{:content (fn []
|
||||
(if (eip1559/enabled?)
|
||||
[sheets/fee-bottom-sheet-eip1559-custom fee-display-symbol]
|
||||
[sheets/fee-bottom-sheet fee-display-symbol]))}])}])))
|
||||
|
||||
(views/defview network-item
|
||||
[]
|
||||
(views/letsubs [network-name [:network-name]]
|
||||
[list.item/list-item
|
||||
{:title (i18n/label :t/network)
|
||||
:size :small
|
||||
:accessory :text
|
||||
:accessory-text network-name}]))
|
||||
|
||||
(defn advanced-item
|
||||
[]
|
||||
[:<>
|
||||
[separator]
|
||||
[list.item/list-item
|
||||
{:size :small
|
||||
:title (i18n/label :t/advanced)
|
||||
:chevron true
|
||||
:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet-old {:content sheets/advanced}])}]])
|
||||
|
||||
(views/defview sheet
|
||||
[{:keys [from contact amount token cancel?] :as tx}]
|
||||
(views/letsubs [fee [:signing/fee]
|
||||
sign [:signing/sign]
|
||||
{:keys [amount-error gas-error gas-error-state insufficient-balalce?]}
|
||||
[:signing/amount-errors (:address from)]
|
||||
keycard-multiaccount? [:keycard-multiaccount?]
|
||||
prices [:prices]
|
||||
wallet-currency [:wallet-legacy/currency]
|
||||
mainnet? [:mainnet?]
|
||||
prices-loading? [:prices-loading?]
|
||||
management-enabled? [:wallet-legacy/transactions-management-enabled?]]
|
||||
(let [display-symbol nil
|
||||
fee-display-symbol nil]
|
||||
[react/view (styles/sheet)
|
||||
[header sign tx display-symbol fee fee-display-symbol]
|
||||
[separator]
|
||||
(if sign
|
||||
[react/view {:padding-top 20}
|
||||
[password-view sign]]
|
||||
[react/view
|
||||
(when-not mainnet?
|
||||
[react/view
|
||||
[network-item]
|
||||
[separator]])
|
||||
[contact-item (i18n/label :t/from-capitalized) from]
|
||||
[separator]
|
||||
[contact-item (i18n/label :t/to-capitalized) contact]
|
||||
(when-not cancel?
|
||||
[separator])
|
||||
(when-not cancel?
|
||||
[token-item token display-symbol])
|
||||
(when-not cancel?
|
||||
[amount-item prices wallet-currency amount amount-error display-symbol fee-display-symbol
|
||||
prices-loading?])
|
||||
[separator]
|
||||
[fee-item prices wallet-currency fee-display-symbol fee insufficient-balalce? gas-error
|
||||
gas-error-state prices-loading?]
|
||||
(when (and management-enabled? (not keycard-multiaccount?))
|
||||
[advanced-item])
|
||||
(when (= :gas-is-set gas-error-state)
|
||||
[react/text {:style {:color colors/gray :margin-horizontal 32 :text-align :center}}
|
||||
(i18n/label :t/tx-fail-description1)])
|
||||
[react/view {:align-items :center :margin-top 16 :margin-bottom 40}
|
||||
(if keycard-multiaccount?
|
||||
[sign-with-keycard-button amount-error gas-error]
|
||||
(if (= :gas-isnt-set gas-error-state)
|
||||
[react/text {:style {:color colors/gray :margin-horizontal 32 :text-align :center}}
|
||||
(i18n/label :t/tx-fail-description2)]
|
||||
[quo/button
|
||||
{:on-press #(re-frame/dispatch [:set :signing/sign {:type :password}])
|
||||
:disabled (or amount-error gas-error)
|
||||
:theme (if gas-error-state :negative :main)}
|
||||
(i18n/label (if gas-error-state
|
||||
:t/sign-anyway
|
||||
:t/sign-with-password))]))]])])))
|
||||
|
||||
(views/defview signing
|
||||
[]
|
||||
(views/letsubs [tx [:signing/tx]]
|
||||
[bottom-panel/animated-bottom-panel
|
||||
;;we use select-keys here because we don't want to update view if other keys in map are changed
|
||||
(when tx (select-keys tx [:from :contact :amount :token :approve? :message :cancel? :hash]))
|
||||
#(if (:message %)
|
||||
[message-sheet]
|
||||
[sheet %])
|
||||
#(re-frame/dispatch [:hide-signing-sheet])]))
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
(defn- f-animated-header-list
|
||||
[{:keys [header-comp main-comp back-button-on-press] :as params}]
|
||||
(let [theme (quo.theme/use-theme-value)
|
||||
(let [theme (quo.theme/use-theme)
|
||||
window-height (:height (rn/get-window))
|
||||
{:keys [top bottom]} (safe-area/get-insets)
|
||||
;; view height calculation is different because window height is different on iOS and
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
{:height (:size opts)
|
||||
:width (:size opts)
|
||||
:borderRadius (style/get-border-radius (:size opts))
|
||||
:backgroundColor (colors/resolve-color (:customization-color opts) :dark)})
|
||||
:backgroundColor (colors/resolve-color (:customization-color opts) :light)})
|
||||
(h/is-truthy (h/query-by-label-text :account-emoji))
|
||||
(h/has-style (h/query-by-label-text :account-emoji)
|
||||
{:fontSize (style/get-emoji-size (:size opts))})
|
||||
@@ -65,7 +65,7 @@
|
||||
{:height (:size opts)
|
||||
:width (:size opts)
|
||||
:borderRadius (style/get-border-radius (:size opts))
|
||||
:backgroundColor (colors/resolve-color (:customization-color opts) :dark)})
|
||||
:backgroundColor (colors/resolve-color (:customization-color opts) :light)})
|
||||
(h/is-truthy (h/query-by-label-text :account-emoji))
|
||||
(h/has-style (h/query-by-label-text :account-emoji)
|
||||
{:fontSize (style/get-emoji-size (:size opts))})
|
||||
|
||||