Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f49383db8e |
@@ -35,4 +35,4 @@ TEST_NETWORKS_ENABLED=1
|
||||
SHOW_NOT_IMPLEMENTED_FEATURES=0
|
||||
ENABLE_ALERT_BANNER=0
|
||||
FLAG_WALLET_CONNECT_ENABLED=1
|
||||
API_LOGGING_ENABLED=1
|
||||
LOG_REQUEST_GO=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
|
||||
API_LOGGING_ENABLED=1
|
||||
LOG_REQUEST_GO=1
|
||||
|
||||
@@ -36,4 +36,4 @@ FAST_CREATE_COMMUNITY_ENABLED=1
|
||||
TEST_NETWORKS_ENABLED=1
|
||||
ENABLE_ALERT_BANNER=1
|
||||
FLAG_WALLET_CONNECT_ENABLED=1
|
||||
API_LOGGING_ENABLED=1
|
||||
LOG_REQUEST_GO=1
|
||||
|
||||
@@ -23,4 +23,4 @@ FAST_CREATE_COMMUNITY_ENABLED=0
|
||||
TEST_NETWORKS_ENABLED=0
|
||||
ENABLE_ALERT_BANNER=1
|
||||
FLAG_WALLET_CONNECT_ENABLED=1
|
||||
API_LOGGING_ENABLED=0
|
||||
LOG_REQUEST_GO=0
|
||||
|
||||
@@ -20,4 +20,4 @@ FAST_CREATE_COMMUNITY_ENABLED=0
|
||||
TEST_NETWORKS_ENABLED=0
|
||||
STATUS_PROXY_STAGE_NAME=prod
|
||||
FLAG_WALLET_CONNECT_ENABLED=1
|
||||
API_LOGGING_ENABLED=0
|
||||
LOG_REQUEST_GO=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(api.log/geth.log) and keystore files etc will be stored in this directory.
|
||||
All the db files and log files(requests.log/geth.log) and keystore files etc will be stored in this directory.
|
||||
|
||||
### Start the status backend server:
|
||||
```shell
|
||||
|
||||
@@ -248,14 +248,10 @@ 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",
|
||||
jsonString,
|
||||
{ Statusgo.initializeApplication(jsonString) },
|
||||
request,
|
||||
{ Statusgo.initializeApplication(request) },
|
||||
callback
|
||||
)
|
||||
}
|
||||
|
||||
@@ -195,6 +195,25 @@ 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
|
||||
@@ -204,7 +223,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 = "api.log"
|
||||
private const val requestsLogFileName = "requests.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:@"api.log"];
|
||||
NSURL *requestsLogFile = [rootUrl URLByAppendingPathComponent:@"requests.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:@"api.log"].path error:nil];
|
||||
[fileManager copyItemAtPath:requestsLogFile.path toPath:[logsFolderName URLByAppendingPathComponent:@"requests.log"].path error:nil];
|
||||
}
|
||||
|
||||
[SSZipArchive createZipFileAtPath:zipFile.path withContentsOfDirectory:logsFolderName.path];
|
||||
@@ -53,6 +53,43 @@ 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,6 +1946,35 @@ 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();
|
||||
@@ -2035,6 +2064,7 @@ 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: 6.8 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 91 KiB |
@@ -2,9 +2,7 @@
|
||||
(: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
|
||||
@@ -256,19 +254,17 @@
|
||||
(catch on-failure))))
|
||||
|
||||
(defn sign
|
||||
[{: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])
|
||||
[{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)))))
|
||||
|
||||
(defn sign-typed-data
|
||||
[{card-hash :hash on-success :on-success on-failure :on-failure}]
|
||||
|
||||
@@ -18,23 +18,25 @@
|
||||
clock-value
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000"))
|
||||
|
||||
(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 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/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 chat-preview-type]}]
|
||||
(fn [{:keys [on-success]}]
|
||||
(json-rpc/call {:method "wakuext_chatsPreview"
|
||||
:params [chat-preview-type]
|
||||
:params []
|
||||
:js-response true
|
||||
:on-success #(on-success ^js %)
|
||||
:on-error #(log/error "failed to fetch chats" 0 -1 %)})))
|
||||
|
||||
@@ -135,6 +135,7 @@
|
||||
:chat/cooldowns
|
||||
:chat/last-outgoing-message-sent-at
|
||||
:chat/spam-messages-frequency
|
||||
:chats/loading?
|
||||
:dimensions/window]))]
|
||||
{:logs/archive-logs [db-json
|
||||
(if (= transport :email)
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
(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,6 +535,10 @@
|
||||
[]
|
||||
(.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 %))))
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
(ns quo.components.cards.wallet-card.component-spec
|
||||
(:require
|
||||
[quo.components.cards.wallet-card.view :as wallet-card]
|
||||
[quo.foundations.resources :as resources]
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(def ^:private base-props
|
||||
{:image (resources/get-image :keycard-logo)
|
||||
:title "Buy"
|
||||
:subtitle "Start investing now"})
|
||||
|
||||
(h/describe "cards: wallet card"
|
||||
(h/test "Test default render"
|
||||
(let [event (h/mock-fn)]
|
||||
(h/render-with-theme-provider [wallet-card/view
|
||||
(assoc base-props
|
||||
:on-press
|
||||
event)])
|
||||
(h/is-truthy (h/get-by-label-text :wallet-card))
|
||||
(h/is-truthy (h/get-by-text "Buy"))
|
||||
(h/is-truthy (h/get-by-text "Start investing now"))
|
||||
(h/is-truthy (h/get-by-label-text :image))
|
||||
(h/fire-event :press (h/get-by-label-text :wallet-card))
|
||||
(h/was-called event)))
|
||||
|
||||
(h/test "Test render with dismissible prop"
|
||||
(let [event (h/mock-fn)]
|
||||
(h/render-with-theme-provider [wallet-card/view
|
||||
(assoc base-props
|
||||
:dismissible? true
|
||||
:on-press-close event)])
|
||||
(h/is-truthy (h/get-by-label-text :close-icon))
|
||||
(h/fire-event :press (h/get-by-label-text :icon-container))
|
||||
(h/was-called event))))
|
||||
@@ -1,14 +0,0 @@
|
||||
(ns quo.components.cards.wallet-card.schema)
|
||||
|
||||
(def ?schema
|
||||
[:=>
|
||||
[:catn
|
||||
[:props
|
||||
[:map {:closed true}
|
||||
[:image :schema.common/image-source]
|
||||
[:title :string]
|
||||
[:subtitle :string]
|
||||
[:dismissible? {:optional true} :boolean]
|
||||
[:on-press {:optional true} fn?]
|
||||
[:on-press-close {:optional true} fn?]]]]
|
||||
:any])
|
||||
@@ -1,30 +0,0 @@
|
||||
(ns quo.components.cards.wallet-card.style
|
||||
(:require [quo.foundations.colors :as colors]
|
||||
[quo.foundations.shadows :as shadows]))
|
||||
|
||||
(defn root-container
|
||||
[theme]
|
||||
(assoc (shadows/get 2 theme)
|
||||
:border-radius 16
|
||||
:padding-vertical 10
|
||||
:padding-horizontal 12
|
||||
:width 161
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-90 theme)))
|
||||
|
||||
(def top-container
|
||||
{:flex-direction :row
|
||||
:height 32
|
||||
:justify-content :space-between
|
||||
:margin-bottom 8})
|
||||
|
||||
(def image
|
||||
{:height 32
|
||||
:width 32})
|
||||
|
||||
(defn title
|
||||
[theme]
|
||||
{:color (colors/theme-colors colors/neutral-100 colors/white theme)})
|
||||
|
||||
(defn subtitle
|
||||
[theme]
|
||||
{:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)})
|
||||
@@ -1,44 +0,0 @@
|
||||
(ns quo.components.cards.wallet-card.view
|
||||
(:require [quo.components.cards.wallet-card.schema :as component-schema]
|
||||
[quo.components.cards.wallet-card.style :as style]
|
||||
[quo.components.icon :as icon]
|
||||
[quo.components.markdown.text :as text]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.fast-image :as fast-image]
|
||||
[schema.core :as schema]))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [image title subtitle dismissible? on-press on-press-close]}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[rn/pressable
|
||||
{:on-press on-press
|
||||
:accessibility-label :wallet-card}
|
||||
[rn/view {:style (style/root-container theme)}
|
||||
[rn/view {:style style/top-container}
|
||||
[fast-image/fast-image
|
||||
{:style style/image
|
||||
:source image
|
||||
:accessibility-label :image}]
|
||||
(when dismissible?
|
||||
[rn/pressable
|
||||
{:on-press on-press-close
|
||||
:accessibility-label :icon-container
|
||||
:hit-slop {:top 5 :bottom 5 :left 5 :right 5}}
|
||||
[icon/icon :i/close
|
||||
{:size 12
|
||||
:accessibility-label :close-icon}]])]
|
||||
[text/text
|
||||
{:style (style/title theme)
|
||||
:size :paragraph-1
|
||||
:weight :semi-bold
|
||||
:number-of-lines 1}
|
||||
title]
|
||||
[text/text
|
||||
{:style (style/subtitle theme)
|
||||
:size :paragraph-2
|
||||
:weight :regular
|
||||
:number-of-lines 1}
|
||||
subtitle]]]))
|
||||
|
||||
(def view (schema/instrument #'view-internal component-schema/?schema))
|
||||
@@ -2,12 +2,11 @@
|
||||
|
||||
(defn container
|
||||
[container-style]
|
||||
(merge
|
||||
{:padding-vertical 7
|
||||
:padding-horizontal 20
|
||||
:flex-direction :row
|
||||
:align-items :flex-start}
|
||||
container-style))
|
||||
(merge container-style
|
||||
{:padding-vertical 7
|
||||
:padding-horizontal 20
|
||||
:flex-direction :row
|
||||
:align-items :flex-start}))
|
||||
|
||||
(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 icon icon-props]
|
||||
customization-color type blur? container-style]
|
||||
:or {type :bullet}}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[rn/view {:style (style/container container-style)}
|
||||
@@ -54,8 +54,6 @@
|
||||
: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 info-error?]
|
||||
[{:keys [number-of-pins number-of-filled-pins error? info]
|
||||
: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 (or error? info-error?)
|
||||
{:style {:color (if error?
|
||||
(colors/theme-colors colors/danger-50 colors/danger-60 theme)
|
||||
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))}
|
||||
:size :paragraph-2}
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
quo.components.calendar.calendar-day.view
|
||||
quo.components.calendar.calendar-year.view
|
||||
quo.components.calendar.calendar.view
|
||||
quo.components.cards.wallet-card.view
|
||||
quo.components.code.snippet-preview.view
|
||||
quo.components.code.snippet.view
|
||||
quo.components.colors.color-picker.view
|
||||
@@ -242,7 +241,6 @@
|
||||
;;;; Cards
|
||||
(def small-option-card quo.components.onboarding.small-option-card.view/small-option-card)
|
||||
(def keycard quo.components.keycard.view/keycard)
|
||||
(def wallet-card quo.components.cards.wallet-card.view/view)
|
||||
|
||||
;;;; Colors
|
||||
(def color-picker quo.components.colors.color-picker.view/view)
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
(ns status-im.common.log
|
||||
(:require
|
||||
[clojure.pprint :as pprint]
|
||||
[clojure.pprint :as promesa]
|
||||
[clojure.string :as string]
|
||||
[native-module.core :as native-module]
|
||||
[re-frame.core :as re-frame]
|
||||
[taoensso.timbre :as log]))
|
||||
[status-im.config :as config]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(def logs-queue (atom #queue []))
|
||||
(def max-log-entries 1000)
|
||||
@@ -18,21 +21,33 @@
|
||||
|
||||
(defn setup
|
||||
[level]
|
||||
(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 %))))))]})))
|
||||
(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)))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:logs/set-level
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
(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})
|
||||
@@ -0,0 +1,119 @@
|
||||
(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,7 +17,6 @@
|
||||
: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")
|
||||
@@ -37,9 +36,7 @@
|
||||
:nfc-success (js/require "../resources/images/ui2/nfc-success.png")
|
||||
:preparing-status (js/require "../resources/images/ui2/preparing-status.png")
|
||||
:syncing-devices (js/require "../resources/images/ui2/syncing_devices.png")
|
||||
:syncing-wrong (js/require "../resources/images/ui2/syncing_wrong.png")
|
||||
:buy (js/require "../resources/images/ui2/buy.png")
|
||||
:receive (js/require "../resources/images/ui2/receive.png")})
|
||||
:syncing-wrong (js/require "../resources/images/ui2/syncing_wrong.png")})
|
||||
|
||||
(def ui-themed
|
||||
{:angry-man
|
||||
|
||||
@@ -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,7 +116,6 @@
|
||||
: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,7 +3,6 @@
|
||||
(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 api-logging-enabled? (enabled? (get-config :API_LOGGING_ENABLED "0")))
|
||||
(def log-request-go (enabled? (get-config :LOG_REQUEST_GO "0")))
|
||||
(def fleet (get-config :FLEET ""))
|
||||
(def apn-topic (get-config :APN_TOPIC "im.status.ethereum"))
|
||||
(def max-installations 2)
|
||||
|
||||
@@ -76,9 +76,6 @@
|
||||
(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,10 +36,18 @@
|
||||
(assoc :centralized-metrics/enabled? enabled?)
|
||||
(assoc :centralized-metrics/onboarding-enabled? (and onboarding? enabled?)))}))
|
||||
|
||||
(rf/reg-event-fx :centralized-metrics/check-user-confirmation
|
||||
(fn [{:keys [db]}]
|
||||
(rf/reg-event-fx :centralized-metrics/check-modal
|
||||
(fn [{:keys [db]} [modal-view]]
|
||||
(when-not (:centralized-metrics/user-confirmed? db)
|
||||
{:fx [[:dispatch [:navigate-to :screen/onboarding.share-usage]]]})))
|
||||
{: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}]]]})))
|
||||
|
||||
(rf/reg-fx :effects.centralized-metrics/track
|
||||
(fn [event]
|
||||
|
||||
@@ -2,39 +2,29 @@
|
||||
(: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- add-shadow
|
||||
[theme styles]
|
||||
(defn shadow
|
||||
[theme]
|
||||
(if platform/ios?
|
||||
(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)}))
|
||||
{: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}))
|
||||
|
||||
(defn container
|
||||
[opacity top 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)})])
|
||||
(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))))
|
||||
|
||||
@@ -10,36 +10,37 @@
|
||||
[status-im.contexts.chat.messenger.messages.constants :as messages.constants]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(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 mention-item
|
||||
[user]
|
||||
[contact-list-item/contact-list-item
|
||||
{:on-press #(rf/dispatch [:chat.ui/select-mention user])}
|
||||
user])
|
||||
|
||||
(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/scroll-view
|
||||
{:accessibility-label :mentions-list
|
||||
:keyboard-should-persist-taps :always}
|
||||
(map mention-item suggestions-state)]]))
|
||||
[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}]]))
|
||||
|
||||
@@ -225,8 +225,7 @@
|
||||
distance-from-list-top
|
||||
chat-list-scroll-y
|
||||
(on-scroll-fn distance-atom layout-height)))
|
||||
:style {:height "100%"
|
||||
:background-color (colors/theme-colors colors/white
|
||||
:style {:background-color (colors/theme-colors colors/white
|
||||
colors/neutral-95
|
||||
theme)}
|
||||
:content-container-style (style/list-paddings add-padding-bottom?)
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
(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 %])}]]}))))
|
||||
@@ -1,62 +0,0 @@
|
||||
(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,13 +1,11 @@
|
||||
(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 []))
|
||||
@@ -52,22 +50,7 @@
|
||||
|
||||
(rf/reg-fx :effects.keycard/sign
|
||||
(fn [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)))))
|
||||
(keycard/sign (keycard.utils/wrap-handlers args))))
|
||||
|
||||
(rf/reg-fx :keycard/init-card
|
||||
(fn [args]
|
||||
|
||||
@@ -7,30 +7,6 @@
|
||||
[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
|
||||
[]
|
||||
[:<>
|
||||
@@ -47,7 +23,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 :import-key-pair-keycard
|
||||
:accessibility-label :get-keycard
|
||||
:image (resources/get-image :keycard-buy)
|
||||
:on-press (fn []
|
||||
(rf/dispatch
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(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
|
||||
@@ -45,7 +44,6 @@
|
||||
(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,4 +14,5 @@
|
||||
{: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,20 +13,17 @@
|
||||
pin-retry-counter (rf/sub [:keycard/pin-retry-counter])
|
||||
error? (or error? (= status :error))]
|
||||
(rn/use-unmount #(rf/dispatch [:keycard.pin/clear]))
|
||||
[rn/view
|
||||
{:style {:flex 1
|
||||
:gap 34
|
||||
:padding-bottom 12}}
|
||||
[rn/view {:style {:flex 1 :justify-content :center :align-items :center}}
|
||||
[rn/view {:padding-bottom 12 :flex 1}
|
||||
[rn/view {:flex 1 :justify-content :center :align-items :center :padding 34}
|
||||
[quo/pin-input
|
||||
{:blur? false
|
||||
:number-of-pins constants/pincode-length
|
||||
:number-of-filled-pins (count text)
|
||||
:info-error? error?
|
||||
:error? error?
|
||||
:info (when error?
|
||||
(if (not (string/blank? error-message))
|
||||
error-message
|
||||
(i18n/label-pluralize pin-retry-counter :t/pin-retries-left)))}]]
|
||||
(i18n/label :t/pin-retries-left {:number pin-retry-counter})))}]]
|
||||
[quo/numbered-keyboard
|
||||
{:delete-key? true
|
||||
:on-delete #(rf/dispatch [:keycard.pin/delete-pressed])
|
||||
|
||||
@@ -2,24 +2,33 @@
|
||||
(:require [utils.address]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx :keycard/sign-hashes
|
||||
(fn [_ [data]]
|
||||
{:effects.keycard/sign-hashes data}))
|
||||
(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/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])]
|
||||
(rf/reg-event-fx :keycard/sign
|
||||
(fn [_ [data]]
|
||||
{:effects.keycard/sign 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])]
|
||||
{:fx [[:dispatch
|
||||
[:keycard/connect
|
||||
{:key-uid key-uid
|
||||
:on-success
|
||||
(fn []
|
||||
(rf/dispatch
|
||||
[:keycard/sign-hashes
|
||||
{:pin keycard-pin
|
||||
[:keycard/sign
|
||||
{:pin pin-text
|
||||
:path path
|
||||
:hashes hashes
|
||||
:on-success (fn [signatures]
|
||||
:hash (utils.address/naked-address tx-hash)
|
||||
:on-success (fn [signature]
|
||||
(rf/dispatch [:keycard/disconnect])
|
||||
(when on-success (on-success signatures)))
|
||||
:on-failure on-failure}]))}]]]})))
|
||||
(rf/dispatch [:wallet/proceed-with-transactions-signatures
|
||||
(get-signature-map tx-hash signature)]))
|
||||
:on-failure #(rf/dispatch [:keycard/on-action-with-pin-error %])}]))}]]]})))
|
||||
|
||||
@@ -57,13 +57,9 @@
|
||||
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 (format-success-data %))))
|
||||
#(when on-success (on-success (normalize-key-uid (transforms/js->clj %)))))
|
||||
|
||||
(defn get-on-failure
|
||||
[{:keys [on-failure]}]
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
[quo.foundations.colors :as colors]))
|
||||
|
||||
(def content-container
|
||||
{:flex 1})
|
||||
{:position :absolute
|
||||
:top 0
|
||||
:bottom 0
|
||||
:left 0
|
||||
:right 0})
|
||||
|
||||
(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.events-helper :as events-helper]
|
||||
[status-im.common.metrics-confirmation-modal.view :as metrics-modal]
|
||||
[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-recovery-phrase
|
||||
(defn- navigate-to-sign-in-by-seed-phrase
|
||||
[create-profile?]
|
||||
(rf/dispatch [:syncing/clear-syncing-fallback-flow])
|
||||
(rf/dispatch [:onboarding/navigate-to-sign-in-by-seed-phrase
|
||||
@@ -50,97 +50,80 @@
|
||||
(* 2 16) ;; spacing between items
|
||||
220)) ;; extra spacing (top bar)
|
||||
|
||||
(defn- start-fresh-main-card
|
||||
|
||||
(defn- create-profile-option-card
|
||||
[window-height]
|
||||
[quo/small-option-card
|
||||
{:variant :main
|
||||
:title (i18n/label :t/start-fresh)
|
||||
:subtitle (i18n/label :t/start-fresh-subtitle)
|
||||
:title (i18n/label :t/generate-keys)
|
||||
:subtitle (i18n/label :t/generate-keys-subtitle)
|
||||
:button-label (i18n/label :t/lets-go)
|
||||
:accessibility-label :start-fresh-main-card
|
||||
:accessibility-label :generate-key-option-card
|
||||
:image (resources/get-image :generate-keys)
|
||||
:max-height (option-card-max-height window-height)
|
||||
:on-press navigate-to-create-profile}])
|
||||
|
||||
(defn- log-in-with-recovery-phrase-main-card
|
||||
(defn- sync-profile-option-card
|
||||
[window-height]
|
||||
[quo/small-option-card
|
||||
{:variant :main
|
||||
: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)
|
||||
: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)
|
||||
: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
|
||||
[create-profile?]
|
||||
(let [window-height (rf/sub [:dimensions/window-height])]
|
||||
[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)]
|
||||
[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/log-in))]
|
||||
(if create-profile?
|
||||
[start-fresh-main-card window-height]
|
||||
[log-in-with-recovery-phrase-main-card window-height])
|
||||
(i18n/label (if create-profile? :t/create-profile :t/sync-or-recover-profile))]
|
||||
[main-option-card window-height]
|
||||
[rn/view {:style style/subtitle-container}
|
||||
[quo/text
|
||||
{:style style/subtitle
|
||||
:size :paragraph-2
|
||||
:weight :medium}
|
||||
(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])]))
|
||||
(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]))
|
||||
|
||||
(defn- navigate-to-quo-preview
|
||||
[]
|
||||
@@ -148,6 +131,7 @@
|
||||
|
||||
(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
|
||||
@@ -155,13 +139,13 @@
|
||||
:type :no-title
|
||||
:background :blur
|
||||
:icon-name :i/arrow-left
|
||||
:on-press events-helper/navigate-back
|
||||
:on-press 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 :create-profile)]]))
|
||||
[sign-in-options sign-in-type]]))
|
||||
|
||||
(defn create-profile
|
||||
[]
|
||||
|
||||
@@ -52,16 +52,13 @@
|
||||
[]
|
||||
(when-let [blur-show-fn @overlay/blur-show-fn-atom]
|
||||
(blur-show-fn))
|
||||
(rf/dispatch [:open-modal
|
||||
:screen/onboarding.share-usage
|
||||
{:next-screen :screen/onboarding.sync-or-recover-profile}]))
|
||||
(rf/dispatch [:open-modal :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.share-usage
|
||||
{:next-screen :screen/onboarding.new-to-status}]))
|
||||
(rf/dispatch [:open-modal :screen/onboarding.new-to-status]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
(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]])
|
||||
@@ -1,18 +0,0 @@
|
||||
(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))})
|
||||
@@ -1,62 +0,0 @@
|
||||
(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)]]]))
|
||||
@@ -1,29 +0,0 @@
|
||||
(ns status-im.contexts.preview.quo.cards.wallet-card
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.contexts.preview.quo.preview :as preview]))
|
||||
|
||||
(def descriptor
|
||||
[{:key :title
|
||||
:type :text}
|
||||
{:key :subtitle
|
||||
:type :text}
|
||||
{:key :dismissible?
|
||||
:type :boolean}])
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [state (reagent/atom {:image (resources/get-image :buy)
|
||||
:title "Buy"
|
||||
:subtitle "Start investing now"
|
||||
:on-press #(js/alert "Item pressed")
|
||||
:on-press-close #(js/alert "Close pressed")
|
||||
:dismissible? false})]
|
||||
(fn []
|
||||
[preview/preview-container
|
||||
{:state state
|
||||
:descriptor descriptor
|
||||
:component-container-style {:align-items :center}}
|
||||
[quo/wallet-card @state]])))
|
||||
@@ -34,7 +34,6 @@
|
||||
[status-im.contexts.preview.quo.calendar.calendar :as calendar]
|
||||
[status-im.contexts.preview.quo.calendar.calendar-day :as calendar-day]
|
||||
[status-im.contexts.preview.quo.calendar.calendar-year :as calendar-year]
|
||||
[status-im.contexts.preview.quo.cards.wallet-card :as wallet-card]
|
||||
[status-im.contexts.preview.quo.code.snippet :as code-snippet]
|
||||
[status-im.contexts.preview.quo.code.snippet-preview :as code-snippet-preview]
|
||||
[status-im.contexts.preview.quo.colors.color :as color]
|
||||
@@ -275,8 +274,6 @@
|
||||
:component calendar-day/view}
|
||||
{:name :calendar-year
|
||||
:component calendar-year/view}]
|
||||
:cards [{:name :wallet-card
|
||||
:component wallet-card/view}]
|
||||
:code [{:name :snippet
|
||||
:component code-snippet/view}
|
||||
{:name :snippet-preview
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
:key :number-of-filled-pins}
|
||||
{:type :boolean
|
||||
:key :error?}
|
||||
{:type :boolean
|
||||
:key :info-error?}
|
||||
{:type :text
|
||||
:key :info}])
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(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]
|
||||
@@ -37,10 +36,7 @@
|
||||
{: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)
|
||||
:logEnabled (not (string/blank? config/log-level))
|
||||
:logLevel config/log-level
|
||||
:apiLoggingEnabled config/api-logging-enabled?}
|
||||
:mediaServerEnableTLS (config/enabled? config/STATUS_BACKEND_SERVER_MEDIA_SERVER_ENABLE_TLS)}
|
||||
callback)))
|
||||
|
||||
(rf/reg-event-fx
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
[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]
|
||||
@@ -42,10 +41,10 @@
|
||||
log-level (or (:log-level settings) config/log-level)
|
||||
pairing-completed? (= (get-in db [:syncing :pairing-status]) :completed)
|
||||
new-db (-> db
|
||||
(assoc :profile/profile
|
||||
(merge profile-overview
|
||||
settings
|
||||
{:log-level log-level}))
|
||||
(assoc :chats/loading? true
|
||||
: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
|
||||
@@ -132,15 +131,10 @@
|
||||
(let [new-account? (get db :onboarding/new-account?)]
|
||||
{:db (assoc db :messenger/started? true)
|
||||
:fx [[:fetch-chats-preview
|
||||
{: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]))}]
|
||||
{: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]))}]
|
||||
(when (and (:syncing/fallback-flow? db) (:syncing/installation-id db))
|
||||
[:dispatch [:pairing/finish-seed-phrase-fallback-syncing]])
|
||||
(when-not new-account?
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
[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]
|
||||
@@ -276,10 +277,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,28 +139,10 @@
|
||||
: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 [{: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]}]]})))
|
||||
(fn [_ [currency]]
|
||||
{:fx [[:dispatch [:profile.settings/profile-update :currency currency]]
|
||||
[:dispatch [:wallet/get-wallet-token-for-all-accounts]]]}))
|
||||
|
||||
;; Logout process
|
||||
(rf/reg-event-fx
|
||||
|
||||
@@ -19,14 +19,12 @@
|
||||
(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 prices-per-token)
|
||||
crypto-value (utils/get-standard-crypto-format token balance)
|
||||
fiat-value (utils/calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance balance
|
||||
:token token
|
||||
:prices-per-token prices-per-token})
|
||||
{:currency currency
|
||||
:balance balance
|
||||
:token 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,13 +12,12 @@
|
||||
disabled? :bridge-disabled?
|
||||
:as token}
|
||||
_ _
|
||||
{:keys [currency currency-symbol on-token-press preselected-token-symbol prices-per-token]}]
|
||||
{:keys [currency currency-symbol on-token-press preselected-token-symbol]}]
|
||||
(let [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)
|
||||
{:currency currency
|
||||
:balance total-balance
|
||||
:token token})
|
||||
crypto-formatted (utils/get-standard-crypto-format token total-balance)
|
||||
fiat-formatted (utils/fiat-formatted-for-ui currency-symbol fiat-value)]
|
||||
[quo/token-network
|
||||
{:token token-symbol
|
||||
@@ -35,19 +34,17 @@
|
||||
(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])
|
||||
prices-per-token (rf/sub [:wallet/prices-per-token])]
|
||||
(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])]
|
||||
[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
|
||||
:prices-per-token prices-per-token}
|
||||
:preselected-token-symbol preselected-token-symbol}
|
||||
:style {:flex 1}
|
||||
:content-container-style content-container-style
|
||||
:keyboard-should-persist-taps :handled
|
||||
|
||||
@@ -27,18 +27,12 @@
|
||||
[balance]
|
||||
(cut-fiat-balance balance 2))
|
||||
|
||||
(defn prepend-curency-symbol-to-fiat-balance
|
||||
[fiat-balance currency-symbol]
|
||||
(defn prettify-balance
|
||||
[currency-symbol balance]
|
||||
(let [formatted-symbol (if (> (count currency-symbol) 1)
|
||||
(str currency-symbol " ")
|
||||
currency-symbol)]
|
||||
(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)))
|
||||
(str formatted-symbol (cut-fiat-balance-to-two-decimals balance))))
|
||||
|
||||
(defn get-derivation-path
|
||||
[number-of-accounts]
|
||||
@@ -77,14 +71,9 @@
|
||||
(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 prices-per-token]
|
||||
(token-price-by-symbol prices-per-token (:symbol token) :usd))
|
||||
[token]
|
||||
(get-in token [:market-values-per-currency :usd :price]))
|
||||
|
||||
(defn one-cent-value
|
||||
[token-price-in-usd]
|
||||
@@ -115,20 +104,16 @@
|
||||
: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]
|
||||
(-> crypto-balance
|
||||
(cut-crypto-decimals-to-fit-usd-cents conversion-rate)
|
||||
(add-token-symbol-to-crypto-balance token-symbol)))
|
||||
(str (cut-crypto-decimals-to-fit-usd-cents crypto-balance conversion-rate)
|
||||
" "
|
||||
(string/upper-case token-symbol)))
|
||||
|
||||
(defn get-standard-crypto-format
|
||||
"For full details: https://github.com/status-im/status-mobile/issues/18225"
|
||||
[token token-units prices-per-token]
|
||||
(let [token-price-in-usd (token-usd-price token prices-per-token)
|
||||
[token token-units]
|
||||
(let [token-price-in-usd (token-usd-price token)
|
||||
{:keys [zero-value? usd-cent-value standardized-decimals-count]}
|
||||
(analyze-token-amount-for-price token-price-in-usd token-units)]
|
||||
(cond
|
||||
@@ -142,9 +127,11 @@
|
||||
(number/remove-trailing-zeroes (.toFixed token-units standardized-decimals-count)))))
|
||||
|
||||
(defn get-market-value
|
||||
[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)
|
||||
[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])
|
||||
;; NOTE: adding fallback value (zero) in case prices are
|
||||
;; unavailable and to prevent crash on calculating fiat value
|
||||
0))
|
||||
@@ -174,15 +161,15 @@
|
||||
|
||||
(defn calculate-token-fiat-value
|
||||
"Returns the token fiat value for provided raw balance"
|
||||
[{:keys [currency balance token prices-per-token]}]
|
||||
(let [price (get-market-value currency token prices-per-token)]
|
||||
[{:keys [currency balance token]}]
|
||||
(let [price (get-market-value currency 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 prices-per-token]}]
|
||||
(let [price (or (get-market-value currency token prices-per-token) 0)
|
||||
[{:keys [currency currency-symbol balance token]}]
|
||||
(let [price (or (get-market-value currency token) 0)
|
||||
price-zero? (zero? price)
|
||||
balance (or balance 0)
|
||||
balance-positive? (pos? balance)
|
||||
@@ -217,13 +204,12 @@
|
||||
(sanitized-token-amount-to-display display-decimals))))
|
||||
|
||||
(defn calculate-balance-from-tokens
|
||||
[{:keys [currency tokens chain-ids prices-per-token]}]
|
||||
[{:keys [currency tokens chain-ids]}]
|
||||
(->> tokens
|
||||
(map #(calculate-token-fiat-value
|
||||
{:currency currency
|
||||
:balance (calculate-total-token-balance % chain-ids)
|
||||
:token %
|
||||
:prices-per-token prices-per-token}))
|
||||
{:currency currency
|
||||
:balance (calculate-total-token-balance % chain-ids)
|
||||
:token %}))
|
||||
(reduce money/add)))
|
||||
|
||||
(defn- add-balances-per-chain
|
||||
@@ -266,10 +252,9 @@
|
||||
|
||||
(defn fiat-formatted-for-ui
|
||||
[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)))
|
||||
(if (money/less-than fiat-value 0.01)
|
||||
(str "<" currency-symbol "0.01")
|
||||
(prettify-balance currency-symbol fiat-value)))
|
||||
|
||||
(defn prettify-percentage-change
|
||||
"Returns unsigned precentage"
|
||||
@@ -281,30 +266,30 @@
|
||||
|
||||
(defn calculate-token-value
|
||||
"This function returns token values in the props of token-value (quo) component"
|
||||
[{: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)]
|
||||
[{: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)]
|
||||
{:token (:symbol token)
|
||||
:token-name (:name token)
|
||||
:state :default
|
||||
:metrics? (money/above-zero? balance)
|
||||
:status (cond
|
||||
(pos? change-pct-24h) :positive
|
||||
(neg? change-pct-24h) :negative
|
||||
:else :empty)
|
||||
(pos? change-pct-24hour) :positive
|
||||
(neg? change-pct-24hour) :negative
|
||||
:else :empty)
|
||||
:customization-color color
|
||||
:values {:crypto-value crypto-value
|
||||
:fiat-value fiat-value
|
||||
@@ -350,10 +335,10 @@
|
||||
(map #(update % :balances-per-chain select-keys chain-ids) tokens))
|
||||
|
||||
(defn calculate-balances-per-chain
|
||||
[{:keys [tokens currency currency-symbol prices-per-token]}]
|
||||
[{:keys [tokens currency currency-symbol]}]
|
||||
(->
|
||||
(reduce (fn [acc {:keys [balances-per-chain decimals] :as token}]
|
||||
(let [currency-value (get-market-value currency token prices-per-token)
|
||||
(let [currency-value (get-market-value currency token)
|
||||
fiat-balance-per-chain (update-vals balances-per-chain
|
||||
#(-> (money/token->unit (:raw-balance %)
|
||||
decimals)
|
||||
@@ -394,14 +379,12 @@
|
||||
(utils.string/contains-special-character? s) :special-character))
|
||||
|
||||
(defn calculate-and-sort-tokens
|
||||
[{:keys [tokens color currency currency-symbol prices-per-token market-values-per-token]}]
|
||||
[{:keys [tokens color currency currency-symbol]}]
|
||||
(let [calculate-token (fn [token]
|
||||
(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}))
|
||||
(calculate-token-value {:token token
|
||||
:color color
|
||||
:currency currency
|
||||
:currency-symbol currency-symbol}))
|
||||
calculated-tokens (map calculate-token tokens)]
|
||||
(sort-by (fn [token]
|
||||
(let [fiat-value (get-in token [:values :fiat-unformatted-value])
|
||||
@@ -566,18 +549,6 @@
|
||||
(: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))
|
||||
|
||||
@@ -59,33 +59,25 @@
|
||||
|
||||
(deftest get-standard-crypto-format-test
|
||||
(testing "get-standard-crypto-format function"
|
||||
(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)
|
||||
(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)
|
||||
"0.005")))
|
||||
(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)
|
||||
(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)
|
||||
"0.012346")))
|
||||
(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)
|
||||
(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)
|
||||
"<2")))
|
||||
(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)
|
||||
(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)
|
||||
"0")))))
|
||||
|
||||
(deftest calculate-total-token-balance-test
|
||||
@@ -159,12 +151,10 @@
|
||||
: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
|
||||
:prices-per-token {}
|
||||
:market-values-per-token {}}
|
||||
mock-input {:tokens mock-tokens
|
||||
:color mock-color
|
||||
:currency mock-currency
|
||||
:currency-symbol mock-currency-symbol}
|
||||
sorted-tokens (map :token (utils/calculate-and-sort-tokens mock-input))
|
||||
expected-order ["DAI" "ETH" "SNT"]]
|
||||
(is (= expected-order sorted-tokens))))))))
|
||||
@@ -180,20 +170,19 @@
|
||||
|
||||
(deftest formatted-token-fiat-value-test
|
||||
(testing "formatted-token-fiat-value function"
|
||||
(let [default-params {:currency "USD"
|
||||
:currency-symbol "$"
|
||||
:balance 0.5
|
||||
:token {:symbol "ETH"}
|
||||
:prices-per-token {:ETH {:usd 2000}}}]
|
||||
(let [default-params {:currency "USD"
|
||||
:currency-symbol "$"
|
||||
:balance 0.5
|
||||
:token {:market-values-per-currency {:usd {:price 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 :prices-per-token {:ETH {:usd nil}}))
|
||||
(assoc default-params :balance 1 :token {:market-values-per-currency {:usd {:price nil}}}))
|
||||
"$0"))
|
||||
(is (= (utils/formatted-token-fiat-value
|
||||
(assoc default-params :balance 1 :prices-per-token {:ETH {:usd 0}}))
|
||||
(assoc default-params :balance 1 :token {:market-values-per-currency {:usd {:price 0}}}))
|
||||
"$0")))))
|
||||
|
||||
(deftest sanitized-token-amount-to-display-test
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
[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]
|
||||
@@ -104,22 +103,3 @@
|
||||
(-> (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_fetchOrGetCachedWalletBalances"
|
||||
[{:method "wallet_getWalletToken"
|
||||
:params [[address]]
|
||||
:on-success [:wallet/store-wallet-token address]
|
||||
:on-error [:wallet/get-wallet-token-for-account-failed address]}]]]}))
|
||||
@@ -232,7 +232,6 @@
|
||||
: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]
|
||||
@@ -242,25 +241,11 @@
|
||||
(update accounts address assoc :tokens tokens-data)
|
||||
accounts))
|
||||
stored-accounts
|
||||
tokens-per-account))
|
||||
symbols (reduce-kv (fn [acc _ v]
|
||||
(into acc (map :symbol v)))
|
||||
#{}
|
||||
tokens)]
|
||||
{:db (-> db
|
||||
tokens-per-account))]
|
||||
{:fx [[:dispatch [:wallet/get-last-wallet-token-update-if-needed]]]
|
||||
:db (-> db
|
||||
(update-in [:wallet :accounts] add-tokens tokens)
|
||||
(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]}]]})))
|
||||
(assoc-in [:wallet :ui :tokens-loading address] false))})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/get-last-wallet-token-update-if-needed
|
||||
@@ -701,36 +686,3 @@
|
||||
(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_fetchOrGetCachedWalletBalances"
|
||||
[{:method "wallet_getWalletToken"
|
||||
:params [[address]]
|
||||
:on-success [:wallet/store-wallet-token address]
|
||||
:on-error [:wallet/get-wallet-token-for-account-failed
|
||||
|
||||
@@ -4,9 +4,3 @@
|
||||
(def list-container
|
||||
{:padding-horizontal 8
|
||||
:padding-bottom constants/floating-shell-button-height})
|
||||
|
||||
(def buy-and-receive-cta-container
|
||||
{:flex-direction :row
|
||||
:justify-content :space-between
|
||||
:padding-horizontal 20
|
||||
:padding-vertical 8})
|
||||
|
||||
@@ -2,46 +2,21 @@
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.contexts.wallet.common.token-value.view :as token-value]
|
||||
[status-im.contexts.wallet.home.tabs.assets.style :as style]
|
||||
[status-im.contexts.wallet.sheets.buy-token.view :as buy-token]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [tokens-loading? (rf/sub [:wallet/home-tokens-loading?])
|
||||
{:keys [tokens]} (rf/sub [:wallet/aggregated-token-values-and-balance])
|
||||
zero-balance? (rf/sub [:wallet/zero-balance-in-all-non-watched-accounts?])
|
||||
buy-assets (rn/use-callback
|
||||
(fn []
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content buy-token/view}])))
|
||||
receive-assets (rn/use-callback
|
||||
(fn []
|
||||
(rf/dispatch [:open-modal :screen/share-shell {:initial-tab :wallet}])))]
|
||||
[:<>
|
||||
(when (and (some? tokens-loading?) (not tokens-loading?) zero-balance?)
|
||||
[rn/view
|
||||
{:style style/buy-and-receive-cta-container}
|
||||
[quo/wallet-card
|
||||
{:image (resources/get-image :buy)
|
||||
:title (i18n/label :t/ways-to-buy)
|
||||
:subtitle (i18n/label :t/via-card-or-bank)
|
||||
:on-press buy-assets}]
|
||||
[quo/wallet-card
|
||||
{:image (resources/get-image :receive)
|
||||
:title (i18n/label :t/receive)
|
||||
:subtitle (i18n/label :t/deposit-to-your-wallet)
|
||||
:on-press receive-assets}]])
|
||||
(if tokens-loading?
|
||||
[quo/skeleton-list
|
||||
{:content :assets
|
||||
:parent-height 560
|
||||
:animated? false}]
|
||||
[rn/flat-list
|
||||
{:render-fn token-value/view
|
||||
:data tokens
|
||||
:render-data {:entry-point :wallet-stack}
|
||||
:content-container-style style/list-container}])]))
|
||||
{:keys [tokens]} (rf/sub [:wallet/aggregated-token-values-and-balance])]
|
||||
(if tokens-loading?
|
||||
[quo/skeleton-list
|
||||
{:content :assets
|
||||
:parent-height 560
|
||||
:animated? false}]
|
||||
[rn/flat-list
|
||||
{:render-fn token-value/view
|
||||
:data tokens
|
||||
:render-data {:entry-point :wallet-stack}
|
||||
:content-container-style style/list-container}])))
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
(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,6 +1,7 @@
|
||||
(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]
|
||||
@@ -8,10 +9,11 @@
|
||||
[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.security.core :as security]))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-send-data
|
||||
(fn [{:keys [db]}]
|
||||
@@ -325,30 +327,22 @@
|
||||
(rf/reg-event-fx
|
||||
:wallet/set-token-amount-to-send
|
||||
(fn [{:keys [db]} [{:keys [amount stack-id start-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}]]]})))
|
||||
{: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}]]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/set-token-amount-to-bridge
|
||||
(fn [{:keys [db]} [{:keys [amount stack-id start-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}]]]})))
|
||||
{: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}]]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/clean-bridge-to-selection
|
||||
@@ -464,8 +458,7 @@
|
||||
:token-networks-ids token-networks-ids
|
||||
:tx-type tx-type
|
||||
:receiver? true}))
|
||||
request-uuid (str (random-uuid))
|
||||
params [{:uuid request-uuid
|
||||
params [{:uuid (str (random-uuid))
|
||||
:sendType send-type
|
||||
:addrFrom from-address
|
||||
:addrTo to-address
|
||||
@@ -484,8 +477,7 @@
|
||||
{:db (update-in db
|
||||
[:wallet :ui :send]
|
||||
#(-> %
|
||||
(assoc :last-request-uuid request-uuid
|
||||
:amount amount
|
||||
(assoc :amount amount
|
||||
:loading-suggested-routes? true
|
||||
:sender-network-values sender-network-values
|
||||
:receiver-network-values receiver-network-values)
|
||||
@@ -573,39 +565,27 @@
|
||||
:else [:wallet/suggested-routes-success (fix-routes data)
|
||||
enough-assets?])]]})))))
|
||||
|
||||
(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))]
|
||||
(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)]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :just-completed-transaction?] true)
|
||||
(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]}]]
|
||||
(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]]
|
||||
[: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?)}))
|
||||
@@ -629,82 +609,100 @@
|
||||
[{:ms 20
|
||||
:dispatch [:wallet/clean-up-transaction-flow]}]]]})))
|
||||
|
||||
(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]))
|
||||
(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])))
|
||||
:on-error (fn [error]
|
||||
(log/error "failed to send router transactions with signatures"
|
||||
{:event :wallet/send-router-transactions-with-signatures
|
||||
:error error})
|
||||
(log/error "failed to send transaction"
|
||||
{:event :wallet/send-transaction
|
||||
:error error
|
||||
:params request-params})
|
||||
(rf/dispatch [:toasts/upsert
|
||||
{:id :send-router-transactions-with-signatures-error
|
||||
{:id :send-transaction-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,6 +575,29 @@
|
||||
: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,22 +43,23 @@
|
||||
: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}
|
||||
: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-loading-suggested-routes? false
|
||||
:wallet/wallet-send-route [{:from {:chainid 1
|
||||
:native-currency-symbol "ETH"}
|
||||
@@ -74,13 +75,14 @@
|
||||
: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}}}
|
||||
: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/wallet-send-disabled-from-chain-ids []
|
||||
:wallet/wallet-send-from-locked-amounts {}
|
||||
:wallet/wallet-send-from-values-by-chain {1 (money/bignumber "250")}
|
||||
@@ -104,7 +106,6 @@
|
||||
: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,14 +164,13 @@
|
||||
(str token-symbol)
|
||||
enabled-from-chain-ids])
|
||||
token-balance (or default-limit-crypto total-balance)
|
||||
prices-per-token (rf/sub [:wallet/prices-per-token])
|
||||
usd-conversion-rate (utils/token-usd-price token prices-per-token)
|
||||
usd-conversion-rate (utils/token-usd-price 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,44 +80,202 @@
|
||||
(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
|
||||
(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))])
|
||||
(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,7 +13,8 @@
|
||||
[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.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(defn- transaction-title
|
||||
[{:keys [token-display-name amount account route to-network image-url transaction-type
|
||||
@@ -237,7 +238,6 @@
|
||||
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,50 +268,51 @@
|
||||
: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}
|
||||
:disabled? (not transaction-for-signing)
|
||||
{: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}
|
||||
:customization-color account-color
|
||||
:on-auth-success
|
||||
(fn [data]
|
||||
(rf/dispatch
|
||||
[:wallet/prepare-signatures-for-transactions
|
||||
:send data]))
|
||||
:auth-button-label (i18n/label :t/confirm)}])]
|
||||
:on-auth-success #(rf/dispatch
|
||||
[:wallet/send-transaction
|
||||
(security/safe-unmask-data %)])
|
||||
:auth-button-label (i18n/label :t/confirm)}])]
|
||||
:gradient-cover? true
|
||||
:customization-color (:color account)}
|
||||
[rn/view
|
||||
[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}]]]]))))
|
||||
[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}]]]]]))))
|
||||
|
||||
@@ -303,9 +303,3 @@
|
||||
(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,7 +49,6 @@
|
||||
(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
|
||||
@@ -57,27 +56,18 @@
|
||||
(oops/oget % :nativeEvent :layout :height)))]
|
||||
[:<>
|
||||
[quo/drawer-top {:title (or title (i18n/label :t/ways-to-buy-assets))}]
|
||||
(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}])]))
|
||||
[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}]]))
|
||||
|
||||
@@ -15,13 +15,11 @@
|
||||
bridge-disabled? :bridge-disabled?
|
||||
:as token}
|
||||
{:keys [currency currency-symbol on-token-press disable-token-fn preselected-token-symbol]}]
|
||||
(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)
|
||||
(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)
|
||||
fiat-formatted (utils/fiat-formatted-for-ui currency-symbol fiat-value)]
|
||||
[rn/view {:style {:padding-horizontal 8}}
|
||||
[quo/token-network
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
(ns status-im.contexts.wallet.swap.events
|
||||
(:require [re-frame.core :as rf]
|
||||
(:require [native-module.core :as native-module]
|
||||
[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]))
|
||||
@@ -111,10 +114,6 @@
|
||||
(fn [{:keys [db]} [max-slippage]]
|
||||
{:db (assoc-in db [:wallet :ui :swap :max-slippage] (number/parse-float max-slippage))}))
|
||||
|
||||
(rf/reg-event-fx :wallet.swap/set-loading-swap-proposal
|
||||
(fn [{:keys [db]}]
|
||||
{:db (assoc-in db [:wallet :ui :swap :loading-swap-proposal?] true)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/start-get-swap-proposal
|
||||
(fn [{:keys [db]} [{:keys [amount-in amount-out clean-approval-transaction?]}]]
|
||||
(let [wallet-address (get-in db [:wallet :current-viewing-account-address])
|
||||
@@ -152,19 +151,21 @@
|
||||
:disabledFromChainIDs disabled-from-chain-ids
|
||||
:disabledToChainIDs disabled-to-chain-ids
|
||||
:gasFeeMode gas-rates
|
||||
:fromLockedAmount from-locked-amount
|
||||
:amountOut (or amount-out-hex "0x0")}
|
||||
amount-in (assoc :amountIn amount-in-hex))]]
|
||||
:fromLockedAmount from-locked-amount}
|
||||
amount-in (assoc :amountIn amount-in-hex)
|
||||
amount-out (assoc :amountOut amount-out-hex))]]
|
||||
|
||||
(when-let [amount (or amount-in amount-out)]
|
||||
{:db (update-in db
|
||||
[:wallet :ui :swap]
|
||||
#(cond-> %
|
||||
:always
|
||||
(assoc
|
||||
:last-request-uuid request-uuid
|
||||
:amount amount
|
||||
:amount-hex amount-in-hex
|
||||
:initial-response? true)
|
||||
:last-request-uuid request-uuid
|
||||
:amount amount
|
||||
:amount-hex amount-in-hex
|
||||
:loading-swap-proposal? true
|
||||
:initial-response? true)
|
||||
clean-approval-transaction?
|
||||
(dissoc :approval-transaction-id :approved-amount :swap-proposal)))
|
||||
:fx [[:dispatch
|
||||
@@ -245,16 +246,13 @@
|
||||
[:centralized-metrics/track :metric/swap-proposal-failed {:error (:code error-response)}]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/stop-get-swap-proposal
|
||||
(fn [{:keys [db]}]
|
||||
(let [route-request-ongoing? (some? (get-in db [:wallet :ui :swap :last-request-uuid]))]
|
||||
(when route-request-ongoing?
|
||||
{:db (update-in db [:wallet :ui :swap] dissoc :last-request-uuid)
|
||||
:json-rpc/call [{:method "wallet_stopSuggestedRoutesAsyncCalculation"
|
||||
:params []
|
||||
:on-error (fn [error]
|
||||
(log/error "failed to stop fetching swap proposals"
|
||||
{:event :wallet/stop-get-swap-proposal
|
||||
:error error}))}]}))))
|
||||
(fn []
|
||||
{:json-rpc/call [{:method "wallet_stopSuggestedRoutesAsyncCalculation"
|
||||
:params []
|
||||
:on-error (fn [error]
|
||||
(log/error "failed to stop fetching swap proposals"
|
||||
{:event :wallet/stop-get-swap-proposal
|
||||
:error error}))}]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/clean-swap-proposal
|
||||
@@ -272,21 +270,150 @@
|
||||
(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 [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))
|
||||
(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))
|
||||
transaction-id (first transaction-ids)
|
||||
transaction-details (cond-> transactions
|
||||
transaction-details (cond-> (send-utils/map-multitransaction-by-ids transaction-batch-id
|
||||
transaction-hashes)
|
||||
: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 wallet-transactions transaction-details))
|
||||
(merge 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)
|
||||
@@ -336,8 +463,7 @@
|
||||
(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
|
||||
@@ -368,8 +494,7 @@
|
||||
: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])
|
||||
@@ -403,169 +528,14 @@
|
||||
:previous_token (:symbol asset-to-receive)
|
||||
:new_token (:symbol asset-to-pay)}]]]})))
|
||||
|
||||
(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
|
||||
(rf/reg-event-fx :wallet/end-swap-flow
|
||||
(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])]
|
||||
{: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]]
|
||||
(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]])
|
||||
[:dispatch [:wallet/fetch-activities-for-current-account]]
|
||||
[:dispatch [:wallet/select-account-tab :activity]]
|
||||
[:dispatch-later
|
||||
[{:ms 20
|
||||
:dispatch [:wallet.swap/clean-up-transaction-flow]}]]]})))
|
||||
[:dispatch [:wallet/select-account-tab :activity]]]})))
|
||||
|
||||
(rf/reg-event-fx :wallet.swap/start-from-account
|
||||
(fn [{:keys [db]} [account]]
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
[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.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(defn- swap-title
|
||||
[]
|
||||
@@ -220,8 +221,9 @@
|
||||
(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/prepare-signatures-for-transactions :swap %]))]
|
||||
on-auth-success (rn/use-callback #(rf/dispatch
|
||||
[:wallet/swap-transaction
|
||||
(security/safe-unmask-data %)]))]
|
||||
[standard-auth/slide-button
|
||||
{:size :size-48
|
||||
:track-text (i18n/label :t/slide-to-sign)
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
[utils.string :as utils.string]))
|
||||
|
||||
(def ^:private default-text-for-unfocused-input "0.00")
|
||||
(def ^:private swap-proposal-debounce-time-ms 1000)
|
||||
|
||||
(defn- on-close
|
||||
[start-point]
|
||||
@@ -37,20 +36,13 @@
|
||||
:clean-approval-transaction? true}])
|
||||
(events-helper/navigate-back))
|
||||
|
||||
(defn- start-get-swap-proposal
|
||||
[amount clean-approval-transaction?]
|
||||
(rf/dispatch [:wallet/stop-get-swap-proposal])
|
||||
(rf/dispatch [:wallet.swap/set-loading-swap-proposal])
|
||||
(debounce/debounce-and-dispatch [:wallet/start-get-swap-proposal
|
||||
{:amount-in amount
|
||||
:clean-approval-transaction? clean-approval-transaction?}]
|
||||
swap-proposal-debounce-time-ms))
|
||||
|
||||
(defn- fetch-swap-proposal
|
||||
[{:keys [amount valid-input? clean-approval-transaction?]}]
|
||||
(debounce/clear-all)
|
||||
(if valid-input?
|
||||
(start-get-swap-proposal amount clean-approval-transaction?)
|
||||
(debounce/debounce-and-dispatch [:wallet/start-get-swap-proposal
|
||||
{:amount-in amount
|
||||
:clean-approval-transaction? clean-approval-transaction?}]
|
||||
100)
|
||||
(rf/dispatch [:wallet/clean-swap-proposal
|
||||
{:clean-amounts? true
|
||||
:clean-approval-transaction? clean-approval-transaction?}])))
|
||||
@@ -103,10 +95,8 @@
|
||||
:subtitle (str max-slippage "%")
|
||||
:subtitle-icon :i/edit
|
||||
:size :small
|
||||
:on-press (fn []
|
||||
(when-not loading-swap-proposal?
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content slippage-settings/view}])))}]]))
|
||||
:on-press #(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?]}]
|
||||
@@ -205,8 +195,7 @@
|
||||
:approve)
|
||||
:token-value approval-label-token-value
|
||||
:button-props (merge {:on-press on-approve-press}
|
||||
(when (or loading-swap-proposal?
|
||||
error-response)
|
||||
(when error-response
|
||||
{:disabled? true}))
|
||||
:customization-color account-color
|
||||
:token-symbol pay-token-symbol}}]))
|
||||
@@ -227,7 +216,6 @@
|
||||
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
|
||||
@@ -236,11 +224,10 @@
|
||||
(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
|
||||
:prices-per-token prices-per-token})]
|
||||
{:currency currency
|
||||
:currency-symbol currency-symbol
|
||||
:balance (or amount-out-whole-number 0)
|
||||
:token asset-to-receive})]
|
||||
[quo/swap-input
|
||||
{:type :receive
|
||||
:error? false
|
||||
@@ -372,7 +359,9 @@
|
||||
(not pay-input-error?))
|
||||
on-review-swap-press (rn/use-callback
|
||||
(fn []
|
||||
(rf/dispatch [:wallet.swap/review-swap])))
|
||||
(rf/dispatch [:navigate-to-within-stack
|
||||
[:screen/wallet.swap-confirmation
|
||||
:screen/wallet.setup-swap]])))
|
||||
on-press (rn/use-callback
|
||||
(fn [c]
|
||||
(let
|
||||
@@ -501,7 +490,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 [:wallet.swap/approve])
|
||||
:on-approve-press #(rf/dispatch [:open-modal :screen/wallet.swap-set-spending-cap])
|
||||
:on-input-focus (fn []
|
||||
(when platform/android? (rf/dispatch [:dismiss-keyboard]))
|
||||
(set-pay-input-focused? true))}]
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
[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.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(defn- on-close-action
|
||||
[]
|
||||
@@ -164,23 +165,22 @@
|
||||
|
||||
(defn- slide-button
|
||||
[]
|
||||
(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)]
|
||||
(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)])))]
|
||||
[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)
|
||||
(not transaction-for-signing))
|
||||
:disabled? (or loading-swap-proposal? (not swap-proposal))
|
||||
:auth-button-label (i18n/label :t/confirm)
|
||||
:on-auth-success (fn [data]
|
||||
(rf/dispatch [:wallet/stop-get-swap-proposal])
|
||||
(rf/dispatch [:wallet/prepare-signatures-for-transactions :swap data]))}]))
|
||||
:on-auth-success on-auth-success}]))
|
||||
|
||||
(defn footer
|
||||
[]
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
(ns status-im.contexts.wallet.swap.swap-proposal.style)
|
||||
|
||||
(def container
|
||||
{:flex 1})
|
||||
@@ -0,0 +1,27 @@
|
||||
(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,7 +21,6 @@
|
||||
(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
|
||||
@@ -49,11 +48,13 @@
|
||||
: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
|
||||
@@ -63,10 +64,9 @@
|
||||
(assoc result token-symbol #{chain-id})))
|
||||
{}
|
||||
by-symbol-vals)]
|
||||
|
||||
{:fx [[:effects.wallet.tokens/fetch-market-values
|
||||
{:symbols symbols
|
||||
:currency profile-currency
|
||||
:currency constants/profile-default-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 profile-currency]
|
||||
:currencies [constants/profile-default-currency]
|
||||
:on-success [:wallet.tokens/store-prices]
|
||||
:on-error [:wallet.tokens/fetch-prices-failed]}]]
|
||||
:db (-> db
|
||||
@@ -116,7 +116,7 @@
|
||||
{}
|
||||
raw-data)]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :tokens :market-values-per-token] merge market-values)
|
||||
(assoc-in [:wallet :tokens :market-values-per-token] 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
|
||||
(update-in [:wallet :tokens :prices-per-token] merge prices)
|
||||
(assoc-in [:wallet :tokens :prices-per-token] prices)
|
||||
(assoc-in [:wallet :ui :loading :prices] false))}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
|
||||
@@ -1,8 +1,63 @@
|
||||
(ns status-im.contexts.wallet.wallet-connect.utils.rpc
|
||||
(:require [promesa.core :as promesa]
|
||||
(: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 :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))
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
(:require
|
||||
[native-module.core :as native-module]
|
||||
[promesa.core :as promesa]
|
||||
[status-im.contexts.wallet.rpc :as wallet-rpc]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.rpc :as rpc]
|
||||
[utils.hex :as hex]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
@@ -19,6 +19,6 @@
|
||||
|
||||
(defn personal-sign
|
||||
[password address data]
|
||||
(-> (wallet-rpc/hash-message-eip-191 data)
|
||||
(promesa/then #(wallet-rpc/sign-message % address password))
|
||||
(-> (rpc/wallet-hash-message-eip-191 data)
|
||||
(promesa/then #(rpc/wallet-sign-message % address password))
|
||||
(promesa/then hex/prefix-hex)))
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
[native-module.core :as native-module]
|
||||
[promesa.core :as promesa]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.rpc :as wallet-rpc]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.data-store :as
|
||||
data-store]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.rpc :as wallet-connect-rpc]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.rpc :as rpc]
|
||||
[utils.money :as money]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
@@ -120,17 +119,16 @@
|
||||
"Formats and builds the incoming transaction, adding the missing properties and returning the final
|
||||
transaction, along with the transaction hash and the suggested fees"
|
||||
[tx chain-id tx-priority]
|
||||
(promesa/let [suggested-fees (wallet-rpc/get-suggested-fees chain-id)
|
||||
(promesa/let [suggested-fees (rpc/wallet-get-suggested-fees chain-id)
|
||||
{:keys [tx-args message-to-sign]} (->>
|
||||
(prepare-transaction-fees tx
|
||||
tx-priority
|
||||
suggested-fees)
|
||||
prepare-transaction-for-rpc
|
||||
(wallet-rpc/build-transaction
|
||||
chain-id))
|
||||
estimated-time (wallet-connect-rpc/wallet-get-transaction-estimated-time
|
||||
chain-id
|
||||
(:maxPriorityFeePerGas suggested-fees))]
|
||||
(rpc/wallet-build-transaction chain-id))
|
||||
estimated-time (rpc/wallet-get-transaction-estimated-time
|
||||
chain-id
|
||||
(:maxPriorityFeePerGas suggested-fees))]
|
||||
{:tx-args tx-args
|
||||
:tx-hash message-to-sign
|
||||
:suggested-fees suggested-fees
|
||||
@@ -139,15 +137,15 @@
|
||||
(defn sign-transaction
|
||||
[password address tx-hash tx-args chain-id]
|
||||
(promesa/let
|
||||
[signature (wallet-rpc/sign-message tx-hash address password)
|
||||
raw-tx (wallet-rpc/build-raw-transaction chain-id tx-args signature)]
|
||||
[signature (rpc/wallet-sign-message tx-hash address password)
|
||||
raw-tx (rpc/wallet-build-raw-transaction chain-id tx-args signature)]
|
||||
raw-tx))
|
||||
|
||||
(defn send-transaction
|
||||
[password address tx-hash tx-args chain-id]
|
||||
(promesa/let
|
||||
[signature (wallet-rpc/sign-message tx-hash address password)
|
||||
tx (wallet-rpc/send-transaction-with-signature chain-id
|
||||
[signature (rpc/wallet-sign-message tx-hash address password)
|
||||
tx (rpc/wallet-send-transaction-with-signature chain-id
|
||||
tx-args
|
||||
signature)]
|
||||
tx))
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
(ns status-im.contexts.wallet.wallet-connect.utils.typed-data
|
||||
(:require [clojure.string :as string]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.rpc :as wallet-rpc]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.networks :as networks]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.rpc :as rpc]
|
||||
[utils.number :as number]))
|
||||
|
||||
(declare flatten-data)
|
||||
@@ -88,7 +88,7 @@
|
||||
[password address data chain-id-eip155 version]
|
||||
(let [legacy? (= version :v1)
|
||||
chain-id (networks/eip155->chain-id chain-id-eip155)]
|
||||
(wallet-rpc/safe-sign-typed-data data
|
||||
(rpc/wallet-safe-sign-typed-data data
|
||||
address
|
||||
password
|
||||
chain-id
|
||||
|
||||
@@ -43,4 +43,4 @@
|
||||
:stickers/packs-pending #{}
|
||||
:settings/change-password {}
|
||||
:keycard {}
|
||||
:theme :dark})
|
||||
:theme :light})
|
||||
|
||||