Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9983dd5f7d | ||
|
|
1a22a0ac10 | ||
|
|
616b5224c7 | ||
|
|
0d8ac7de81 | ||
|
|
e9f97f7b3b | ||
|
|
f45f96975e | ||
|
|
53d5ac4ea2 | ||
|
|
874f07bd77 | ||
|
|
4efb3c111a | ||
|
|
de2b5fb935 | ||
|
|
5f8d5fd57e | ||
|
|
763b291629 | ||
|
|
9f50686042 | ||
|
|
1652601a82 | ||
|
|
7a44db36fe | ||
|
|
338b241c8e | ||
|
|
91761a92c7 | ||
|
|
4b2a1db12f | ||
|
|
05d4b4b068 | ||
|
|
9c9b55fe3e | ||
|
|
6ec307a8bb | ||
|
|
86553eff14 | ||
|
|
60911a1dd1 |
@@ -35,4 +35,4 @@ TEST_NETWORKS_ENABLED=1
|
||||
SHOW_NOT_IMPLEMENTED_FEATURES=0
|
||||
ENABLE_ALERT_BANNER=0
|
||||
FLAG_WALLET_CONNECT_ENABLED=1
|
||||
LOG_REQUEST_GO=1
|
||||
API_LOGGING_ENABLED=1
|
||||
|
||||
@@ -39,4 +39,4 @@ DELETE_MESSAGE_UNDO_TIME_LIMIT=10000
|
||||
ENABLE_ALERT_BANNER=0
|
||||
FLAG_WALLET_CONNECT_ENABLED=1
|
||||
MOBILE_DATA_SYNCING_TOGGLE_ENABLE=0
|
||||
LOG_REQUEST_GO=1
|
||||
API_LOGGING_ENABLED=1
|
||||
|
||||
@@ -36,4 +36,4 @@ FAST_CREATE_COMMUNITY_ENABLED=1
|
||||
TEST_NETWORKS_ENABLED=1
|
||||
ENABLE_ALERT_BANNER=1
|
||||
FLAG_WALLET_CONNECT_ENABLED=1
|
||||
LOG_REQUEST_GO=1
|
||||
API_LOGGING_ENABLED=1
|
||||
|
||||
@@ -23,4 +23,4 @@ FAST_CREATE_COMMUNITY_ENABLED=0
|
||||
TEST_NETWORKS_ENABLED=0
|
||||
ENABLE_ALERT_BANNER=1
|
||||
FLAG_WALLET_CONNECT_ENABLED=1
|
||||
LOG_REQUEST_GO=0
|
||||
API_LOGGING_ENABLED=0
|
||||
|
||||
@@ -20,4 +20,4 @@ FAST_CREATE_COMMUNITY_ENABLED=0
|
||||
TEST_NETWORKS_ENABLED=0
|
||||
STATUS_PROXY_STAGE_NAME=prod
|
||||
FLAG_WALLET_CONNECT_ENABLED=1
|
||||
LOG_REQUEST_GO=0
|
||||
API_LOGGING_ENABLED=0
|
||||
|
||||
@@ -26,7 +26,7 @@ export STATUS_BACKEND_SERVER_HOST="127.0.0.1:60000"
|
||||
export STATUS_BACKEND_SERVER_ROOT_DATA_DIR="/path/to/your/root/data/dir"
|
||||
```
|
||||
You need to change `STATUS_BACKEND_SERVER_ROOT_DATA_DIR` to your preferred directory and ensure it exists, it should be in absolute path.
|
||||
All the db files and log files(requests.log/geth.log) and keystore files etc will be stored in this directory.
|
||||
All the db files and log files(api.log/geth.log) and keystore files etc will be stored in this directory.
|
||||
|
||||
### Start the status backend server:
|
||||
```shell
|
||||
|
||||
@@ -248,10 +248,14 @@ class AccountManager(private val reactContext: ReactApplicationContext) : ReactC
|
||||
@ReactMethod
|
||||
private fun initializeApplication(request: String, callback: Callback) {
|
||||
Log.d(TAG, "initializeApplication")
|
||||
val jsonParams = JSONObject(request)
|
||||
// for ios, the log dir will be the same as the root data dir, status-go will default to root data dir if logDir is not provided
|
||||
jsonParams.put("logDir", utils.getPublicStorageDirectory()?.absolutePath)
|
||||
val jsonString = jsonParams.toString()
|
||||
StatusBackendClient.executeStatusGoRequestWithCallback(
|
||||
"InitializeApplication",
|
||||
request,
|
||||
{ Statusgo.initializeApplication(request) },
|
||||
jsonString,
|
||||
{ Statusgo.initializeApplication(jsonString) },
|
||||
callback
|
||||
)
|
||||
}
|
||||
|
||||
@@ -195,25 +195,6 @@ class LogManager(private val reactContext: ReactApplicationContext) : ReactConte
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun initLogging(enabled: Boolean, mobileSystem: Boolean, logLevel: String, logRequestGo: Boolean, callback: Callback) {
|
||||
val jsonConfig = JSONObject().apply {
|
||||
put("Enabled", enabled)
|
||||
put("MobileSystem", mobileSystem)
|
||||
put("Level", logLevel)
|
||||
put("File", getGethLogFile().absolutePath)
|
||||
put("LogRequestGo", logRequestGo)
|
||||
put("LogRequestFile", getRequestLogFile().absolutePath)
|
||||
}
|
||||
val config = jsonConfig.toString()
|
||||
StatusBackendClient.executeStatusGoRequestWithCallback(
|
||||
endpoint = "InitLogging",
|
||||
requestBody = config,
|
||||
statusgoFunction = { Statusgo.initLogging(config) },
|
||||
callback = callback
|
||||
)
|
||||
}
|
||||
|
||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||
fun logFileDirectory(): String? {
|
||||
return utils.getPublicStorageDirectory()?.absolutePath
|
||||
@@ -223,7 +204,7 @@ class LogManager(private val reactContext: ReactApplicationContext) : ReactConte
|
||||
private const val TAG = "LogManager"
|
||||
private const val gethLogFileName = "geth.log"
|
||||
private const val statusLogFileName = "Status.log"
|
||||
private const val requestsLogFileName = "requests.log"
|
||||
private const val requestsLogFileName = "api.log"
|
||||
private const val logsZipFileName = "Status-debug-logs.zip"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ RCT_EXPORT_METHOD(sendLogs:(NSString *)dbJson
|
||||
NSURL *mainGethLogsFile = [rootUrl URLByAppendingPathComponent:@"geth.log"];
|
||||
NSURL *mainLogsFile = [logsFolderName URLByAppendingPathComponent:@"geth.log"];
|
||||
|
||||
NSURL *requestsLogFile = [rootUrl URLByAppendingPathComponent:@"requests.log"];
|
||||
NSURL *requestsLogFile = [rootUrl URLByAppendingPathComponent:@"api.log"];
|
||||
|
||||
[dbJson writeToFile:dbFile.path atomically:YES encoding:NSUTF8StringEncoding error:nil];
|
||||
[jsLogs writeToFile:jsLogsFile.path atomically:YES encoding:NSUTF8StringEncoding error:nil];
|
||||
@@ -44,7 +44,7 @@ RCT_EXPORT_METHOD(sendLogs:(NSString *)dbJson
|
||||
[fileManager copyItemAtPath:mainGethLogsFile.path toPath:mainLogsFile.path error:nil];
|
||||
|
||||
if ([fileManager fileExistsAtPath:requestsLogFile.path]) {
|
||||
[fileManager copyItemAtPath:requestsLogFile.path toPath:[logsFolderName URLByAppendingPathComponent:@"requests.log"].path error:nil];
|
||||
[fileManager copyItemAtPath:requestsLogFile.path toPath:[logsFolderName URLByAppendingPathComponent:@"api.log"].path error:nil];
|
||||
}
|
||||
|
||||
[SSZipArchive createZipFileAtPath:zipFile.path withContentsOfDirectory:logsFolderName.path];
|
||||
@@ -53,43 +53,6 @@ RCT_EXPORT_METHOD(sendLogs:(NSString *)dbJson
|
||||
callback(@[zipFile.absoluteString]);
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(initLogging:(BOOL)enabled
|
||||
mobileSystem:(BOOL)mobileSystem
|
||||
logLevel:(NSString *)logLevel
|
||||
logRequestGo:(BOOL)logRequestGo
|
||||
callback:(RCTResponseSenderBlock)callback)
|
||||
{
|
||||
NSString *logDirectory = [self logFileDirectory];
|
||||
NSString *logFilePath = [logDirectory stringByAppendingPathComponent:@"geth.log"];
|
||||
NSString *logRequestFilePath = [logDirectory stringByAppendingPathComponent:@"requests.log"];
|
||||
|
||||
NSDictionary *config = @{
|
||||
@"Enabled": @(enabled),
|
||||
@"MobileSystem": @(mobileSystem),
|
||||
@"Level": logLevel,
|
||||
@"File": logFilePath,
|
||||
@"LogRequestGo": @(logRequestGo),
|
||||
@"LogRequestFile": logRequestFilePath
|
||||
};
|
||||
|
||||
NSError *error;
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:config options:0 error:&error];
|
||||
|
||||
if (error) {
|
||||
NSLog(@"Error creating JSON: %@", [error localizedDescription]);
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *configJson = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
||||
|
||||
[StatusBackendClient executeStatusGoRequestWithCallback:@"InitLogging"
|
||||
body:configJson
|
||||
statusgoFunction:^NSString *{
|
||||
return StatusgoInitLogging(configJson);
|
||||
}
|
||||
callback:callback];
|
||||
}
|
||||
|
||||
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(logFileDirectory) {
|
||||
NSURL *rootUrl = [Utils getRootUrl];
|
||||
return rootUrl.path;
|
||||
|
||||
@@ -1946,35 +1946,6 @@ void _ConnectionChange(const FunctionCallbackInfo<Value>& args) {
|
||||
ConnectionChange(arg0, arg1);
|
||||
}
|
||||
|
||||
void _InitLogging(const FunctionCallbackInfo<Value>& args) {
|
||||
Isolate* isolate = args.GetIsolate();
|
||||
Local<Context> context = isolate->GetCurrentContext();
|
||||
|
||||
if (args.Length() != 1) {
|
||||
// Throw an Error that is passed back to JavaScript
|
||||
isolate->ThrowException(Exception::TypeError(
|
||||
String::NewFromUtf8Literal(isolate, "Wrong number of arguments for InitLogging")));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the argument types
|
||||
if (!args[0]->IsString()) {
|
||||
isolate->ThrowException(Exception::TypeError(
|
||||
String::NewFromUtf8Literal(isolate, "Wrong argument type for 'logSettingsJSON'")));
|
||||
return;
|
||||
}
|
||||
|
||||
String::Utf8Value arg0Obj(isolate, args[0]->ToString(context).ToLocalChecked());
|
||||
char *arg0 = *arg0Obj;
|
||||
|
||||
// Call exported Go function, which returns a C string
|
||||
char *c = InitLogging(arg0);
|
||||
|
||||
Local<String> ret = String::NewFromUtf8(isolate, c).ToLocalChecked();
|
||||
args.GetReturnValue().Set(ret);
|
||||
delete c;
|
||||
}
|
||||
|
||||
void _RestoreAccountAndLogin(const FunctionCallbackInfo<Value>& args) {
|
||||
Isolate* isolate = args.GetIsolate();
|
||||
Local<Context> context = isolate->GetCurrentContext();
|
||||
@@ -2064,7 +2035,6 @@ void init(Local<Object> exports) {
|
||||
NODE_SET_METHOD(exports, "hashTransaction", _HashTransaction);
|
||||
NODE_SET_METHOD(exports, "connectionChange", _ConnectionChange);
|
||||
NODE_SET_METHOD(exports, "pollSignal", _PollSignal);
|
||||
NODE_SET_METHOD(exports, "initLogging", _InitLogging);
|
||||
NODE_SET_METHOD(exports, "restoreAccountAndLogin", _RestoreAccountAndLogin);
|
||||
}
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 91 KiB |
@@ -2,7 +2,9 @@
|
||||
(:require
|
||||
["react-native" :as rn]
|
||||
["react-native-status-keycard" :default status-keycard]
|
||||
[oops.core :as oops]
|
||||
[react-native.platform :as platform]
|
||||
[schema.core :as schema]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(defonce event-emitter
|
||||
@@ -254,17 +256,19 @@
|
||||
(catch on-failure))))
|
||||
|
||||
(defn sign
|
||||
[{pin :pin path :path card-hash :hash on-success :on-success on-failure :on-failure}]
|
||||
(when (and pin card-hash)
|
||||
(if path
|
||||
(.. status-keycard
|
||||
(signWithPath pin path card-hash)
|
||||
(then on-success)
|
||||
(catch on-failure))
|
||||
(.. status-keycard
|
||||
(sign pin card-hash)
|
||||
(then on-success)
|
||||
(catch on-failure)))))
|
||||
[{:keys [pin path hash-data]}]
|
||||
(if path
|
||||
(oops/ocall status-keycard "signWithPath" pin path hash-data)
|
||||
(oops/ocall status-keycard "sign" pin hash-data)))
|
||||
|
||||
(schema/=> sign
|
||||
[:=>
|
||||
[:cat
|
||||
[:map
|
||||
[:pin :string]
|
||||
[:hash-data :string]
|
||||
[:path {:optional true} [:maybe :string]]]]
|
||||
:any])
|
||||
|
||||
(defn sign-typed-data
|
||||
[{card-hash :hash on-success :on-success on-failure :on-failure}]
|
||||
|
||||
@@ -18,25 +18,23 @@
|
||||
clock-value
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000"))
|
||||
|
||||
(rf/defn update-chats-in-app-db
|
||||
{:events [:chats-list/load-success]}
|
||||
[{:keys [db]} ^js new-chats-js]
|
||||
(let [{:keys [all-chats chats-home-list]}
|
||||
(reduce (fn [acc ^js chat-js]
|
||||
(let [{:keys [chat-id profile-public-key timeline? community-id active] :as chat}
|
||||
(data-store.chats/<-rpc-js chat-js)]
|
||||
(cond-> acc
|
||||
(and (not profile-public-key) (not timeline?) (not community-id) active)
|
||||
(update :chats-home-list conj chat-id)
|
||||
:always
|
||||
(assoc-in [:all-chats chat-id] chat))))
|
||||
{:all-chats {}
|
||||
:chats-home-list #{}}
|
||||
new-chats-js)]
|
||||
{:db (assoc db
|
||||
:chats all-chats
|
||||
:chats-home-list chats-home-list
|
||||
:chats/loading? false)}))
|
||||
(rf/reg-event-fx :chats-list/load-success
|
||||
(fn [{:keys [db]} [^js new-chats-js]]
|
||||
(let [{:keys [all-chats chats-home-list]}
|
||||
(reduce (fn [acc ^js chat-js]
|
||||
(let [{:keys [chat-id profile-public-key timeline? community-id active] :as chat}
|
||||
(data-store.chats/<-rpc-js chat-js)]
|
||||
(cond-> acc
|
||||
(and (not profile-public-key) (not timeline?) (not community-id) active)
|
||||
(update :chats-home-list conj chat-id)
|
||||
:always
|
||||
(assoc-in [:all-chats chat-id] chat))))
|
||||
{:all-chats {}
|
||||
:chats-home-list #{}}
|
||||
new-chats-js)]
|
||||
{:db (-> db
|
||||
(update :chats merge all-chats)
|
||||
(update :chats-home-list into chats-home-list))})))
|
||||
|
||||
(rf/defn load-chat-success
|
||||
{:events [:chats-list/load-chat-success]}
|
||||
|
||||
@@ -134,9 +134,9 @@
|
||||
unmarshal-members))
|
||||
|
||||
(re-frame/reg-fx :fetch-chats-preview
|
||||
(fn [{:keys [on-success]}]
|
||||
(fn [{:keys [on-success chat-preview-type]}]
|
||||
(json-rpc/call {:method "wakuext_chatsPreview"
|
||||
:params []
|
||||
:params [chat-preview-type]
|
||||
:js-response true
|
||||
:on-success #(on-success ^js %)
|
||||
:on-error #(log/error "failed to fetch chats" 0 -1 %)})))
|
||||
|
||||
@@ -135,7 +135,6 @@
|
||||
:chat/cooldowns
|
||||
:chat/last-outgoing-message-sent-at
|
||||
:chat/spam-messages-frequency
|
||||
:chats/loading?
|
||||
:dimensions/window]))]
|
||||
{:logs/archive-logs [db-json
|
||||
(if (= transport :email)
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
(ns legacy.status-im.utils.prices
|
||||
(:require
|
||||
[status-im.common.json-rpc.events :as json-rpc]))
|
||||
|
||||
(defn- format-price-resp
|
||||
[resp to mainnet?]
|
||||
(if mainnet?
|
||||
resp
|
||||
{:ETH (into {}
|
||||
(for [[_ price] resp]
|
||||
{(keyword to) price}))}))
|
||||
|
||||
(defn get-prices
|
||||
[from to mainnet? on-success on-error]
|
||||
(json-rpc/call {:method "wallet_fetchPrices"
|
||||
:params [from to]
|
||||
:on-success (fn [resp] (on-success (format-price-resp resp to mainnet?)))
|
||||
:on-error on-error}))
|
||||
@@ -535,10 +535,6 @@
|
||||
[]
|
||||
(.logFileDirectory ^js (log-manager)))
|
||||
|
||||
(defn init-status-go-logging
|
||||
[{:keys [enable? mobile-system? log-level log-request-go? callback]}]
|
||||
(.initLogging ^js (log-manager) enable? mobile-system? log-level log-request-go? callback))
|
||||
|
||||
(defn get-random-mnemonic
|
||||
[callback]
|
||||
(.getRandomMnemonic ^js (account-manager) #(callback (types/json->clj %))))
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
(defn container
|
||||
[container-style]
|
||||
(merge container-style
|
||||
{:padding-vertical 7
|
||||
:padding-horizontal 20
|
||||
:flex-direction :row
|
||||
:align-items :flex-start}))
|
||||
(merge
|
||||
{:padding-vertical 7
|
||||
:padding-horizontal 20
|
||||
:flex-direction :row
|
||||
:align-items :flex-start}
|
||||
container-style))
|
||||
|
||||
(def index
|
||||
{:margin-left 5})
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
(defn view
|
||||
[{:keys [title description tag-picture tag-name description-after-tag step-number
|
||||
customization-color type blur? container-style]
|
||||
customization-color type blur? container-style icon icon-props]
|
||||
:or {type :bullet}}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[rn/view {:style (style/container container-style)}
|
||||
@@ -54,6 +54,8 @@
|
||||
:type (if customization-color :complete :neutral)} step-number]
|
||||
:lock
|
||||
[icon/icon :i/locked {:color (get-colors theme blur?)}]
|
||||
:custom-icon
|
||||
[icon/icon icon icon-props]
|
||||
[icon/icon :i/bullet {:color (get-colors theme blur?)}])]
|
||||
[rn/view {:style style/text-container}
|
||||
(when title
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn view
|
||||
[{:keys [number-of-pins number-of-filled-pins error? info]
|
||||
[{:keys [number-of-pins number-of-filled-pins error? info info-error?]
|
||||
:or {number-of-pins 6 number-of-filled-pins 0}}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[rn/view {:style {:align-items :center}}
|
||||
@@ -20,7 +20,7 @@
|
||||
(= i (inc number-of-filled-pins)) :active)}])]
|
||||
(when info
|
||||
[text/text
|
||||
{:style {:color (if error?
|
||||
{:style {:color (if (or error? info-error?)
|
||||
(colors/theme-colors colors/danger-50 colors/danger-60 theme)
|
||||
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))}
|
||||
:size :paragraph-2}
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
["@walletconnect/utils" :as wc-utils]
|
||||
["@walletconnect/web3wallet$default" :as Web3Wallet]
|
||||
[cljs-bean.core :as bean]
|
||||
[oops.core :as oops]))
|
||||
[oops.core :as oops]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(defn- wallet-connect-core
|
||||
[project-id]
|
||||
@@ -34,7 +35,7 @@
|
||||
(defn parse-uri
|
||||
[uri]
|
||||
(-> (oops/ocall wc-utils "parseUri" uri)
|
||||
(bean/->clj)))
|
||||
transforms/js->clj))
|
||||
|
||||
(defn respond-session-request
|
||||
[{:keys [web3-wallet topic id result error]}]
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
(ns status-im.common.log
|
||||
(:require
|
||||
[clojure.pprint :as promesa]
|
||||
[clojure.pprint :as pprint]
|
||||
[clojure.string :as string]
|
||||
[native-module.core :as native-module]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.config :as config]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.transforms :as transforms]))
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(def logs-queue (atom #queue []))
|
||||
(def max-log-entries 1000)
|
||||
@@ -21,33 +18,21 @@
|
||||
|
||||
(defn setup
|
||||
[level]
|
||||
(let [handle-error (fn [res]
|
||||
(let [{:keys [error]} (transforms/json->clj res)]
|
||||
(when-not (string/blank? error)
|
||||
(log/error "init statusgo logging failed" error))))
|
||||
logging-params {:enable? true
|
||||
:mobile-system? false
|
||||
:log-level level
|
||||
:log-request-go? config/log-request-go
|
||||
:callback handle-error}]
|
||||
(log/merge-config! {:ns-filter {:allow #{"*"} :deny #{"taoensso.sente"}}})
|
||||
(if (string/blank? level)
|
||||
(native-module/init-status-go-logging (merge logging-params {:log-level "WARN"}))
|
||||
(do
|
||||
(log/set-min-level! (-> level
|
||||
string/lower-case
|
||||
keyword))
|
||||
(log/merge-config!
|
||||
{:output-fn (fn [& data]
|
||||
(let [res (apply log/default-output-fn data)]
|
||||
(add-log-entry res)
|
||||
res))
|
||||
:middleware [(fn [data]
|
||||
(update data
|
||||
:vargs
|
||||
(partial mapv
|
||||
#(if (string? %) % (with-out-str (promesa/pprint %))))))]})
|
||||
(native-module/init-status-go-logging logging-params)))))
|
||||
(log/merge-config! {:ns-filter {:allow #{"*"} :deny #{"taoensso.sente"}}})
|
||||
(when-not (string/blank? level)
|
||||
(log/set-min-level! (-> level
|
||||
string/lower-case
|
||||
keyword))
|
||||
(log/merge-config!
|
||||
{:output-fn (fn [& data]
|
||||
(let [res (apply log/default-output-fn data)]
|
||||
(add-log-entry res)
|
||||
res))
|
||||
:middleware [(fn [data]
|
||||
(update data
|
||||
:vargs
|
||||
(partial mapv
|
||||
#(if (string? %) % (with-out-str (pprint/pprint %))))))]})))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:logs/set-level
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
(ns status-im.common.metrics-confirmation-modal.style)
|
||||
|
||||
(def points-wrapper
|
||||
{:margin-top 11
|
||||
:margin-horizontal 20
|
||||
:gap 21
|
||||
:margin-bottom 8})
|
||||
|
||||
(def item-text
|
||||
{:margin-left -24})
|
||||
|
||||
(def info-text
|
||||
{:margin-top -5})
|
||||
|
||||
(def privacy-policy
|
||||
{:margin-top 4
|
||||
:margin-horizontal 20
|
||||
:margin-bottom 20
|
||||
:align-items :center})
|
||||
@@ -1,119 +0,0 @@
|
||||
(ns status-im.common.metrics-confirmation-modal.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.metrics-confirmation-modal.style :as style]
|
||||
[status-im.common.privacy.view :as privacy]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- dismiss-keyboard
|
||||
[]
|
||||
(rf/dispatch [:dismiss-keyboard]))
|
||||
|
||||
(defn- hide-bottom-sheet
|
||||
[]
|
||||
(rf/dispatch [:hide-bottom-sheet]))
|
||||
|
||||
(def ^:private will-receive-for-current-points
|
||||
[:t/number-of-messages-sent
|
||||
:t/connected-peers
|
||||
:t/successful-messages-rate
|
||||
:t/connection-type
|
||||
:t/os-app-version-bandwidth])
|
||||
|
||||
(def ^:private will-receive-for-all-points
|
||||
[:t/action-logs
|
||||
:t/ip-addresses-uuid])
|
||||
|
||||
(def ^:private not-receive-points
|
||||
[:t/your-profile-information
|
||||
:t/your-addresses
|
||||
:t/information-you-input-and-send])
|
||||
|
||||
(defn- bullet-points
|
||||
[{:keys [title points lock?]}]
|
||||
[rn/view
|
||||
[quo/text {:weight :semi-bold}
|
||||
title]
|
||||
(for [label points]
|
||||
^{:key label}
|
||||
[quo/markdown-list
|
||||
{:description (i18n/label label)
|
||||
:blur? true
|
||||
:type (when lock? :lock)
|
||||
:container-style style/item-text}])])
|
||||
|
||||
(defn- on-share-usage
|
||||
[]
|
||||
(rf/dispatch [:centralized-metrics/toggle-centralized-metrics true true])
|
||||
(hide-bottom-sheet))
|
||||
|
||||
(defn- on-do-not-share
|
||||
[]
|
||||
(rf/dispatch [:centralized-metrics/toggle-centralized-metrics false true])
|
||||
(hide-bottom-sheet))
|
||||
|
||||
(declare view)
|
||||
|
||||
(defn- on-privacy-policy-press
|
||||
[]
|
||||
(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content privacy/privacy-statement
|
||||
:on-close (fn []
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content view
|
||||
:theme :dark
|
||||
:shell? true}]))
|
||||
:theme :dark
|
||||
:shell? true}]))
|
||||
|
||||
(defn- privacy-policy-text
|
||||
[]
|
||||
[rn/view {:style style/privacy-policy}
|
||||
[quo/text
|
||||
[quo/text
|
||||
{:style {:color colors/white-opa-50}
|
||||
:size :paragraph-2}
|
||||
(i18n/label :t/more-details-in-privacy-policy-1)]
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :bold
|
||||
:on-press on-privacy-policy-press}
|
||||
(i18n/label :t/more-details-in-privacy-policy-2)]]])
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(rn/use-mount #(dismiss-keyboard))
|
||||
[:<>
|
||||
[quo/drawer-top
|
||||
{:title (i18n/label :t/help-us-improve-status)
|
||||
:description (i18n/label :t/collecting-usage-data)}]
|
||||
[rn/scroll-view
|
||||
[rn/view {:style style/points-wrapper}
|
||||
[bullet-points
|
||||
{:title (i18n/label :t/we-will-receive-from-all-profiles)
|
||||
:points will-receive-for-all-points}]
|
||||
[bullet-points
|
||||
{:title (i18n/label :t/we-will-receive-from-the-current-profile)
|
||||
:points will-receive-for-current-points}]
|
||||
[bullet-points
|
||||
{:title (i18n/label :t/what-we-wont-receive)
|
||||
:points not-receive-points
|
||||
:lock? true}]
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:style style/info-text}
|
||||
(i18n/label :t/sharing-usage-data-can-be-turned-off)]]]
|
||||
[quo/bottom-actions
|
||||
{:actions :two-actions
|
||||
:blur? true
|
||||
:button-one-label (i18n/label :t/help-us-improve-status)
|
||||
:button-one-props {:on-press on-share-usage}
|
||||
:button-two-label (i18n/label :t/not-now)
|
||||
:button-two-props {:type :grey
|
||||
:on-press on-do-not-share}}]
|
||||
[privacy-policy-text]])
|
||||
@@ -17,6 +17,7 @@
|
||||
:generate-keys1 (js/require "../resources/images/ui2/generating-keys-1.png")
|
||||
:ethereum-address (js/require "../resources/images/ui2/ethereum-address.png")
|
||||
:use-keycard (js/require "../resources/images/ui2/keycard.png")
|
||||
:use-recovery-phrase (js/require "../resources/images/ui2/recovery-phrase.png")
|
||||
:check-your-keycard (js/require "../resources/images/ui2/check-your-keycard.png")
|
||||
:onboarding-illustration (js/require "../resources/images/ui2/onboarding_illustration.png")
|
||||
:qr-code (js/require "../resources/images/ui2/qr-code.png")
|
||||
|
||||
@@ -36,15 +36,15 @@
|
||||
"wallet"
|
||||
{:fx [[:dispatch [:wallet/signal-received event-js]]]}
|
||||
|
||||
"wallet.sign.transactions"
|
||||
{:fx [[:dispatch
|
||||
[:standard-auth/authorize-with-keycard
|
||||
{:on-complete #(rf/dispatch [:keycard/sign-hash %
|
||||
(first (transforms/js->clj event-js))])}]]]}
|
||||
|
||||
"wallet.suggested.routes"
|
||||
{:fx [[:dispatch [:wallet/handle-suggested-routes (transforms/js->clj event-js)]]]}
|
||||
|
||||
"wallet.router.sign-transactions"
|
||||
{:fx [[:dispatch [:wallet/sign-transactions-signal-received (transforms/js->clj event-js)]]]}
|
||||
|
||||
"wallet.router.transactions-sent"
|
||||
{:fx [[:dispatch [:wallet/transactions-sent-signal-received (transforms/js->clj event-js)]]]}
|
||||
|
||||
"envelope.sent"
|
||||
(messages.transport/update-envelopes-status
|
||||
cofx
|
||||
|
||||
@@ -116,6 +116,7 @@
|
||||
:on-close #(rf/dispatch [:standard-auth/reset-login-password])
|
||||
:content (fn []
|
||||
[keycard.pin/auth {:on-complete on-complete}])}]]]})
|
||||
|
||||
(rf/reg-event-fx :standard-auth/authorize-with-keycard authorize-with-keycard)
|
||||
|
||||
(defn authorize-with-password
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
(def error-message
|
||||
{:margin-top 8
|
||||
:flex-direction :row
|
||||
:gap 4
|
||||
:align-items :center})
|
||||
|
||||
(def auth-button
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
|
||||
;; CONFIG VALUES
|
||||
(def log-level (string/upper-case (get-config :LOG_LEVEL "")))
|
||||
(def log-request-go (enabled? (get-config :LOG_REQUEST_GO "0")))
|
||||
(def api-logging-enabled? (enabled? (get-config :API_LOGGING_ENABLED "0")))
|
||||
(def fleet (get-config :FLEET ""))
|
||||
(def apn-topic (get-config :APN_TOPIC "im.status.ethereum"))
|
||||
(def max-installations 2)
|
||||
|
||||
@@ -76,6 +76,9 @@
|
||||
(def ^:const timeline-chat-type 5)
|
||||
(def ^:const community-chat-type 6)
|
||||
|
||||
(def ^:const chat-preview-type-community 0)
|
||||
(def ^:const chat-preview-type-non-community 1)
|
||||
|
||||
(def ^:const contact-request-message-state-none 0)
|
||||
(def ^:const contact-request-message-state-pending 1)
|
||||
(def ^:const contact-request-message-state-accepted 2)
|
||||
|
||||
@@ -36,18 +36,10 @@
|
||||
(assoc :centralized-metrics/enabled? enabled?)
|
||||
(assoc :centralized-metrics/onboarding-enabled? (and onboarding? enabled?)))}))
|
||||
|
||||
(rf/reg-event-fx :centralized-metrics/check-modal
|
||||
(fn [{:keys [db]} [modal-view]]
|
||||
(rf/reg-event-fx :centralized-metrics/check-user-confirmation
|
||||
(fn [{:keys [db]}]
|
||||
(when-not (:centralized-metrics/user-confirmed? db)
|
||||
{:fx [[:dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content (fn [] [modal-view])
|
||||
;; When in the profiles screen do biometric auth after the metrics sheet is dismissed
|
||||
;; https://github.com/status-im/status-mobile/issues/20932
|
||||
:on-close (when (= (:view-id db) :screen/profile.profiles)
|
||||
#(rf/dispatch [:profile.login/login-with-biometric-if-available
|
||||
(get-in db [:profile/login :key-uid])]))
|
||||
:shell? true}]]]})))
|
||||
{:fx [[:dispatch [:navigate-to :screen/onboarding.share-usage]]]})))
|
||||
|
||||
(rf/reg-fx :effects.centralized-metrics/track
|
||||
(fn [event]
|
||||
|
||||
@@ -2,29 +2,39 @@
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im.contexts.chat.messenger.composer.constants :as constants]))
|
||||
|
||||
(defn shadow
|
||||
[theme]
|
||||
(defn- add-shadow
|
||||
[theme styles]
|
||||
(if platform/ios?
|
||||
{:shadow-radius (colors/theme-colors 30 50 theme)
|
||||
:shadow-opacity (colors/theme-colors 0.1 0.7 theme)
|
||||
:shadow-color colors/neutral-100
|
||||
:shadow-offset {:width 0 :height (colors/theme-colors 8 12 theme)}}
|
||||
{:elevation 10}))
|
||||
(assoc styles
|
||||
:shadow-radius (colors/theme-colors 30 50 theme)
|
||||
:shadow-opacity (colors/theme-colors 0.1 0.7 theme)
|
||||
:shadow-color colors/neutral-100
|
||||
:shadow-offset {:width 0 :height (colors/theme-colors 8 12 theme)})
|
||||
(assoc styles :elevation 10)))
|
||||
|
||||
(defn inner
|
||||
[top theme]
|
||||
(add-shadow theme
|
||||
{:position :absolute
|
||||
:top (- (+ 8 top))
|
||||
:left 8
|
||||
:right 8
|
||||
:border-radius 16
|
||||
:z-index 4
|
||||
:max-height constants/mentions-max-height
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)}))
|
||||
|
||||
(defn container
|
||||
[opacity top theme]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity opacity}
|
||||
(merge
|
||||
{:position :absolute
|
||||
:top (- (+ 8 top))
|
||||
:left 8
|
||||
:right 8
|
||||
:border-radius 16
|
||||
:z-index 4
|
||||
:max-height constants/mentions-max-height
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)}
|
||||
(shadow theme))))
|
||||
[{:opacity opacity}
|
||||
(add-shadow theme
|
||||
{:position :absolute
|
||||
:top (- (+ 8 top))
|
||||
:left 8
|
||||
:right 8
|
||||
:border-radius 16
|
||||
:z-index 4
|
||||
:max-height constants/mentions-max-height
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)})])
|
||||
|
||||
@@ -10,37 +10,36 @@
|
||||
[status-im.contexts.chat.messenger.messages.constants :as messages.constants]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn mention-item
|
||||
[user]
|
||||
[contact-list-item/contact-list-item
|
||||
{:on-press #(rf/dispatch [:chat.ui/select-mention user])}
|
||||
user])
|
||||
(defn- mention-item
|
||||
[[user-key user]]
|
||||
(with-meta
|
||||
[contact-list-item/contact-list-item {:on-press #(rf/dispatch [:chat.ui/select-mention user])}
|
||||
user]
|
||||
{:key user-key}))
|
||||
|
||||
(defn view
|
||||
[layout-height]
|
||||
(let [suggestions (rf/sub [:chat/mention-suggestions])
|
||||
suggestions? (seq suggestions)
|
||||
theme (quo.theme/use-theme)
|
||||
opacity (reanimated/use-shared-value (if suggestions? 1 0))
|
||||
[suggestions-state set-suggestions-state] (rn/use-state suggestions)
|
||||
top (min constants/mentions-max-height
|
||||
(* (count suggestions-state) 56)
|
||||
(- @layout-height
|
||||
(+ (safe-area/get-top)
|
||||
messages.constants/top-bar-height
|
||||
5)))]
|
||||
(let [suggestions (rf/sub [:chat/mention-suggestions])
|
||||
suggestions? (seq suggestions)
|
||||
theme (quo.theme/use-theme)
|
||||
opacity (reanimated/use-shared-value (if suggestions? 1 0))
|
||||
[suggestions-state
|
||||
set-suggestions-state] (rn/use-state suggestions)
|
||||
top (min constants/mentions-max-height
|
||||
(* (count suggestions-state) 56)
|
||||
(- @layout-height
|
||||
(+ (safe-area/get-top)
|
||||
messages.constants/top-bar-height
|
||||
5)))]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(if suggestions?
|
||||
(set-suggestions-state suggestions)
|
||||
(js/setTimeout #(set-suggestions-state suggestions) 300))
|
||||
(reanimated/animate opacity (if suggestions? 1 0)))
|
||||
[suggestions?])
|
||||
[reanimated/view
|
||||
{:style (style/container opacity top theme)}
|
||||
[rn/flat-list
|
||||
{:keyboard-should-persist-taps :always
|
||||
:data (vals suggestions-state)
|
||||
:key-fn :key
|
||||
:render-fn mention-item
|
||||
:accessibility-label :mentions-list}]]))
|
||||
[suggestions])
|
||||
[reanimated/view {:style (style/container opacity top theme)}
|
||||
[rn/scroll-view
|
||||
{:accessibility-label :mentions-list
|
||||
:keyboard-should-persist-taps :always}
|
||||
(map mention-item suggestions-state)]]))
|
||||
|
||||
@@ -225,7 +225,8 @@
|
||||
distance-from-list-top
|
||||
chat-list-scroll-y
|
||||
(on-scroll-fn distance-atom layout-height)))
|
||||
:style {:background-color (colors/theme-colors colors/white
|
||||
:style {:height "100%"
|
||||
:background-color (colors/theme-colors colors/white
|
||||
colors/neutral-95
|
||||
theme)}
|
||||
:content-container-style (style/list-paddings add-padding-bottom?)
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
(ns status-im.contexts.keycard.create.events
|
||||
(:require [clojure.string :as string]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(rf/reg-event-fx :keycard/create.check-empty-card
|
||||
(fn [_]
|
||||
{:fx [[:dispatch
|
||||
[:keycard/connect
|
||||
{:on-error
|
||||
(fn [error]
|
||||
(if (= error :keycard/error.keycard-blank)
|
||||
(do
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:open-modal :screen/keycard.empty-create]))
|
||||
(rf/dispatch [:keycard/on-application-info-error error])))}]]]}))
|
||||
|
||||
(rf/reg-event-fx :keycard/create.get-phrase
|
||||
(fn [{:keys [db]}]
|
||||
{:db (assoc-in db [:keycard :create] nil)
|
||||
:fx [[:dispatch [:navigate-back]]
|
||||
[:dispatch
|
||||
[:open-modal :screen/backup-recovery-phrase-dark
|
||||
{:on-success #(rf/dispatch [:keycard/create.phrase-backed-up %])}]]]}))
|
||||
|
||||
(rf/reg-event-fx :keycard/create.phrase-backed-up
|
||||
(fn [{:keys [db]} [masked-phrase-vector]]
|
||||
{:db (assoc-in db
|
||||
[:keycard :create :masked-phrase]
|
||||
(->> masked-phrase-vector
|
||||
security/safe-unmask-data
|
||||
(string/join " ")
|
||||
security/mask-data))
|
||||
:fx [[:dispatch [:keycard/create.create-or-enter-pin]]]}))
|
||||
|
||||
(rf/reg-event-fx :keycard/create.create-or-enter-pin
|
||||
(fn [{:keys [db]}]
|
||||
(let [{:keys [initialized?]} (get-in db [:keycard :application-info])]
|
||||
{:fx [[:dispatch [:navigate-back]]
|
||||
(if initialized?
|
||||
[:dispatch
|
||||
[:open-modal :screen/keycard.pin.enter
|
||||
{:on-complete (fn [new-pin]
|
||||
(rf/dispatch [:keycard/create.save-pin new-pin])
|
||||
(rf/dispatch [:keycard/create.start]))}]]
|
||||
[:dispatch
|
||||
[:open-modal :screen/keycard.pin.create
|
||||
{:on-complete (fn [new-pin]
|
||||
(rf/dispatch [:navigate-back])
|
||||
(rf/dispatch [:keycard/create.save-pin new-pin])
|
||||
(rf/dispatch [:open-modal :screen/keycard.create.ready-to-add]))}]])]})))
|
||||
|
||||
(rf/reg-event-fx :keycard/create.save-pin
|
||||
(fn [{:keys [db]} [pin]]
|
||||
{:db (assoc-in db [:keycard :create :pin] pin)}))
|
||||
|
||||
(rf/reg-event-fx :keycard/create.start
|
||||
(fn [_]
|
||||
{:fx [[:dispatch
|
||||
[:keycard/connect
|
||||
{:on-error
|
||||
(fn [error]
|
||||
(if (= error :keycard/error.keycard-blank)
|
||||
(rf/dispatch [:keycard/create.continue])
|
||||
(rf/dispatch [:keycard/on-application-info-error error])))}]]]}))
|
||||
|
||||
(defn get-application-info-and-continue
|
||||
[init?]
|
||||
(rf/dispatch [:keycard/get-application-info
|
||||
{:on-success #(rf/dispatch [:keycard/create.continue])
|
||||
:on-error
|
||||
(fn [error]
|
||||
(if (or (= error :keycard/error.keycard-blank)
|
||||
(and (not init?) (= error :keycard/error.keycard-wrong-profile)))
|
||||
(rf/dispatch [:keycard/create.continue])
|
||||
(rf/dispatch [:keycard/on-application-info-error error])))}]))
|
||||
|
||||
(rf/reg-event-fx :keycard/create.continue
|
||||
(fn [{:keys [db]}]
|
||||
(let [{:keys [initialized? has-master-key?]} (get-in db [:keycard :application-info])
|
||||
{:keys [masked-phrase pin]} (get-in db [:keycard :create])]
|
||||
|
||||
(cond
|
||||
|
||||
(not initialized?)
|
||||
{:fx [[:keycard/init-card
|
||||
{:pin pin
|
||||
:on-success #(get-application-info-and-continue true)}]]}
|
||||
|
||||
(not has-master-key?)
|
||||
{:fx [[:effects.keycard/generate-and-load-key
|
||||
{:mnemonic (security/safe-unmask-data masked-phrase)
|
||||
:pin pin
|
||||
:on-success #(get-application-info-and-continue false)
|
||||
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]]}
|
||||
|
||||
:else
|
||||
{:fx [[:effects.keycard/get-more-keys
|
||||
{:pin pin
|
||||
:on-success #(rf/dispatch [:keycard.login/recover-profile-and-login %])
|
||||
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]]}))))
|
||||
@@ -0,0 +1,62 @@
|
||||
(ns status-im.contexts.keycard.create.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.constants :as constants]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:key :header
|
||||
:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/create-profile-keycard)}]
|
||||
[rn/view {:style {:padding-horizontal 20 :padding-top 20}}
|
||||
[quo/small-option-card
|
||||
{:variant :main
|
||||
:title (i18n/label :t/check-keycard)
|
||||
:subtitle (i18n/label :t/see-keycard-ready)
|
||||
:button-label (i18n/label :t/scan-keycard)
|
||||
:accessibility-label :get-keycard
|
||||
:image (resources/get-image :check-your-keycard)
|
||||
:on-press #(rf/dispatch [:keycard/create.check-empty-card])}]
|
||||
[rn/view {:style {:height 12}}]
|
||||
[quo/small-option-card
|
||||
{:variant :icon
|
||||
:title (i18n/label :t/learn-more-keycard)
|
||||
:subtitle (i18n/label :t/secure-wallet-card)
|
||||
:accessibility-label :setup-keycard
|
||||
:image (resources/get-image :use-keycard)
|
||||
:on-press #(rf/dispatch [:browser.ui/open-url constants/get-keycard-url])}]]
|
||||
[rn/view {:style {:flex 1}}]
|
||||
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
|
||||
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
|
||||
[quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]])
|
||||
|
||||
(defn ready-to-add
|
||||
[]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/arrow-left
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/ready-add-keypair-keycard)
|
||||
:description :text
|
||||
:description-text ""}]
|
||||
[rn/view {:style {:flex 1 :align-items :center :justify-content :center}}
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:source (resources/get-image :generate-keys1)}]]
|
||||
[quo/divider-label (i18n/label :t/tips-scan-keycard)]
|
||||
[quo/markdown-list {:description (i18n/label :t/remove-phone-case)}]
|
||||
[quo/markdown-list {:description (i18n/label :t/keep-card-steady)}]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/ready-to-scan)
|
||||
:button-one-props {:on-press #(rf/dispatch [:keycard/create.start])}}]])
|
||||
@@ -1,11 +1,13 @@
|
||||
(ns status-im.contexts.keycard.effects
|
||||
(:require [keycard.keycard :as keycard]
|
||||
[native-module.core :as native-module]
|
||||
[promesa.core :as promesa]
|
||||
[react-native.async-storage :as async-storage]
|
||||
[react-native.platform :as platform]
|
||||
status-im.contexts.keycard.nfc.effects
|
||||
[status-im.contexts.keycard.utils :as keycard.utils]
|
||||
[status-im.contexts.profile.config :as profile.config]
|
||||
[utils.hex :as hex]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defonce ^:private active-listeners (atom []))
|
||||
@@ -50,7 +52,22 @@
|
||||
|
||||
(rf/reg-fx :effects.keycard/sign
|
||||
(fn [args]
|
||||
(keycard/sign (keycard.utils/wrap-handlers args))))
|
||||
(-> (keycard/sign args)
|
||||
(promesa/then (keycard.utils/get-on-success args))
|
||||
(promesa/catch (keycard.utils/get-on-failure args)))))
|
||||
|
||||
(rf/reg-fx :effects.keycard/sign-hashes
|
||||
(fn [{:keys [hashes pin path on-success] :as args}]
|
||||
(-> (promesa/all
|
||||
(for [hash-data hashes]
|
||||
(-> (keycard/sign {:pin pin
|
||||
:path path
|
||||
:hash-data (hex/normalize-hex hash-data)})
|
||||
(promesa/then (fn [signature]
|
||||
{:signature signature
|
||||
:message hash-data})))))
|
||||
(promesa/then on-success)
|
||||
(promesa/catch (keycard.utils/get-on-failure args)))))
|
||||
|
||||
(rf/reg-fx :keycard/init-card
|
||||
(fn [args]
|
||||
|
||||
@@ -7,6 +7,30 @@
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn create
|
||||
[]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top
|
||||
{:title (i18n/label :t/keycard-empty)
|
||||
:description :text
|
||||
:description-text (i18n/label :t/what-to-do)}]
|
||||
[rn/view {:style {:padding-horizontal 28 :padding-top 20}}
|
||||
[quo/small-option-card
|
||||
{:variant :main
|
||||
:title (i18n/label :t/create-new-profile)
|
||||
:subtitle (i18n/label :t/new-key-pair-keycard)
|
||||
:button-label (i18n/label :t/lets-go)
|
||||
:accessibility-label :create-new-profile-keycard
|
||||
:image (resources/get-image :keycard-buy)
|
||||
:on-press #(rf/dispatch [:keycard/create.get-phrase])}]]
|
||||
[quo/information-box
|
||||
{:type :default
|
||||
:style {:margin-top 32 :margin-horizontal 28}}
|
||||
(i18n/label :t/add-key-pair-desktop)]])
|
||||
|
||||
(defn view
|
||||
[]
|
||||
[:<>
|
||||
@@ -23,7 +47,7 @@
|
||||
:title (i18n/label :t/import-key-pair-keycard)
|
||||
:subtitle (i18n/label :t/use-keycard-login-sign)
|
||||
:button-label (i18n/label :t/import-profile-key-pair)
|
||||
:accessibility-label :get-keycard
|
||||
:accessibility-label :import-key-pair-keycard
|
||||
:image (resources/get-image :keycard-buy)
|
||||
:on-press (fn []
|
||||
(rf/dispatch
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
(ns status-im.contexts.keycard.events
|
||||
(:require [re-frame.core :as rf]
|
||||
status-im.contexts.keycard.create.events
|
||||
status-im.contexts.keycard.login.events
|
||||
status-im.contexts.keycard.migrate.events
|
||||
status-im.contexts.keycard.migrate.re-encrypting.events
|
||||
@@ -44,6 +45,7 @@
|
||||
(when-not (or tag-was-lost? (nil? pin-retries-count))
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :application-info :pin-retry-counter] pin-retries-count)
|
||||
(assoc-in [:keycard :pin :text] "")
|
||||
(assoc-in [:keycard :pin :status] :error))
|
||||
:fx [[:dispatch [:keycard/disconnect]]
|
||||
(when (zero? pin-retries-count)
|
||||
|
||||
@@ -14,5 +14,4 @@
|
||||
{:icon-name :i/close
|
||||
:on-press events-helper/navigate-back}]
|
||||
[quo/page-top {:title (i18n/label :t/enter-keycard-pin)}]
|
||||
[rn/view {:style {:flex 1}}]
|
||||
[keycard.pin/auth {:on-complete on-complete}]]))
|
||||
|
||||
@@ -13,17 +13,20 @@
|
||||
pin-retry-counter (rf/sub [:keycard/pin-retry-counter])
|
||||
error? (or error? (= status :error))]
|
||||
(rn/use-unmount #(rf/dispatch [:keycard.pin/clear]))
|
||||
[rn/view {:padding-bottom 12 :flex 1}
|
||||
[rn/view {:flex 1 :justify-content :center :align-items :center :padding 34}
|
||||
[rn/view
|
||||
{:style {:flex 1
|
||||
:gap 34
|
||||
:padding-bottom 12}}
|
||||
[rn/view {:style {:flex 1 :justify-content :center :align-items :center}}
|
||||
[quo/pin-input
|
||||
{:blur? false
|
||||
:number-of-pins constants/pincode-length
|
||||
:number-of-filled-pins (count text)
|
||||
:error? error?
|
||||
:info-error? error?
|
||||
:info (when error?
|
||||
(if (not (string/blank? error-message))
|
||||
error-message
|
||||
(i18n/label :t/pin-retries-left {:number pin-retry-counter})))}]]
|
||||
(i18n/label-pluralize pin-retry-counter :t/pin-retries-left)))}]]
|
||||
[quo/numbered-keyboard
|
||||
{:delete-key? true
|
||||
:on-delete #(rf/dispatch [:keycard.pin/delete-pressed])
|
||||
|
||||
@@ -2,33 +2,24 @@
|
||||
(:require [utils.address]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn get-signature-map
|
||||
[tx-hash signature]
|
||||
{tx-hash {:r (subs signature 0 64)
|
||||
:s (subs signature 64 128)
|
||||
:v (subs signature 128 130)}})
|
||||
|
||||
(rf/reg-event-fx :keycard/sign
|
||||
(rf/reg-event-fx :keycard/sign-hashes
|
||||
(fn [_ [data]]
|
||||
{:effects.keycard/sign data}))
|
||||
{:effects.keycard/sign-hashes data}))
|
||||
|
||||
(rf/reg-event-fx :keycard/sign-hash
|
||||
(fn [{:keys [db]} [pin-text tx-hash]]
|
||||
(let [current-address (get-in db [:wallet :current-viewing-account-address])
|
||||
path (get-in db [:wallet :accounts current-address :path])
|
||||
key-uid (get-in db [:profile/profile :key-uid])]
|
||||
(rf/reg-event-fx :keycard/connect-and-sign-hashes
|
||||
(fn [{:keys [db]} [{:keys [keycard-pin address hashes on-success on-failure]}]]
|
||||
(let [{:keys [path key-uid]} (get-in db [:wallet :accounts address])]
|
||||
{:fx [[:dispatch
|
||||
[:keycard/connect
|
||||
{:key-uid key-uid
|
||||
:on-success
|
||||
(fn []
|
||||
(rf/dispatch
|
||||
[:keycard/sign
|
||||
{:pin pin-text
|
||||
[:keycard/sign-hashes
|
||||
{:pin keycard-pin
|
||||
:path path
|
||||
:hash (utils.address/naked-address tx-hash)
|
||||
:on-success (fn [signature]
|
||||
:hashes hashes
|
||||
:on-success (fn [signatures]
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(rf/dispatch [:wallet/proceed-with-transactions-signatures
|
||||
(get-signature-map tx-hash signature)]))
|
||||
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]))}]]]})))
|
||||
(when on-success (on-success signatures)))
|
||||
:on-failure on-failure}]))}]]]})))
|
||||
|
||||
@@ -57,9 +57,13 @@
|
||||
data
|
||||
(update data :key-uid address/normalized-hex)))
|
||||
|
||||
(defn format-success-data
|
||||
[data]
|
||||
(normalize-key-uid (transforms/js->clj data)))
|
||||
|
||||
(defn get-on-success
|
||||
[{:keys [on-success]}]
|
||||
#(when on-success (on-success (normalize-key-uid (transforms/js->clj %)))))
|
||||
#(when on-success (on-success (format-success-data %))))
|
||||
|
||||
(defn get-on-failure
|
||||
[{:keys [on-failure]}]
|
||||
|
||||
@@ -3,11 +3,7 @@
|
||||
[quo.foundations.colors :as colors]))
|
||||
|
||||
(def content-container
|
||||
{:position :absolute
|
||||
:top 0
|
||||
:bottom 0
|
||||
:left 0
|
||||
:right 0})
|
||||
{:flex 1})
|
||||
|
||||
(def options-container
|
||||
{:padding-top 12
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
[react-native.core :as rn]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.check-before-syncing.view :as check-before-syncing]
|
||||
[status-im.common.metrics-confirmation-modal.view :as metrics-modal]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.config :as config]
|
||||
[status-im.contexts.onboarding.create-or-sync-profile.style :as style]
|
||||
@@ -35,7 +35,7 @@
|
||||
{:on-submit navigate-to-sign-in-by-syncing}])
|
||||
:shell? true}]))
|
||||
|
||||
(defn- navigate-to-sign-in-by-seed-phrase
|
||||
(defn- navigate-to-sign-in-by-recovery-phrase
|
||||
[create-profile?]
|
||||
(rf/dispatch [:syncing/clear-syncing-fallback-flow])
|
||||
(rf/dispatch [:onboarding/navigate-to-sign-in-by-seed-phrase
|
||||
@@ -50,80 +50,97 @@
|
||||
(* 2 16) ;; spacing between items
|
||||
220)) ;; extra spacing (top bar)
|
||||
|
||||
|
||||
(defn- create-profile-option-card
|
||||
(defn- start-fresh-main-card
|
||||
[window-height]
|
||||
[quo/small-option-card
|
||||
{:variant :main
|
||||
:title (i18n/label :t/generate-keys)
|
||||
:subtitle (i18n/label :t/generate-keys-subtitle)
|
||||
:title (i18n/label :t/start-fresh)
|
||||
:subtitle (i18n/label :t/start-fresh-subtitle)
|
||||
:button-label (i18n/label :t/lets-go)
|
||||
:accessibility-label :generate-key-option-card
|
||||
:accessibility-label :start-fresh-main-card
|
||||
:image (resources/get-image :generate-keys)
|
||||
:max-height (option-card-max-height window-height)
|
||||
:on-press navigate-to-create-profile}])
|
||||
|
||||
(defn- sync-profile-option-card
|
||||
(defn- log-in-with-recovery-phrase-main-card
|
||||
[window-height]
|
||||
[quo/small-option-card
|
||||
{:variant :main
|
||||
:title (i18n/label :t/sign-in-by-syncing)
|
||||
:subtitle (i18n/label :t/if-you-have-status-on-another-device)
|
||||
:button-label (i18n/label :t/scan-sync-code)
|
||||
:accessibility-label :scan-sync-code-option-card
|
||||
:image (resources/get-image :generate-keys)
|
||||
:title (i18n/label :t/log-in-with-recovery-phrase)
|
||||
:subtitle (i18n/label :t/log-in-with-recovery-phrase-subtitle)
|
||||
:button-label (i18n/label :t/use-recovery-phrase)
|
||||
:accessibility-label :log-in-with-recovery-phrase-main-card
|
||||
:image (resources/get-image :use-recovery-phrase)
|
||||
:max-height (option-card-max-height window-height)
|
||||
:on-press #(navigate-to-sign-in-by-recovery-phrase false)}])
|
||||
|
||||
(defn- use-recovery-phrase-icon-card
|
||||
[]
|
||||
[quo/small-option-card
|
||||
{:variant :icon
|
||||
:title (i18n/label :t/use-a-recovery-phrase)
|
||||
:subtitle (i18n/label :t/use-a-recovery-phrase-subtitle)
|
||||
:accessibility-label :use-a-recovery-phrase-icon-card
|
||||
:image (resources/get-image :ethereum-address)
|
||||
:on-press #(navigate-to-sign-in-by-recovery-phrase true)}])
|
||||
|
||||
(defn- log-in-by-syncing-icon-card
|
||||
[]
|
||||
[quo/small-option-card
|
||||
{:variant :icon
|
||||
:title (i18n/label :t/log-in-by-syncing)
|
||||
:subtitle (i18n/label :t/log-in-by-syncing-subtitle)
|
||||
:accessibility-label :log-in-by-syncing-icon-card
|
||||
:image (resources/get-image :ethereum-address)
|
||||
:on-press show-check-before-syncing}])
|
||||
|
||||
(defn- use-empty-keycard-icon-card
|
||||
[]
|
||||
[quo/small-option-card
|
||||
{:variant :icon
|
||||
:title (i18n/label :t/use-an-empty-keycard)
|
||||
:subtitle (i18n/label :t/use-an-empty-keycard-subtitle)
|
||||
:accessibility-label :use-an-empty-keycard-icon-card
|
||||
:image (resources/get-image :use-keycard)
|
||||
:on-press #(rf/dispatch [:open-modal :screen/keycard.create-profile])}])
|
||||
|
||||
(defn- log-in-with-keycard-icon-card
|
||||
[]
|
||||
[quo/small-option-card
|
||||
{:variant :icon
|
||||
:title (i18n/label :t/log-in-with-keycard)
|
||||
:subtitle (i18n/label :t/log-in-with-keycard-subtitle)
|
||||
:accessibility-label :log-in-with-keycard
|
||||
:image (resources/get-image :use-keycard)
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:open-modal :screen/keycard.check
|
||||
{:on-press #(rf/dispatch [:keycard.login/check-card])}]))}])
|
||||
|
||||
(defn sign-in-options
|
||||
[sign-in-type]
|
||||
(let [window-height (rf/sub [:dimensions/window-height])
|
||||
create-profile? (= sign-in-type :create-profile)
|
||||
nav-to-seed-phrase-with-cur-screen (rn/use-callback
|
||||
#(navigate-to-sign-in-by-seed-phrase
|
||||
create-profile?)
|
||||
[create-profile?])
|
||||
main-option-card (if create-profile?
|
||||
create-profile-option-card
|
||||
sync-profile-option-card)]
|
||||
[create-profile?]
|
||||
(let [window-height (rf/sub [:dimensions/window-height])]
|
||||
[rn/view {:style style/options-container}
|
||||
[quo/text
|
||||
{:style style/title
|
||||
:size :heading-1
|
||||
:weight :semi-bold}
|
||||
(i18n/label (if create-profile? :t/create-profile :t/sync-or-recover-profile))]
|
||||
[main-option-card window-height]
|
||||
(i18n/label (if create-profile? :t/create-profile :t/log-in))]
|
||||
(if create-profile?
|
||||
[start-fresh-main-card window-height]
|
||||
[log-in-with-recovery-phrase-main-card window-height])
|
||||
[rn/view {:style style/subtitle-container}
|
||||
[quo/text
|
||||
{:style style/subtitle
|
||||
:size :paragraph-2
|
||||
:weight :medium}
|
||||
(i18n/label (if create-profile? :t/experienced-web3 :t/dont-have-statatus-on-another-device))]]
|
||||
[rn/view
|
||||
[quo/small-option-card
|
||||
{:variant :icon
|
||||
:title (i18n/label :t/use-recovery-phrase)
|
||||
:subtitle (i18n/label :t/use-recovery-phrase-subtitle)
|
||||
:accessibility-label :use-recovery-phrase-option-card
|
||||
:image (resources/get-image :ethereum-address)
|
||||
:on-press nav-to-seed-phrase-with-cur-screen}]
|
||||
[rn/view {:style style/space-between-suboptions}]
|
||||
[quo/small-option-card
|
||||
{:variant :icon
|
||||
:title (i18n/label :t/use-keycard)
|
||||
:subtitle (i18n/label :t/profile-keys-on-keycard)
|
||||
:accessibility-label :use-keycard-option-card
|
||||
:image (resources/get-image :use-keycard)
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:open-modal :screen/keycard.check
|
||||
{:on-press
|
||||
#(rf/dispatch
|
||||
[:keycard.login/check-card])}]))}]]]))
|
||||
|
||||
(defn- navigate-back
|
||||
[]
|
||||
(rf/dispatch [:onboarding/overlay-dismiss])
|
||||
(rf/dispatch [:navigate-back]))
|
||||
(i18n/label :t/other-options)]]
|
||||
(if create-profile?
|
||||
[use-recovery-phrase-icon-card]
|
||||
[log-in-by-syncing-icon-card])
|
||||
[rn/view {:style style/space-between-suboptions}]
|
||||
(if create-profile?
|
||||
[use-empty-keycard-icon-card]
|
||||
[log-in-with-keycard-icon-card])]))
|
||||
|
||||
(defn- navigate-to-quo-preview
|
||||
[]
|
||||
@@ -131,7 +148,6 @@
|
||||
|
||||
(defn- internal-view
|
||||
[sign-in-type]
|
||||
(rn/use-mount #(rf/dispatch [:centralized-metrics/check-modal metrics-modal/view]))
|
||||
(let [{:keys [top]} (safe-area/get-insets)]
|
||||
[rn/view {:style style/content-container}
|
||||
[quo/page-nav
|
||||
@@ -139,13 +155,13 @@
|
||||
:type :no-title
|
||||
:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press navigate-back
|
||||
:on-press events-helper/navigate-back
|
||||
:right-side [{:icon-name :i/info
|
||||
:on-press getting-started-doc/show-as-bottom-sheet}
|
||||
(when config/quo-preview-enabled?
|
||||
{:icon-name :i/reveal-whitelist
|
||||
:on-press navigate-to-quo-preview})]}]
|
||||
[sign-in-options sign-in-type]]))
|
||||
[sign-in-options (= sign-in-type :create-profile)]]))
|
||||
|
||||
(defn create-profile
|
||||
[]
|
||||
|
||||
@@ -52,13 +52,16 @@
|
||||
[]
|
||||
(when-let [blur-show-fn @overlay/blur-show-fn-atom]
|
||||
(blur-show-fn))
|
||||
(rf/dispatch [:open-modal :screen/onboarding.sync-or-recover-profile]))
|
||||
(rf/dispatch [:open-modal
|
||||
:screen/onboarding.share-usage
|
||||
{:next-screen :screen/onboarding.sync-or-recover-profile}]))
|
||||
|
||||
(defn- create-profile
|
||||
[]
|
||||
(when-let [blur-show-fn @overlay/blur-show-fn-atom]
|
||||
(blur-show-fn))
|
||||
(rf/dispatch [:open-modal :screen/onboarding.new-to-status]))
|
||||
(rf/dispatch [:open-modal :screen/onboarding.share-usage
|
||||
{:next-screen :screen/onboarding.new-to-status}]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
(ns status-im.contexts.onboarding.share-usage.learn-more-sheet
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.terms.view :as terms]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def ^:private bullet-points-data
|
||||
[[:t/help-us-improve-status-bullet-point-1 true]
|
||||
[:t/help-us-improve-status-bullet-point-2 true]
|
||||
[:t/help-us-improve-status-bullet-point-3 false]
|
||||
[:t/help-us-improve-status-bullet-point-4 false]
|
||||
[:t/help-us-improve-status-bullet-point-5 false]])
|
||||
|
||||
(defn- privacy-policy-text
|
||||
[]
|
||||
[rn/view {:style {:margin-horizontal 20 :margin-vertical 8}}
|
||||
[quo/text
|
||||
[quo/text
|
||||
{:style {:color colors/white-opa-50}
|
||||
:size :paragraph-2}
|
||||
(i18n/label :t/more-details-in-privacy-policy-1-onboarding)]
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :bold
|
||||
:on-press #(rf/dispatch [:show-bottom-sheet {:content terms/terms-of-use :shell? true}])}
|
||||
(i18n/label :t/more-details-in-privacy-policy-2)]]])
|
||||
|
||||
(defn- bullet-points
|
||||
[]
|
||||
[:<>
|
||||
(for [[label collected?] bullet-points-data]
|
||||
^{:key label}
|
||||
[quo/markdown-list
|
||||
{:description (i18n/label label)
|
||||
:blur? true
|
||||
:type :custom-icon
|
||||
:container-style {:padding-vertical 5}
|
||||
:icon (if collected? :i/check-circle :i/clear)
|
||||
:icon-props (if collected?
|
||||
{:no-color true}
|
||||
{:size 20 :color colors/danger-60 :color-2 colors/white})}])])
|
||||
|
||||
(defn view
|
||||
[]
|
||||
[:<>
|
||||
[quo/drawer-top
|
||||
{:title (i18n/label :t/help-us-improve-status)}]
|
||||
[quo/text
|
||||
{:size :paragraph-1
|
||||
:style {:padding-horizontal 20}}
|
||||
(i18n/label :t/help-us-improve-status-subtitle)]
|
||||
[rn/view {:style {:padding-vertical 8}}
|
||||
[bullet-points]]
|
||||
[privacy-policy-text]])
|
||||
@@ -0,0 +1,18 @@
|
||||
(ns status-im.contexts.onboarding.share-usage.style)
|
||||
|
||||
(def title-container
|
||||
{:margin-horizontal 20
|
||||
:padding-bottom 20
|
||||
:padding-top 12})
|
||||
|
||||
(defn page-illustration
|
||||
[width]
|
||||
{:flex 1
|
||||
:margin-top 12
|
||||
:margin-bottom 10
|
||||
:width width})
|
||||
|
||||
(defn buttons
|
||||
[insets]
|
||||
{:margin 20
|
||||
:margin-bottom (+ 12 (:bottom insets))})
|
||||
@@ -0,0 +1,62 @@
|
||||
(ns status-im.contexts.onboarding.share-usage.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.events-helper :as events-helper]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.contexts.onboarding.share-usage.learn-more-sheet :as learn-more-sheet]
|
||||
[status-im.contexts.onboarding.share-usage.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- share-usage-data-fn
|
||||
[enabled? next-screen]
|
||||
(rf/dispatch [:centralized-metrics/toggle-centralized-metrics enabled? true])
|
||||
(if next-screen
|
||||
(rf/dispatch [:navigate-to-within-stack [next-screen :screen/onboarding.share-usage]]) ;; Onboarding
|
||||
(rf/dispatch [:navigate-back]))) ;; Login Screen
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [insets (safe-area/get-insets)
|
||||
next-screen (:next-screen (rf/sub [:get-screen-params :screen/onboarding.share-usage]))
|
||||
share-usage-data (rn/use-callback #(share-usage-data-fn true next-screen))
|
||||
maybe-later (rn/use-callback #(share-usage-data-fn false next-screen))
|
||||
learn-more (rn/use-callback #(rf/dispatch [:show-bottom-sheet
|
||||
{:content learn-more-sheet/view
|
||||
:shell? true}]))]
|
||||
[:<>
|
||||
[quo/page-nav
|
||||
{:margin-top (:top insets)
|
||||
:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press events-helper/navigate-back
|
||||
:right-side [{:icon-left :i/info
|
||||
:accessibility-label :learn-more
|
||||
:label (i18n/label :t/learn-more)
|
||||
:on-press learn-more}]}]
|
||||
[quo/text-combinations
|
||||
{:container-style style/title-container
|
||||
:title (i18n/label :t/help-us-improve-status)
|
||||
:title-accessibility-label :share-usage-title
|
||||
:description (i18n/label :t/collecting-usage-data)
|
||||
:description-accessibility-label :share-usage-subtitle}]
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:style (style/page-illustration (:width (rn/get-window)))
|
||||
:source (resources/get-image :biometrics)}]
|
||||
[rn/view {:style (style/buttons insets)}
|
||||
[quo/button
|
||||
{:size 40
|
||||
:accessibility-label :share-usage-data
|
||||
:on-press share-usage-data}
|
||||
(i18n/label :t/agree)]
|
||||
[quo/button
|
||||
{:size 40
|
||||
:accessibility-label :maybe-later-button
|
||||
:background :blur
|
||||
:type :grey
|
||||
:on-press maybe-later
|
||||
:container-style {:margin-top 12}}
|
||||
(i18n/label :t/maybe-later)]]]))
|
||||
@@ -11,6 +11,8 @@
|
||||
:key :number-of-filled-pins}
|
||||
{:type :boolean
|
||||
:key :error?}
|
||||
{:type :boolean
|
||||
:key :info-error?}
|
||||
{:type :text
|
||||
:key :info}])
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
(ns status-im.contexts.profile.events
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.data-store.settings :as data-store.settings]
|
||||
[legacy.status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
[native-module.core :as native-module]
|
||||
@@ -36,7 +37,10 @@
|
||||
{:dataDir (native-module/backup-disabled-data-dir)
|
||||
:mixpanelAppId config/mixpanel-app-id
|
||||
:mixpanelToken config/mixpanel-token
|
||||
:mediaServerEnableTLS (config/enabled? config/STATUS_BACKEND_SERVER_MEDIA_SERVER_ENABLE_TLS)}
|
||||
:mediaServerEnableTLS (config/enabled? config/STATUS_BACKEND_SERVER_MEDIA_SERVER_ENABLE_TLS)
|
||||
:logEnabled (not (string/blank? config/log-level))
|
||||
:logLevel config/log-level
|
||||
:apiLoggingEnabled config/api-logging-enabled?}
|
||||
callback)))
|
||||
|
||||
(rf/reg-event-fx
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
[native-module.core :as native-module]
|
||||
[status-im.common.keychain.events :as keychain]
|
||||
[status-im.config :as config]
|
||||
[status-im.constants :as constants]
|
||||
status-im.contexts.profile.login.effects
|
||||
[status-im.contexts.profile.rpc :as profile.rpc]
|
||||
[taoensso.timbre :as log]
|
||||
@@ -41,10 +42,10 @@
|
||||
log-level (or (:log-level settings) config/log-level)
|
||||
pairing-completed? (= (get-in db [:syncing :pairing-status]) :completed)
|
||||
new-db (-> db
|
||||
(assoc :chats/loading? true
|
||||
:profile/profile (merge profile-overview
|
||||
settings
|
||||
{:log-level log-level}))
|
||||
(assoc :profile/profile
|
||||
(merge profile-overview
|
||||
settings
|
||||
{:log-level log-level}))
|
||||
(assoc-in [:activity-center :loading?] true)
|
||||
(dissoc :centralized-metrics/onboarding-enabled?))]
|
||||
{:db (cond-> new-db
|
||||
@@ -131,10 +132,15 @@
|
||||
(let [new-account? (get db :onboarding/new-account?)]
|
||||
{:db (assoc db :messenger/started? true)
|
||||
:fx [[:fetch-chats-preview
|
||||
{:on-success (fn [result]
|
||||
(rf/dispatch [:chats-list/load-success result])
|
||||
(rf/dispatch [:communities/get-user-requests-to-join])
|
||||
(rf/dispatch [:profile.login/get-chats-callback]))}]
|
||||
{:chat-preview-type constants/chat-preview-type-non-community
|
||||
:on-success (fn [result]
|
||||
(rf/dispatch [:chats-list/load-success result])
|
||||
(rf/dispatch [:profile.login/get-chats-callback]))}]
|
||||
[:fetch-chats-preview
|
||||
{:chat-preview-type constants/chat-preview-type-community
|
||||
:on-success (fn [result]
|
||||
(rf/dispatch [:chats-list/load-success result])
|
||||
(rf/dispatch [:communities/get-user-requests-to-join]))}]
|
||||
(when (and (:syncing/fallback-flow? db) (:syncing/installation-id db))
|
||||
[:dispatch [:pairing/finish-seed-phrase-fallback-syncing]])
|
||||
(when-not new-account?
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.confirmation-drawer.view :as confirmation-drawer]
|
||||
[status-im.common.metrics-confirmation-modal.view :as metrics-modal]
|
||||
[status-im.common.standard-authentication.core :as standard-authentication]
|
||||
[status-im.config :as config]
|
||||
[status-im.constants :as constants]
|
||||
@@ -277,10 +276,10 @@
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(rn/use-mount #(rf/dispatch [:centralized-metrics/check-modal metrics-modal/view]))
|
||||
(let [[show-profiles? set-show-profiles] (rn/use-state true)
|
||||
show-profiles (rn/use-callback #(set-show-profiles true))
|
||||
hide-profiles (rn/use-callback #(set-show-profiles false))]
|
||||
(rn/use-mount #(rf/dispatch [:centralized-metrics/check-user-confirmation]))
|
||||
[:<>
|
||||
[background/view true]
|
||||
(if show-profiles?
|
||||
|
||||
@@ -139,10 +139,28 @@
|
||||
:on-success #(log/debug "mnemonic was marked as shown")
|
||||
:on-error #(log/error "mnemonic was not marked as shown" %)}]]]}))
|
||||
|
||||
(defn token-symbols-from-accounts
|
||||
[accounts]
|
||||
(reduce-kv (fn [acc _ account]
|
||||
(into acc (map :symbol (:tokens account))))
|
||||
#{}
|
||||
accounts))
|
||||
|
||||
(rf/reg-event-fx :profile.settings/update-currency
|
||||
(fn [_ [currency]]
|
||||
{:fx [[:dispatch [:profile.settings/profile-update :currency currency]]
|
||||
[:dispatch [:wallet/get-wallet-token-for-all-accounts]]]}))
|
||||
(fn [{:keys [db]} [currency]]
|
||||
(let [accounts (get-in db [:wallet :accounts])
|
||||
symbols (token-symbols-from-accounts accounts)]
|
||||
{:fx [[:dispatch [:profile.settings/profile-update :currency currency]]
|
||||
[:effects.wallet.tokens/fetch-market-values
|
||||
{:symbols symbols
|
||||
:currency currency
|
||||
:on-success [:wallet.tokens/store-market-values]
|
||||
:on-error [:wallet.tokens/fetch-market-values-failed]}]
|
||||
[:effects.wallet.tokens/fetch-prices
|
||||
{:symbols symbols
|
||||
:currencies [constants/profile-default-currency currency]
|
||||
:on-success [:wallet.tokens/store-prices]
|
||||
:on-error [:wallet.tokens/fetch-prices-failed]}]]})))
|
||||
|
||||
;; Logout process
|
||||
(rf/reg-event-fx
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
[status-im.common.validation.general :as validators]
|
||||
[status-im.contexts.communities.events]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.uri :as wc-uri]
|
||||
[status-im.feature-flags :as ff]
|
||||
[utils.address :as utils-address]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.ethereum.eip.eip681 :as eip681]
|
||||
@@ -99,9 +98,7 @@
|
||||
;; TODO: https://github.com/status-im/status-mobile/issues/18744
|
||||
nil
|
||||
|
||||
(and
|
||||
(wc-uri/valid-uri? scanned-text)
|
||||
(ff/enabled? ::ff/wallet.wallet-connect))
|
||||
(-> scanned-text wc-uri/parse wc-uri/valid?)
|
||||
(handle-wallet-connect scanned-text)
|
||||
|
||||
(url? scanned-text)
|
||||
|
||||
@@ -19,12 +19,14 @@
|
||||
(let [network (rf/sub [:wallet/network-details-by-chain-id chain-id])
|
||||
currency (rf/sub [:profile/currency])
|
||||
currency-symbol (rf/sub [:profile/currency-symbol])
|
||||
prices-per-token (rf/sub [:wallet/prices-per-token])
|
||||
balance (utils/calculate-total-token-balance token [chain-id])
|
||||
crypto-value (utils/get-standard-crypto-format token balance)
|
||||
crypto-value (utils/get-standard-crypto-format token balance prices-per-token)
|
||||
fiat-value (utils/calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance balance
|
||||
:token token})
|
||||
{:currency currency
|
||||
:balance balance
|
||||
:token token
|
||||
:prices-per-token prices-per-token})
|
||||
fiat-formatted (utils/fiat-formatted-for-ui currency-symbol
|
||||
fiat-value)
|
||||
token-available-on-network? (network-utils/token-available-on-network? supported-networks
|
||||
|
||||
@@ -12,12 +12,13 @@
|
||||
disabled? :bridge-disabled?
|
||||
:as token}
|
||||
_ _
|
||||
{:keys [currency currency-symbol on-token-press preselected-token-symbol]}]
|
||||
{:keys [currency currency-symbol on-token-press preselected-token-symbol prices-per-token]}]
|
||||
(let [fiat-value (utils/calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance total-balance
|
||||
:token token})
|
||||
crypto-formatted (utils/get-standard-crypto-format token total-balance)
|
||||
{:currency currency
|
||||
:balance total-balance
|
||||
:token token
|
||||
:prices-per-token prices-per-token})
|
||||
crypto-formatted (utils/get-standard-crypto-format token total-balance prices-per-token)
|
||||
fiat-formatted (utils/fiat-formatted-for-ui currency-symbol fiat-value)]
|
||||
[quo/token-network
|
||||
{:token token-symbol
|
||||
@@ -34,17 +35,19 @@
|
||||
(defn view
|
||||
[{:keys [content-container-style search-text on-token-press preselected-token-symbol chain-ids]
|
||||
:or {content-container-style {:padding-horizontal 8}}}]
|
||||
(let [filtered-tokens (rf/sub [:wallet/current-viewing-account-tokens-filtered
|
||||
{:query search-text
|
||||
:chain-ids chain-ids}])
|
||||
currency (rf/sub [:profile/currency])
|
||||
currency-symbol (rf/sub [:profile/currency-symbol])]
|
||||
(let [filtered-tokens (rf/sub [:wallet/current-viewing-account-tokens-filtered
|
||||
{:query search-text
|
||||
:chain-ids chain-ids}])
|
||||
currency (rf/sub [:profile/currency])
|
||||
currency-symbol (rf/sub [:profile/currency-symbol])
|
||||
prices-per-token (rf/sub [:wallet/prices-per-token])]
|
||||
[gesture/flat-list
|
||||
{:data filtered-tokens
|
||||
:render-data {:currency currency
|
||||
:currency-symbol currency-symbol
|
||||
:on-token-press on-token-press
|
||||
:preselected-token-symbol preselected-token-symbol}
|
||||
:preselected-token-symbol preselected-token-symbol
|
||||
:prices-per-token prices-per-token}
|
||||
:style {:flex 1}
|
||||
:content-container-style content-container-style
|
||||
:keyboard-should-persist-taps :handled
|
||||
|
||||
@@ -27,12 +27,18 @@
|
||||
[balance]
|
||||
(cut-fiat-balance balance 2))
|
||||
|
||||
(defn prettify-balance
|
||||
[currency-symbol balance]
|
||||
(defn prepend-curency-symbol-to-fiat-balance
|
||||
[fiat-balance currency-symbol]
|
||||
(let [formatted-symbol (if (> (count currency-symbol) 1)
|
||||
(str currency-symbol " ")
|
||||
currency-symbol)]
|
||||
(str formatted-symbol (cut-fiat-balance-to-two-decimals balance))))
|
||||
(str formatted-symbol fiat-balance)))
|
||||
|
||||
(defn prettify-balance
|
||||
[currency-symbol fiat-balance]
|
||||
(-> fiat-balance
|
||||
cut-fiat-balance-to-two-decimals
|
||||
(prepend-curency-symbol-to-fiat-balance currency-symbol)))
|
||||
|
||||
(defn get-derivation-path
|
||||
[number-of-accounts]
|
||||
@@ -71,9 +77,14 @@
|
||||
(inc max-decimals)
|
||||
max-decimals)))
|
||||
|
||||
(defn token-price-by-symbol
|
||||
"Get token price for specific currency from prices-per-token structure"
|
||||
[prices-per-token token-symbol currency]
|
||||
(get-in prices-per-token [(keyword token-symbol) currency]))
|
||||
|
||||
(defn token-usd-price
|
||||
[token]
|
||||
(get-in token [:market-values-per-currency :usd :price]))
|
||||
[token prices-per-token]
|
||||
(token-price-by-symbol prices-per-token (:symbol token) :usd))
|
||||
|
||||
(defn one-cent-value
|
||||
[token-price-in-usd]
|
||||
@@ -104,16 +115,20 @@
|
||||
:else (number/remove-trailing-zeroes
|
||||
(.toFixed token-units standardized-decimals-count)))))
|
||||
|
||||
(defn add-token-symbol-to-crypto-balance
|
||||
[crypto-balance token-symbol]
|
||||
(str crypto-balance " " (string/upper-case token-symbol)))
|
||||
|
||||
(defn prettify-crypto-balance
|
||||
[token-symbol crypto-balance conversion-rate]
|
||||
(str (cut-crypto-decimals-to-fit-usd-cents crypto-balance conversion-rate)
|
||||
" "
|
||||
(string/upper-case token-symbol)))
|
||||
(-> crypto-balance
|
||||
(cut-crypto-decimals-to-fit-usd-cents conversion-rate)
|
||||
(add-token-symbol-to-crypto-balance token-symbol)))
|
||||
|
||||
(defn get-standard-crypto-format
|
||||
"For full details: https://github.com/status-im/status-mobile/issues/18225"
|
||||
[token token-units]
|
||||
(let [token-price-in-usd (token-usd-price token)
|
||||
[token token-units prices-per-token]
|
||||
(let [token-price-in-usd (token-usd-price token prices-per-token)
|
||||
{:keys [zero-value? usd-cent-value standardized-decimals-count]}
|
||||
(analyze-token-amount-for-price token-price-in-usd token-units)]
|
||||
(cond
|
||||
@@ -127,11 +142,9 @@
|
||||
(number/remove-trailing-zeroes (.toFixed token-units standardized-decimals-count)))))
|
||||
|
||||
(defn get-market-value
|
||||
[currency {:keys [market-values-per-currency]}]
|
||||
(or (get-in market-values-per-currency
|
||||
[currency :price])
|
||||
(get-in market-values-per-currency
|
||||
[constants/profile-default-currency :price])
|
||||
[currency {token-symbol :symbol} prices-per-token]
|
||||
(or (token-price-by-symbol prices-per-token token-symbol currency)
|
||||
(token-price-by-symbol prices-per-token token-symbol constants/profile-default-currency)
|
||||
;; NOTE: adding fallback value (zero) in case prices are
|
||||
;; unavailable and to prevent crash on calculating fiat value
|
||||
0))
|
||||
@@ -161,15 +174,15 @@
|
||||
|
||||
(defn calculate-token-fiat-value
|
||||
"Returns the token fiat value for provided raw balance"
|
||||
[{:keys [currency balance token]}]
|
||||
(let [price (get-market-value currency token)]
|
||||
[{:keys [currency balance token prices-per-token]}]
|
||||
(let [price (get-market-value currency token prices-per-token)]
|
||||
(money/crypto->fiat balance price)))
|
||||
|
||||
(defn formatted-token-fiat-value
|
||||
"Converts a token balance into its equivalent fiat value, formatted with a currency symbol.
|
||||
If the fiat value is below $0.01, it returns a <$0.01 string"
|
||||
[{:keys [currency currency-symbol balance token]}]
|
||||
(let [price (or (get-market-value currency token) 0)
|
||||
[{:keys [currency currency-symbol balance token prices-per-token]}]
|
||||
(let [price (or (get-market-value currency token prices-per-token) 0)
|
||||
price-zero? (zero? price)
|
||||
balance (or balance 0)
|
||||
balance-positive? (pos? balance)
|
||||
@@ -204,12 +217,13 @@
|
||||
(sanitized-token-amount-to-display display-decimals))))
|
||||
|
||||
(defn calculate-balance-from-tokens
|
||||
[{:keys [currency tokens chain-ids]}]
|
||||
[{:keys [currency tokens chain-ids prices-per-token]}]
|
||||
(->> tokens
|
||||
(map #(calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance (calculate-total-token-balance % chain-ids)
|
||||
:token %}))
|
||||
{:currency currency
|
||||
:balance (calculate-total-token-balance % chain-ids)
|
||||
:token %
|
||||
:prices-per-token prices-per-token}))
|
||||
(reduce money/add)))
|
||||
|
||||
(defn- add-balances-per-chain
|
||||
@@ -252,9 +266,10 @@
|
||||
|
||||
(defn fiat-formatted-for-ui
|
||||
[currency-symbol fiat-value]
|
||||
(if (money/less-than fiat-value 0.01)
|
||||
(str "<" currency-symbol "0.01")
|
||||
(prettify-balance currency-symbol fiat-value)))
|
||||
(cond
|
||||
(money/equal-to fiat-value 0) (str currency-symbol "0.00")
|
||||
(money/less-than fiat-value 0.01) (str "<" currency-symbol "0.01")
|
||||
:else (prettify-balance currency-symbol fiat-value)))
|
||||
|
||||
(defn prettify-percentage-change
|
||||
"Returns unsigned precentage"
|
||||
@@ -266,30 +281,30 @@
|
||||
|
||||
(defn calculate-token-value
|
||||
"This function returns token values in the props of token-value (quo) component"
|
||||
[{:keys [token color currency currency-symbol]}]
|
||||
(let [balance (calculate-total-token-balance token)
|
||||
fiat-unformatted-value (calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance balance
|
||||
:token token})
|
||||
market-values (or (get-in token [:market-values-per-currency currency])
|
||||
(get-in token
|
||||
[:market-values-per-currency
|
||||
constants/profile-default-currency]))
|
||||
{:keys [price change-pct-24hour]} market-values
|
||||
formatted-token-price (prettify-balance currency-symbol price)
|
||||
percentage-change (prettify-percentage-change change-pct-24hour)
|
||||
crypto-value (get-standard-crypto-format token balance)
|
||||
fiat-value (fiat-formatted-for-ui currency-symbol
|
||||
fiat-unformatted-value)]
|
||||
[{:keys [token color currency currency-symbol prices-per-token market-values-per-token]}]
|
||||
(let [balance (calculate-total-token-balance token)
|
||||
fiat-unformatted-value (calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance balance
|
||||
:token token
|
||||
:prices-per-token prices-per-token})
|
||||
currency (or currency constants/profile-default-currency)
|
||||
market-values (get market-values-per-token (keyword (:symbol token)))
|
||||
{:keys [change-pct-24h]} market-values
|
||||
price (token-price-by-symbol prices-per-token (:symbol token) currency)
|
||||
formatted-token-price (prettify-balance currency-symbol price)
|
||||
percentage-change (prettify-percentage-change change-pct-24h)
|
||||
crypto-value (get-standard-crypto-format token balance prices-per-token)
|
||||
fiat-value (fiat-formatted-for-ui currency-symbol
|
||||
fiat-unformatted-value)]
|
||||
{:token (:symbol token)
|
||||
:token-name (:name token)
|
||||
:state :default
|
||||
:metrics? (money/above-zero? balance)
|
||||
:status (cond
|
||||
(pos? change-pct-24hour) :positive
|
||||
(neg? change-pct-24hour) :negative
|
||||
:else :empty)
|
||||
(pos? change-pct-24h) :positive
|
||||
(neg? change-pct-24h) :negative
|
||||
:else :empty)
|
||||
:customization-color color
|
||||
:values {:crypto-value crypto-value
|
||||
:fiat-value fiat-value
|
||||
@@ -335,10 +350,10 @@
|
||||
(map #(update % :balances-per-chain select-keys chain-ids) tokens))
|
||||
|
||||
(defn calculate-balances-per-chain
|
||||
[{:keys [tokens currency currency-symbol]}]
|
||||
[{:keys [tokens currency currency-symbol prices-per-token]}]
|
||||
(->
|
||||
(reduce (fn [acc {:keys [balances-per-chain decimals] :as token}]
|
||||
(let [currency-value (get-market-value currency token)
|
||||
(let [currency-value (get-market-value currency token prices-per-token)
|
||||
fiat-balance-per-chain (update-vals balances-per-chain
|
||||
#(-> (money/token->unit (:raw-balance %)
|
||||
decimals)
|
||||
@@ -379,12 +394,14 @@
|
||||
(utils.string/contains-special-character? s) :special-character))
|
||||
|
||||
(defn calculate-and-sort-tokens
|
||||
[{:keys [tokens color currency currency-symbol]}]
|
||||
[{:keys [tokens color currency currency-symbol prices-per-token market-values-per-token]}]
|
||||
(let [calculate-token (fn [token]
|
||||
(calculate-token-value {:token token
|
||||
:color color
|
||||
:currency currency
|
||||
:currency-symbol currency-symbol}))
|
||||
(calculate-token-value {:token token
|
||||
:color color
|
||||
:currency currency
|
||||
:currency-symbol currency-symbol
|
||||
:prices-per-token prices-per-token
|
||||
:market-values-per-token market-values-per-token}))
|
||||
calculated-tokens (map calculate-token tokens)]
|
||||
(sort-by (fn [token]
|
||||
(let [fiat-value (get-in token [:values :fiat-unformatted-value])
|
||||
@@ -549,6 +566,18 @@
|
||||
(:less-than-five-minutes constants/wallet-transaction-estimation) "3-5"
|
||||
">5"))
|
||||
|
||||
(defn transactions->hash-to-transaction-map
|
||||
[transactions]
|
||||
(reduce
|
||||
(fn [acc {to-chain :toChain tx-hash :hash}]
|
||||
(assoc acc
|
||||
tx-hash
|
||||
{:status :pending
|
||||
:id tx-hash
|
||||
:chain-id to-chain}))
|
||||
{}
|
||||
transactions))
|
||||
|
||||
(defn get-accounts-with-token-balance
|
||||
[accounts token]
|
||||
(let [operable-account (filter :operable? (vals accounts))
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
(ns status-im.contexts.wallet.common.utils.account
|
||||
(:require [clojure.string :as string]))
|
||||
|
||||
(defn filter-operable
|
||||
[accounts]
|
||||
(filter #(and (:operable? %)
|
||||
(not (:watch-only? %)))
|
||||
accounts))
|
||||
|
||||
(defn to-eip155
|
||||
[address chain-id]
|
||||
(str chain-id ":" address))
|
||||
|
||||
(defn from-eip155
|
||||
[address]
|
||||
(-> address
|
||||
(string/split #":")
|
||||
last))
|
||||
|
||||
@@ -59,25 +59,33 @@
|
||||
|
||||
(deftest get-standard-crypto-format-test
|
||||
(testing "get-standard-crypto-format function"
|
||||
(let [market-values-per-currency {:usd {:price 100}}
|
||||
token-units (money/bignumber 0.005)]
|
||||
(is (= (utils/get-standard-crypto-format {:market-values-per-currency market-values-per-currency}
|
||||
token-units)
|
||||
(let [token {:symbol "ETH"}
|
||||
prices-per-token {:ETH {:usd 100}}
|
||||
token-units (money/bignumber 0.005)]
|
||||
(is (= (utils/get-standard-crypto-format token
|
||||
token-units
|
||||
prices-per-token)
|
||||
"0.005")))
|
||||
(let [market-values-per-currency {:usd {:price nil}}
|
||||
token-units (money/bignumber 0.0123456)]
|
||||
(is (= (utils/get-standard-crypto-format {:market-values-per-currency market-values-per-currency}
|
||||
token-units)
|
||||
(let [token {:symbol "ETH"}
|
||||
prices-per-token {:ETH {:usd nil}}
|
||||
token-units (money/bignumber 0.0123456)]
|
||||
(is (= (utils/get-standard-crypto-format token
|
||||
token-units
|
||||
prices-per-token)
|
||||
"0.012346")))
|
||||
(let [market-values-per-currency {:usd {:price 0.005}}
|
||||
token-units (money/bignumber 0.01)]
|
||||
(is (= (utils/get-standard-crypto-format {:market-values-per-currency market-values-per-currency}
|
||||
token-units)
|
||||
(let [token {:symbol "ETH"}
|
||||
prices-per-token {:ETH {:usd 0.005}}
|
||||
token-units (money/bignumber 0.01)]
|
||||
(is (= (utils/get-standard-crypto-format token
|
||||
token-units
|
||||
prices-per-token)
|
||||
"<2")))
|
||||
(let [market-values-per-currency {:usd {:price 0.005}}
|
||||
token-units "0.01"]
|
||||
(is (= (utils/get-standard-crypto-format {:market-values-per-currency market-values-per-currency}
|
||||
token-units)
|
||||
(let [token {:symbol "ETH"}
|
||||
prices-per-token {:ETH {:usd 0.005}}
|
||||
token-units "0.01"]
|
||||
(is (= (utils/get-standard-crypto-format token
|
||||
token-units
|
||||
prices-per-token)
|
||||
"0")))))
|
||||
|
||||
(deftest calculate-total-token-balance-test
|
||||
@@ -151,10 +159,12 @@
|
||||
:name "Status Network Token"
|
||||
:balances-per-chain {:mock-chain 1}
|
||||
:decimals 18}]
|
||||
mock-input {:tokens mock-tokens
|
||||
:color mock-color
|
||||
:currency mock-currency
|
||||
:currency-symbol mock-currency-symbol}
|
||||
mock-input {:tokens mock-tokens
|
||||
:color mock-color
|
||||
:currency mock-currency
|
||||
:currency-symbol mock-currency-symbol
|
||||
:prices-per-token {}
|
||||
:market-values-per-token {}}
|
||||
sorted-tokens (map :token (utils/calculate-and-sort-tokens mock-input))
|
||||
expected-order ["DAI" "ETH" "SNT"]]
|
||||
(is (= expected-order sorted-tokens))))))))
|
||||
@@ -170,19 +180,20 @@
|
||||
|
||||
(deftest formatted-token-fiat-value-test
|
||||
(testing "formatted-token-fiat-value function"
|
||||
(let [default-params {:currency "USD"
|
||||
:currency-symbol "$"
|
||||
:balance 0.5
|
||||
:token {:market-values-per-currency {:usd {:price 2000}}}}]
|
||||
(let [default-params {:currency "USD"
|
||||
:currency-symbol "$"
|
||||
:balance 0.5
|
||||
:token {:symbol "ETH"}
|
||||
:prices-per-token {:ETH {:usd 2000}}}]
|
||||
(is (= (utils/formatted-token-fiat-value default-params) "$1000"))
|
||||
(is (= (utils/formatted-token-fiat-value (assoc default-params :balance 0)) "$0"))
|
||||
(is (= (utils/formatted-token-fiat-value (assoc default-params :balance 0.000001)) "<$0.01"))
|
||||
(is (= (utils/formatted-token-fiat-value (assoc default-params :balance nil)) "$0"))
|
||||
(is (= (utils/formatted-token-fiat-value
|
||||
(assoc default-params :balance 1 :token {:market-values-per-currency {:usd {:price nil}}}))
|
||||
(assoc default-params :balance 1 :prices-per-token {:ETH {:usd nil}}))
|
||||
"$0"))
|
||||
(is (= (utils/formatted-token-fiat-value
|
||||
(assoc default-params :balance 1 :token {:market-values-per-currency {:usd {:price 0}}}))
|
||||
(assoc default-params :balance 1 :prices-per-token {:ETH {:usd 0}}))
|
||||
"$0")))))
|
||||
|
||||
(deftest sanitized-token-amount-to-display-test
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.contexts.wallet.connected-dapps.disconnect-dapp.view :as disconnect-dapp]
|
||||
[status-im.contexts.wallet.connected-dapps.style :as style]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.dapp :as dapp]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.string]))
|
||||
@@ -107,17 +107,15 @@
|
||||
:content-container-style (style/dapps-list theme)
|
||||
:render-fn (fn [{:keys [topic pairingTopic name url iconUrl]}]
|
||||
[quo/dapp
|
||||
{:dapp {:avatar
|
||||
(data-store/compute-dapp-icon-path
|
||||
iconUrl
|
||||
url)
|
||||
:name
|
||||
(data-store/compute-dapp-name
|
||||
name
|
||||
url)
|
||||
:value url
|
||||
:topic topic
|
||||
:pairing-topic pairingTopic
|
||||
{:dapp {:avatar (dapp/compute-icon
|
||||
iconUrl
|
||||
url)
|
||||
:name (dapp/compute-name
|
||||
name
|
||||
url)
|
||||
:value url
|
||||
:topic topic
|
||||
:pairing-topic pairingTopic
|
||||
:customization-color customization-color}
|
||||
:accessibility-label (str "dapp-" topic)
|
||||
:state :default
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
[promesa.core :as promesa]
|
||||
[status-im.common.json-rpc.events :as json-rpc]
|
||||
[status-im.contexts.profile.recover.effects :as profile.recover.effects]
|
||||
[status-im.contexts.wallet.rpc :as wallet-rpc]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]
|
||||
@@ -103,3 +104,22 @@
|
||||
(-> (verify-private-key-for-keypair keypair-key-uid private-key)
|
||||
(promesa/then (partial rf/call-continuation on-success))
|
||||
(promesa/catch (partial rf/call-continuation on-error)))))
|
||||
|
||||
(defn sign-transaction-hashes
|
||||
[hashes address password]
|
||||
(-> (promesa/all
|
||||
(for [h hashes]
|
||||
(promesa/let [signature (wallet-rpc/sign-message h address password)]
|
||||
{:message h
|
||||
:signature signature})))
|
||||
(promesa/catch (fn [err]
|
||||
(throw (ex-info "Failed to sign transaction hashes"
|
||||
{:error err
|
||||
:code :error/sign-transaction-hashes}))))))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.wallet/sign-transaction-hashes
|
||||
(fn [{:keys [hashes address password on-success on-error]}]
|
||||
(-> (sign-transaction-hashes hashes address password)
|
||||
(promesa/then on-success)
|
||||
(promesa/catch on-error))))
|
||||
|
||||
@@ -213,7 +213,7 @@
|
||||
(fn [{:keys [db]} [address]]
|
||||
{:db (assoc-in db [:wallet :ui :tokens-loading address] true)
|
||||
:fx [[:json-rpc/call
|
||||
[{:method "wallet_getWalletToken"
|
||||
[{:method "wallet_fetchOrGetCachedWalletBalances"
|
||||
:params [[address]]
|
||||
:on-success [:wallet/store-wallet-token address]
|
||||
:on-error [:wallet/get-wallet-token-for-account-failed address]}]]]}))
|
||||
@@ -232,6 +232,7 @@
|
||||
:wallet/store-wallet-token
|
||||
(fn [{:keys [db]} [address raw-tokens-data]]
|
||||
(let [supported-chains-by-token-symbol (get-in db [:wallet :tokens :supported-chains-by-symbol])
|
||||
profile-currency (get-in db [:profile/profile :currency])
|
||||
tokens (data-store/rpc->tokens raw-tokens-data
|
||||
supported-chains-by-token-symbol)
|
||||
add-tokens (fn [stored-accounts tokens-per-account]
|
||||
@@ -241,11 +242,25 @@
|
||||
(update accounts address assoc :tokens tokens-data)
|
||||
accounts))
|
||||
stored-accounts
|
||||
tokens-per-account))]
|
||||
{:fx [[:dispatch [:wallet/get-last-wallet-token-update-if-needed]]]
|
||||
:db (-> db
|
||||
tokens-per-account))
|
||||
symbols (reduce-kv (fn [acc _ v]
|
||||
(into acc (map :symbol v)))
|
||||
#{}
|
||||
tokens)]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :accounts] add-tokens tokens)
|
||||
(assoc-in [:wallet :ui :tokens-loading address] false))})))
|
||||
(assoc-in [:wallet :ui :tokens-loading address] false))
|
||||
:fx [[:dispatch [:wallet/get-last-wallet-token-update-if-needed]]
|
||||
[:effects.wallet.tokens/fetch-market-values
|
||||
{:symbols symbols
|
||||
:currency profile-currency
|
||||
:on-success [:wallet.tokens/store-market-values]
|
||||
:on-error [:wallet.tokens/fetch-market-values-failed]}]
|
||||
[:effects.wallet.tokens/fetch-prices
|
||||
{:symbols symbols
|
||||
:currencies [constants/profile-default-currency profile-currency]
|
||||
:on-success [:wallet.tokens/store-prices]
|
||||
:on-error [:wallet.tokens/fetch-prices-failed]}]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/get-last-wallet-token-update-if-needed
|
||||
@@ -686,3 +701,36 @@
|
||||
(let [full-status (cske/transform-keys message transforms/->kebab-case-keyword)]
|
||||
{:db (assoc-in db [:wallet :blockchain] full-status)})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/sign-transactions-signal-received
|
||||
(fn [{:keys [db]} [{send-details :sendDetails :as data}]]
|
||||
(let [type (if (or (= (:fromToken send-details)
|
||||
(:toToken send-details))
|
||||
(string/blank? (:toToken send-details)))
|
||||
:send
|
||||
:swap)
|
||||
callback-fx (get-in db [:wallet :ui type :sign-transactions-callback-fx])
|
||||
error-response (:errorResponse send-details)]
|
||||
{:fx [(when (and callback-fx (not error-response))
|
||||
callback-fx)]
|
||||
:db (-> db
|
||||
(assoc-in [:wallet :ui type :sign-transactions-callback-fx] nil)
|
||||
(assoc-in [:wallet :ui type :error-response] error-response)
|
||||
(assoc-in [:wallet :ui type :transaction-for-signing] data))})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/transactions-sent-signal-received
|
||||
(fn [{:keys [db]}
|
||||
[{sent-transactions :sentTransactions
|
||||
send-details :sendDetails}]]
|
||||
(let [swap? (get-in db [:wallet :ui :swap])]
|
||||
{:fx [[:dispatch
|
||||
(if-let [error-response (:errorResponse send-details)]
|
||||
[(if swap?
|
||||
:wallet.swap/transaction-failure
|
||||
:wallet/transaction-failure)
|
||||
error-response]
|
||||
[(if swap?
|
||||
:wallet.swap/transaction-success
|
||||
:wallet/transaction-success)
|
||||
sent-transactions])]]})))
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
[event-id dispatch]
|
||||
(let [expected-effects {:db {:wallet {:ui {:tokens-loading {address true}}}}
|
||||
:fx [[:json-rpc/call
|
||||
[{:method "wallet_getWalletToken"
|
||||
[{:method "wallet_fetchOrGetCachedWalletBalances"
|
||||
:params [[address]]
|
||||
:on-success [:wallet/store-wallet-token address]
|
||||
:on-error [:wallet/get-wallet-token-for-account-failed
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
(ns status-im.contexts.wallet.rpc
|
||||
(:require [oops.core :as oops]
|
||||
[promesa.core :as promesa]
|
||||
[status-im.common.json-rpc.events :as rpc-events]
|
||||
[status-im.constants :as constants]
|
||||
[utils.hex]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(defn build-transaction
|
||||
[chain-id tx]
|
||||
(promesa/let [res (rpc-events/call-async "wallet_buildTransaction" true chain-id tx)]
|
||||
{:message-to-sign (oops/oget res :messageToSign)
|
||||
:tx-args (oops/oget res :txArgs)}))
|
||||
|
||||
(defn build-raw-transaction
|
||||
[chain-id tx-args signature]
|
||||
(-> (rpc-events/call-async "wallet_buildRawTransaction"
|
||||
true
|
||||
chain-id
|
||||
(transforms/js-stringify tx-args 0)
|
||||
signature)
|
||||
(promesa/then #(oops/oget % "rawTx"))))
|
||||
|
||||
(defn hash-message-eip-191
|
||||
[message]
|
||||
(rpc-events/call-async "wallet_hashMessageEIP191" true message))
|
||||
|
||||
(defn safe-sign-typed-data
|
||||
[data address password chain-id legacy?]
|
||||
(rpc-events/call-async "wallet_safeSignTypedDataForDApps"
|
||||
true
|
||||
data
|
||||
address
|
||||
password
|
||||
chain-id
|
||||
legacy?))
|
||||
|
||||
(defn get-suggested-fees
|
||||
[chain-id]
|
||||
(-> (rpc-events/call-async "wallet_getSuggestedFees" true chain-id)
|
||||
(promesa/then transforms/js->clj)))
|
||||
|
||||
(defn send-transaction-with-signature
|
||||
[chain-id tx-args signature]
|
||||
(rpc-events/call-async "wallet_sendTransactionWithSignature"
|
||||
true
|
||||
chain-id
|
||||
constants/transaction-pending-type-wallet-connect-transfer
|
||||
(transforms/js-stringify tx-args 0)
|
||||
signature))
|
||||
|
||||
(defn sign-message
|
||||
[message address password]
|
||||
(-> (rpc-events/call-async "wallet_signMessage"
|
||||
true
|
||||
message
|
||||
address
|
||||
password)
|
||||
(promesa/then utils.hex/normalize-hex)))
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns status-im.contexts.wallet.send.events
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[native-module.core :as native-module]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.collectible.utils :as collectible.utils]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
@@ -9,11 +8,10 @@
|
||||
[status-im.contexts.wallet.data-store :as data-store]
|
||||
[status-im.contexts.wallet.send.utils :as send-utils]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.address :as address]
|
||||
[utils.hex :as utils.hex]
|
||||
[utils.money :as utils.money]
|
||||
[utils.number]
|
||||
[utils.re-frame :as rf]))
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-send-data
|
||||
(fn [{:keys [db]}]
|
||||
@@ -327,22 +325,30 @@
|
||||
(rf/reg-event-fx
|
||||
:wallet/set-token-amount-to-send
|
||||
(fn [{:keys [db]} [{:keys [amount stack-id start-flow?]}]]
|
||||
{:db (assoc-in db [:wallet :ui :send :amount] amount)
|
||||
:fx [[:dispatch
|
||||
[:wallet/wizard-navigate-forward
|
||||
{:current-screen stack-id
|
||||
:start-flow? start-flow?
|
||||
:flow-id :wallet-send-flow}]]]}))
|
||||
(let [last-request-uuid (get-in db [:wallet :ui :send :last-request-uuid])]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :amount] amount)
|
||||
(update-in [:wallet :ui :send] dissoc :transaction-for-signing))
|
||||
:fx [[:dispatch [:wallet/build-transactions-from-route {:request-uuid last-request-uuid}]]
|
||||
[:dispatch
|
||||
[:wallet/wizard-navigate-forward
|
||||
{:current-screen stack-id
|
||||
:start-flow? start-flow?
|
||||
:flow-id :wallet-send-flow}]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/set-token-amount-to-bridge
|
||||
(fn [{:keys [db]} [{:keys [amount stack-id start-flow?]}]]
|
||||
{:db (assoc-in db [:wallet :ui :send :amount] amount)
|
||||
:fx [[:dispatch
|
||||
[:wallet/wizard-navigate-forward
|
||||
{:current-screen stack-id
|
||||
:start-flow? start-flow?
|
||||
:flow-id :wallet-bridge-flow}]]]}))
|
||||
(let [last-request-uuid (get-in db [:wallet :ui :send :last-request-uuid])]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :amount] amount)
|
||||
(update-in [:wallet :ui :send] dissoc :transaction-for-signing))
|
||||
:fx [[:dispatch [:wallet/build-transactions-from-route {:request-uuid last-request-uuid}]]
|
||||
[:dispatch
|
||||
[:wallet/wizard-navigate-forward
|
||||
{:current-screen stack-id
|
||||
:start-flow? start-flow?
|
||||
:flow-id :wallet-bridge-flow}]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/clean-bridge-to-selection
|
||||
@@ -458,7 +464,8 @@
|
||||
:token-networks-ids token-networks-ids
|
||||
:tx-type tx-type
|
||||
:receiver? true}))
|
||||
params [{:uuid (str (random-uuid))
|
||||
request-uuid (str (random-uuid))
|
||||
params [{:uuid request-uuid
|
||||
:sendType send-type
|
||||
:addrFrom from-address
|
||||
:addrTo to-address
|
||||
@@ -477,7 +484,8 @@
|
||||
{:db (update-in db
|
||||
[:wallet :ui :send]
|
||||
#(-> %
|
||||
(assoc :amount amount
|
||||
(assoc :last-request-uuid request-uuid
|
||||
:amount amount
|
||||
:loading-suggested-routes? true
|
||||
:sender-network-values sender-network-values
|
||||
:receiver-network-values receiver-network-values)
|
||||
@@ -565,27 +573,39 @@
|
||||
:else [:wallet/suggested-routes-success (fix-routes data)
|
||||
enough-assets?])]]})))))
|
||||
|
||||
(rf/reg-event-fx :wallet/add-authorized-transaction
|
||||
(fn [{:keys [db]} [transaction]]
|
||||
(let [transaction-batch-id (:id transaction)
|
||||
transaction-hashes (:hashes transaction)
|
||||
transaction-ids (flatten (vals transaction-hashes))
|
||||
transaction-details (send-utils/map-multitransaction-by-ids transaction-batch-id
|
||||
transaction-hashes)]
|
||||
(rf/reg-event-fx
|
||||
:wallet/transaction-success
|
||||
(fn [{:keys [db]} [sent-transactions]]
|
||||
(let [wallet-transactions (get-in db [:wallet :transactions] {})
|
||||
transactions (utils/transactions->hash-to-transaction-map sent-transactions)
|
||||
transaction-ids (->> transactions
|
||||
vals
|
||||
(map :hash))]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :just-completed-transaction?] true)
|
||||
(assoc-in [:wallet :transactions] transaction-details)
|
||||
(assoc-in [:wallet :ui :send :transaction-ids] transaction-ids))
|
||||
:fx [;; Remove wallet/stop-and-clean-suggested-routes event when we move to new transaction
|
||||
;; submission process as the routes as stopped by status-go
|
||||
[:dispatch
|
||||
[:wallet/stop-and-clean-suggested-routes]]
|
||||
[:dispatch
|
||||
[:wallet/end-transaction-flow]]
|
||||
(assoc-in [:wallet :ui :send :transaction-ids] transaction-ids)
|
||||
(assoc-in [:wallet :transactions] (merge wallet-transactions transactions)))
|
||||
:fx [[:dispatch [:wallet/end-transaction-flow]]
|
||||
[:dispatch-later
|
||||
[{:ms 2000
|
||||
:dispatch [:wallet/stop-and-clean-suggested-routes]}]]
|
||||
[:dispatch-later
|
||||
[{:ms 2000
|
||||
:dispatch [:wallet/clean-just-completed-transaction]}]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/transaction-failure
|
||||
(fn [_ [{:keys [details]}]]
|
||||
{:fx [[:dispatch [:wallet/end-transaction-flow]]
|
||||
[:dispatch-later
|
||||
[{:ms 2000
|
||||
:dispatch [:wallet/stop-and-clean-suggested-routes]}]]
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:id :send-transaction-failure
|
||||
:type :negative
|
||||
:text (or details "An error occured")}]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-just-completed-transaction
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db [:wallet :ui :send] dissoc :just-completed-transaction?)}))
|
||||
@@ -609,100 +629,82 @@
|
||||
[{:ms 20
|
||||
:dispatch [:wallet/clean-up-transaction-flow]}]]]})))
|
||||
|
||||
(rf/reg-event-fx :wallet/send-transaction
|
||||
(fn [{:keys [db]} [sha3-pwd]]
|
||||
(let [routes (get-in db [:wallet :ui :send :route])
|
||||
first-route (first routes)
|
||||
from-address (get-in db [:wallet :current-viewing-account-address])
|
||||
transaction-type (get-in db [:wallet :ui :send :tx-type])
|
||||
multi-transaction-type (if (= :tx/bridge transaction-type)
|
||||
constants/multi-transaction-type-bridge
|
||||
constants/multi-transaction-type-send)
|
||||
token (get-in db [:wallet :ui :send :token])
|
||||
collectible (get-in db [:wallet :ui :send :collectible])
|
||||
first-route-from-chain-id (get-in first-route [:from :chain-id])
|
||||
token-id (if token
|
||||
(:symbol token)
|
||||
(get-in collectible [:id :token-id]))
|
||||
erc20-transfer? (and token (not= token-id "ETH"))
|
||||
eth-transfer? (and token (not erc20-transfer?))
|
||||
token-address (cond collectible
|
||||
(get-in collectible
|
||||
[:id :contract-id :address])
|
||||
erc20-transfer?
|
||||
(get-in token [:balances-per-chain first-route-from-chain-id :address]))
|
||||
to-address (get-in db [:wallet :ui :send :to-address])
|
||||
transaction-paths (into []
|
||||
(mapcat
|
||||
(fn [route]
|
||||
(let [approval-required? (:approval-required route)
|
||||
data (when erc20-transfer?
|
||||
(native-module/encode-transfer
|
||||
(address/normalized-hex to-address)
|
||||
(:amount-in route)))
|
||||
base-path (utils/transaction-path
|
||||
{:to-address to-address
|
||||
:from-address from-address
|
||||
:route route
|
||||
:token-address token-address
|
||||
:token-id-from (if collectible
|
||||
(utils.hex/number-to-hex
|
||||
token-id)
|
||||
token-id)
|
||||
:data data
|
||||
:eth-transfer? eth-transfer?})]
|
||||
(if approval-required?
|
||||
[(utils/approval-path {:route route
|
||||
:token-address token-address
|
||||
:from-address from-address
|
||||
:to-address to-address})
|
||||
base-path]
|
||||
[base-path]))))
|
||||
routes)
|
||||
request-params
|
||||
[(utils/multi-transaction-command
|
||||
{:from-address from-address
|
||||
:to-address to-address
|
||||
:from-asset token-id
|
||||
:to-asset token-id
|
||||
:amount-out (if eth-transfer? (:amount-out first-route) "0x0")
|
||||
:multi-transaction-type multi-transaction-type})
|
||||
transaction-paths
|
||||
sha3-pwd]]
|
||||
(log/info "multi transaction called")
|
||||
{:json-rpc/call [{:method "wallet_createMultiTransaction"
|
||||
:params request-params
|
||||
:on-success (fn [result]
|
||||
(when result
|
||||
(rf/dispatch [:wallet/add-authorized-transaction result])
|
||||
(rf/dispatch [:hide-bottom-sheet])))
|
||||
(rf/reg-event-fx
|
||||
:wallet/build-transactions-from-route
|
||||
(fn [_ [{:keys [request-uuid slippage] :or {slippage constants/default-slippage}}]]
|
||||
{:json-rpc/call [{:method "wallet_buildTransactionsFromRoute"
|
||||
:params [{:uuid request-uuid
|
||||
:slippagePercentage slippage}]
|
||||
:on-error (fn [error]
|
||||
(log/error "failed to build transactions from route"
|
||||
{:event :wallet/build-transactions-from-route
|
||||
:error error})
|
||||
(rf/dispatch [:toasts/upsert
|
||||
{:id :build-transactions-from-route-error
|
||||
:type :negative
|
||||
:text (:message error)}]))}]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/prepare-signatures-for-transactions
|
||||
(fn [{:keys [db]} [type sha3-pwd]]
|
||||
(let [{:keys [hashes address signOnKeycard]} (get-in db
|
||||
[:wallet :ui type :transaction-for-signing
|
||||
:signingDetails])
|
||||
on-success (fn [signatures]
|
||||
(rf/dispatch
|
||||
[:wallet/send-router-transactions-with-signatures type
|
||||
signatures]))
|
||||
on-error (fn [error]
|
||||
(log/error
|
||||
"failed to prepare signatures for transactions"
|
||||
{:event :wallet/prepare-signatures-for-transactions
|
||||
:error error})
|
||||
(rf/dispatch
|
||||
[:toasts/upsert
|
||||
{:id :prepare-signatures-for-transactions-error
|
||||
:type :negative
|
||||
:text (:message error)}]))]
|
||||
(if signOnKeycard
|
||||
{:fx [[:dispatch
|
||||
[:standard-auth/authorize-with-keycard
|
||||
{:on-complete #(rf/dispatch [:keycard/connect-and-sign-hashes
|
||||
{:keycard-pin %
|
||||
:address address
|
||||
:hashes hashes
|
||||
:on-success on-success
|
||||
:on-failure on-error}])}]]]}
|
||||
{:fx [[:effects.wallet/sign-transaction-hashes
|
||||
{:hashes hashes
|
||||
:address address
|
||||
:password (security/safe-unmask-data sha3-pwd)
|
||||
:on-success on-success
|
||||
:on-error on-error}]]}))))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/send-router-transactions-with-signatures
|
||||
(fn [{:keys [db]} [type signatures]]
|
||||
(let [transaction-for-signing (get-in db [:wallet :ui type :transaction-for-signing])
|
||||
signatures-map (reduce (fn [acc {:keys [message signature]}]
|
||||
(assoc acc
|
||||
message
|
||||
(send-utils/signature-rsv signature)))
|
||||
{}
|
||||
signatures)]
|
||||
{:json-rpc/call [{:method "wallet_sendRouterTransactionsWithSignatures"
|
||||
:params [{:uuid (get-in transaction-for-signing [:sendDetails :uuid])
|
||||
:signatures signatures-map}]
|
||||
:on-success (fn []
|
||||
(rf/dispatch [:wallet/clean-send-data])
|
||||
(rf/dispatch [:hide-bottom-sheet]))
|
||||
:on-error (fn [error]
|
||||
(log/error "failed to send transaction"
|
||||
{:event :wallet/send-transaction
|
||||
:error error
|
||||
:params request-params})
|
||||
(log/error "failed to send router transactions with signatures"
|
||||
{:event :wallet/send-router-transactions-with-signatures
|
||||
:error error})
|
||||
(rf/dispatch [:toasts/upsert
|
||||
{:id :send-transaction-error
|
||||
{:id :send-router-transactions-with-signatures-error
|
||||
:type :negative
|
||||
:text (:message error)}]))}]})))
|
||||
|
||||
(rf/reg-event-fx :wallet/proceed-with-transactions-signatures
|
||||
(fn [_ [signatures]]
|
||||
{:json-rpc/call [{:method "wallet_proceedWithTransactionsSignatures"
|
||||
:params [signatures]
|
||||
:on-success (fn [result]
|
||||
(when result
|
||||
(rf/dispatch [:wallet/add-authorized-transaction result])
|
||||
(rf/dispatch [:hide-bottom-sheet])))
|
||||
:on-error (fn [error]
|
||||
(log/error "failed to proceed-with-transactions-signatures"
|
||||
{:event :wallet/proceed-with-transactions-signatures
|
||||
:error error})
|
||||
(rf/dispatch [:toasts/upsert
|
||||
{:id :send-transaction-error
|
||||
:type :negative
|
||||
:text (:message error)}]))}]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/select-from-account
|
||||
(fn [{db :db} [{:keys [address stack-id network-details start-flow?]}]]
|
||||
|
||||
@@ -575,29 +575,6 @@
|
||||
:from-locked-amounts {}}}}})
|
||||
(is (match? expected-db (:db (dispatch [event-id suggested-routes timestamp]))))))
|
||||
|
||||
(h/deftest-event :wallet/add-authorized-transaction
|
||||
[event-id dispatch]
|
||||
(let [hashes {:chain-1 ["tx-1" "tx-2" "tx-3"]
|
||||
:chain-2 ["tx-4" "tx-5"]
|
||||
:chain-3 ["tx-6" "tx-7" "tx-8" "tx-9"]}
|
||||
transaction-id "txid-1"
|
||||
expected-result {:db {:wallet {:ui {:send {:transaction-ids ["tx-1" "tx-2" "tx-3"
|
||||
"tx-4" "tx-5" "tx-6"
|
||||
"tx-7" "tx-8" "tx-9"]}}
|
||||
:transactions (send-utils/map-multitransaction-by-ids
|
||||
transaction-id
|
||||
hashes)}}
|
||||
:fx [[:dispatch
|
||||
[:wallet/stop-and-clean-suggested-routes]]
|
||||
[:dispatch [:wallet/end-transaction-flow]]
|
||||
[:dispatch-later
|
||||
[{:ms 2000
|
||||
:dispatch [:wallet/clean-just-completed-transaction]}]]]}]
|
||||
(is (match? expected-result
|
||||
(dispatch [event-id
|
||||
{:id transaction-id
|
||||
:hashes hashes}])))))
|
||||
|
||||
(h/deftest-event :wallet/select-from-account
|
||||
[event-id dispatch]
|
||||
(let [stack-id :screen/stack
|
||||
|
||||
@@ -43,23 +43,22 @@
|
||||
:removed false}
|
||||
:wallet/current-viewing-account-color :purple
|
||||
:wallet/wallet-send-enough-assets? true
|
||||
:wallet/wallet-send-token {:symbol :eth
|
||||
:networks [{:source 879
|
||||
:short-name "eth"
|
||||
:network-name :mainnet
|
||||
:abbreviated-name
|
||||
"Eth."
|
||||
:full-name "Mainnet"
|
||||
:chain-id 1
|
||||
:related-chain-id 1
|
||||
:layer 1}]
|
||||
:balances-per-chain {1 {:raw-balance
|
||||
(money/bignumber
|
||||
"2500")
|
||||
:has-error false}}
|
||||
:total-balance 100
|
||||
:available-balance 100
|
||||
:market-values-per-currency {:usd {:price 10}}}
|
||||
:wallet/wallet-send-token {:symbol "ETH"
|
||||
:networks [{:source 879
|
||||
:short-name "eth"
|
||||
:network-name :mainnet
|
||||
:abbreviated-name
|
||||
"Eth."
|
||||
:full-name "Mainnet"
|
||||
:chain-id 1
|
||||
:related-chain-id 1
|
||||
:layer 1}]
|
||||
:balances-per-chain {1 {:raw-balance
|
||||
(money/bignumber
|
||||
"2500")
|
||||
:has-error false}}
|
||||
:total-balance 100
|
||||
:available-balance 100}
|
||||
:wallet/wallet-send-loading-suggested-routes? false
|
||||
:wallet/wallet-send-route [{:from {:chainid 1
|
||||
:native-currency-symbol "ETH"}
|
||||
@@ -75,14 +74,13 @@
|
||||
:wallet/wallet-send-to-address "0x04371e2d9d66b82f056bc128064"
|
||||
:profile/currency-symbol "$"
|
||||
:profile/currency :usd
|
||||
:wallet/token-by-symbol {:symbol :eth
|
||||
:total-balance 100
|
||||
:available-balance 100
|
||||
:balances-per-chain {1 {:raw-balance
|
||||
(money/bignumber
|
||||
"2500")
|
||||
:has-error false}}
|
||||
:market-values-per-currency {:usd {:price 10}}}
|
||||
:wallet/token-by-symbol {:symbol "ETH"
|
||||
:total-balance 100
|
||||
:available-balance 100
|
||||
:balances-per-chain {1 {:raw-balance
|
||||
(money/bignumber
|
||||
"2500")
|
||||
:has-error false}}}
|
||||
:wallet/wallet-send-disabled-from-chain-ids []
|
||||
:wallet/wallet-send-from-locked-amounts {}
|
||||
:wallet/wallet-send-from-values-by-chain {1 (money/bignumber "250")}
|
||||
@@ -106,6 +104,7 @@
|
||||
:wallet/sending-collectible? false
|
||||
:wallet/send-total-amount-formatted "250 ETH"
|
||||
:wallet/total-amount (money/bignumber "250")
|
||||
:wallet/prices-per-token {:ETH {:usd 10}}
|
||||
:wallet/bridge-to-network-details nil
|
||||
:wallet/send-amount-fixed ""
|
||||
:wallet/send-display-token-decimals 5})
|
||||
|
||||
@@ -164,13 +164,14 @@
|
||||
(str token-symbol)
|
||||
enabled-from-chain-ids])
|
||||
token-balance (or default-limit-crypto total-balance)
|
||||
usd-conversion-rate (utils/token-usd-price token)
|
||||
prices-per-token (rf/sub [:wallet/prices-per-token])
|
||||
usd-conversion-rate (utils/token-usd-price token prices-per-token)
|
||||
currency (rf/sub [:profile/currency])
|
||||
conversion-rate (-> token
|
||||
:market-values-per-currency
|
||||
currency
|
||||
:price)
|
||||
token-decimals (rf/sub [:wallet/send-display-token-decimals])
|
||||
|
||||
conversion-rate (utils/token-price-by-symbol prices-per-token
|
||||
token-symbol
|
||||
currency)
|
||||
[input-state set-input-state] (rn/use-state controlled-input/init-state)
|
||||
clear-input! #(set-input-state controlled-input/delete-all)
|
||||
currency-symbol (rf/sub [:profile/currency-symbol])
|
||||
|
||||
@@ -80,202 +80,44 @@
|
||||
(rf/dispatch [:wallet/update-receiver-networks
|
||||
chain-ids]))}]))}]))
|
||||
|
||||
#_(defn- edit-amount
|
||||
[{:keys [chain-id token-symbol send-amount-in-crypto init-amount]}]
|
||||
(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content
|
||||
(fn []
|
||||
(let [{:keys [network-name] :as network-details} (rf/sub [:wallet/network-details-by-chain-id
|
||||
chain-id])
|
||||
{fiat-currency :currency} (rf/sub [:profile/profile])
|
||||
{token-decimals :decimals
|
||||
:as
|
||||
token} (rf/sub [:wallet/wallet-send-token])
|
||||
currency (rf/sub [:profile/currency])
|
||||
currency-symbol (rf/sub [:profile/currency-symbol])
|
||||
send-from-locked-amounts (rf/sub
|
||||
[:wallet/wallet-send-from-locked-amounts])
|
||||
{account-color :color} (rf/sub [:wallet/current-viewing-account])
|
||||
locked-amount (get send-from-locked-amounts chain-id)
|
||||
network-name-str (string/capitalize (name network-name))
|
||||
[input-state set-input-state] (rn/use-state
|
||||
(cond-> controlled-input/init-state
|
||||
init-amount
|
||||
(controlled-input/set-input-value
|
||||
(money/to-string init-amount))
|
||||
locked-amount
|
||||
(controlled-input/set-input-value
|
||||
locked-amount)))
|
||||
[crypto-currency? set-crypto-currency] (rn/use-state true)
|
||||
conversion-rate (-> token
|
||||
:market-values-per-currency
|
||||
currency
|
||||
:price)
|
||||
{token-balance :total-balance} (rf/sub [:wallet/token-by-symbol
|
||||
(str token-symbol)
|
||||
[chain-id]])
|
||||
current-crypto-limit (utils/get-standard-crypto-format
|
||||
token
|
||||
token-balance)
|
||||
current-fiat-limit (.toFixed (* token-balance conversion-rate) 2)
|
||||
current-limit (if crypto-currency?
|
||||
current-crypto-limit
|
||||
current-fiat-limit)
|
||||
crypto-decimals token-decimals
|
||||
input-amount (controlled-input/input-value input-state)
|
||||
[is-amount-locked? set-is-amount-locked] (rn/use-state (some? locked-amount))
|
||||
bottom (safe-area/get-bottom)
|
||||
amount-in-crypto (if crypto-currency?
|
||||
input-amount
|
||||
(number/remove-trailing-zeroes
|
||||
(.toFixed (/ input-amount
|
||||
conversion-rate)
|
||||
crypto-decimals)))
|
||||
locked-greater-then-send-amount? (let [amount (money/bignumber
|
||||
amount-in-crypto)
|
||||
send-amount (money/bignumber
|
||||
send-amount-in-crypto)]
|
||||
(and (money/bignumber? amount)
|
||||
(money/bignumber? send-amount)
|
||||
(money/greater-than amount
|
||||
send-amount)))
|
||||
swap-between-fiat-and-crypto (fn [swap-to-crypto-currency?]
|
||||
(set-crypto-currency
|
||||
swap-to-crypto-currency?)
|
||||
(set-input-state
|
||||
(fn [input-state]
|
||||
(controlled-input/set-input-value
|
||||
input-state
|
||||
(let [value (controlled-input/input-value
|
||||
input-state)
|
||||
new-value
|
||||
(if
|
||||
swap-to-crypto-currency?
|
||||
(.toFixed
|
||||
(/ value
|
||||
conversion-rate)
|
||||
crypto-decimals)
|
||||
(.toFixed
|
||||
(* value
|
||||
conversion-rate)
|
||||
12))]
|
||||
(number/remove-trailing-zeroes
|
||||
new-value))))))
|
||||
lock-or-unlock-amount (fn []
|
||||
(if is-amount-locked?
|
||||
(rf/dispatch [:wallet/lock-from-amount
|
||||
chain-id
|
||||
amount-in-crypto])
|
||||
(rf/dispatch [:wallet/unlock-from-amount
|
||||
chain-id]))
|
||||
(rf/dispatch [:hide-bottom-sheet]))]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(set-input-state #(controlled-input/set-upper-limit % current-limit)))
|
||||
[current-limit])
|
||||
[:<>
|
||||
[quo/drawer-top
|
||||
{:title (i18n/label :t/send-from-network {:network network-name-str})
|
||||
:description (i18n/label :t/define-amount-sent-from-network {:network network-name-str})}]
|
||||
[quo/token-input
|
||||
{:container-style style/input-container
|
||||
:token token-symbol
|
||||
:currency fiat-currency
|
||||
:currency-symbol currency-symbol
|
||||
:crypto-decimals (min token-decimals 6)
|
||||
:error? (controlled-input/input-error input-state)
|
||||
:networks [network-details]
|
||||
:title (i18n/label
|
||||
:t/send-limit
|
||||
{:limit (if crypto-currency?
|
||||
(utils/make-limit-label-crypto current-limit token-symbol)
|
||||
(utils/make-limit-label-fiat current-limit currency-symbol))})
|
||||
:conversion conversion-rate
|
||||
:show-keyboard? false
|
||||
:value (controlled-input/input-value input-state)
|
||||
:on-swap swap-between-fiat-and-crypto
|
||||
:allow-selection? false}]
|
||||
(when locked-greater-then-send-amount?
|
||||
[quo/information-box
|
||||
{:type :error
|
||||
:icon :i/info
|
||||
:style style/error-box}
|
||||
(i18n/label :t/value-higher-than-send-amount)])
|
||||
[quo/disclaimer
|
||||
{:on-change (fn [checked?]
|
||||
(set-is-amount-locked checked?))
|
||||
:checked? is-amount-locked?
|
||||
:container-style style/disclaimer
|
||||
:icon (if is-amount-locked?
|
||||
:i/locked
|
||||
:i/unlocked)
|
||||
:customization-color account-color}
|
||||
(i18n/label :t/dont-auto-recalculate-network {:network network-name-str})]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (i18n/label :t/update)
|
||||
:button-one-props {:on-press lock-or-unlock-amount
|
||||
:customization-color account-color
|
||||
:disabled? (or (controlled-input/empty-value? input-state)
|
||||
(controlled-input/input-error input-state)
|
||||
locked-greater-then-send-amount?)}}]
|
||||
[quo/numbered-keyboard
|
||||
{:container-style (style/keyboard-container bottom)
|
||||
:left-action :dot
|
||||
:delete-key? true
|
||||
:on-press (fn [c]
|
||||
(let [new-text (str input-amount c)
|
||||
max-decimals (if crypto-currency? crypto-decimals 2)
|
||||
regex-pattern (str "^\\d*\\.?\\d{0," max-decimals "}$")
|
||||
regex (re-pattern regex-pattern)]
|
||||
(when (re-matches regex new-text)
|
||||
(set-is-amount-locked true)
|
||||
(set-input-state #(controlled-input/add-character % c)))))
|
||||
:on-delete (fn []
|
||||
(set-is-amount-locked true)
|
||||
(set-input-state controlled-input/delete-last))
|
||||
:on-long-press-delete (fn []
|
||||
(set-is-amount-locked true)
|
||||
(set-input-state controlled-input/delete-all))}]]))}]))
|
||||
|
||||
(defn render-network-values
|
||||
[{:keys [network-values token-symbol on-press on-long-press receiver? loading-routes?
|
||||
token-not-supported-in-receiver-networks?]}]
|
||||
[rn/view
|
||||
(map-indexed (fn [index
|
||||
{chain-id :chain-id
|
||||
network-value-type :type
|
||||
total-amount :total-amount}]
|
||||
(let [status (cond (and (= network-value-type :not-available)
|
||||
loading-routes?
|
||||
token-not-supported-in-receiver-networks?)
|
||||
:loading
|
||||
(= network-value-type :not-available)
|
||||
:disabled
|
||||
:else network-value-type)
|
||||
amount-formatted (-> (rf/sub [:wallet/send-amount-fixed total-amount])
|
||||
(str " " token-symbol))]
|
||||
[rn/view
|
||||
{:key (str (if receiver? "to" "from") "-" chain-id)
|
||||
:style {:margin-top (if (pos? index) 11 7.5)}}
|
||||
[quo/network-bridge
|
||||
{:amount (if (= network-value-type :not-available)
|
||||
(i18n/label :t/not-available)
|
||||
amount-formatted)
|
||||
:network (network-utils/id->network chain-id)
|
||||
:status status
|
||||
:on-press #(when (not loading-routes?)
|
||||
(cond
|
||||
(= network-value-type :edit)
|
||||
(open-preferences)
|
||||
on-press (on-press chain-id total-amount)))
|
||||
:on-long-press #(when (and (not loading-routes?) (not= status :disabled))
|
||||
(cond
|
||||
(= network-value-type :add)
|
||||
(open-preferences)
|
||||
on-long-press (on-long-press chain-id total-amount)))}]]))
|
||||
network-values)])
|
||||
(doall
|
||||
(map-indexed (fn [index
|
||||
{chain-id :chain-id
|
||||
network-value-type :type
|
||||
total-amount :total-amount}]
|
||||
(let [status (cond (and (= network-value-type :not-available)
|
||||
loading-routes?
|
||||
token-not-supported-in-receiver-networks?)
|
||||
:loading
|
||||
(= network-value-type :not-available)
|
||||
:disabled
|
||||
:else network-value-type)
|
||||
amount-formatted (-> (rf/sub [:wallet/send-amount-fixed total-amount])
|
||||
(str " " token-symbol))]
|
||||
[rn/view
|
||||
{:key (str (if receiver? "to" "from") "-" chain-id)
|
||||
:style {:margin-top (if (pos? index) 11 7.5)}}
|
||||
[quo/network-bridge
|
||||
{:amount (if (= network-value-type :not-available)
|
||||
(i18n/label :t/not-available)
|
||||
amount-formatted)
|
||||
:network (network-utils/id->network chain-id)
|
||||
:status status
|
||||
:on-press #(when (not loading-routes?)
|
||||
(cond
|
||||
(= network-value-type :edit)
|
||||
(open-preferences)
|
||||
on-press (on-press chain-id total-amount)))
|
||||
:on-long-press #(when (and (not loading-routes?) (not= status :disabled))
|
||||
(cond
|
||||
(= network-value-type :add)
|
||||
(open-preferences)
|
||||
on-long-press (on-long-press chain-id total-amount)))}]]))
|
||||
network-values))])
|
||||
|
||||
(defn render-network-links
|
||||
[{:keys [network-links sender-network-values]}]
|
||||
|
||||
@@ -13,8 +13,7 @@
|
||||
[status-im.contexts.wallet.send.utils :as send-utils]
|
||||
[status-im.feature-flags :as ff]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- transaction-title
|
||||
[{:keys [token-display-name amount account route to-network image-url transaction-type
|
||||
@@ -238,6 +237,7 @@
|
||||
bridge-to-chain-id]))
|
||||
loading-suggested-routes? (rf/sub
|
||||
[:wallet/wallet-send-loading-suggested-routes?])
|
||||
transaction-for-signing (rf/sub [:wallet/wallet-send-transaction-for-signing])
|
||||
from-account-props {:customization-color account-color
|
||||
:size 32
|
||||
:emoji (:emoji account)
|
||||
@@ -268,51 +268,50 @@
|
||||
:transaction-type transaction-type}]
|
||||
(when (and (not loading-suggested-routes?) route (seq route))
|
||||
[standard-auth/slide-button
|
||||
{:keycard-supported? true
|
||||
:size :size-48
|
||||
:track-text (if (= transaction-type :tx/bridge)
|
||||
(i18n/label :t/slide-to-bridge)
|
||||
(i18n/label :t/slide-to-send))
|
||||
:container-style {:z-index 2}
|
||||
{:keycard-supported? true
|
||||
:size :size-48
|
||||
:track-text (if (= transaction-type :tx/bridge)
|
||||
(i18n/label :t/slide-to-bridge)
|
||||
(i18n/label :t/slide-to-send))
|
||||
:container-style {:z-index 2}
|
||||
:disabled? (not transaction-for-signing)
|
||||
:customization-color account-color
|
||||
:on-auth-success #(rf/dispatch
|
||||
[:wallet/send-transaction
|
||||
(security/safe-unmask-data %)])
|
||||
:auth-button-label (i18n/label :t/confirm)}])]
|
||||
:on-auth-success
|
||||
(fn [data]
|
||||
(rf/dispatch
|
||||
[:wallet/prepare-signatures-for-transactions
|
||||
:send data]))
|
||||
:auth-button-label (i18n/label :t/confirm)}])]
|
||||
:gradient-cover? true
|
||||
:customization-color (:color account)}
|
||||
[rn/view
|
||||
[rn/pressable
|
||||
{:on-press #(rf/dispatch [:navigate-to-within-stack
|
||||
[:screen/wallet.transaction-details
|
||||
:screen/wallet.transaction-confirmation]])}
|
||||
[transaction-title
|
||||
{:token-display-name token-symbol
|
||||
:amount amount
|
||||
:account account
|
||||
:type type
|
||||
:recipient recipient
|
||||
:route route
|
||||
:to-network bridge-to-network
|
||||
:image-url image-url
|
||||
:transaction-type transaction-type
|
||||
:collectible? collectible?}]
|
||||
[user-summary
|
||||
{:summary-type :status-account
|
||||
:accessibility-label :summary-from-label
|
||||
:label (i18n/label :t/from-capitalized)
|
||||
:account-props from-account-props
|
||||
:theme theme}]
|
||||
[user-summary
|
||||
{:summary-type (if (= transaction-type :tx/bridge)
|
||||
:status-account
|
||||
:account)
|
||||
:accessibility-label :summary-to-label
|
||||
:label (i18n/label :t/to-capitalized)
|
||||
:account-props (if (= transaction-type :tx/bridge)
|
||||
from-account-props
|
||||
user-props)
|
||||
:recipient recipient
|
||||
:bridge-tx? (= transaction-type :tx/bridge)
|
||||
:account-to? true
|
||||
:theme theme}]]]]]))))
|
||||
[transaction-title
|
||||
{:token-display-name token-symbol
|
||||
:amount amount
|
||||
:account account
|
||||
:type type
|
||||
:recipient recipient
|
||||
:route route
|
||||
:to-network bridge-to-network
|
||||
:image-url image-url
|
||||
:transaction-type transaction-type
|
||||
:collectible? collectible?}]
|
||||
[user-summary
|
||||
{:summary-type :status-account
|
||||
:accessibility-label :summary-from-label
|
||||
:label (i18n/label :t/from-capitalized)
|
||||
:account-props from-account-props
|
||||
:theme theme}]
|
||||
[user-summary
|
||||
{:summary-type (if (= transaction-type :tx/bridge)
|
||||
:status-account
|
||||
:account)
|
||||
:accessibility-label :summary-to-label
|
||||
:label (i18n/label :t/to-capitalized)
|
||||
:account-props (if (= transaction-type :tx/bridge)
|
||||
from-account-props
|
||||
user-props)
|
||||
:recipient recipient
|
||||
:bridge-tx? (= transaction-type :tx/bridge)
|
||||
:account-to? true
|
||||
:theme theme}]]]]))))
|
||||
|
||||
@@ -303,3 +303,9 @@
|
||||
(defn bridge-disabled?
|
||||
[token-symbol]
|
||||
(not (constants/bridge-assets token-symbol)))
|
||||
|
||||
(defn signature-rsv
|
||||
[signature]
|
||||
{:r (subs signature 0 64)
|
||||
:s (subs signature 64 128)
|
||||
:v (subs signature 128 130)})
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
(rf/dispatch [:wallet/get-crypto-on-ramps])))
|
||||
(let [crypto-on-ramps (rf/sub [:wallet/crypto-on-ramps])
|
||||
account (rf/sub [:wallet/current-viewing-account-or-default])
|
||||
has-recurrent? (seq (:recurrent crypto-on-ramps))
|
||||
[selected-tab set-selected-tab] (rn/use-state initial-tab)
|
||||
[min-height set-min-height] (rn/use-state 0)
|
||||
on-layout (rn/use-callback
|
||||
@@ -56,18 +57,27 @@
|
||||
(oops/oget % :nativeEvent :layout :height)))]
|
||||
[:<>
|
||||
[quo/drawer-top {:title (or title (i18n/label :t/ways-to-buy-assets))}]
|
||||
[quo/segmented-control
|
||||
{:size 32
|
||||
:container-style style/tabs
|
||||
:default-active initial-tab
|
||||
:on-change set-selected-tab
|
||||
:data tabs}]
|
||||
[rn/flat-list
|
||||
{:data (if (= selected-tab :recurrent)
|
||||
(:recurrent crypto-on-ramps)
|
||||
(:one-time crypto-on-ramps))
|
||||
:on-layout on-layout
|
||||
:style (style/list-container min-height)
|
||||
:render-data {:tab selected-tab
|
||||
:account account}
|
||||
:render-fn crypto-on-ramp-item}]]))
|
||||
(when has-recurrent?
|
||||
[:<>
|
||||
[quo/segmented-control
|
||||
{:size 32
|
||||
:container-style style/tabs
|
||||
:default-active initial-tab
|
||||
:on-change set-selected-tab
|
||||
:data tabs}]
|
||||
[rn/flat-list
|
||||
{:data (if (= selected-tab :recurrent)
|
||||
(:recurrent crypto-on-ramps)
|
||||
(:one-time crypto-on-ramps))
|
||||
:on-layout on-layout
|
||||
:style (style/list-container min-height)
|
||||
:render-data {:tab selected-tab
|
||||
:account account}
|
||||
:render-fn crypto-on-ramp-item}]])
|
||||
(when-not has-recurrent?
|
||||
[rn/flat-list
|
||||
{:data (:one-time crypto-on-ramps)
|
||||
:on-layout on-layout
|
||||
:style (style/list-container min-height)
|
||||
:render-data {:account account}
|
||||
:render-fn crypto-on-ramp-item}])]))
|
||||
|
||||
@@ -15,11 +15,13 @@
|
||||
bridge-disabled? :bridge-disabled?
|
||||
:as token}
|
||||
{:keys [currency currency-symbol on-token-press disable-token-fn preselected-token-symbol]}]
|
||||
(let [fiat-value (utils/calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance total-balance
|
||||
:token token})
|
||||
crypto-formatted (utils/get-standard-crypto-format token total-balance)
|
||||
(let [prices-per-token (rf/sub [:wallet/prices-per-token])
|
||||
fiat-value (utils/calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance total-balance
|
||||
:token token
|
||||
:prices-per-token prices-per-token})
|
||||
crypto-formatted (utils/get-standard-crypto-format token total-balance prices-per-token)
|
||||
fiat-formatted (utils/fiat-formatted-for-ui currency-symbol fiat-value)]
|
||||
[rn/view {:style {:padding-horizontal 8}}
|
||||
[quo/token-network
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
(ns status-im.contexts.wallet.swap.events
|
||||
(:require [native-module.core :as native-module]
|
||||
[re-frame.core :as rf]
|
||||
(:require [re-frame.core :as rf]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.send.utils :as send-utils]
|
||||
[status-im.contexts.wallet.sheets.network-selection.view :as network-selection]
|
||||
[status-im.contexts.wallet.swap.utils :as swap-utils]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.address :as address]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.money :as money]
|
||||
[utils.number :as number]))
|
||||
@@ -151,10 +148,9 @@
|
||||
:disabledFromChainIDs disabled-from-chain-ids
|
||||
:disabledToChainIDs disabled-to-chain-ids
|
||||
:gasFeeMode gas-rates
|
||||
:fromLockedAmount from-locked-amount}
|
||||
amount-in (assoc :amountIn amount-in-hex)
|
||||
amount-out (assoc :amountOut amount-out-hex))]]
|
||||
|
||||
:fromLockedAmount from-locked-amount
|
||||
:amountOut (or amount-out-hex "0x0")}
|
||||
amount-in (assoc :amountIn amount-in-hex))]]
|
||||
(when-let [amount (or amount-in amount-out)]
|
||||
{:db (update-in db
|
||||
[:wallet :ui :swap]
|
||||
@@ -270,150 +266,21 @@
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db [:wallet :ui] dissoc :swap)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/swap-transaction
|
||||
(fn [{:keys [db]} [sha3-pwd]]
|
||||
(let [wallet-address (get-in db
|
||||
[:wallet
|
||||
:current-viewing-account-address])
|
||||
{:keys [asset-to-pay asset-to-receive
|
||||
swap-proposal network amount
|
||||
approval-transaction-id
|
||||
max-slippage]} (get-in db [:wallet :ui :swap])
|
||||
transactions (get-in db [:wallet :transactions])
|
||||
approval-transaction (when approval-transaction-id
|
||||
(get transactions approval-transaction-id))
|
||||
already-approved? (and approval-transaction
|
||||
(= (:status approval-transaction)
|
||||
:confirmed))
|
||||
approval-required? (and (:approval-required swap-proposal)
|
||||
(not already-approved?))
|
||||
multi-transaction-type constants/multi-transaction-type-swap
|
||||
swap-chain-id (:chain-id network)
|
||||
token-id-from (:symbol asset-to-pay)
|
||||
token-id-to (:symbol asset-to-receive)
|
||||
erc20-transfer? (and asset-to-pay (not= token-id-from "ETH"))
|
||||
eth-transfer? (and asset-to-pay (not erc20-transfer?))
|
||||
token-address (when erc20-transfer?
|
||||
(get-in asset-to-pay
|
||||
[:balances-per-chain swap-chain-id
|
||||
:address]))
|
||||
data (when erc20-transfer?
|
||||
(native-module/encode-transfer
|
||||
(address/normalized-hex wallet-address)
|
||||
(:amount-in swap-proposal)))
|
||||
transaction-paths (if approval-required?
|
||||
[(utils/approval-path
|
||||
{:route swap-proposal
|
||||
:token-address token-address
|
||||
:from-address wallet-address
|
||||
:to-address wallet-address})]
|
||||
[(utils/transaction-path
|
||||
{:to-address wallet-address
|
||||
:from-address wallet-address
|
||||
:route swap-proposal
|
||||
:token-address token-address
|
||||
:token-id-from token-id-from
|
||||
:token-id-to token-id-to
|
||||
:data data
|
||||
:slippage-percentage max-slippage
|
||||
:eth-transfer? eth-transfer?})])
|
||||
request-params [(utils/multi-transaction-command
|
||||
{:from-address wallet-address
|
||||
:to-address wallet-address
|
||||
:from-asset token-id-from
|
||||
:to-asset (if approval-required?
|
||||
token-id-from
|
||||
token-id-to)
|
||||
:amount-out (if eth-transfer?
|
||||
(:amount-out swap-proposal)
|
||||
"0x0")
|
||||
:multi-transaction-type
|
||||
multi-transaction-type})
|
||||
transaction-paths
|
||||
sha3-pwd]]
|
||||
(log/info "multi transaction called")
|
||||
{:json-rpc/call [{:method "wallet_createMultiTransaction"
|
||||
:params request-params
|
||||
:on-success (fn [result]
|
||||
(when result
|
||||
(let [receive-token-decimals (:decimals asset-to-receive)
|
||||
amount-out (:amount-out swap-proposal)
|
||||
receive-amount
|
||||
(when amount-out
|
||||
(-> amount-out
|
||||
(number/hex->whole receive-token-decimals)
|
||||
(money/to-fixed receive-token-decimals)))]
|
||||
(rf/dispatch [:centralized-metrics/track
|
||||
(if approval-required?
|
||||
:metric/swap-approval-execution-start
|
||||
:metric/swap-transaction-execution-start)
|
||||
(cond-> {:network swap-chain-id
|
||||
:pay_token token-id-from}
|
||||
(not approval-required?)
|
||||
(assoc :receive_token token-id-to))])
|
||||
(rf/dispatch [:wallet.swap/add-authorized-transaction
|
||||
(cond-> {:transaction result
|
||||
:approval-transaction?
|
||||
approval-required?}
|
||||
(not approval-required?)
|
||||
(assoc :swap-data
|
||||
{:pay-token-symbol token-id-from
|
||||
:pay-amount amount
|
||||
:receive-token-symbol token-id-to
|
||||
:receive-amount receive-amount
|
||||
:swap-chain-id swap-chain-id}))])
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(rf/dispatch [:dismiss-modal
|
||||
(if approval-required?
|
||||
:screen/wallet.swap-set-spending-cap
|
||||
:screen/wallet.swap-confirmation)])
|
||||
(when-not approval-required?
|
||||
(rf/dispatch [:wallet/end-swap-flow])
|
||||
(debounce/debounce-and-dispatch
|
||||
[:toasts/upsert
|
||||
{:id :swap-transaction-pending
|
||||
:icon :i/info
|
||||
:type :neutral
|
||||
:text (i18n/label :t/swapping-to
|
||||
{:pay-amount amount
|
||||
:pay-token-symbol token-id-from
|
||||
:receive-token-symbol token-id-to
|
||||
:receive-amount receive-amount})}]
|
||||
500)))))
|
||||
:on-error (fn [error]
|
||||
(rf/dispatch [:centralized-metrics/track
|
||||
(if approval-required?
|
||||
:metric/swap-approval-execution-failed
|
||||
:metric/swap-transaction-execution-failed)
|
||||
(cond-> {:network swap-chain-id
|
||||
:error error
|
||||
:pay_token token-id-from}
|
||||
(not approval-required?)
|
||||
(assoc :receive_token token-id-to))])
|
||||
(log/error "failed swap transaction"
|
||||
{:event :wallet/swap-transaction
|
||||
:error error
|
||||
:params request-params})
|
||||
(rf/dispatch [:toasts/upsert
|
||||
{:id :swap-transaction-error
|
||||
:type :negative
|
||||
:text (:message error)}]))}]})))
|
||||
|
||||
(rf/reg-event-fx :wallet.swap/add-authorized-transaction
|
||||
(fn [{:keys [db]} [{:keys [transaction swap-data approval-transaction?]}]]
|
||||
(let [transactions (get-in db [:wallet :transactions] {})
|
||||
transaction-batch-id (:id transaction)
|
||||
transaction-hashes (:hashes transaction)
|
||||
transaction-ids (flatten (vals transaction-hashes))
|
||||
(fn [{:keys [db]} [{:keys [sent-transactions swap-data approval-transaction?]}]]
|
||||
(let [wallet-transactions (get-in db [:wallet :transactions] {})
|
||||
transactions (utils/transactions->hash-to-transaction-map sent-transactions)
|
||||
transaction-ids (->> transactions
|
||||
vals
|
||||
(map :hash))
|
||||
transaction-id (first transaction-ids)
|
||||
transaction-details (cond-> (send-utils/map-multitransaction-by-ids transaction-batch-id
|
||||
transaction-hashes)
|
||||
transaction-details (cond-> transactions
|
||||
:always (assoc-in [transaction-id :tx-type] :swap)
|
||||
swap-data (assoc-in [transaction-id :swap-data] swap-data))
|
||||
swap-transaction-ids (get-in db [:wallet :swap-transaction-ids])]
|
||||
{:db (cond-> db
|
||||
:always (assoc-in [:wallet :transactions]
|
||||
(merge transactions transaction-details))
|
||||
(merge wallet-transactions transaction-details))
|
||||
:always (assoc-in [:wallet :ui :swap :transaction-ids] transaction-ids)
|
||||
approval-transaction? (assoc-in [:wallet :ui :swap :approval-transaction-id]
|
||||
transaction-id)
|
||||
@@ -463,7 +330,8 @@
|
||||
(not transaction-confirmed?)
|
||||
(assoc :db (update-in db [:wallet :ui :swap] dissoc :approval-transaction-id)))))))
|
||||
|
||||
(rf/reg-event-fx :wallet.swap/swap-transaction-update
|
||||
(rf/reg-event-fx
|
||||
:wallet.swap/swap-transaction-update
|
||||
(fn [{:keys [db]} [{:keys [tx-hash status]}]]
|
||||
(let [{:keys [pay-amount pay-token-symbol
|
||||
receive-amount receive-token-symbol
|
||||
@@ -494,7 +362,8 @@
|
||||
:receive-amount receive-amount})
|
||||
(i18n/label :t/swap-failed))}]]]}))))
|
||||
|
||||
(rf/reg-event-fx :wallet.swap/flip-assets
|
||||
(rf/reg-event-fx
|
||||
:wallet.swap/flip-assets
|
||||
(fn [{:keys [db]}]
|
||||
(let [{:keys [asset-to-pay asset-to-receive
|
||||
swap-proposal amount network]} (get-in db [:wallet :ui :swap])
|
||||
@@ -528,14 +397,169 @@
|
||||
:previous_token (:symbol asset-to-receive)
|
||||
:new_token (:symbol asset-to-pay)}]]]})))
|
||||
|
||||
(rf/reg-event-fx :wallet/end-swap-flow
|
||||
(rf/reg-event-fx
|
||||
:wallet.swap/set-sign-transactions-callback-fx
|
||||
(fn [{:keys [db]} [callback-fx]]
|
||||
{:db (assoc-in db [:wallet :ui :swap :sign-transactions-callback-fx] callback-fx)}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet.swap/approve
|
||||
(fn [{:keys [db]}]
|
||||
(let [launch-screen (get-in db [:wallet :ui :swap :launch-screen])
|
||||
address (get-in db [:wallet :current-viewing-account-address])]
|
||||
{:fx [(when (= launch-screen :wallet-stack)
|
||||
[:dispatch [:wallet/navigate-to-account-within-stack address]])
|
||||
(let [last-request-uuid (get-in db [:wallet :ui :swap :last-request-uuid])
|
||||
max-slippage (get-in db [:wallet :ui :swap :max-slippage])]
|
||||
{:fx [[:dispatch
|
||||
[:wallet/build-transactions-from-route
|
||||
{:request-uuid last-request-uuid
|
||||
:slippage max-slippage}]]
|
||||
[:dispatch
|
||||
[:wallet.swap/set-sign-transactions-callback-fx
|
||||
[:dispatch [:open-modal :screen/wallet.swap-set-spending-cap]]]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet.swap/review-swap
|
||||
(fn [{:keys [db]}]
|
||||
(let [last-request-uuid (get-in db [:wallet :ui :swap :last-request-uuid])
|
||||
max-slippage (get-in db [:wallet :ui :swap :max-slippage])]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :swap] dissoc :transaction-for-signing))
|
||||
:fx [[:dispatch
|
||||
[:wallet/build-transactions-from-route
|
||||
{:request-uuid last-request-uuid
|
||||
:slippage max-slippage}]]
|
||||
[:dispatch
|
||||
[:navigate-to-within-stack
|
||||
[:screen/wallet.swap-confirmation
|
||||
:screen/wallet.setup-swap]]]]})))
|
||||
|
||||
(defn transaction-approval-required?
|
||||
[transactions {:keys [swap-proposal approval-transaction-id]}]
|
||||
(let [approval-transaction (when approval-transaction-id
|
||||
(get transactions approval-transaction-id))
|
||||
already-approved? (and approval-transaction
|
||||
(= (:status approval-transaction)
|
||||
:confirmed))]
|
||||
(and (:approval-required swap-proposal)
|
||||
(not already-approved?))))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet.swap/mark-as-pending
|
||||
(fn [{:keys [db]} [transaction-id]]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :transactions transaction-id :status] :pending)
|
||||
(assoc-in [:wallet :ui :swap :approval-transaction-id] transaction-id))}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet.swap/transaction-success
|
||||
(fn [{:keys [db]} [sent-transactions]]
|
||||
(let [transactions (get-in db [:wallet :transactions])
|
||||
{:keys [swap-proposal
|
||||
asset-to-pay
|
||||
asset-to-receive
|
||||
network
|
||||
amount]
|
||||
:as swap} (get-in db [:wallet :ui :swap])
|
||||
swap-chain-id (:chain-id network)
|
||||
token-id-from (:symbol asset-to-pay)
|
||||
token-id-to (:symbol asset-to-receive)
|
||||
receive-token-decimals (:decimals asset-to-receive)
|
||||
amount-out (:amount-out swap-proposal)
|
||||
receive-amount (when amount-out
|
||||
(-> amount-out
|
||||
(number/hex->whole receive-token-decimals)
|
||||
(money/to-fixed receive-token-decimals)))
|
||||
approval-required? (transaction-approval-required? transactions swap)]
|
||||
{:fx [[:dispatch
|
||||
[:centralized-metrics/track
|
||||
(if approval-required?
|
||||
:metric/swap-approval-execution-start
|
||||
:metric/swap-transaction-execution-start)
|
||||
(cond-> {:network swap-chain-id
|
||||
:pay_token token-id-from}
|
||||
(not approval-required?)
|
||||
(assoc :receive_token token-id-to))]]
|
||||
[:dispatch
|
||||
[:wallet.swap/add-authorized-transaction
|
||||
(cond-> {:sent-transactions sent-transactions
|
||||
:approval-transaction? approval-required?}
|
||||
(not approval-required?)
|
||||
(assoc :swap-data
|
||||
{:pay-token-symbol token-id-from
|
||||
:pay-amount amount
|
||||
:receive-token-symbol token-id-to
|
||||
:receive-amount receive-amount
|
||||
:swap-chain-id swap-chain-id}))]]
|
||||
(when approval-required?
|
||||
;; dismiss the spending cap dialog if the transaction needs to be approved
|
||||
[:dispatch [:dismiss-modal :screen/wallet.swap-set-spending-cap]])
|
||||
(when approval-required?
|
||||
[:dispatch [:wallet.swap/mark-as-pending (-> sent-transactions first :hash)]])
|
||||
(when-not approval-required?
|
||||
;; just end the whole transaction flow if no approval needed
|
||||
[:dispatch [:wallet.swap/end-transaction-flow]])
|
||||
(when-not approval-required?
|
||||
[:dispatch-later
|
||||
{:ms 500
|
||||
:dispatch [:toasts/upsert
|
||||
{:id :swap-transaction-pending
|
||||
:icon :i/info
|
||||
:type :neutral
|
||||
:text (i18n/label :t/swapping-to
|
||||
{:pay-amount amount
|
||||
:pay-token-symbol token-id-from
|
||||
:receive-token-symbol token-id-to
|
||||
:receive-amount receive-amount})}]}])]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet.swap/transaction-failure
|
||||
(fn [{:keys [db]} [{:keys [details] :as error}]]
|
||||
(let [transactions (get-in db [:wallet :transactions])
|
||||
{:keys [asset-to-pay
|
||||
asset-to-receive
|
||||
network]
|
||||
:as swap} (get-in db [:wallet :ui :swap])
|
||||
swap-chain-id (:chain-id network)
|
||||
token-id-from (:symbol asset-to-pay)
|
||||
token-id-to (:symbol asset-to-receive)
|
||||
approval-required? (transaction-approval-required? transactions swap)]
|
||||
{:fx [[:centralized-metrics/track
|
||||
(if approval-required?
|
||||
:metric/swap-approval-execution-failed
|
||||
:metric/swap-transaction-execution-failed)
|
||||
(cond-> {:network swap-chain-id
|
||||
:error error
|
||||
:pay_token token-id-from}
|
||||
(not approval-required?)
|
||||
(assoc :receive_token token-id-to))]
|
||||
[:dispatch [:wallet.swap/end-transaction-flow]]
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:id :send-transaction-error
|
||||
:type :negative
|
||||
:text (or details "An error occured")}]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet.swap/clean-up-transaction-flow
|
||||
(fn [{:keys [db]}]
|
||||
(let [transactions (get-in db [:wallet :transactions])
|
||||
swap (get-in db [:wallet :ui :swap])
|
||||
approval-required? (transaction-approval-required? transactions swap)]
|
||||
{:db (update-in db [:wallet :ui] dissoc :swap)
|
||||
:fx [[:dispatch
|
||||
[:dismiss-modal
|
||||
(if approval-required?
|
||||
:screen/wallet.swap-set-spending-cap
|
||||
:screen/wallet.swap-confirmation)]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet.swap/end-transaction-flow
|
||||
(fn [{:keys [db]}]
|
||||
(let [address (get-in db [:wallet :current-viewing-account-address])]
|
||||
{:fx [[:dispatch [:wallet/navigate-to-account-within-stack address]]
|
||||
[:dispatch [:wallet/fetch-activities-for-current-account]]
|
||||
[:dispatch [:wallet/select-account-tab :activity]]]})))
|
||||
[:dispatch [:wallet/select-account-tab :activity]]
|
||||
[:dispatch-later
|
||||
[{:ms 20
|
||||
:dispatch [:wallet.swap/clean-up-transaction-flow]}]]]})))
|
||||
|
||||
(rf/reg-event-fx :wallet.swap/start-from-account
|
||||
(fn [{:keys [db]} [account]]
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
[status-im.contexts.wallet.swap.set-spending-cap.style :as style]
|
||||
[utils.address :as address-utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- swap-title
|
||||
[]
|
||||
@@ -221,9 +220,8 @@
|
||||
(let [loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?])
|
||||
swap-proposal (rf/sub [:wallet/swap-proposal-without-fees])
|
||||
account (rf/sub [:wallet/current-viewing-account])
|
||||
on-auth-success (rn/use-callback #(rf/dispatch
|
||||
[:wallet/swap-transaction
|
||||
(security/safe-unmask-data %)]))]
|
||||
on-auth-success (rn/use-callback
|
||||
#(rf/dispatch [:wallet/prepare-signatures-for-transactions :swap %]))]
|
||||
[standard-auth/slide-button
|
||||
{:size :size-48
|
||||
:track-text (i18n/label :t/slide-to-sign)
|
||||
|
||||
@@ -95,8 +95,10 @@
|
||||
:subtitle (str max-slippage "%")
|
||||
:subtitle-icon :i/edit
|
||||
:size :small
|
||||
:on-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content slippage-settings/view}])}]]))
|
||||
:on-press (fn []
|
||||
(when-not loading-swap-proposal?
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content slippage-settings/view}])))}]]))
|
||||
|
||||
(defn- pay-token-input
|
||||
[{:keys [input-state on-max-press on-input-focus on-token-press on-approve-press input-focused?]}]
|
||||
@@ -195,7 +197,8 @@
|
||||
:approve)
|
||||
:token-value approval-label-token-value
|
||||
:button-props (merge {:on-press on-approve-press}
|
||||
(when error-response
|
||||
(when (or loading-swap-proposal?
|
||||
error-response)
|
||||
{:disabled? true}))
|
||||
:customization-color account-color
|
||||
:token-symbol pay-token-symbol}}]))
|
||||
@@ -216,6 +219,7 @@
|
||||
currency-symbol (rf/sub [:profile/currency-symbol])
|
||||
amount-out (rf/sub [:wallet/swap-proposal-amount-out])
|
||||
approval-required? (rf/sub [:wallet/swap-proposal-approval-required])
|
||||
prices-per-token (rf/sub [:wallet/prices-per-token])
|
||||
receive-token-symbol (:symbol asset-to-receive)
|
||||
receive-token-decimals (:decimals asset-to-receive)
|
||||
amount-out-whole-number (when amount-out
|
||||
@@ -224,10 +228,11 @@
|
||||
(number/to-fixed amount-out-whole-number receive-token-decimals)
|
||||
default-text-for-unfocused-input)
|
||||
receive-token-fiat-value (utils/formatted-token-fiat-value
|
||||
{:currency currency
|
||||
:currency-symbol currency-symbol
|
||||
:balance (or amount-out-whole-number 0)
|
||||
:token asset-to-receive})]
|
||||
{:currency currency
|
||||
:currency-symbol currency-symbol
|
||||
:balance (or amount-out-whole-number 0)
|
||||
:token asset-to-receive
|
||||
:prices-per-token prices-per-token})]
|
||||
[quo/swap-input
|
||||
{:type :receive
|
||||
:error? false
|
||||
@@ -359,9 +364,7 @@
|
||||
(not pay-input-error?))
|
||||
on-review-swap-press (rn/use-callback
|
||||
(fn []
|
||||
(rf/dispatch [:navigate-to-within-stack
|
||||
[:screen/wallet.swap-confirmation
|
||||
:screen/wallet.setup-swap]])))
|
||||
(rf/dispatch [:wallet.swap/review-swap])))
|
||||
on-press (rn/use-callback
|
||||
(fn [c]
|
||||
(let
|
||||
@@ -490,7 +493,7 @@
|
||||
:on-max-press on-max-press
|
||||
:input-focused? pay-input-focused?
|
||||
:on-token-press #(rf/dispatch [:show-bottom-sheet {:content pay-token-bottom-sheet}])
|
||||
:on-approve-press #(rf/dispatch [:open-modal :screen/wallet.swap-set-spending-cap])
|
||||
:on-approve-press #(rf/dispatch [:wallet.swap/approve])
|
||||
:on-input-focus (fn []
|
||||
(when platform/android? (rf/dispatch [:dismiss-keyboard]))
|
||||
(set-pay-input-focused? true))}]
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
[status-im.contexts.wallet.swap.swap-confirmation.style :as style]
|
||||
[utils.address :as address-utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- on-close-action
|
||||
[]
|
||||
@@ -165,22 +164,23 @@
|
||||
|
||||
(defn- slide-button
|
||||
[]
|
||||
(let [loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?])
|
||||
swap-proposal (rf/sub [:wallet/swap-proposal-without-fees])
|
||||
account (rf/sub [:wallet/current-viewing-account])
|
||||
account-color (:color account)
|
||||
on-auth-success (rn/use-callback (fn [data]
|
||||
(rf/dispatch [:wallet/stop-get-swap-proposal])
|
||||
(rf/dispatch [:wallet/swap-transaction
|
||||
(security/safe-unmask-data data)])))]
|
||||
(let [loading-swap-proposal? (rf/sub [:wallet/swap-loading-swap-proposal?])
|
||||
transaction-for-signing (rf/sub [:wallet/swap-transaction-for-signing])
|
||||
swap-proposal (rf/sub [:wallet/swap-proposal-without-fees])
|
||||
account (rf/sub [:wallet/current-viewing-account])
|
||||
account-color (:color account)]
|
||||
[standard-auth/slide-button
|
||||
{:size :size-48
|
||||
:track-text (i18n/label :t/slide-to-swap)
|
||||
:container-style {:z-index 2}
|
||||
:customization-color account-color
|
||||
:disabled? (or loading-swap-proposal? (not swap-proposal))
|
||||
:disabled? (or loading-swap-proposal?
|
||||
(not swap-proposal)
|
||||
(not transaction-for-signing))
|
||||
:auth-button-label (i18n/label :t/confirm)
|
||||
:on-auth-success on-auth-success}]))
|
||||
:on-auth-success (fn [data]
|
||||
(rf/dispatch [:wallet/stop-get-swap-proposal])
|
||||
(rf/dispatch [:wallet/prepare-signatures-for-transactions :swap data]))}]))
|
||||
|
||||
(defn footer
|
||||
[]
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
(ns status-im.contexts.wallet.swap.swap-proposal.style)
|
||||
|
||||
(def container
|
||||
{:flex 1})
|
||||
@@ -1,27 +0,0 @@
|
||||
(ns status-im.contexts.wallet.swap.swap-proposal.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.contexts.wallet.sheets.slippage-settings.view :as slippage-settings]
|
||||
[status-im.contexts.wallet.swap.swap-proposal.style :as style]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [max-slippage (rf/sub [:wallet/swap-max-slippage])]
|
||||
[rn/view {:style style/container}
|
||||
[quo/button
|
||||
{:on-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content slippage-settings/view}])}
|
||||
(str "Edit Slippage: " max-slippage "%")]
|
||||
[quo/button
|
||||
{:on-press #(rf/dispatch [:navigate-to-within-stack
|
||||
[:screen/wallet.swap-confirmation :screen/wallet.swap-propasal]])}
|
||||
"Swap confirmation"]
|
||||
[quo/button
|
||||
{:on-press #(rf/dispatch [:open-modal :screen/wallet.swap-set-spending-cap])}
|
||||
"Set spending cap"]
|
||||
[quo/button
|
||||
{:on-press #(rf/dispatch [:navigate-to-within-stack
|
||||
[:screen/wallet.setup-swap :screen/wallet.swap-propasal]])}
|
||||
"Setup swap"]]))
|
||||
@@ -21,6 +21,7 @@
|
||||
(defn store-token-list
|
||||
[{:keys [db]} [{:keys [data]}]]
|
||||
(let [chain-ids (chain/chain-ids db)
|
||||
profile-currency (get-in db [:profile/profile :currency])
|
||||
tokens (reduce (fn [{:keys [by-address by-symbol] :as data}
|
||||
{:keys [name source version tokens]}]
|
||||
(-> data
|
||||
@@ -48,13 +49,11 @@
|
||||
:by-address {}
|
||||
:by-symbol {}}
|
||||
data)
|
||||
symbols (->> tokens
|
||||
:by-symbol
|
||||
vals
|
||||
(map :symbol)
|
||||
set
|
||||
vec)
|
||||
by-symbol-vals (-> tokens :by-symbol vals)
|
||||
symbols (reduce (fn [acc token]
|
||||
(conj acc (:symbol token)))
|
||||
#{}
|
||||
by-symbol-vals)
|
||||
supported-chains-by-symbol (reduce
|
||||
(fn [result
|
||||
{token-symbol :symbol
|
||||
@@ -64,9 +63,10 @@
|
||||
(assoc result token-symbol #{chain-id})))
|
||||
{}
|
||||
by-symbol-vals)]
|
||||
|
||||
{:fx [[:effects.wallet.tokens/fetch-market-values
|
||||
{:symbols symbols
|
||||
:currency constants/profile-default-currency
|
||||
:currency profile-currency
|
||||
:on-success [:wallet.tokens/store-market-values]
|
||||
:on-error [:wallet.tokens/fetch-market-values-failed]}]
|
||||
[:effects.wallet.tokens/fetch-details
|
||||
@@ -75,7 +75,7 @@
|
||||
:on-error [:wallet.tokens/fetch-details-failed]}]
|
||||
[:effects.wallet.tokens/fetch-prices
|
||||
{:symbols symbols
|
||||
:currencies [constants/profile-default-currency]
|
||||
:currencies [constants/profile-default-currency profile-currency]
|
||||
:on-success [:wallet.tokens/store-prices]
|
||||
:on-error [:wallet.tokens/fetch-prices-failed]}]]
|
||||
:db (-> db
|
||||
@@ -116,7 +116,7 @@
|
||||
{}
|
||||
raw-data)]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :tokens :market-values-per-token] market-values)
|
||||
(update-in [:wallet :tokens :market-values-per-token] merge market-values)
|
||||
(assoc-in [:wallet :ui :loading :market-values] false))})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
@@ -146,7 +146,7 @@
|
||||
:wallet.tokens/store-prices
|
||||
(fn [{:keys [db]} [prices]]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :tokens :prices-per-token] prices)
|
||||
(update-in [:wallet :tokens :prices-per-token] merge prices)
|
||||
(assoc-in [:wallet :ui :loading :prices] false))}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[react-native.wallet-connect :as wallet-connect]
|
||||
[status-im.config :as config]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.sessions :as sessions]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.session :as session]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.signing :as signing]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.transactions :as transactions]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.typed-data :as typed-data]
|
||||
@@ -44,14 +44,14 @@
|
||||
(rf/reg-fx
|
||||
:effects.wallet-connect/disconnect
|
||||
(fn [{:keys [web3-wallet topic on-success on-fail]}]
|
||||
(-> (sessions/disconnect web3-wallet topic)
|
||||
(-> (session/disconnect web3-wallet topic)
|
||||
(promesa/then on-success)
|
||||
(promesa/catch on-fail))))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.wallet-connect/approve-session
|
||||
(fn [{:keys [web3-wallet proposal-request session-networks address on-success on-fail]}]
|
||||
(-> (sessions/approve
|
||||
(-> (session/approve
|
||||
{:web3-wallet web3-wallet
|
||||
:proposal-request proposal-request
|
||||
:address address
|
||||
@@ -145,6 +145,6 @@
|
||||
(rf/reg-fx
|
||||
:effects.wallet-connect/get-sessions
|
||||
(fn [{:keys [web3-wallet addresses online? on-success on-error]}]
|
||||
(-> (sessions/get-sessions web3-wallet addresses online?)
|
||||
(-> (session/get-sessions web3-wallet addresses online?)
|
||||
(promesa/then on-success)
|
||||
(promesa/catch on-error))))
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
(ns status-im.contexts.wallet.wallet-connect.events.session-proposals
|
||||
(:require [clojure.string :as string]
|
||||
[re-frame.core :as rf]
|
||||
[react-native.wallet-connect :as wallet-connect]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[status-im.contexts.wallet.common.utils.account :as account-utils]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.sessions :as sessions]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.proposal :as session-proposal]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.session :as sessions]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.uri :as uri]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]))
|
||||
@@ -23,37 +24,27 @@
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/on-scan-connection
|
||||
(fn [{:keys [db]} [scanned-text]]
|
||||
(let [network-status (:network/status db)
|
||||
parsed-uri (wallet-connect/parse-uri scanned-text)
|
||||
version (:version parsed-uri)
|
||||
valid-wc-uri? (uri/valid-wc-uri? parsed-uri)
|
||||
expired? (-> parsed-uri
|
||||
:expiryTimestamp
|
||||
uri/timestamp-expired?)
|
||||
version-supported? (uri/version-supported? version)]
|
||||
(if (or (not valid-wc-uri?)
|
||||
(not version-supported?)
|
||||
(= network-status :offline)
|
||||
expired?)
|
||||
(let [network-status (:network/status db)
|
||||
parsed-uri (uri/parse scanned-text)
|
||||
error-toast (cond
|
||||
(= network-status :offline)
|
||||
(i18n/label :t/wallet-connect-no-internet-warning)
|
||||
|
||||
(not (uri/valid? parsed-uri))
|
||||
(i18n/label :t/wallet-connect-wrong-qr)
|
||||
|
||||
(uri/expired? parsed-uri)
|
||||
(i18n/label :t/wallet-connect-qr-expired)
|
||||
|
||||
(not (uri/version-supported? parsed-uri))
|
||||
(i18n/label :t/wallet-connect-version-not-supported
|
||||
{:version (:version parsed-uri)}))]
|
||||
(if error-toast
|
||||
{:fx [[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :negative
|
||||
:theme :dark
|
||||
:text (cond (= network-status :offline)
|
||||
(i18n/label :t/wallet-connect-no-internet-warning)
|
||||
|
||||
(not valid-wc-uri?)
|
||||
(i18n/label :t/wallet-connect-wrong-qr)
|
||||
|
||||
expired?
|
||||
(i18n/label :t/wallet-connect-qr-expired)
|
||||
|
||||
(not version-supported?)
|
||||
(i18n/label :t/wallet-connect-version-not-supported
|
||||
{:version version})
|
||||
|
||||
:else
|
||||
(i18n/label :t/something-went-wrong))}]]]}
|
||||
:text error-toast}]]]}
|
||||
{:fx [[:dispatch [:wallet-connect/pair scanned-text]]]}))))
|
||||
|
||||
(rf/reg-event-fx
|
||||
@@ -63,11 +54,12 @@
|
||||
(let [accounts (get-in db [:wallet :accounts])
|
||||
current-viewing-address (get-in db [:wallet :current-viewing-account-address])
|
||||
sessions (get db :wallet-connect/sessions)
|
||||
available-accounts (sessions/filter-operable-accounts (vals accounts))
|
||||
available-accounts (-> accounts vals account-utils/filter-operable)
|
||||
latest-connected-account-address (sessions/latest-connected-account-address sessions)
|
||||
networks (networks/get-networks-by-mode db)
|
||||
session-networks (networks/proposal-networks-intersection proposal networks)
|
||||
required-networks-supported? (networks/required-networks-supported? proposal networks)]
|
||||
session-networks (session-proposal/networks-intersection proposal networks)
|
||||
required-networks-supported? (session-proposal/required-networks-supported? proposal
|
||||
networks)]
|
||||
(if (and (not-empty session-networks) required-networks-supported?)
|
||||
{:db (update db
|
||||
:wallet-connect/current-proposal assoc
|
||||
@@ -91,13 +83,12 @@
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/show-session-networks-unsupported-toast
|
||||
(fn [{:keys [db]} [proposal]]
|
||||
(let [{:keys [name url]} (data-store/get-session-dapp-metadata proposal)]
|
||||
{:fx [[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :negative
|
||||
:theme (:theme db)
|
||||
:text (i18n/label :t/wallet-connect-networks-not-supported
|
||||
{:dapp (data-store/compute-dapp-name name url)})}]]]})))
|
||||
{:fx [[:dispatch
|
||||
[:toasts/upsert
|
||||
{:type :negative
|
||||
:theme (:theme db)
|
||||
:text (i18n/label :t/wallet-connect-networks-not-supported
|
||||
{:dapp (session-proposal/dapp-name proposal)})}]]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/reset-current-session-proposal
|
||||
@@ -118,13 +109,10 @@
|
||||
(map networks/chain-id->eip155)
|
||||
vec)
|
||||
current-address (get-in db [:wallet-connect/current-proposal :address])
|
||||
network-status (:network/status db)
|
||||
expired? (-> current-proposal
|
||||
(get-in [:params :expiryTimestamp])
|
||||
uri/timestamp-expired?)]
|
||||
network-status (:network/status db)]
|
||||
(if (= network-status :online)
|
||||
{:db (assoc-in db [:wallet-connect/current-proposal :response-sent?] true)
|
||||
:fx [(if expired?
|
||||
:fx [(if (session-proposal/expired? current-proposal)
|
||||
[:dispatch
|
||||
[:toasts/upsert
|
||||
{:id :wallet-connect-proposal-expired
|
||||
@@ -173,11 +161,9 @@
|
||||
(fn [{:keys [db]} [proposal]]
|
||||
(let [web3-wallet (get db :wallet-connect/web3-wallet)
|
||||
{:keys [request response-sent?]} (:wallet-connect/current-proposal db)
|
||||
networks (networks/get-proposal-networks (or proposal request))
|
||||
rejected? (nil? proposal)
|
||||
dapp-name (-> (data-store/get-session-dapp-metadata (or proposal
|
||||
request))
|
||||
:name)]
|
||||
networks (session-proposal/networks (or proposal request))
|
||||
dapp-name (session-proposal/dapp-name (or proposal request))
|
||||
rejected? (nil? proposal)]
|
||||
{:fx (concat
|
||||
(when-not response-sent?
|
||||
[[:effects.wallet-connect/reject-session-proposal
|
||||
|
||||
@@ -6,29 +6,32 @@
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.request :as session-request]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.transactions :as transactions]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.typed-data :as typed-data]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.transforms :as transforms]))
|
||||
[utils.transforms :as transforms]
|
||||
[cljs.pprint :as pprint]))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/show-request-modal
|
||||
(fn [{:keys [db]}]
|
||||
(let [event (get-in db [:wallet-connect/current-request :event])
|
||||
method (data-store/get-request-method event)
|
||||
screen (data-store/method-to-screen method)]
|
||||
(let [screen (-> db
|
||||
data-store/get-db-current-request-event
|
||||
session-request/screen)]
|
||||
(if screen
|
||||
{:fx [[:dispatch [:open-modal screen]]]}
|
||||
(log/error "Didn't find screen for Wallet Connect method"
|
||||
{:method method
|
||||
:event :wallet-connect/process-session-request})))))
|
||||
{:event :wallet-connect/process-session-request})))))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/process-session-request
|
||||
(fn [{:keys [db]} [event]]
|
||||
(let [method (data-store/get-request-method event)
|
||||
existing-event (get-in db [:wallet-connect/current-request :event])]
|
||||
(pprint/pprint event)
|
||||
(let [method (session-request/method event)
|
||||
existing-event (data-store/get-db-current-request-event db)]
|
||||
(log/info "Processing Wallet Connect session request" method)
|
||||
;; NOTE: make sure we don't show two requests at the same time
|
||||
(when-not existing-event
|
||||
@@ -95,17 +98,14 @@
|
||||
:address address
|
||||
:raw-data prepared-tx
|
||||
:transaction tx
|
||||
:chain-id chain-id
|
||||
:display-data display-data)})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/process-eth-send-transaction
|
||||
(fn [{:keys [db]} [{:keys [on-success]}]]
|
||||
(let [event (data-store/get-db-current-request-event db)
|
||||
tx (-> event data-store/get-request-params first)
|
||||
chain-id (-> event
|
||||
(get-in [:params :chainId])
|
||||
networks/eip155->chain-id)]
|
||||
tx (-> event session-request/params first)
|
||||
chain-id (session-request/chain event)]
|
||||
(when tx
|
||||
{:fx [[:effects.wallet-connect/prepare-transaction
|
||||
{:tx tx
|
||||
@@ -120,10 +120,8 @@
|
||||
:wallet-connect/process-eth-sign-transaction
|
||||
(fn [{:keys [db]}]
|
||||
(let [event (data-store/get-db-current-request-event db)
|
||||
tx (-> event data-store/get-request-params first)
|
||||
chain-id (-> event
|
||||
(get-in [:params :chainId])
|
||||
networks/eip155->chain-id)]
|
||||
tx (-> event session-request/params first)
|
||||
chain-id (session-request/chain event)]
|
||||
{:fx [[:effects.wallet-connect/prepare-transaction
|
||||
{:tx tx
|
||||
:chain-id chain-id
|
||||
@@ -135,9 +133,9 @@
|
||||
(fn [{:keys [db]}]
|
||||
(try
|
||||
(let [[address raw-data] (data-store/get-db-current-request-params db)
|
||||
session-chain-id (-> (data-store/get-db-current-request-event db)
|
||||
(get-in [:params :chainId])
|
||||
networks/eip155->chain-id)
|
||||
session-chain-id (-> db
|
||||
data-store/get-db-current-request-event
|
||||
session-request/chain)
|
||||
typed-data (-> raw-data
|
||||
transforms/js-parse
|
||||
transforms/js->clj)
|
||||
@@ -189,11 +187,10 @@
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/on-processing-error
|
||||
(fn [{:keys [db]} [error]]
|
||||
(let [{:keys [address event]} (get db :wallet-connect/current-request)
|
||||
method (data-store/get-request-method event)]
|
||||
(let [event (data-store/get-db-current-request-event db)
|
||||
method (session-request/method event)]
|
||||
(log/error "Failed to process Wallet Connect request"
|
||||
{:error error
|
||||
:address address
|
||||
:method method
|
||||
:wallet-connect-event event
|
||||
:event :wallet-connect/on-processing-error})
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
(:require [re-frame.core :as rf]
|
||||
[react-native.wallet-connect :as wallet-connect]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.uri :as uri]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.request :as session-request]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.transforms :as transforms]))
|
||||
@@ -12,18 +11,15 @@
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/respond-current-session
|
||||
(fn [{:keys [db]} [password]]
|
||||
(let [event (get-in db [:wallet-connect/current-request :event])
|
||||
method (data-store/get-request-method event)
|
||||
screen (data-store/method-to-screen method)
|
||||
expiry (get-in event [:params :request :expiryTimestamp])]
|
||||
(if (uri/timestamp-expired? expiry)
|
||||
(let [event (data-store/get-db-current-request-event db)]
|
||||
(if (session-request/expired? event)
|
||||
{:fx [[:dispatch
|
||||
[:toasts/upsert
|
||||
{:id :new-wallet-account-created
|
||||
:type :negative
|
||||
:text (i18n/label :t/wallet-connect-request-expired)}]]
|
||||
[:dispatch [:dismiss-modal screen]]]}
|
||||
{:fx [(condp = method
|
||||
[:dispatch [:dismiss-modal (session-request/screen event)]]]}
|
||||
{:fx [(condp = (session-request/method event)
|
||||
constants/wallet-connect-personal-sign-method
|
||||
[:dispatch [:wallet-connect/respond-sign-message password :personal-sign]]
|
||||
|
||||
@@ -58,7 +54,7 @@
|
||||
:wallet-connect/respond-sign-typed-data
|
||||
(fn [{:keys [db]} [password typed-data-version]]
|
||||
(let [{:keys [address raw-data event]} (get db :wallet-connect/current-request)
|
||||
chain-id (get-in event [:params :chainId])]
|
||||
chain-id (session-request/chain event)]
|
||||
{:fx [[:effects.wallet-connect/sign-typed-data
|
||||
{:password password
|
||||
:address address
|
||||
@@ -71,8 +67,9 @@
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/respond-send-transaction-data
|
||||
(fn [{:keys [db]} [password]]
|
||||
(let [{:keys [chain-id raw-data address]} (get db :wallet-connect/current-request)
|
||||
{:keys [tx-hash tx-args]} raw-data]
|
||||
(let [{:keys [raw-data address event]} (get db :wallet-connect/current-request)
|
||||
{:keys [tx-hash tx-args]} raw-data
|
||||
chain-id (session-request/chain event)]
|
||||
{:fx [[:effects.wallet-connect/send-transaction
|
||||
{:password password
|
||||
:address address
|
||||
@@ -100,7 +97,7 @@
|
||||
:wallet-connect/on-sign-error
|
||||
(fn [{:keys [db]} [error]]
|
||||
(let [{:keys [raw-data address event]} (get db :wallet-connect/current-request)
|
||||
method (data-store/get-request-method event)]
|
||||
method (session-request/method event)]
|
||||
(log/error "Failed to sign Wallet Connect request"
|
||||
{:error error
|
||||
:address address
|
||||
@@ -118,8 +115,8 @@
|
||||
:wallet-connect/send-response
|
||||
(fn [{:keys [db]} [{:keys [request result error]}]]
|
||||
(when-let [{:keys [id topic] :as event} (or request
|
||||
(get-in db [:wallet-connect/current-request :event]))]
|
||||
(let [method (data-store/get-request-method event)
|
||||
(data-store/get-db-current-request-event db))]
|
||||
(let [method (session-request/method event)
|
||||
web3-wallet (get db :wallet-connect/web3-wallet)]
|
||||
{:db (assoc-in db [:wallet-connect/current-request :response-sent?] true)
|
||||
:fx [[:effects.wallet-connect/respond-session-request
|
||||
@@ -141,13 +138,14 @@
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/redirect-to-dapp
|
||||
(fn [{:keys [db]} [url]]
|
||||
(let [redirect-url (or url
|
||||
(->> (get db :wallet-connect/current-request)
|
||||
(data-store/get-current-request-dapp
|
||||
(get db :wallet-connect/sessions))
|
||||
:sessionJson
|
||||
transforms/json->clj
|
||||
data-store/get-dapp-redirect-url))]
|
||||
(let [sessions (get db :wallet-connect/sessions)
|
||||
redirect-url (or url
|
||||
(-> db
|
||||
data-store/get-db-current-request-event
|
||||
(data-store/get-current-request-dapp sessions)
|
||||
:sessionJson
|
||||
transforms/json->clj
|
||||
data-store/get-dapp-redirect-url))]
|
||||
{:fx [[:effects/open-url redirect-url]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
@@ -155,15 +153,14 @@
|
||||
(fn [{:keys [db]} _]
|
||||
(let [screen (-> db
|
||||
(get-in [:wallet-connect/current-request :event])
|
||||
data-store/get-request-method
|
||||
data-store/method-to-screen)]
|
||||
session-request/screen)]
|
||||
{:fx [[:dispatch [:dismiss-modal screen]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/finish-session-request
|
||||
(fn [{:keys [db]} [result]]
|
||||
(let [event (get-in db [:wallet-connect/current-request :event])
|
||||
method (data-store/get-request-method event)
|
||||
method (session-request/method event)
|
||||
toast-text (condp contains? method
|
||||
constants/wallet-connect-message-signing-methods
|
||||
(i18n/label :t/wallet-connect-message-request-success-toast)
|
||||
@@ -192,11 +189,11 @@
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/on-request-modal-dismissed
|
||||
(fn [{:keys [db]}]
|
||||
(let [{:keys [response-sent? event] :as request} (get db :wallet-connect/current-request)
|
||||
method (data-store/get-request-method event)
|
||||
dapp (->> (get db :wallet-connect/sessions)
|
||||
(data-store/get-current-request-dapp request)
|
||||
:name)]
|
||||
(let [{:keys [response-sent? event]} (get db :wallet-connect/current-request)
|
||||
method (session-request/method event)
|
||||
dapp (->> (get db :wallet-connect/sessions)
|
||||
(data-store/get-current-request-dapp event)
|
||||
:name)]
|
||||
{:fx (concat
|
||||
(when-not response-sent?
|
||||
[[:dispatch
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.sessions :as sessions]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.session :as session-utils]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]))
|
||||
[utils.i18n :as i18n]
|
||||
[status-im.contexts.wallet.common.utils.account :as account-utils]))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/on-session-delete
|
||||
@@ -58,7 +59,7 @@
|
||||
(fn [{:keys [db]}]
|
||||
(let [addresses (->> (get-in db [:wallet :accounts])
|
||||
vals
|
||||
sessions/filter-operable-accounts
|
||||
account-utils/filter-operable
|
||||
(map :address))]
|
||||
(if (not (seq addresses))
|
||||
;; NOTE: Re-trying to get active sessions if accounts weren't loaded yet during
|
||||
@@ -94,7 +95,7 @@
|
||||
:wallet-connect/sessions
|
||||
(fn [sessions]
|
||||
(->> new-session
|
||||
sessions/sdk-session->db-session
|
||||
session-utils/session->db
|
||||
(conj sessions))))}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
|
||||
@@ -3,14 +3,13 @@
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.contexts.wallet.wallet-connect.modals.common.header.style :as style]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]))
|
||||
[status-im.contexts.wallet.wallet-connect.utils.dapp :as dapp-utils]))
|
||||
|
||||
(defn view
|
||||
[{:keys [label dapp account]}]
|
||||
[rn/view {:style style/header-container}
|
||||
(let [{:keys [name iconUrl url]} dapp
|
||||
image-source (data-store/compute-dapp-icon-path iconUrl url)]
|
||||
image-source (dapp-utils/compute-icon iconUrl url)]
|
||||
[rn/view {:style style/dapp-container}
|
||||
[quo/summary-tag
|
||||
{:type :dapp
|
||||
|
||||
@@ -7,22 +7,19 @@
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.floating-button-page.view :as floating-button-page]
|
||||
[status-im.contexts.wallet.wallet-connect.modals.session-proposal.style :as style]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as data-store]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.string]))
|
||||
|
||||
(defn- dapp-metadata
|
||||
[]
|
||||
(let [proposer (rf/sub [:wallet-connect/session-proposer])
|
||||
{:keys [icons name url]} (:metadata proposer)
|
||||
first-icon (first icons)
|
||||
dapp-name (data-store/compute-dapp-name name url)
|
||||
profile-picture (data-store/compute-dapp-icon-path first-icon url)]
|
||||
(let [dapp-name (rf/sub [:wallet-connect/session-proposer-name])
|
||||
dapp-icon (rf/sub [:wallet-connect/session-proposer-icon])
|
||||
dapp-url (rf/sub [:wallet-connect/session-proposer-url])]
|
||||
[:<>
|
||||
[rn/view {:style style/dapp-avatar}
|
||||
[quo/user-avatar
|
||||
{:profile-picture profile-picture
|
||||
{:profile-picture dapp-icon
|
||||
:size :big
|
||||
:full-name dapp-name}]]
|
||||
[quo/page-top
|
||||
@@ -31,7 +28,7 @@
|
||||
:context-tag {:type :icon
|
||||
:size 32
|
||||
:icon :i/link
|
||||
:context url}}]]))
|
||||
:context dapp-url}}]]))
|
||||
|
||||
(defn- approval-note
|
||||
[]
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
(ns status-im.contexts.wallet.wallet-connect.utils.dapp
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
utils.string))
|
||||
|
||||
(defn compute-name
|
||||
"Sometimes dapps have no name or an empty name. Return url as name in that case"
|
||||
[name url]
|
||||
(if (seq name)
|
||||
name
|
||||
(when (seq url)
|
||||
(-> url
|
||||
utils.string/remove-trailing-slash
|
||||
utils.string/remove-http-prefix
|
||||
string/capitalize))))
|
||||
|
||||
(defn compute-icon
|
||||
"Some dapps have icons with relative paths, make paths absolute in those cases, send nil if icon is missing"
|
||||
[icon-path url]
|
||||
(when (and (seq icon-path)
|
||||
(seq url))
|
||||
(if (string/starts-with? icon-path "http")
|
||||
icon-path
|
||||
(str (utils.string/remove-trailing-slash url) icon-path))))
|
||||
|
||||
(defn best-icon
|
||||
"Find the icon format from the provided list that can be rendered (prefer images)"
|
||||
[icons]
|
||||
(let [image-extensions [".png" ".jpg" ".jpeg"]
|
||||
image? (fn [icon]
|
||||
(some #(string/ends-with? icon %) image-extensions))]
|
||||
(or (first (filter image? icons))
|
||||
(first icons))))
|
||||
@@ -1,65 +1,22 @@
|
||||
(ns status-im.contexts.wallet.wallet-connect.utils.data-store
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils :as wallet-utils]
|
||||
[status-im.contexts.wallet.common.utils.networks :as network-utils]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.request :as session-request]
|
||||
utils.string
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(defn compute-dapp-name
|
||||
"Sometimes dapps have no name or an empty name. Return url as name in that case"
|
||||
[name url]
|
||||
(if (seq name)
|
||||
name
|
||||
(when (seq url)
|
||||
(-> url
|
||||
utils.string/remove-trailing-slash
|
||||
utils.string/remove-http-prefix
|
||||
string/capitalize))))
|
||||
|
||||
(defn compute-dapp-icon-path
|
||||
"Some dapps have icons with relative paths, make paths absolute in those cases, send nil if icon is missing"
|
||||
[icon-path url]
|
||||
(when (and (seq icon-path)
|
||||
(seq url))
|
||||
(if (string/starts-with? icon-path "http")
|
||||
icon-path
|
||||
(str (utils.string/remove-trailing-slash url) icon-path))))
|
||||
|
||||
(def method-to-screen
|
||||
{constants/wallet-connect-personal-sign-method :screen/wallet-connect.sign-message
|
||||
constants/wallet-connect-eth-sign-typed-method :screen/wallet-connect.sign-message
|
||||
constants/wallet-connect-eth-sign-method :screen/wallet-connect.sign-message
|
||||
constants/wallet-connect-eth-sign-typed-v4-method :screen/wallet-connect.sign-message
|
||||
constants/wallet-connect-eth-send-transaction-method :screen/wallet-connect.send-transaction
|
||||
constants/wallet-connect-eth-sign-transaction-method :screen/wallet-connect.sign-transaction})
|
||||
|
||||
(defn extract-native-call-signature
|
||||
[data]
|
||||
(-> data transforms/json->clj :result))
|
||||
|
||||
(defn get-request-method
|
||||
[event]
|
||||
(get-in event [:params :request :method]))
|
||||
|
||||
(defn get-request-params
|
||||
[event]
|
||||
(get-in event [:params :request :params]))
|
||||
|
||||
(defn get-db-current-request-event
|
||||
[db]
|
||||
(get-in db [:wallet-connect/current-request :event]))
|
||||
|
||||
(defn get-session-dapp-metadata
|
||||
[proposal]
|
||||
(let [metadata (get-in proposal [:params :proposer :metadata])
|
||||
origin (get-in proposal [:verifyContext :verified :origin])]
|
||||
(or metadata {:url origin})))
|
||||
|
||||
(defn get-current-request-dapp
|
||||
[request sessions]
|
||||
(let [dapp-url (get-in request [:event :verifyContext :verified :origin])]
|
||||
[event sessions]
|
||||
(let [dapp-url (session-request/url event)]
|
||||
(->> sessions
|
||||
(filter (fn [session]
|
||||
(= (utils.string/remove-trailing-slash dapp-url)
|
||||
@@ -78,7 +35,7 @@
|
||||
[db]
|
||||
(-> db
|
||||
get-db-current-request-event
|
||||
get-request-params))
|
||||
session-request/params))
|
||||
|
||||
(defn get-total-connected-dapps
|
||||
[db]
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
|
||||
(deftest get-current-request-dapp-test
|
||||
(testing "returns the correct dapp based on the request's origin"
|
||||
(let [request {:event {:verifyContext {:verified {:origin "https://dapp.com"}}}}
|
||||
(let [request {:verifyContext {:verified {:origin "https://dapp.com"}}}
|
||||
sessions [{:url "https://dapp.com"}
|
||||
{:url "https://anotherdapp.com"}]]
|
||||
(is (= {:url "https://dapp.com"}
|
||||
(sut/get-current-request-dapp request sessions)))))
|
||||
|
||||
(testing "returns nil if no matching dapp is found"
|
||||
(let [request {:event {:verifyContext {:verified {:origin "https://dapp.com"}}}}
|
||||
(let [request {:verifyContext {:verified {:origin "https://dapp.com"}}}
|
||||
sessions [{:url "https://anotherdapp.com"}]]
|
||||
(is (nil? (sut/get-current-request-dapp request sessions))))))
|
||||
|
||||
|
||||
@@ -17,10 +17,6 @@
|
||||
last
|
||||
edn/read-string))
|
||||
|
||||
(defn format-eip155-address
|
||||
[address chain-id]
|
||||
(str chain-id ":" address))
|
||||
|
||||
(defn- add-full-testnet-name
|
||||
"Updates the `:full-name` key with the full testnet name if using testnet `:chain-id`.\n
|
||||
e.g. `{:full-name \"Mainnet\"}` -> `{:full-name \"Mainnet Sepolia\"`}`"
|
||||
@@ -49,33 +45,19 @@
|
||||
(set/subset? chain-ids constants/sepolia-chain-ids)
|
||||
(set/subset? chain-ids constants/mainnet-chain-ids))))
|
||||
|
||||
(defn get-proposal-networks
|
||||
[proposal]
|
||||
(let [required-namespaces (get-in proposal [:params :requiredNamespaces])
|
||||
optional-namespaces (get-in proposal [:params :optionalNamespaces])]
|
||||
(->> [required-namespaces optional-namespaces]
|
||||
(map #(get-in % [:eip155 :chains]))
|
||||
(apply concat)
|
||||
(into #{}))))
|
||||
|
||||
(defn proposal-networks-intersection
|
||||
[proposal supported-networks]
|
||||
(let [proposed-networks (get-proposal-networks proposal)]
|
||||
(->> supported-networks
|
||||
(filter #(->> %
|
||||
chain-id->eip155
|
||||
(contains? proposed-networks))))))
|
||||
(defn networks-intersection
|
||||
[proposed-networks supported-networks]
|
||||
(->> supported-networks
|
||||
(filter #(->> %
|
||||
chain-id->eip155
|
||||
(contains? proposed-networks)))))
|
||||
|
||||
(defn required-networks-supported?
|
||||
[proposal supported-networks]
|
||||
(let [supported-namespaces #{:eip155}
|
||||
required-namespaces (get-in proposal [:params :requiredNamespaces])]
|
||||
(when (every? #(contains? supported-namespaces %)
|
||||
(keys required-namespaces))
|
||||
(let [required-networks (get-in required-namespaces [:eip155 :chains])
|
||||
supported-eip155 (set (map chain-id->eip155 supported-networks))]
|
||||
(every? #(contains? supported-eip155 %)
|
||||
required-networks)))))
|
||||
[required-networks supported-networks]
|
||||
(every? #(-> (map chain-id->eip155 supported-networks)
|
||||
set
|
||||
(contains? %))
|
||||
required-networks))
|
||||
|
||||
(defn get-networks-by-mode
|
||||
[db]
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
(ns status-im.contexts.wallet.wallet-connect.utils.proposal
|
||||
(:require [clojure.string :as string]
|
||||
[schema.core :as schema]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.dapp :as dapp-utils]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks-utils]
|
||||
[utils.datetime :as datetime]))
|
||||
|
||||
(def ^:private ?proposer-metadata
|
||||
[:map
|
||||
[:name {:optional true} :string]
|
||||
[:url {:optional true} :string]
|
||||
[:description {:optional true} :string]
|
||||
[:icons {:optional true} [:sequential :string]]])
|
||||
|
||||
(def ^:private ?namespace
|
||||
[:map
|
||||
[:methods [:sequential :string]]
|
||||
[:chains [:sequential :string]]
|
||||
[:events [:sequential :string]]])
|
||||
|
||||
(def ^:private ?proposal
|
||||
[:map
|
||||
[:id :int]
|
||||
[:verifyContext
|
||||
[:map
|
||||
[:verified
|
||||
[:map
|
||||
[:validation :string]
|
||||
[:origin :string]
|
||||
[:verifyUrl :string]
|
||||
[:isScam {:optional true} :boolean]]]]]
|
||||
[:params
|
||||
[:map
|
||||
[:id :int]
|
||||
[:expiryTimestamp :int]
|
||||
[:pairingTopic :string]
|
||||
[:requiredNamespaces [:map-of :keyword ?namespace]]
|
||||
[:optionalNamespaces [:map-of :keyword ?namespace]]
|
||||
[:relays [:sequential :any]]
|
||||
[:proposer
|
||||
[:map
|
||||
[:publicKey :string]
|
||||
[:metadata ?proposer-metadata]]]]]])
|
||||
|
||||
(defn expired?
|
||||
[proposal]
|
||||
(some-> proposal
|
||||
:params
|
||||
:expiryTimestamp
|
||||
datetime/timestamp-expired?))
|
||||
|
||||
(schema/=> expired?
|
||||
[:=>
|
||||
[:cat ?proposal]
|
||||
:boolean])
|
||||
|
||||
(defn dapp-metadata
|
||||
[proposal]
|
||||
(let [metadata (get-in proposal [:params :proposer :metadata])
|
||||
origin (get-in proposal [:verifyContext :verified :origin])]
|
||||
(or metadata {:url origin})))
|
||||
|
||||
(schema/=> dapp-metadata
|
||||
[:=>
|
||||
[:cat ?proposal]
|
||||
?proposer-metadata])
|
||||
|
||||
(defn dapp-name
|
||||
[proposal]
|
||||
(let [{:keys [name url]} (-> proposal dapp-metadata)]
|
||||
(dapp-utils/compute-name name url)))
|
||||
|
||||
(schema/=> dapp-name
|
||||
[:=>
|
||||
[:cat ?proposal]
|
||||
[:maybe :string]])
|
||||
|
||||
(defn dapp-icon
|
||||
[proposal]
|
||||
(let [{:keys [icons url]} (-> proposal dapp-metadata)
|
||||
icon (dapp-utils/best-icon icons)]
|
||||
(dapp-utils/compute-icon icon url)))
|
||||
|
||||
(schema/=> dapp-icon
|
||||
[:=>
|
||||
[:cat ?proposal]
|
||||
[:maybe :string]])
|
||||
|
||||
(defn dapp-url
|
||||
[proposal]
|
||||
(-> proposal dapp-metadata :url))
|
||||
|
||||
(schema/=> dapp-url
|
||||
[:=>
|
||||
[:cat ?proposal]
|
||||
[:maybe :string]])
|
||||
|
||||
(defn networks
|
||||
[proposal]
|
||||
(let [required-namespaces (get-in proposal [:params :requiredNamespaces])
|
||||
optional-namespaces (get-in proposal [:params :optionalNamespaces])]
|
||||
(->> [required-namespaces optional-namespaces]
|
||||
(map #(get-in % [:eip155 :chains]))
|
||||
(apply concat)
|
||||
(into #{}))))
|
||||
|
||||
(schema/=> networks
|
||||
[:=>
|
||||
[:cat ?proposal]
|
||||
[:set :string]])
|
||||
|
||||
(defn networks-intersection
|
||||
[proposal supported-networks]
|
||||
(let [proposed-networks (networks proposal)]
|
||||
(networks-utils/networks-intersection proposed-networks
|
||||
supported-networks)))
|
||||
|
||||
(schema/=> networks-intersection
|
||||
[:=>
|
||||
[:cat ?proposal [:sequential :int]]
|
||||
[:sequential :int]])
|
||||
|
||||
(defn required-networks-supported?
|
||||
[proposal supported-networks]
|
||||
(let [supported-namespaces #{:eip155}
|
||||
required-namespaces (get-in proposal [:params :requiredNamespaces])
|
||||
required-networks (get-in required-namespaces [:eip155 :chains])]
|
||||
(when (every? #(contains? supported-namespaces %)
|
||||
(keys required-namespaces))
|
||||
(networks-utils/required-networks-supported? required-networks supported-networks))))
|
||||
|
||||
(schema/=> required-networks-supported?
|
||||
[:=>
|
||||
[:cat ?proposal [:sequential :int]]
|
||||
:boolean])
|
||||
@@ -0,0 +1,87 @@
|
||||
(ns status-im.contexts.wallet.wallet-connect.utils.request
|
||||
(:require
|
||||
[schema.core :as schema]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
|
||||
[utils.datetime :as datetime]))
|
||||
|
||||
(def ^:private ?event
|
||||
[:map
|
||||
[:id :string]
|
||||
[:params
|
||||
[:map
|
||||
[:chainId :string]
|
||||
[:request
|
||||
[:map
|
||||
[:method :string]
|
||||
[:params :any]
|
||||
[:expiryTimestamp :int]]]]]
|
||||
[:verifyContext
|
||||
[:map
|
||||
[:verified
|
||||
[:map
|
||||
[:validation :string]
|
||||
[:origin :string]
|
||||
[:verifyUrl :string]
|
||||
[:isScam {:optional true} :boolean]]]]]])
|
||||
|
||||
(defn expired?
|
||||
[event]
|
||||
(some-> event
|
||||
:params
|
||||
:request
|
||||
:expiryTimestamp
|
||||
datetime/timestamp-expired?))
|
||||
|
||||
(schema/=> expired?
|
||||
[:=> [:cat ?event]
|
||||
[:maybe :boolean]])
|
||||
|
||||
(defn method
|
||||
[event]
|
||||
(get-in event [:params :request :method]))
|
||||
|
||||
(schema/=> method
|
||||
[:=> [:cat ?event]
|
||||
:string])
|
||||
|
||||
(defn chain
|
||||
[event]
|
||||
(-> event
|
||||
(get-in [:params :chainId])
|
||||
networks/eip155->chain-id))
|
||||
|
||||
(schema/=> chain
|
||||
[:=> [:cat ?event]
|
||||
:int])
|
||||
|
||||
(defn screen
|
||||
[event]
|
||||
(let [method-to-screen
|
||||
{constants/wallet-connect-personal-sign-method :screen/wallet-connect.sign-message
|
||||
constants/wallet-connect-eth-sign-typed-method :screen/wallet-connect.sign-message
|
||||
constants/wallet-connect-eth-sign-method :screen/wallet-connect.sign-message
|
||||
constants/wallet-connect-eth-sign-typed-v4-method :screen/wallet-connect.sign-message
|
||||
constants/wallet-connect-eth-send-transaction-method :screen/wallet-connect.send-transaction
|
||||
constants/wallet-connect-eth-sign-transaction-method :screen/wallet-connect.sign-transaction}]
|
||||
(-> event method method-to-screen)))
|
||||
|
||||
(schema/=> screen
|
||||
[:=> [:cat ?event]
|
||||
[:maybe :keyword]])
|
||||
|
||||
(defn params
|
||||
[event]
|
||||
(get-in event [:params :request :params]))
|
||||
|
||||
(schema/=> screen
|
||||
[:=> [:cat ?event]
|
||||
:any])
|
||||
|
||||
(defn url
|
||||
[event]
|
||||
(get-in event [:verifyContext :verified :origin]))
|
||||
|
||||
(schema/=> screen
|
||||
[:=> [:cat ?event]
|
||||
:string])
|
||||
@@ -1,63 +1,8 @@
|
||||
(ns status-im.contexts.wallet.wallet-connect.utils.rpc
|
||||
(:require [oops.core :as oops]
|
||||
[promesa.core :as promesa]
|
||||
(:require [promesa.core :as promesa]
|
||||
[status-im.common.json-rpc.events :as rpc-events]
|
||||
[status-im.constants :as constants]
|
||||
[utils.hex :as hex]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(defn wallet-build-transaction
|
||||
[chain-id tx]
|
||||
(promesa/let [res (rpc-events/call-async :wallet_buildTransaction true chain-id tx)]
|
||||
{:message-to-sign (oops/oget res :messageToSign)
|
||||
:tx-args (oops/oget res :txArgs)}))
|
||||
|
||||
(defn wallet-build-raw-transaction
|
||||
[chain-id tx-args signature]
|
||||
(-> (rpc-events/call-async "wallet_buildRawTransaction"
|
||||
true
|
||||
chain-id
|
||||
(transforms/js-stringify tx-args 0)
|
||||
signature)
|
||||
(promesa/then #(oops/oget % "rawTx"))))
|
||||
|
||||
(defn wallet-send-transaction-with-signature
|
||||
[chain-id tx-args signature]
|
||||
(rpc-events/call-async "wallet_sendTransactionWithSignature"
|
||||
true
|
||||
chain-id
|
||||
constants/transaction-pending-type-wallet-connect-transfer
|
||||
(transforms/js-stringify tx-args 0)
|
||||
signature))
|
||||
|
||||
(defn wallet-sign-message
|
||||
[message address password]
|
||||
(-> (rpc-events/call-async "wallet_signMessage"
|
||||
true
|
||||
message
|
||||
address
|
||||
password)
|
||||
(promesa/then hex/normalize-hex)))
|
||||
|
||||
(defn wallet-hash-message-eip-191
|
||||
[message]
|
||||
(rpc-events/call-async "wallet_hashMessageEIP191" true message))
|
||||
|
||||
(defn wallet-safe-sign-typed-data
|
||||
[data address password chain-id legacy?]
|
||||
(rpc-events/call-async "wallet_safeSignTypedDataForDApps"
|
||||
true
|
||||
data
|
||||
address
|
||||
password
|
||||
chain-id
|
||||
legacy?))
|
||||
|
||||
(defn wallet-get-suggested-fees
|
||||
[chain-id]
|
||||
(-> (rpc-events/call-async "wallet_getSuggestedFees" true chain-id)
|
||||
(promesa/then transforms/js->clj)))
|
||||
|
||||
(defn wallet-disconnect-persisted-session
|
||||
[topic]
|
||||
(rpc-events/call-async "wallet_disconnectWalletConnectSession" true topic))
|
||||
|
||||