Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6ab9caf39 | ||
|
|
7ffa680761 | ||
|
|
d6041c90a4 | ||
|
|
9e9833e732 | ||
|
|
dd0ba49bea | ||
|
|
6105435207 | ||
|
|
711fd19967 | ||
|
|
d58553f67a | ||
|
|
76882690d7 | ||
|
|
6a33c4723a | ||
|
|
6a26ebafa3 | ||
|
|
3c55fc1fa2 | ||
|
|
15a1a15c08 | ||
|
|
9e43aa04c7 |
Binary file not shown.
|
After Width: | Height: | Size: 999 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
@@ -48,7 +48,7 @@
|
||||
:accessibility-label :receive}]
|
||||
(when swap-action
|
||||
[action-button
|
||||
{:icon :i/swap
|
||||
{:icon :i/transaction
|
||||
:text (i18n/label :t/swap)
|
||||
:on-press swap-action
|
||||
:theme theme
|
||||
|
||||
@@ -60,7 +60,8 @@
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [type account-props token-props networks? values]}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
address (or (:address account-props) (:address token-props))]
|
||||
[rn/view
|
||||
{:style (style/container networks? theme)}
|
||||
[rn/view
|
||||
@@ -89,12 +90,13 @@
|
||||
(get-in account-props [:status-account :name])]
|
||||
[rn/view
|
||||
{:style (style/dot-divider theme)}]])
|
||||
[text/text
|
||||
{:size (when (not= type :account) :paragraph-2)
|
||||
:weight (when (= type :account) :semi-bold)
|
||||
:style {:color (when (not= type :account)
|
||||
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))}}
|
||||
(or (:address account-props) (:address token-props))]]]]
|
||||
(when address
|
||||
[text/text
|
||||
{:size (when (not= type :account) :paragraph-2)
|
||||
:weight (when (= type :account) :semi-bold)
|
||||
:style {:color (when (not= type :account)
|
||||
(colors/theme-colors colors/neutral-50 colors/neutral-40 theme))}}
|
||||
address])]]]
|
||||
(when networks?
|
||||
[:<>
|
||||
[rn/view
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
(def transaction-icon
|
||||
{:send :i/send
|
||||
:swap :i/swap
|
||||
:swap :i/transaction
|
||||
:bridge :i/bridge})
|
||||
|
||||
(defn transaction-header
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
(def transaction-icon
|
||||
{:receive :i/receive
|
||||
:send :i/send
|
||||
:swap :i/swap
|
||||
:swap :i/transaction
|
||||
:bridge :i/bridge
|
||||
:buy :i/buy
|
||||
:destroy :i/destroy
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
(take 7)))
|
||||
|
||||
(defn recovery-phrase-screen
|
||||
[{:keys [banner-offset initial-insets keypair title recovering-keypair? render-controls]}]
|
||||
[{:keys [banner-offset initial-insets keypair title on-success render-controls]}]
|
||||
(reagent/with-let [keyboard-shown? (reagent/atom false)
|
||||
keyboard-show-listener (.addListener rn/keyboard
|
||||
"keyboardDidShow"
|
||||
@@ -120,14 +120,20 @@
|
||||
(reset! seed-phrase new-phrase))
|
||||
on-submit (fn []
|
||||
(swap! seed-phrase clean-seed-phrase)
|
||||
(if recovering-keypair?
|
||||
(rf/dispatch [:wallet/seed-phrase-entered
|
||||
(security/mask-data
|
||||
@seed-phrase)
|
||||
set-invalid-seed-phrase])
|
||||
(rf/dispatch [:onboarding/seed-phrase-entered
|
||||
(security/mask-data @seed-phrase)
|
||||
set-invalid-seed-phrase])))]
|
||||
(rf/dispatch
|
||||
[:profile.recover/validate-recovery-phrase
|
||||
(security/mask-data @seed-phrase)
|
||||
{:on-success (fn [mnemonic key-uid]
|
||||
(if on-success
|
||||
(on-success
|
||||
{:key-uid key-uid
|
||||
:phrase mnemonic
|
||||
:on-error
|
||||
set-invalid-seed-phrase})
|
||||
(rf/dispatch
|
||||
[:onboarding/seed-phrase-validated
|
||||
mnemonic key-uid])))
|
||||
:on-error set-invalid-seed-phrase}]))]
|
||||
(let [words-coll (mnemonic/passphrase->words @seed-phrase)
|
||||
last-word (peek words-coll)
|
||||
pick-suggested-word (fn [pressed-word]
|
||||
@@ -191,7 +197,7 @@
|
||||
[rn/view {:style style/keyboard-container}
|
||||
[quo/predictive-keyboard
|
||||
{:type suggestions-state
|
||||
:blur? (not recovering-keypair?)
|
||||
:blur? (not on-success)
|
||||
:text suggestions-text
|
||||
:words (keyboard-suggestions last-word)
|
||||
:on-press pick-suggested-word}]])])
|
||||
@@ -200,7 +206,7 @@
|
||||
(.remove keyboard-hide-listener))))
|
||||
|
||||
(defn screen
|
||||
[{:keys [title keypair navigation-icon recovering-keypair? render-controls]}]
|
||||
[{:keys [title keypair navigation-icon on-success render-controls]}]
|
||||
(let [[insets _] (rn/use-state (safe-area/get-insets))
|
||||
banner-offset (rf/sub [:alert-banners/top-margin])]
|
||||
[rn/view {:style style/full-layout}
|
||||
@@ -209,21 +215,22 @@
|
||||
{:margin-top (:top insets)
|
||||
:background :blur
|
||||
:icon-name (or navigation-icon
|
||||
(if recovering-keypair? :i/close :i/arrow-left))
|
||||
(if on-success :i/close :i/arrow-left))
|
||||
:on-press #(rf/dispatch [:navigate-back])}]
|
||||
[recovery-phrase-screen
|
||||
{:title title
|
||||
:keypair keypair
|
||||
:render-controls render-controls
|
||||
:banner-offset banner-offset
|
||||
:initial-insets insets
|
||||
:recovering-keypair? recovering-keypair?}]]]))
|
||||
{:title title
|
||||
:keypair keypair
|
||||
:render-controls render-controls
|
||||
:banner-offset banner-offset
|
||||
:initial-insets insets
|
||||
:on-success on-success}]]]))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [{:keys [recovering-keypair?]} (rf/sub [:get-screen-params])]
|
||||
(let [{:keys [on-success]} (rf/sub [:get-screen-params])]
|
||||
(rn/use-unmount
|
||||
#(rf/dispatch [:onboarding/clear-navigated-to-enter-seed-phrase-from-screen]))
|
||||
(when-not on-success
|
||||
#(rf/dispatch [:onboarding/clear-navigated-to-enter-seed-phrase-from-screen])))
|
||||
[screen
|
||||
{:title (i18n/label :t/use-recovery-phrase)
|
||||
:recovering-keypair? recovering-keypair?}]))
|
||||
{:title (i18n/label :t/use-recovery-phrase)
|
||||
:on-success on-success}]))
|
||||
|
||||
@@ -45,3 +45,15 @@
|
||||
#(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]
|
||||
(native-module/add-centralized-metric event)))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:centralized-metrics/track
|
||||
(fn [{:keys [db]} [event-name data]]
|
||||
(let [event-id (name event-name)]
|
||||
(when (push-event? db)
|
||||
{:fx [[:effects.centralized-metrics/track
|
||||
(tracking/key-value-event event-id data)]]}))))
|
||||
|
||||
@@ -4,20 +4,20 @@
|
||||
[react-native.platform :as platform]))
|
||||
|
||||
(defn key-value-event
|
||||
[event-name val-key value]
|
||||
[event-name event-value]
|
||||
{:metric
|
||||
{:eventName event-name
|
||||
:platform platform/os
|
||||
:appVersion build/app-short-version
|
||||
:eventValue {val-key value}}})
|
||||
:eventValue event-value}})
|
||||
|
||||
(defn user-journey-event
|
||||
[action]
|
||||
(key-value-event "user-journey" :action action))
|
||||
(key-value-event "user-journey" {:action action}))
|
||||
|
||||
(defn navigation-event
|
||||
[view-id]
|
||||
(key-value-event "navigation" :viewId view-id))
|
||||
(key-value-event "navigation" {:viewId view-id}))
|
||||
|
||||
(def ^:const app-started-event "app-started")
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
(user-journey-event app-started-event)
|
||||
|
||||
:centralized-metrics/toggle-centralized-metrics
|
||||
(key-value-event "events.metrics-enabled" :enabled second-parameter)
|
||||
(key-value-event "events.metrics-enabled" {:enabled second-parameter})
|
||||
|
||||
:set-view-id
|
||||
(track-view-id-event second-parameter)
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
:platform platform-os
|
||||
:appVersion app-version
|
||||
:eventValue {val-key value}}}]
|
||||
(is (= expected (tracking/key-value-event event-name val-key value))))))
|
||||
(is (= expected (tracking/key-value-event event-name {val-key value}))))))
|
||||
|
||||
(deftest user-journey-event-test
|
||||
(testing "creates correct user journey event"
|
||||
|
||||
@@ -72,22 +72,21 @@
|
||||
|
||||
(rf/reg-event-fx :keycard/on-get-application-info-success
|
||||
(fn [{:keys [db]} [application-info {:keys [key-uid on-success-fx]}]]
|
||||
(let [error (keycard.utils/validate-application-info key-uid application-info)]
|
||||
(if error
|
||||
(case error
|
||||
:keycard/error.not-keycard
|
||||
{:fx [[:dispatch [:keycard/disconnect]]
|
||||
[:dispatch [:open-modal :screen/keycard.not-keycard]]]}
|
||||
:keycard/error.keycard-blank
|
||||
{:fx [[:dispatch [:keycard/disconnect]]
|
||||
[:dispatch [:open-modal :screen/keycard.empty]]]}
|
||||
{:db (assoc-in db [:keycard :application-info-error] error)
|
||||
:fx [[:dispatch [:keycard/disconnect]]
|
||||
[:dispatch [:open-modal :screen/keycard.error]]]})
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :application-info] application-info)
|
||||
(assoc-in [:keycard :pin :status] :verifying))
|
||||
:fx on-success-fx}))))
|
||||
(if-let [error (keycard.utils/validate-application-info key-uid application-info)]
|
||||
(case error
|
||||
:keycard/error.not-keycard
|
||||
{:fx [[:dispatch [:keycard/disconnect]]
|
||||
[:dispatch [:open-modal :screen/keycard.not-keycard]]]}
|
||||
:keycard/error.keycard-blank
|
||||
{:fx [[:dispatch [:keycard/disconnect]]
|
||||
[:dispatch [:open-modal :screen/keycard.empty]]]}
|
||||
{:db (assoc-in db [:keycard :application-info-error] error)
|
||||
:fx [[:dispatch [:keycard/disconnect]]
|
||||
[:dispatch [:open-modal :screen/keycard.error]]]})
|
||||
{:db (-> db
|
||||
(assoc-in [:keycard :application-info] application-info)
|
||||
(assoc-in [:keycard :pin :status] :verifying))
|
||||
:fx on-success-fx})))
|
||||
|
||||
(rf/reg-event-fx :keycard/get-application-info
|
||||
(fn [_ [{:keys [on-success on-failure]}]]
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [profile-name (rf/sub [:profile/name])
|
||||
profile-picture (rf/sub [:profile/image])
|
||||
customization-color (rf/sub [:profile/customization-color])]
|
||||
(let [profile-name (rf/sub [:profile/name])
|
||||
profile-picture (rf/sub [:profile/image])
|
||||
customization-color (rf/sub [:profile/customization-color])
|
||||
recovery-phrase-backed-up? (rf/sub [:profile/recovery-phrase-backed-up?])]
|
||||
[:<>
|
||||
[quo/drawer-top
|
||||
{:type :context-tag
|
||||
@@ -27,7 +28,11 @@
|
||||
[quo/bottom-actions
|
||||
{:actions :two-actions
|
||||
:button-one-label (i18n/label :t/continue)
|
||||
:button-one-props {:on-press #()}
|
||||
:button-one-props {:on-press #(if recovery-phrase-backed-up?
|
||||
(rf/dispatch [:open-modal :screen/use-recovery-phrase
|
||||
{:on-success (fn [])}])
|
||||
(rf/dispatch [:open-modal :screen/backup-recovery-phrase
|
||||
{:on-success (fn [])}]))}
|
||||
:button-two-label (i18n/label :t/cancel)
|
||||
:button-two-props {:type :grey
|
||||
:on-press #(rf/dispatch [:hide-bottom-sheet])}}]]))
|
||||
|
||||
@@ -131,15 +131,6 @@
|
||||
[:open-modal :screen/onboarding.enable-biometrics]
|
||||
[:open-modal :screen/onboarding.enable-notifications])}))
|
||||
|
||||
(rf/defn seed-phrase-entered
|
||||
{:events [:onboarding/seed-phrase-entered]}
|
||||
[_ seed-phrase on-error]
|
||||
{:multiaccount/validate-mnemonic [seed-phrase
|
||||
(fn [mnemonic key-uid]
|
||||
(re-frame/dispatch [:onboarding/seed-phrase-validated
|
||||
mnemonic key-uid]))
|
||||
on-error]})
|
||||
|
||||
(rf/defn seed-phrase-validated
|
||||
{:events [:onboarding/seed-phrase-validated]}
|
||||
[{:keys [db]} seed-phrase key-uid]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns status-im.contexts.onboarding.syncing.progress.style
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]))
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.safe-area :as safe-area]))
|
||||
|
||||
(def absolute-fill
|
||||
{:position :absolute
|
||||
@@ -17,6 +18,7 @@
|
||||
:bottom 0
|
||||
:left 0
|
||||
:right 0
|
||||
:padding-top (safe-area/get-top)
|
||||
:padding-bottom 20
|
||||
:background-color (when-not in-onboarding? colors/neutral-80-opa-80-blur)})
|
||||
|
||||
|
||||
@@ -15,16 +15,14 @@
|
||||
|
||||
(defn page-title
|
||||
[pairing-progress?]
|
||||
[quo/text-combinations
|
||||
{:container-style {:margin-top 56 :margin-horizontal 20}
|
||||
:title (i18n/label (if pairing-progress?
|
||||
:t/sync-devices-title
|
||||
:t/sync-devices-error-title))
|
||||
:description (i18n/label (if pairing-progress?
|
||||
:t/sync-devices-sub-title
|
||||
:t/sync-devices-error-sub-title))
|
||||
:title-accessibility-label :progress-screen-title
|
||||
:description-accessibility-label :progress-screen-sub-title}])
|
||||
[quo/page-top
|
||||
{:title (i18n/label (if pairing-progress?
|
||||
:t/sync-devices-title
|
||||
:t/sync-devices-error-title))
|
||||
:description :text
|
||||
:description-text (i18n/label (if pairing-progress?
|
||||
:t/sync-devices-sub-title
|
||||
:t/sync-devices-error-sub-title))}])
|
||||
|
||||
(defn- navigate-to-enter-seed-phrase
|
||||
[]
|
||||
@@ -42,32 +40,41 @@
|
||||
|
||||
(defn try-again-button
|
||||
[profile-color logged-in?]
|
||||
[quo/bottom-actions
|
||||
{:actions (if logged-in? :one-action :two-actions)
|
||||
:blur? true
|
||||
:button-one-label (i18n/label :t/recovery-phrase)
|
||||
:button-one-props {:type :primary
|
||||
:accessibility-label :try-seed-phrase-button
|
||||
:customization-color profile-color
|
||||
:container-style {:flex 1}
|
||||
:size 40
|
||||
:on-press navigate-to-enter-seed-phrase}
|
||||
(if logged-in? :button-one-label :button-two-label)
|
||||
(i18n/label :t/try-again)
|
||||
(if logged-in? :button-one-props :button-two-props)
|
||||
{:type (if logged-in? :primary :grey)
|
||||
:accessibility-label :try-again-later-button
|
||||
:customization-color profile-color
|
||||
:container-style {:flex 1}
|
||||
:size 40
|
||||
:on-press #(try-again logged-in?)}}])
|
||||
(let [number-of-actions (if logged-in? :one-action :two-actions)
|
||||
try-again-label (i18n/label :t/try-again)
|
||||
try-again-props {:type (if logged-in? :primary :grey)
|
||||
:accessibility-label :try-again-later-button
|
||||
:customization-color profile-color
|
||||
:container-style {:flex 1}
|
||||
:size 40
|
||||
:on-press #(try-again logged-in?)}
|
||||
recovery-phrase-label (i18n/label :t/recovery-phrase)
|
||||
recovery-phrase-props {:type :primary
|
||||
:accessibility-label :try-seed-phrase-button
|
||||
:customization-color profile-color
|
||||
:container-style {:flex 1}
|
||||
:size 40
|
||||
:on-press navigate-to-enter-seed-phrase}
|
||||
buttons (if logged-in?
|
||||
{:button-one-label try-again-label
|
||||
:button-one-props try-again-props}
|
||||
{:button-one-label recovery-phrase-label
|
||||
:button-one-props recovery-phrase-props
|
||||
:button-two-label try-again-label
|
||||
:button-two-props try-again-props})]
|
||||
[quo/bottom-actions
|
||||
(assoc buttons
|
||||
:actions number-of-actions
|
||||
:blur? true)]))
|
||||
|
||||
(defn- illustration
|
||||
[pairing-progress?]
|
||||
[rn/image
|
||||
{:resize-mode :contain
|
||||
:style (style/page-illustration (:width (rn/get-window)))
|
||||
:source (resources/get-image (if pairing-progress? :syncing-devices :syncing-wrong))}])
|
||||
:source (resources/get-image (if pairing-progress?
|
||||
:syncing-devices
|
||||
:syncing-wrong))}])
|
||||
|
||||
(defn view
|
||||
[in-onboarding?]
|
||||
@@ -83,7 +90,7 @@
|
||||
[quo/page-nav {:type :no-title :background :blur}]
|
||||
[page-title pairing-progress?]
|
||||
[illustration pairing-progress?]
|
||||
(when-not (pairing-progress pairing-status)
|
||||
(when-not pairing-progress?
|
||||
[try-again-button profile-color logged-in?])]))
|
||||
|
||||
(defn view-onboarding
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
:title "floating button page"
|
||||
:description "press right icon to swap button type"
|
||||
:text-align :left
|
||||
:right-side [{:icon-name :i/swap
|
||||
:right-side [{:icon-name :i/transaction
|
||||
:on-press #(swap! slide? not)}]
|
||||
:background :blur
|
||||
:icon-name :i/close
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
(ns status-im.contexts.wallet.add-account.create-account.new-keypair.backup-recovery-phrase.style
|
||||
(ns status-im.contexts.profile.backup-recovery-phrase.style
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.platform :as platform]))
|
||||
+18
-19
@@ -1,4 +1,4 @@
|
||||
(ns status-im.contexts.wallet.add-account.create-account.new-keypair.backup-recovery-phrase.view
|
||||
(ns status-im.contexts.profile.backup-recovery-phrase.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[native-module.core :as native-module]
|
||||
@@ -6,8 +6,7 @@
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.contexts.wallet.add-account.create-account.new-keypair.backup-recovery-phrase.style :as
|
||||
style]
|
||||
[status-im.contexts.profile.backup-recovery-phrase.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
@@ -45,20 +44,20 @@
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [step-labels [:t/backup-step-1 :t/backup-step-2 :t/backup-step-3
|
||||
:t/backup-step-4]
|
||||
checked? (reagent/atom
|
||||
{:0 false
|
||||
:1 false
|
||||
:2 false
|
||||
:3 false})
|
||||
revealed? (reagent/atom false)
|
||||
customization-color (rf/sub [:profile/customization-color])
|
||||
seed-phrase (reagent/atom [])
|
||||
random-phrase (reagent/atom [])]
|
||||
(let [step-labels [:t/backup-step-1 :t/backup-step-2 :t/backup-step-3
|
||||
:t/backup-step-4]
|
||||
checked? (reagent/atom
|
||||
{:0 false
|
||||
:1 false
|
||||
:2 false
|
||||
:3 false})
|
||||
revealed? (reagent/atom false)
|
||||
customization-color (rf/sub [:profile/customization-color])
|
||||
{:keys [on-success]} (rf/sub [:get-screen-params])
|
||||
seed-phrase (reagent/atom [])
|
||||
random-phrase (reagent/atom [])]
|
||||
(fn []
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
|
||||
(rn/use-mount
|
||||
(fn []
|
||||
(native-module/get-random-mnemonic #(reset! seed-phrase (string/split % #"\s")))
|
||||
@@ -107,10 +106,10 @@
|
||||
:button-one-label (i18n/label :t/i-have-written)
|
||||
:button-one-props {:disabled? (some false? (vals @checked?))
|
||||
:customization-color customization-color
|
||||
:on-press #(rf/dispatch [:wallet/store-new-seed-phrase
|
||||
{:seed-phrase (security/mask-data
|
||||
@seed-phrase)
|
||||
:random-phrase @random-phrase}])}}]
|
||||
:on-press #(on-success {:masked-seed-phrase
|
||||
(security/mask-data
|
||||
@seed-phrase)
|
||||
:random-phrase @random-phrase})}}]
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:style (style/description-text theme)}
|
||||
@@ -1,9 +1,31 @@
|
||||
(ns status-im.contexts.profile.recover.effects
|
||||
(:require
|
||||
[native-module.core :as native-module]
|
||||
[utils.re-frame :as rf]))
|
||||
[promesa.core :as promesa]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]
|
||||
[utils.transforms :as transforms]))
|
||||
|
||||
(rf/reg-fx :effects.profile/restore-and-login
|
||||
(fn [request]
|
||||
;;"node.login" signal will be triggered as a callback
|
||||
(native-module/restore-account-and-login request)))
|
||||
|
||||
(defn validate-mnemonic
|
||||
[mnemonic]
|
||||
(-> mnemonic
|
||||
(security/safe-unmask-data)
|
||||
(native-module/validate-mnemonic)
|
||||
(promesa/then (fn [result]
|
||||
(let [{:keys [keyUID]} (transforms/json->clj result)]
|
||||
{:key-uid keyUID})))))
|
||||
|
||||
(rf/reg-fx :effects.profile/validate-recovery-phrase
|
||||
(fn [[mnemonic on-success on-error]]
|
||||
(-> (validate-mnemonic mnemonic)
|
||||
(promesa/then (fn [{:keys [key-uid]}]
|
||||
(when (fn? on-success)
|
||||
(on-success mnemonic key-uid))))
|
||||
(promesa/catch (fn [error]
|
||||
(when (and error (fn? on-error))
|
||||
(on-error error)))))))
|
||||
|
||||
@@ -24,3 +24,7 @@
|
||||
:imagePath (profile.config/strip-file-prefix image-path)
|
||||
:customizationColor (or color constants/profile-default-color)
|
||||
:fetchBackup true)}))
|
||||
|
||||
(rf/reg-event-fx :profile.recover/validate-recovery-phrase
|
||||
(fn [_ [phrase {:keys [on-success on-error]}]]
|
||||
{:effects.profile/validate-recovery-phrase [phrase on-success on-error]}))
|
||||
|
||||
@@ -49,13 +49,14 @@
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
insets (safe-area/get-insets)
|
||||
customization-color (rf/sub [:profile/customization-color])
|
||||
scroll-y (reanimated/use-shared-value 0)
|
||||
profile (rf/sub [:profile/profile])
|
||||
full-name (profile.utils/displayed-name profile)
|
||||
on-scroll (rn/use-callback #(scroll-handler % scroll-y))]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
insets (safe-area/get-insets)
|
||||
customization-color (rf/sub [:profile/customization-color])
|
||||
scroll-y (reanimated/use-shared-value 0)
|
||||
profile (rf/sub [:profile/profile])
|
||||
recovery-phrase-backed-up? (rf/sub [:profile/recovery-phrase-backed-up?])
|
||||
full-name (profile.utils/displayed-name profile)
|
||||
on-scroll (rn/use-callback #(scroll-handler % scroll-y))]
|
||||
[quo/overlay {:type :shell}
|
||||
[rn/view
|
||||
{:style (style/navigation-wrapper {:customization-color customization-color
|
||||
@@ -79,7 +80,7 @@
|
||||
profile)}}])}]}]]
|
||||
[rn/flat-list
|
||||
{:header [settings.header/view {:scroll-y scroll-y}]
|
||||
:data (settings.items/items (boolean (seq (:mnemonic profile))))
|
||||
:data (settings.items/items (not recovery-phrase-backed-up?))
|
||||
:shows-vertical-scroll-indicator false
|
||||
:render-fn settings-category-view
|
||||
:get-item-layout get-item-layout
|
||||
|
||||
@@ -160,7 +160,7 @@
|
||||
|
||||
(defn wallet-validate-seed-phrase
|
||||
[_ [seed-phrase on-success on-error]]
|
||||
{:fx [[:multiaccount/validate-mnemonic [seed-phrase on-success on-error]]]})
|
||||
{:fx [[:effects.profile/validate-recovery-phrase [seed-phrase on-success on-error]]]})
|
||||
|
||||
(rf/reg-event-fx :wallet/validate-seed-phrase wallet-validate-seed-phrase)
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
seed-phrase-masked (security/mask-data "seed phrase")
|
||||
on-success #(prn "success")
|
||||
on-error #(prn "error")
|
||||
expected {:fx [[:multiaccount/validate-mnemonic
|
||||
expected {:fx [[:effects.profile/validate-recovery-phrase
|
||||
[seed-phrase-masked on-success on-error]]]}]
|
||||
(is (= expected
|
||||
(sut/wallet-validate-seed-phrase
|
||||
|
||||
+5
-8
@@ -6,24 +6,21 @@
|
||||
[react-native.platform :as platform]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.settings.wallet.saved-addresses.sheets.remove-address.view :as remove-address]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.common.utils.networks :as network-utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn view
|
||||
[{:keys [name full-address chain-short-names address] :as opts}]
|
||||
(let [[_ splitted-address] (network-utils/split-network-full-address address)
|
||||
open-send-flow (rn/use-callback
|
||||
[{:keys [name full-address chain-short-names address customization-color] :as opts}]
|
||||
(let [open-send-flow (rn/use-callback
|
||||
(fn []
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(rf/dispatch [:pop-to-root :shell-stack])
|
||||
(js/setTimeout #(rf/dispatch [:wallet/select-send-address
|
||||
{:address full-address
|
||||
:recipient
|
||||
{:label
|
||||
(utils/get-shortened-address
|
||||
splitted-address)
|
||||
{:label name
|
||||
:customization-color
|
||||
customization-color
|
||||
:recipient-type :saved-address}
|
||||
:stack-id :wallet-select-address
|
||||
:start-flow? true}])
|
||||
|
||||
@@ -61,16 +61,6 @@
|
||||
|
||||
(rf/reg-event-fx :wallet/seed-phrase-validated seed-phrase-validated)
|
||||
|
||||
(defn seed-phrase-entered
|
||||
[_ [seed-phrase on-error]]
|
||||
{:fx [[:multiaccount/validate-mnemonic
|
||||
[seed-phrase
|
||||
(fn [mnemonic key-uid]
|
||||
(rf/dispatch [:wallet/seed-phrase-validated mnemonic key-uid on-error]))
|
||||
on-error]]]})
|
||||
|
||||
(rf/reg-event-fx :wallet/seed-phrase-entered seed-phrase-entered)
|
||||
|
||||
(defn store-account-generated-with-mnemonic
|
||||
[{:keys [db]} [{:keys [new-account-data keypair-name]}]]
|
||||
(let [new-account (update new-account-data :mnemonic security/mask-data)]
|
||||
|
||||
@@ -16,13 +16,21 @@
|
||||
[[{:icon :i/add
|
||||
:accessibility-label :generate-new-keypair
|
||||
:label (i18n/label :t/generate-new-keypair)
|
||||
:on-press #(rf/dispatch [:navigate-to :screen/wallet.backup-recovery-phrase])}
|
||||
:on-press #(rf/dispatch [:navigate-to :screen/backup-recovery-phrase
|
||||
{:on-success (fn [{:keys [masked-seed-phrase random-phrase]}]
|
||||
(rf/dispatch [:wallet/store-new-seed-phrase
|
||||
{:seed-phrase masked-seed-phrase
|
||||
:random-phrase
|
||||
random-phrase}]))}])}
|
||||
{:icon :i/seed
|
||||
:accessibility-label :import-using-phrase
|
||||
:label (i18n/label :t/import-using-phrase)
|
||||
:add-divider? true
|
||||
:on-press #(rf/dispatch [:navigate-to :screen/wallet.enter-seed-phrase
|
||||
{:recovering-keypair? true}])}
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:navigate-to :screen/use-recovery-phrase
|
||||
{:on-success (fn [{:keys [key-uid phrase on-error]}]
|
||||
(rf/dispatch [:wallet/seed-phrase-validated
|
||||
phrase key-uid on-error]))}]))}
|
||||
(when (ff/enabled? ::ff/wallet.import-private-key)
|
||||
{:icon :i/key
|
||||
:accessibility-label :import-private-key
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
(defn- action-swap
|
||||
[{:keys [token asset-to-receive token-symbol testnet-mode?]}]
|
||||
{:icon :i/swap
|
||||
{:icon :i/transaction
|
||||
:accessibility-label :swap
|
||||
:label (i18n/label :t/swap)
|
||||
:disabled? testnet-mode?
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
[native-module.core :as native-module]
|
||||
[promesa.core :as promesa]
|
||||
[status-im.common.json-rpc.events :as json-rpc]
|
||||
[status-im.contexts.profile.recover.effects :as profile.recover.effects]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]
|
||||
@@ -26,26 +27,6 @@
|
||||
:paths paths}
|
||||
on-success))))
|
||||
|
||||
(defn validate-mnemonic
|
||||
[mnemonic]
|
||||
(-> mnemonic
|
||||
(security/safe-unmask-data)
|
||||
(native-module/validate-mnemonic)
|
||||
(promesa/then (fn [result]
|
||||
(let [{:keys [keyUID]} (transforms/json->clj result)]
|
||||
{:key-uid keyUID})))))
|
||||
|
||||
(rf/reg-fx
|
||||
:multiaccount/validate-mnemonic
|
||||
(fn [[mnemonic on-success on-error]]
|
||||
(-> (validate-mnemonic mnemonic)
|
||||
(promesa/then (fn [{:keys [key-uid]}]
|
||||
(when (fn? on-success)
|
||||
(on-success mnemonic key-uid))))
|
||||
(promesa/catch (fn [error]
|
||||
(when (and error (fn? on-error))
|
||||
(on-error error)))))))
|
||||
|
||||
(defn create-account-from-private-key
|
||||
[private-key]
|
||||
(-> private-key
|
||||
@@ -81,7 +62,7 @@
|
||||
|
||||
(defn import-missing-keypair-by-seed-phrase
|
||||
[keypair-key-uid seed-phrase password]
|
||||
(-> (validate-mnemonic seed-phrase)
|
||||
(-> (profile.recover.effects/validate-mnemonic seed-phrase)
|
||||
(promesa/then
|
||||
(fn [{:keys [key-uid]}]
|
||||
(if (not= keypair-key-uid key-uid)
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
[status-im.common.refreshable-flat-list.view :as refreshable-flat-list]
|
||||
[status-im.contexts.wallet.home.style :as style]
|
||||
[status-im.contexts.wallet.home.tabs.view :as tabs]
|
||||
[status-im.contexts.wallet.send.transaction-details.view :as transaction-details]
|
||||
[status-im.contexts.wallet.sheets.network-filter.view :as network-filter]
|
||||
[status-im.feature-flags :as ff]
|
||||
[utils.i18n :as i18n]
|
||||
@@ -94,18 +93,14 @@
|
||||
:tint-color colors/neutral-40
|
||||
:on-refresh #(rf/dispatch [:wallet/get-accounts])}]
|
||||
:header [rn/view {:style (style/header-container theme)}
|
||||
[rn/pressable
|
||||
{:on-press #(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content transaction-details/sheet}])}
|
||||
[quo/wallet-overview
|
||||
{:state (if tokens-loading? :loading :default)
|
||||
:time-frame :none
|
||||
:metrics :none
|
||||
:balance formatted-balance
|
||||
:networks networks
|
||||
:dropdown-on-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content network-filter/view}])}]]
|
||||
[quo/wallet-overview
|
||||
{:state (if tokens-loading? :loading :default)
|
||||
:time-frame :none
|
||||
:metrics :none
|
||||
:balance formatted-balance
|
||||
:networks networks
|
||||
:dropdown-on-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content network-filter/view}])}]
|
||||
(when (ff/enabled? ::ff/wallet.graph)
|
||||
[quo/wallet-graph {:time-frame :empty}])
|
||||
[render-cards cards account-list-ref]
|
||||
|
||||
@@ -28,95 +28,108 @@
|
||||
{:fx [[:dispatch [:wallet/stop-get-suggested-routes]]
|
||||
[:dispatch [:wallet/clean-suggested-routes]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/suggested-routes-success
|
||||
(fn [{:keys [db]} [suggested-routes-data]]
|
||||
(let [chosen-route (:best suggested-routes-data)
|
||||
{:keys [token collectible token-display-name
|
||||
receiver-networks
|
||||
receiver-network-values
|
||||
sender-network-values tx-type
|
||||
disabled-from-chain-ids
|
||||
from-locked-amounts]} (get-in db [:wallet :ui :send])
|
||||
token-decimals (if collectible 0 (:decimals token))
|
||||
native-token? (and token (= token-display-name "ETH"))
|
||||
routes-available? (pos? (count chosen-route))
|
||||
token-networks (:networks token)
|
||||
token-networks-ids (when token-networks
|
||||
(map #(:chain-id %) token-networks))
|
||||
from-network-amounts-by-chain (send-utils/network-amounts-by-chain
|
||||
{:route chosen-route
|
||||
:token-decimals token-decimals
|
||||
:native-token? native-token?
|
||||
:receiver? false})
|
||||
to-network-amounts-by-chain (send-utils/network-amounts-by-chain
|
||||
{:route chosen-route
|
||||
:token-decimals token-decimals
|
||||
:native-token? native-token?
|
||||
:receiver? true})
|
||||
sender-possible-chain-ids (map :chain-id sender-network-values)
|
||||
sender-network-values (if routes-available?
|
||||
(send-utils/network-amounts
|
||||
{:network-values
|
||||
(if (= tx-type :tx/bridge)
|
||||
from-network-amounts-by-chain
|
||||
(send-utils/add-zero-values-to-network-values
|
||||
from-network-amounts-by-chain
|
||||
sender-possible-chain-ids))
|
||||
:disabled-chain-ids disabled-from-chain-ids
|
||||
:receiver-networks receiver-networks
|
||||
:token-networks-ids token-networks-ids
|
||||
:from-locked-amounts from-locked-amounts
|
||||
:tx-type tx-type
|
||||
:receiver? false})
|
||||
(send-utils/reset-loading-network-amounts-to-zero
|
||||
sender-network-values))
|
||||
receiver-network-values (if routes-available?
|
||||
(send-utils/network-amounts
|
||||
{:network-values to-network-amounts-by-chain
|
||||
:disabled-chain-ids disabled-from-chain-ids
|
||||
:receiver-networks receiver-networks
|
||||
:token-networks-ids token-networks-ids
|
||||
:tx-type tx-type
|
||||
:receiver? true})
|
||||
(cond->
|
||||
(defn- add-not-enough-assets-data
|
||||
[send-data chosen-route]
|
||||
(-> send-data
|
||||
(assoc :route chosen-route
|
||||
:loading-suggested-routes? false
|
||||
:suggested-routes {:best []}
|
||||
:enough-assets? false)
|
||||
(update :sender-network-values send-utils/reset-loading-network-amounts-to-zero)
|
||||
(update :receiver-network-values send-utils/reset-loading-network-amounts-to-zero)))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/suggested-routes-success
|
||||
(fn [{:keys [db]} [suggested-routes-data enough-assets?]]
|
||||
(if-not enough-assets?
|
||||
{:db (update-in db [:wallet :ui :send] add-not-enough-assets-data (:best suggested-routes-data))}
|
||||
(let [chosen-route (:best suggested-routes-data)
|
||||
{:keys [token collectible token-display-name
|
||||
receiver-networks
|
||||
receiver-network-values
|
||||
sender-network-values tx-type
|
||||
disabled-from-chain-ids
|
||||
from-locked-amounts]} (get-in db [:wallet :ui :send])
|
||||
token-decimals (if collectible 0 (:decimals token))
|
||||
native-token? (and token (= token-display-name "ETH"))
|
||||
routes-available? (pos? (count chosen-route))
|
||||
token-networks (:networks token)
|
||||
token-networks-ids (when token-networks
|
||||
(map #(:chain-id %) token-networks))
|
||||
from-network-amounts-by-chain (send-utils/network-amounts-by-chain
|
||||
{:route chosen-route
|
||||
:token-decimals token-decimals
|
||||
:native-token? native-token?
|
||||
:receiver? false})
|
||||
to-network-amounts-by-chain (send-utils/network-amounts-by-chain
|
||||
{:route chosen-route
|
||||
:token-decimals token-decimals
|
||||
:native-token? native-token?
|
||||
:receiver? true})
|
||||
sender-possible-chain-ids (map :chain-id sender-network-values)
|
||||
sender-network-values (if routes-available?
|
||||
(send-utils/network-amounts
|
||||
{:network-values
|
||||
(if (= tx-type :tx/bridge)
|
||||
from-network-amounts-by-chain
|
||||
(send-utils/add-zero-values-to-network-values
|
||||
from-network-amounts-by-chain
|
||||
sender-possible-chain-ids))
|
||||
:disabled-chain-ids disabled-from-chain-ids
|
||||
:receiver-networks receiver-networks
|
||||
:token-networks-ids token-networks-ids
|
||||
:from-locked-amounts from-locked-amounts
|
||||
:tx-type tx-type
|
||||
:receiver? false})
|
||||
(send-utils/reset-loading-network-amounts-to-zero
|
||||
receiver-network-values)
|
||||
sender-network-values))
|
||||
receiver-network-values (if routes-available?
|
||||
(send-utils/network-amounts
|
||||
{:network-values to-network-amounts-by-chain
|
||||
:disabled-chain-ids disabled-from-chain-ids
|
||||
:receiver-networks receiver-networks
|
||||
:token-networks-ids token-networks-ids
|
||||
:tx-type tx-type
|
||||
:receiver? true})
|
||||
(cond->
|
||||
(send-utils/reset-loading-network-amounts-to-zero
|
||||
receiver-network-values)
|
||||
|
||||
(not= tx-type :tx/bridge)
|
||||
send-utils/safe-add-type-edit))
|
||||
network-links (when routes-available?
|
||||
(send-utils/network-links chosen-route
|
||||
sender-network-values
|
||||
receiver-network-values))]
|
||||
{:db (update-in db
|
||||
[:wallet :ui :send]
|
||||
assoc
|
||||
:suggested-routes suggested-routes-data
|
||||
:route chosen-route
|
||||
:from-values-by-chain from-network-amounts-by-chain
|
||||
:to-values-by-chain to-network-amounts-by-chain
|
||||
:sender-network-values sender-network-values
|
||||
:receiver-network-values receiver-network-values
|
||||
:network-links network-links
|
||||
:loading-suggested-routes? false)})))
|
||||
(not= tx-type :tx/bridge)
|
||||
send-utils/safe-add-type-edit))
|
||||
network-links (when routes-available?
|
||||
(send-utils/network-links chosen-route
|
||||
sender-network-values
|
||||
receiver-network-values))]
|
||||
{:db (update-in db
|
||||
[:wallet :ui :send]
|
||||
assoc
|
||||
:suggested-routes suggested-routes-data
|
||||
:route chosen-route
|
||||
:from-values-by-chain from-network-amounts-by-chain
|
||||
:to-values-by-chain to-network-amounts-by-chain
|
||||
:sender-network-values sender-network-values
|
||||
:receiver-network-values receiver-network-values
|
||||
:network-links network-links
|
||||
:loading-suggested-routes? false
|
||||
:enough-assets? true)}))))
|
||||
|
||||
(rf/reg-event-fx :wallet/suggested-routes-error
|
||||
(rf/reg-event-fx
|
||||
:wallet/suggested-routes-error
|
||||
(fn [{:keys [db]} [error-message]]
|
||||
(let [cleaned-sender-network-values (-> (get-in db [:wallet :ui :send :sender-network-values])
|
||||
(send-utils/reset-loading-network-amounts-to-zero))
|
||||
cleaned-receiver-network-values (-> (get-in db [:wallet :ui :send :receiver-network-values])
|
||||
(send-utils/reset-loading-network-amounts-to-zero))]
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :route)
|
||||
(assoc-in [:wallet :ui :send :sender-network-values] cleaned-sender-network-values)
|
||||
(assoc-in [:wallet :ui :send :receiver-network-values] cleaned-receiver-network-values)
|
||||
(assoc-in [:wallet :ui :send :loading-suggested-routes?] false)
|
||||
(assoc-in [:wallet :ui :send :suggested-routes] {:best []}))
|
||||
:fx [[:dispatch
|
||||
[:toasts/upsert
|
||||
{:id :send-transaction-error
|
||||
:type :negative
|
||||
:text error-message}]]]})))
|
||||
{:db (-> db
|
||||
(update-in [:wallet :ui :send] dissoc :route)
|
||||
(update-in [:wallet :ui :send :sender-network-values]
|
||||
send-utils/reset-loading-network-amounts-to-zero)
|
||||
(update-in [:wallet :ui :send :receiver-network-values]
|
||||
send-utils/reset-loading-network-amounts-to-zero)
|
||||
(assoc-in [:wallet :ui :send :loading-suggested-routes?] false)
|
||||
(assoc-in [:wallet :ui :send :suggested-routes] {:best []}))
|
||||
:fx [[:dispatch
|
||||
[:toasts/upsert
|
||||
{:id :send-transaction-error
|
||||
:type :negative
|
||||
:text error-message}]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/clean-send-address
|
||||
(fn [{:keys [db]}]
|
||||
@@ -378,8 +391,7 @@
|
||||
from-locked-amounts bridge-to-chain-id]
|
||||
:or {token updated-token}} (get-in db [:wallet :ui :send])
|
||||
test-networks-enabled? (get-in db [:profile/profile :test-networks-enabled?])
|
||||
networks ((if test-networks-enabled? :test :prod)
|
||||
(get-in db [:wallet :networks]))
|
||||
networks (get-in db [:wallet :networks (if test-networks-enabled? :test :prod)])
|
||||
network-chain-ids (map :chain-id networks)
|
||||
token-decimal (when token (:decimals token))
|
||||
token-id (utils/format-token-id token collectible)
|
||||
@@ -509,40 +521,43 @@
|
||||
[routes]
|
||||
(map data-store/new->old-route-path routes))
|
||||
|
||||
(def ^:private best-routes-fix
|
||||
(comp ->old-route-paths
|
||||
remove-invalid-bonder-fees-routes
|
||||
remove-multichain-routes))
|
||||
|
||||
(def ^:private candidates-fix
|
||||
(comp ->old-route-paths remove-invalid-bonder-fees-routes))
|
||||
|
||||
(defn- fix-routes
|
||||
[data]
|
||||
(-> data
|
||||
(data-store/rpc->suggested-routes)
|
||||
(update :best best-routes-fix)
|
||||
(update :candidates candidates-fix)))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/handle-suggested-routes
|
||||
(fn [{:keys [db]} [data]]
|
||||
(let [swap? (get-in db [:wallet :ui :swap])
|
||||
{:keys [code details] :as error-response} (-> data :ErrorResponse)
|
||||
skip-processing-suggested-routes? (get-in db
|
||||
[:wallet :ui :send
|
||||
:skip-processing-suggested-routes?])
|
||||
process-response? (and (not swap?)
|
||||
(not skip-processing-suggested-routes?))]
|
||||
(if (and (not swap?) error-response)
|
||||
(let [error-message (if (= code "0") "An error occurred" details)]
|
||||
(log/error "failed to get suggested routes (async)"
|
||||
{:event :wallet/handle-suggested-routes
|
||||
:error error-message})
|
||||
{:fx [(cond
|
||||
swap?
|
||||
[:dispatch [:wallet/swap-proposal-error error-message]]
|
||||
process-response?
|
||||
[:dispatch [:wallet/suggested-routes-error error-message]])]})
|
||||
(let [best-routes-fix (comp ->old-route-paths
|
||||
remove-invalid-bonder-fees-routes
|
||||
remove-multichain-routes)
|
||||
candidates-fix (comp ->old-route-paths
|
||||
remove-invalid-bonder-fees-routes)
|
||||
routes (-> data
|
||||
(data-store/rpc->suggested-routes)
|
||||
(update :best best-routes-fix)
|
||||
(update :candidates candidates-fix))]
|
||||
{:fx [(cond
|
||||
swap?
|
||||
[:dispatch [:wallet/swap-proposal-success routes]]
|
||||
process-response?
|
||||
[:dispatch [:wallet/suggested-routes-success routes]])]})))))
|
||||
(let [{send :send swap? :swap} (-> db :wallet :ui)
|
||||
skip-processing-routes? (:skip-processing-suggested-routes? send)]
|
||||
(when (or swap? (not skip-processing-routes?))
|
||||
(let [{error-code :code
|
||||
:as error} (:ErrorResponse data)
|
||||
enough-assets? (not (and (:Best data) (= error-code "WR-002")))
|
||||
failure? (and error enough-assets? (not swap?))
|
||||
error-message (if (zero? error-code) "An error occurred" (:details error))]
|
||||
(when failure?
|
||||
(log/error "failed to get suggested routes (async)"
|
||||
{:event :wallet/handle-suggested-routes
|
||||
:error error-message}))
|
||||
{:fx [[:dispatch
|
||||
(cond
|
||||
(and failure? swap?) [:wallet/swap-proposal-error error-message]
|
||||
failure? [:wallet/suggested-routes-error error-message]
|
||||
swap? [:wallet/swap-proposal-success (fix-routes data)]
|
||||
:else [:wallet/suggested-routes-success (fix-routes data)
|
||||
enough-assets?])]]})))))
|
||||
|
||||
(rf/reg-event-fx :wallet/add-authorized-transaction
|
||||
(fn [{:keys [db]} [transaction]]
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
:mixedcase-address "0x7bcDfc75c431"
|
||||
:public-key "0x04371e2d9d66b82f056bc128064"
|
||||
: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"
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
[quo/alert-banner
|
||||
{:action? true
|
||||
:text (i18n/label :t/not-enough-assets-to-pay-gas-fees)
|
||||
:button-text (i18n/label :t/buy-eth)
|
||||
:button-text (i18n/label :t/add-eth)
|
||||
:on-button-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content buy-token/view}])}])
|
||||
|
||||
@@ -140,6 +140,26 @@
|
||||
|
||||
:else (rf/dispatch [:wallet/stop-and-clean-suggested-routes])))
|
||||
|
||||
(defn- get-fee-formatted
|
||||
[route]
|
||||
(when-let [native-currency-symbol (-> route first :from :native-currency-symbol)]
|
||||
(rf/sub [:wallet/wallet-send-fee-fiat-formatted native-currency-symbol])))
|
||||
|
||||
(defn- insufficient-asset-amount?
|
||||
[{:keys [token-symbol owned-eth-token input-state no-routes-found? limit-exceeded?
|
||||
sender-network-values enough-assets?]}]
|
||||
(let [eth-selected? (= token-symbol (string/upper-case constants/mainnet-short-name))
|
||||
zero-owned-eth? (money/equal-to (:total-balance owned-eth-token) 0)
|
||||
input-at-max-owned-amount? (money/equal-to
|
||||
(controlled-input/value-bn input-state)
|
||||
(controlled-input/upper-limit-bn input-state))
|
||||
exceeded-input? (if eth-selected?
|
||||
input-at-max-owned-amount?
|
||||
zero-owned-eth?)]
|
||||
(and (or no-routes-found? limit-exceeded?)
|
||||
(seq sender-network-values)
|
||||
(or exceeded-input? (not enough-assets?)))))
|
||||
|
||||
(defn view
|
||||
;; crypto-decimals, limit-crypto and initial-crypto-currency? args are needed
|
||||
;; for component tests only
|
||||
@@ -154,143 +174,129 @@
|
||||
enabled-from-chain-ids :enabled-from-chain-ids
|
||||
from-enabled-networks :from-enabled-networks
|
||||
:or {initial-crypto-currency? true}}]
|
||||
(let [view-id (rf/sub [:view-id])
|
||||
active-screen? (= view-id current-screen-id)
|
||||
bottom (safe-area/get-bottom)
|
||||
[crypto-currency? set-crypto-currency] (rn/use-state initial-crypto-currency?)
|
||||
handle-on-confirm (fn [amount]
|
||||
(rf/dispatch [:wallet/set-token-amount-to-send
|
||||
{:amount amount
|
||||
:stack-id current-screen-id}]))
|
||||
{fiat-currency :currency} (rf/sub [:profile/profile])
|
||||
(let [view-id (rf/sub [:view-id])
|
||||
active-screen? (= view-id current-screen-id)
|
||||
bottom (safe-area/get-bottom)
|
||||
[crypto-currency?
|
||||
set-crypto-currency] (rn/use-state initial-crypto-currency?)
|
||||
handle-on-confirm (fn [amount]
|
||||
(rf/dispatch [:wallet/set-token-amount-to-send
|
||||
{:amount amount
|
||||
:stack-id current-screen-id}]))
|
||||
{fiat-currency :currency} (rf/sub [:profile/profile])
|
||||
{token-symbol :symbol
|
||||
token-networks :networks
|
||||
:as token} (rf/sub [:wallet/wallet-send-token])
|
||||
send-from-locked-amounts (rf/sub [:wallet/wallet-send-from-locked-amounts])
|
||||
:as token} (rf/sub [:wallet/wallet-send-token])
|
||||
send-from-locked-amounts (rf/sub [:wallet/wallet-send-from-locked-amounts])
|
||||
{:keys [total-balance]
|
||||
:as token-by-symbol} (rf/sub [:wallet/token-by-symbol
|
||||
(str token-symbol)
|
||||
enabled-from-chain-ids])
|
||||
token-balance (or default-limit-crypto total-balance)
|
||||
usd-conversion-rate (utils/token-usd-price token)
|
||||
currency (rf/sub [:profile/currency])
|
||||
conversion-rate (-> token
|
||||
:market-values-per-currency
|
||||
currency
|
||||
:price)
|
||||
token-decimals (-> token
|
||||
utils/token-usd-price
|
||||
utils/one-cent-value
|
||||
utils/calc-max-crypto-decimals)
|
||||
[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])
|
||||
loading-routes? (rf/sub
|
||||
[:wallet/wallet-send-loading-suggested-routes?])
|
||||
route (rf/sub [:wallet/wallet-send-route])
|
||||
on-confirm (or default-on-confirm handle-on-confirm)
|
||||
crypto-decimals (or token-decimals default-crypto-decimals)
|
||||
max-limit (if crypto-currency?
|
||||
(utils/cut-crypto-decimals-to-fit-usd-cents
|
||||
token-balance
|
||||
usd-conversion-rate)
|
||||
(utils/cut-fiat-balance-to-two-decimals
|
||||
(money/crypto->fiat token-balance conversion-rate)))
|
||||
input-value (controlled-input/input-value input-state)
|
||||
valid-input? (not (or (controlled-input/empty-value? input-state)
|
||||
(controlled-input/input-error input-state)))
|
||||
confirm-disabled? (or (nil? route)
|
||||
(empty? route)
|
||||
(not valid-input?))
|
||||
amount-in-crypto (if crypto-currency?
|
||||
input-value
|
||||
(number/remove-trailing-zeroes
|
||||
(.toFixed (/ input-value conversion-rate)
|
||||
crypto-decimals)))
|
||||
total-amount-receiver (rf/sub [:wallet/total-amount true])
|
||||
amount-text (str (number/remove-trailing-zeroes
|
||||
(.toFixed total-amount-receiver
|
||||
(min token-decimals 6)))
|
||||
" "
|
||||
token-symbol)
|
||||
first-route (first route)
|
||||
native-currency-symbol (when-not confirm-disabled?
|
||||
(get-in first-route
|
||||
[:from :native-currency-symbol]))
|
||||
fee-formatted (when native-currency-symbol
|
||||
(rf/sub [:wallet/wallet-send-fee-fiat-formatted
|
||||
native-currency-symbol]))
|
||||
show-select-asset-sheet #(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content (fn []
|
||||
[select-asset-bottom-sheet
|
||||
clear-input!])}])
|
||||
sender-network-values (rf/sub
|
||||
[:wallet/wallet-send-sender-network-values])
|
||||
receiver-network-values (rf/sub
|
||||
[:wallet/wallet-send-receiver-network-values])
|
||||
tx-type (rf/sub [:wallet/wallet-send-tx-type])
|
||||
token-not-supported-in-receiver-networks? (and (not= tx-type :tx/bridge)
|
||||
(->> receiver-network-values
|
||||
(remove #(= (:type %) :add))
|
||||
(every? #(= (:type %) :not-available))))
|
||||
suggested-routes (rf/sub [:wallet/wallet-send-suggested-routes])
|
||||
routes (when suggested-routes
|
||||
(or (:best suggested-routes) []))
|
||||
no-routes-found? (and
|
||||
(every-network-value-is-zero?
|
||||
sender-network-values)
|
||||
(not (nil? routes))
|
||||
(not loading-routes?)
|
||||
(not token-not-supported-in-receiver-networks?))
|
||||
receiver-networks (rf/sub [:wallet/wallet-send-receiver-networks])
|
||||
receiver-preferred-networks (rf/sub
|
||||
[:wallet/wallet-send-receiver-preferred-networks])
|
||||
receiver-preferred-networks-set (set receiver-preferred-networks)
|
||||
sending-to-unpreferred-networks? (not (every? (fn [receiver-selected-network]
|
||||
(contains?
|
||||
receiver-preferred-networks-set
|
||||
receiver-selected-network))
|
||||
receiver-networks))
|
||||
input-error (controlled-input/input-error input-state)
|
||||
limit-exceeded? (controlled-input/upper-limit-exceeded? input-state)
|
||||
should-try-again? (and (not limit-exceeded?) no-routes-found?)
|
||||
current-address (rf/sub [:wallet/current-viewing-account-address])
|
||||
owned-eth-token (rf/sub [:wallet/token-by-symbol
|
||||
(string/upper-case
|
||||
constants/mainnet-short-name)
|
||||
enabled-from-chain-ids])
|
||||
not-enough-asset? (and
|
||||
(or no-routes-found? limit-exceeded?)
|
||||
(not-empty sender-network-values)
|
||||
(if (= token-symbol
|
||||
(string/upper-case
|
||||
constants/mainnet-short-name))
|
||||
(money/equal-to
|
||||
(controlled-input/value-bn input-state)
|
||||
(controlled-input/upper-limit-bn input-state))
|
||||
(money/equal-to (:total-balance
|
||||
owned-eth-token)
|
||||
0)))
|
||||
show-no-routes? (and
|
||||
(or no-routes-found? limit-exceeded?)
|
||||
(not-empty sender-network-values)
|
||||
(not not-enough-asset?))
|
||||
request-fetch-routes (fn [bounce-duration-ms]
|
||||
(fetch-routes
|
||||
{:amount amount-in-crypto
|
||||
:valid-input? valid-input?
|
||||
:bounce-duration-ms bounce-duration-ms
|
||||
:token token
|
||||
:reset-amounts-to-zero? (and limit-exceeded?
|
||||
(some? routes))}))
|
||||
swap-between-fiat-and-crypto (fn []
|
||||
(if crypto-currency?
|
||||
(set-input-state
|
||||
#(controlled-input/->fiat % conversion-rate))
|
||||
(set-input-state
|
||||
#(controlled-input/->crypto % conversion-rate)))
|
||||
(set-crypto-currency (not crypto-currency?)))]
|
||||
:as token-by-symbol} (rf/sub [:wallet/token-by-symbol
|
||||
(str token-symbol)
|
||||
enabled-from-chain-ids])
|
||||
token-balance (or default-limit-crypto total-balance)
|
||||
usd-conversion-rate (utils/token-usd-price token)
|
||||
currency (rf/sub [:profile/currency])
|
||||
conversion-rate (-> token
|
||||
:market-values-per-currency
|
||||
currency
|
||||
:price)
|
||||
token-decimals (-> token
|
||||
utils/token-usd-price
|
||||
utils/one-cent-value
|
||||
utils/calc-max-crypto-decimals)
|
||||
[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])
|
||||
loading-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
|
||||
route (rf/sub [:wallet/wallet-send-route])
|
||||
on-confirm (or default-on-confirm handle-on-confirm)
|
||||
crypto-decimals (or token-decimals default-crypto-decimals)
|
||||
max-limit (if crypto-currency?
|
||||
(utils/cut-crypto-decimals-to-fit-usd-cents
|
||||
token-balance
|
||||
usd-conversion-rate)
|
||||
(utils/cut-fiat-balance-to-two-decimals
|
||||
(money/crypto->fiat token-balance conversion-rate)))
|
||||
input-value (controlled-input/input-value input-state)
|
||||
valid-input? (not (or (controlled-input/empty-value? input-state)
|
||||
(controlled-input/input-error input-state)))
|
||||
amount-in-crypto (if crypto-currency?
|
||||
input-value
|
||||
(number/remove-trailing-zeroes
|
||||
(.toFixed (/ input-value conversion-rate)
|
||||
crypto-decimals)))
|
||||
total-amount-receiver (rf/sub [:wallet/total-amount true])
|
||||
amount-text (str (number/remove-trailing-zeroes
|
||||
(.toFixed total-amount-receiver
|
||||
(min token-decimals 6)))
|
||||
" "
|
||||
token-symbol)
|
||||
show-select-asset-sheet #(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content (fn []
|
||||
[select-asset-bottom-sheet
|
||||
clear-input!])}])
|
||||
sender-network-values (rf/sub [:wallet/wallet-send-sender-network-values])
|
||||
receiver-network-values (rf/sub [:wallet/wallet-send-receiver-network-values])
|
||||
tx-type (rf/sub [:wallet/wallet-send-tx-type])
|
||||
unsupported-token-in-receiver? (and (not= tx-type :tx/bridge)
|
||||
(->> receiver-network-values
|
||||
(remove #(= (:type %) :add))
|
||||
(every? #(= (:type %) :not-available))))
|
||||
suggested-routes (rf/sub [:wallet/wallet-send-suggested-routes])
|
||||
routes (when suggested-routes
|
||||
(or (:best suggested-routes) []))
|
||||
no-routes-found? (and
|
||||
(every-network-value-is-zero? sender-network-values)
|
||||
(some? routes)
|
||||
(not loading-routes?)
|
||||
(not unsupported-token-in-receiver?))
|
||||
receiver-networks (rf/sub [:wallet/wallet-send-receiver-networks])
|
||||
receiver-preferred-networks (rf/sub [:wallet/wallet-send-receiver-preferred-networks])
|
||||
receiver-preferred-network? (set receiver-preferred-networks)
|
||||
sending-to-unpreferred-networks? (some (comp not receiver-preferred-network?)
|
||||
receiver-networks)
|
||||
input-error (controlled-input/input-error input-state)
|
||||
limit-exceeded? (controlled-input/upper-limit-exceeded? input-state)
|
||||
current-address (rf/sub [:wallet/current-viewing-account-address])
|
||||
current-color (rf/sub [:wallet/current-viewing-account-color])
|
||||
enough-assets? (rf/sub [:wallet/wallet-send-enough-assets?])
|
||||
owned-eth-token (rf/sub [:wallet/token-by-symbol
|
||||
(string/upper-case constants/mainnet-short-name)
|
||||
enabled-from-chain-ids])
|
||||
not-enough-asset? (insufficient-asset-amount?
|
||||
{:enough-assets? enough-assets?
|
||||
:token-symbol token-symbol
|
||||
:owned-eth-token owned-eth-token
|
||||
:input-state input-state
|
||||
:no-routes-found? no-routes-found?
|
||||
:limit-exceeded? limit-exceeded?
|
||||
:sender-network-values sender-network-values})
|
||||
should-try-again? (and (not limit-exceeded?)
|
||||
no-routes-found?
|
||||
(not not-enough-asset?))
|
||||
show-no-routes? (and (or no-routes-found? limit-exceeded?)
|
||||
(not-empty sender-network-values)
|
||||
(not not-enough-asset?))
|
||||
confirm-disabled? (or (nil? route)
|
||||
(empty? route)
|
||||
(not valid-input?))
|
||||
fee-formatted (when (or (not confirm-disabled?) not-enough-asset?)
|
||||
(get-fee-formatted route))
|
||||
request-fetch-routes (fn [bounce-duration-ms]
|
||||
(fetch-routes
|
||||
{:amount amount-in-crypto
|
||||
:valid-input? valid-input?
|
||||
:bounce-duration-ms bounce-duration-ms
|
||||
:token token
|
||||
:reset-amounts-to-zero? (and limit-exceeded?
|
||||
(some? routes))}))
|
||||
swap-between-fiat-and-crypto (fn []
|
||||
(if crypto-currency?
|
||||
(set-input-state
|
||||
#(controlled-input/->fiat % conversion-rate))
|
||||
(set-input-state
|
||||
#(controlled-input/->crypto % conversion-rate)))
|
||||
(set-crypto-currency (not crypto-currency?)))]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(when active-screen?
|
||||
@@ -365,21 +371,23 @@
|
||||
{:token token-by-symbol
|
||||
:send-amount-in-crypto amount-in-crypto
|
||||
:valid-input? valid-input?
|
||||
:token-not-supported-in-receiver-networks? token-not-supported-in-receiver-networks?
|
||||
:token-not-supported-in-receiver-networks? unsupported-token-in-receiver?
|
||||
:current-screen-id current-screen-id
|
||||
:request-fetch-routes request-fetch-routes}]
|
||||
(when (and (not loading-routes?)
|
||||
sender-network-values
|
||||
token-not-supported-in-receiver-networks?)
|
||||
unsupported-token-in-receiver?)
|
||||
[token-not-available token-symbol receiver-networks token-networks])
|
||||
(when (and (not no-routes-found?) (or loading-routes? route))
|
||||
(when not-enough-asset?
|
||||
[not-enough-asset])
|
||||
(when (or (and (not no-routes-found?) (or loading-routes? route))
|
||||
not-enough-asset?)
|
||||
[estimated-fees
|
||||
{:loading-routes? loading-routes?
|
||||
:fees fee-formatted
|
||||
:amount amount-text}])
|
||||
(cond
|
||||
show-no-routes? [no-routes-found]
|
||||
not-enough-asset? [not-enough-asset])
|
||||
(when show-no-routes?
|
||||
[no-routes-found])
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-label (if should-try-again?
|
||||
@@ -387,17 +395,20 @@
|
||||
button-one-label)
|
||||
:button-one-props (merge (when-not should-try-again?
|
||||
button-one-props)
|
||||
{:disabled? (or loading-routes?
|
||||
(and (not should-try-again?) confirm-disabled?))
|
||||
:on-press (cond
|
||||
should-try-again?
|
||||
#(rf/dispatch [:wallet/start-get-suggested-routes
|
||||
{:amount amount-in-crypto
|
||||
:updated-token token-by-symbol}])
|
||||
sending-to-unpreferred-networks?
|
||||
#(show-unpreferred-networks-alert on-confirm)
|
||||
:else
|
||||
#(on-confirm amount-in-crypto))}
|
||||
{:disabled? (or not-enough-asset?
|
||||
loading-routes?
|
||||
(and (not should-try-again?)
|
||||
confirm-disabled?))
|
||||
:on-press (cond
|
||||
should-try-again?
|
||||
#(rf/dispatch [:wallet/start-get-suggested-routes
|
||||
{:amount amount-in-crypto
|
||||
:updated-token token-by-symbol}])
|
||||
sending-to-unpreferred-networks?
|
||||
#(show-unpreferred-networks-alert on-confirm)
|
||||
:else
|
||||
#(on-confirm amount-in-crypto))
|
||||
:customization-color current-color}
|
||||
(when should-try-again?
|
||||
{:type :grey}))}]
|
||||
[quo/numbered-keyboard
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
[status-im.common.standard-authentication.core :as standard-auth]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.send.transaction-confirmation.style :as style]
|
||||
[status-im.contexts.wallet.send.transaction-details.view :as transaction-details]
|
||||
[status-im.contexts.wallet.send.utils :as send-utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
@@ -179,17 +178,6 @@
|
||||
[rn/activity-indicator {:style {:flex 1}}]
|
||||
route-loaded?
|
||||
[:<>
|
||||
[quo/button
|
||||
{:icon-only? true
|
||||
:type :outline
|
||||
:size 32
|
||||
:inner-style {:opacity 1}
|
||||
:accessibility-label :advanced-button
|
||||
:container-style {:margin-right 8}
|
||||
:on-press #(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content transaction-details/sheet}])}
|
||||
:i/advanced]
|
||||
[data-item
|
||||
{:title (i18n/label :t/est-time)
|
||||
:subtitle (i18n/label :t/time-in-mins {:minutes (str estimated-time-min)})}]
|
||||
@@ -282,37 +270,33 @@
|
||||
:gradient-cover? true
|
||||
:customization-color (:color account)}
|
||||
[rn/view
|
||||
[rn/pressable
|
||||
{:on-press #(rf/dispatch [:navigate-to-within-stack
|
||||
[:screen/wallet.transaction-details
|
||||
:screen/wallet.transaction-confirmation]])}
|
||||
[transaction-title
|
||||
{:token-display-name token-symbol
|
||||
:amount amount
|
||||
:account account
|
||||
:type type
|
||||
:recipient recipient
|
||||
:route route
|
||||
:to-network bridge-to-network
|
||||
:image-url image-url
|
||||
:transaction-type transaction-type
|
||||
:collectible? collectible?}]
|
||||
[user-summary
|
||||
{:summary-type :status-account
|
||||
:accessibility-label :summary-from-label
|
||||
:label (i18n/label :t/from-capitalized)
|
||||
:account-props from-account-props
|
||||
:theme theme}]
|
||||
[user-summary
|
||||
{:summary-type (if (= transaction-type :tx/bridge)
|
||||
:status-account
|
||||
:account)
|
||||
:accessibility-label :summary-to-label
|
||||
:label (i18n/label :t/to-capitalized)
|
||||
:account-props (if (= transaction-type :tx/bridge)
|
||||
from-account-props
|
||||
user-props)
|
||||
:recipient recipient
|
||||
:bridge-tx? (= transaction-type :tx/bridge)
|
||||
:account-to? true
|
||||
:theme theme}]]]]]))))
|
||||
[transaction-title
|
||||
{:token-display-name token-symbol
|
||||
:amount amount
|
||||
:account account
|
||||
:type type
|
||||
:recipient recipient
|
||||
:route route
|
||||
:to-network bridge-to-network
|
||||
:image-url image-url
|
||||
:transaction-type transaction-type
|
||||
:collectible? collectible?}]
|
||||
[user-summary
|
||||
{:summary-type :status-account
|
||||
:accessibility-label :summary-from-label
|
||||
:label (i18n/label :t/from-capitalized)
|
||||
:account-props from-account-props
|
||||
:theme theme}]
|
||||
[user-summary
|
||||
{:summary-type (if (= transaction-type :tx/bridge)
|
||||
:status-account
|
||||
:account)
|
||||
:accessibility-label :summary-to-label
|
||||
:label (i18n/label :t/to-capitalized)
|
||||
:account-props (if (= transaction-type :tx/bridge)
|
||||
from-account-props
|
||||
user-props)
|
||||
:recipient recipient
|
||||
:bridge-tx? (= transaction-type :tx/bridge)
|
||||
:account-to? true
|
||||
:theme theme}]]]]))))
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
(ns status-im.contexts.wallet.send.transaction-details.style
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]))
|
||||
|
||||
(defn prop-text
|
||||
[theme]
|
||||
{:color (colors/theme-colors colors/neutral-100 colors/white theme)})
|
||||
|
||||
(def content-line
|
||||
{:flex-direction :row
|
||||
:margin-top 2
|
||||
:align-items :center
|
||||
:column-gap 4
|
||||
:justify-content :flex-start})
|
||||
@@ -1,49 +0,0 @@
|
||||
(ns status-im.contexts.wallet.send.transaction-details.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[utils.i18n :as i18n]))
|
||||
|
||||
(defn sheet
|
||||
[_]
|
||||
[rn/view
|
||||
[quo/drawer-top
|
||||
{:title "Transaction settings"}]
|
||||
[quo/category
|
||||
{:list-type :settings
|
||||
:data [{:title "Normal ~60s"
|
||||
:image :icon
|
||||
:image-props :i/placeholder
|
||||
:description :text
|
||||
:description-props {:text "€1.45"}
|
||||
:on-press #()
|
||||
:action :selector
|
||||
:action-props {:type :radio}
|
||||
:label :text
|
||||
:preview-size :size-32}
|
||||
{:title "Fast ~40s"
|
||||
:image :icon
|
||||
:image-props :i/placeholder
|
||||
:description :text
|
||||
:description-props {:text "€1.65"}
|
||||
:on-press #()
|
||||
:action :selector
|
||||
:action-props {:type :radio}
|
||||
:label :text
|
||||
:preview-size :size-32}
|
||||
{:title "Urget ~15s"
|
||||
:image :icon
|
||||
:image-props :i/placeholder
|
||||
:description :text
|
||||
:description-props {:text "€1.85"}
|
||||
:on-press #()
|
||||
:action :selector
|
||||
:action-props {:type :radio}
|
||||
:label :text
|
||||
:preview-size :size-32}]}]
|
||||
[quo/bottom-actions
|
||||
{:actions :one-action
|
||||
:button-one-props {:on-press #()}
|
||||
:button-one-label (i18n/label :t/confirm)}]])
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
#(set-min-height
|
||||
(oops/oget % :nativeEvent :layout :height)))]
|
||||
[:<>
|
||||
[quo/drawer-top {:title (or title (i18n/label :t/buy-assets))}]
|
||||
[quo/drawer-top {:title (or title (i18n/label :t/ways-to-buy-assets))}]
|
||||
[quo/segmented-control
|
||||
{:size 32
|
||||
:container-style style/tabs
|
||||
|
||||
@@ -204,6 +204,12 @@
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db [:wallet :ui] dissoc :swap)}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/on-swap-done
|
||||
(fn [_]
|
||||
{:fx [[:dispatch [:wallet/select-account-tab :activity]]
|
||||
[:dispatch [:wallet/clean-swap]]]}))
|
||||
|
||||
(rf/reg-event-fx :wallet/swap-transaction
|
||||
(fn [{:keys [db]} [sha3-pwd]]
|
||||
(let [wallet-address (get-in db
|
||||
@@ -298,8 +304,6 @@
|
||||
:screen/wallet.swap-set-spending-cap
|
||||
:screen/wallet.swap-confirmation)])
|
||||
(when-not approval-required?
|
||||
(rf/dispatch [:wallet/select-account-tab :activity])
|
||||
(rf/dispatch [:wallet/clean-swap])
|
||||
(debounce/debounce-and-dispatch
|
||||
[:toasts/upsert
|
||||
{:id :swap-transaction-pending
|
||||
|
||||
@@ -148,6 +148,7 @@
|
||||
:valid-input? valid-pay-input?
|
||||
:clean-approval-transaction? true}))
|
||||
[pay-input-amount])]
|
||||
(rn/use-unmount #(rf/dispatch [:wallet/on-swap-done]))
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(request-fetch-swap-proposal))
|
||||
@@ -257,17 +258,15 @@
|
||||
(merge {:action? true
|
||||
:on-button-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content buy-token/view}])
|
||||
:button-text (i18n/label :t/buy-assets)})
|
||||
:button-text (i18n/label :t/add-assets)})
|
||||
(= error-response-code
|
||||
constants/router-error-code-not-enough-native-balance)
|
||||
(merge {:action? true
|
||||
:on-button-press #(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content (fn []
|
||||
[buy-token/view
|
||||
{:title (i18n/label
|
||||
:t/buy-ethereum)}])}])
|
||||
:button-text (i18n/label :t/buy-eth)}))]
|
||||
[buy-token/view])}])
|
||||
:button-text (i18n/label :t/add-eth)}))]
|
||||
(when (or pay-input-error? error-response)
|
||||
[quo/alert-banner props])))
|
||||
|
||||
|
||||
@@ -80,7 +80,8 @@
|
||||
:values (send-utils/network-values-for-ui network-values)
|
||||
:token-props {:token token-symbol
|
||||
:label (str amount " " token-symbol)
|
||||
:address (address-utils/get-shortened-compressed-key token-address)
|
||||
:address (when token-address
|
||||
(address-utils/get-shortened-compressed-key token-address))
|
||||
:size 32}}]]))
|
||||
|
||||
(defn- pay-section
|
||||
@@ -98,7 +99,8 @@
|
||||
:label (i18n/label :t/pay)
|
||||
:token-symbol pay-token-symbol
|
||||
:amount pay-amount
|
||||
:token-address pay-token-address
|
||||
:token-address (when-not (address-utils/zero-address? pay-token-address)
|
||||
pay-token-address)
|
||||
:network network-name
|
||||
:theme theme}]))
|
||||
|
||||
@@ -117,7 +119,8 @@
|
||||
:label (i18n/label :t/receive)
|
||||
:token-symbol receive-token-symbol
|
||||
:amount receive-amount
|
||||
:token-address receive-token-address
|
||||
:token-address (when-not (address-utils/zero-address? receive-token-address)
|
||||
receive-token-address)
|
||||
:network network-name
|
||||
:theme theme}]))
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns status-im.contexts.wallet.wallet-connect.events.effects
|
||||
(:require
|
||||
[promesa.core :as promesa]
|
||||
[re-frame.core :as rf]
|
||||
[react-native.wallet-connect :as wallet-connect]
|
||||
[status-im.config :as config]
|
||||
[status-im.constants :as constants]
|
||||
@@ -10,6 +9,7 @@
|
||||
[status-im.contexts.wallet.wallet-connect.utils.transactions :as transactions]
|
||||
[status-im.contexts.wallet.wallet-connect.utils.typed-data :as typed-data]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.security.core :as security]))
|
||||
|
||||
(rf/reg-fx
|
||||
@@ -56,8 +56,8 @@
|
||||
:proposal-request proposal-request
|
||||
:address address
|
||||
:session-networks session-networks})
|
||||
(promesa/then on-success)
|
||||
(promesa/catch on-fail))))
|
||||
(promesa/then (partial rf/call-continuation on-success))
|
||||
(promesa/catch (partial rf/call-continuation on-fail)))))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.wallet-connect/sign-message
|
||||
@@ -72,8 +72,8 @@
|
||||
(signing/eth-sign password address data)
|
||||
|
||||
(signing/personal-sign password address data))
|
||||
(promesa/then on-success)
|
||||
(promesa/catch on-error)))))
|
||||
(promesa/then (partial rf/call-continuation on-success))
|
||||
(promesa/catch (partial rf/call-continuation on-error))))))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.wallet-connect/prepare-transaction
|
||||
@@ -92,8 +92,8 @@
|
||||
tx-hash
|
||||
tx-args
|
||||
chain-id)
|
||||
(promesa/then on-success)
|
||||
(promesa/catch on-error))))
|
||||
(promesa/then (partial rf/call-continuation on-success))
|
||||
(promesa/catch (partial rf/call-continuation on-error)))))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.wallet-connect/send-transaction
|
||||
@@ -103,8 +103,8 @@
|
||||
tx-hash
|
||||
tx-args
|
||||
chain-id)
|
||||
(promesa/then on-success)
|
||||
(promesa/catch on-error))))
|
||||
(promesa/then (partial rf/call-continuation on-success))
|
||||
(promesa/catch (partial rf/call-continuation on-error)))))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.wallet-connect/sign-typed-data
|
||||
@@ -114,8 +114,8 @@
|
||||
data
|
||||
chain-id
|
||||
version)
|
||||
(promesa/then on-success)
|
||||
(promesa/catch on-error))))
|
||||
(promesa/then (partial rf/call-continuation on-success))
|
||||
(promesa/catch (partial rf/call-continuation on-error)))))
|
||||
|
||||
(rf/reg-fx
|
||||
:effects.wallet-connect/respond-session-request
|
||||
|
||||
@@ -135,17 +135,21 @@
|
||||
:proposal-request current-proposal
|
||||
:session-networks session-networks
|
||||
:address current-address
|
||||
:on-success #(rf/dispatch [:wallet-connect/approve-session-success %])
|
||||
:on-fail #(rf/dispatch [:wallet-connect/approve-session-error %])}])
|
||||
:on-success [:wallet-connect/approve-session-success]
|
||||
:on-fail [:wallet-connect/approve-session-error]}])
|
||||
[:dispatch [:dismiss-modal :screen/wallet.wallet-connect-session-proposal]]]}
|
||||
{:fx [[:dispatch [:wallet-connect/no-internet-toast]]]}))))
|
||||
|
||||
(rf/reg-event-fx :wallet-connect/approve-session-success
|
||||
(fn [_ [session]]
|
||||
(log/info "Wallet Connect session approved")
|
||||
{:fx [[:dispatch [:wallet-connect/on-new-session session]]
|
||||
[:dispatch [:wallet-connect/reset-current-session-proposal]]
|
||||
[:dispatch [:wallet-connect/redirect-to-dapp (data-store/get-dapp-redirect-url session)]]]}))
|
||||
(fn [{:keys [db]} [session]]
|
||||
(let [total-connected-dapps (data-store/get-total-connected-dapps db)]
|
||||
{:fx [[:dispatch [:wallet-connect/on-new-session session]]
|
||||
[:dispatch [:wallet-connect/reset-current-session-proposal]]
|
||||
[:dispatch [:wallet-connect/redirect-to-dapp (data-store/get-dapp-redirect-url session)]]
|
||||
[:dispatch
|
||||
[:centralized-metrics/track :metric/dapp-session-proposal
|
||||
{:action :approved
|
||||
:total_connected_dapps total-connected-dapps}]]]})))
|
||||
|
||||
(rf/reg-event-fx :wallet-connect/approve-session-error
|
||||
(fn [_ [error]]
|
||||
@@ -158,11 +162,18 @@
|
||||
:wallet-connect/reject-session-proposal
|
||||
(fn [{:keys [db]} [proposal]]
|
||||
(let [web3-wallet (get db :wallet-connect/web3-wallet)
|
||||
{:keys [request response-sent?]} (:wallet-connect/current-proposal db)]
|
||||
{:fx [(when-not response-sent?
|
||||
[:effects.wallet-connect/reject-session-proposal
|
||||
{:web3-wallet web3-wallet
|
||||
:proposal (or proposal request)
|
||||
:on-success #(log/info "Wallet Connect session proposal rejected")
|
||||
:on-error #(log/error "Wallet Connect unable to reject session proposal")}])
|
||||
[:dispatch [:wallet-connect/reset-current-session-proposal]]]})))
|
||||
{:keys [request response-sent?]} (:wallet-connect/current-proposal db)
|
||||
networks (networks/get-proposal-networks (or proposal request))
|
||||
rejected? (nil? proposal)]
|
||||
{:fx (concat
|
||||
(when-not response-sent?
|
||||
[[:effects.wallet-connect/reject-session-proposal
|
||||
{:web3-wallet web3-wallet
|
||||
:proposal (or proposal request)
|
||||
:on-success #(log/info "Wallet Connect session proposal rejected")
|
||||
:on-error #(log/error "Wallet Connect unable to reject session proposal")}]
|
||||
[:dispatch
|
||||
[:centralized-metrics/track :metric/dapp-session-proposal
|
||||
{:action (if rejected? :rejected :not_supported)
|
||||
:networks networks}]]])
|
||||
[[:dispatch [:wallet-connect/reset-current-session-proposal]]])})))
|
||||
|
||||
@@ -51,8 +51,8 @@
|
||||
:address address
|
||||
:data raw-data
|
||||
:rpc-method rpc-method
|
||||
:on-error #(rf/dispatch [:wallet-connect/on-sign-error %])
|
||||
:on-success #(rf/dispatch [:wallet-connect/finish-session-request %])}]]})))
|
||||
:on-error [:wallet-connect/on-sign-error]
|
||||
:on-success [:wallet-connect/finish-session-request]}]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/respond-sign-typed-data
|
||||
@@ -65,8 +65,8 @@
|
||||
:data raw-data
|
||||
:chain-id chain-id
|
||||
:version typed-data-version
|
||||
:on-error #(rf/dispatch [:wallet-connect/on-sign-error %])
|
||||
:on-success #(rf/dispatch [:wallet-connect/finish-session-request %])}]]})))
|
||||
:on-error [:wallet-connect/on-sign-error]
|
||||
:on-success [:wallet-connect/finish-session-request]}]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/respond-send-transaction-data
|
||||
@@ -79,8 +79,8 @@
|
||||
:chain-id chain-id
|
||||
:tx-hash tx-hash
|
||||
:tx-args tx-args
|
||||
:on-error #(rf/dispatch [:wallet-connect/on-sign-error %])
|
||||
:on-success #(rf/dispatch [:wallet-connect/finish-session-request %])}]]})))
|
||||
:on-error [:wallet-connect/on-sign-error]
|
||||
:on-success [:wallet-connect/finish-session-request]}]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/respond-sign-transaction-data
|
||||
@@ -93,8 +93,8 @@
|
||||
:chain-id chain-id
|
||||
:tx-hash tx-hash
|
||||
:tx-params tx-args
|
||||
:on-error #(rf/dispatch [:wallet-connect/on-sign-error %])
|
||||
:on-success #(rf/dispatch [:wallet-connect/finish-session-request %])}]]})))
|
||||
:on-error [:wallet-connect/on-sign-error]
|
||||
:on-success [:wallet-connect/finish-session-request]}]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/on-sign-error
|
||||
@@ -161,9 +161,15 @@
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/finish-session-request
|
||||
(fn [_ [result]]
|
||||
{:fx [[:dispatch [:wallet-connect/send-response {:result result}]]
|
||||
[:dispatch [:wallet-connect/dismiss-request-modal]]]}))
|
||||
(fn [{:keys [db]} [result]]
|
||||
(let [event (get-in db [:wallet-connect/current-request :event])
|
||||
method (data-store/get-request-method event)]
|
||||
{:fx [[:dispatch
|
||||
[:centralized-metrics/track :metric/dapp-session-response
|
||||
{:method method
|
||||
:approved true}]]
|
||||
[:dispatch [:wallet-connect/send-response {:result result}]]
|
||||
[:dispatch [:wallet-connect/dismiss-request-modal]]]})))
|
||||
|
||||
;; NOTE: Currently we only reject a session if the user dismissed a modal
|
||||
;; without accepting the session first.
|
||||
@@ -176,9 +182,17 @@
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/on-request-modal-dismissed
|
||||
(fn [{:keys [db]}]
|
||||
{:fx [(when-not (get-in db [:wallet-connect/current-request :response-sent?])
|
||||
[:dispatch
|
||||
[:wallet-connect/send-response
|
||||
{:error (wallet-connect/get-sdk-error
|
||||
constants/wallet-connect-user-rejected-error-key)}]])
|
||||
[:dispatch [:wallet-connect/reset-current-request]]]}))
|
||||
(let [{:keys [response-sent? event]} (get db :wallet-connect/current-request)
|
||||
method (data-store/get-request-method event)]
|
||||
{:fx (concat
|
||||
(when-not response-sent?
|
||||
[[:dispatch
|
||||
[:centralized-metrics/track :metric/dapp-session-response
|
||||
{:method method
|
||||
:approved false}]]
|
||||
[:dispatch
|
||||
[:wallet-connect/send-response
|
||||
{:request event
|
||||
:error (wallet-connect/get-sdk-error
|
||||
constants/wallet-connect-user-rejected-error-key)}]]])
|
||||
[[:dispatch [:wallet-connect/reset-current-request]]])})))
|
||||
|
||||
@@ -14,7 +14,10 @@
|
||||
[{:method "wallet_disconnectWalletConnectSession"
|
||||
:params [topic]
|
||||
:on-success [:wallet-connect/delete-session topic]
|
||||
:on-error #(log/info "Wallet Connect session persistence failed" %)}]]]})))
|
||||
:on-error #(log/info "Wallet Connect session persistence failed" %)}]]
|
||||
[:dispatch
|
||||
[:centralized-metrics/track
|
||||
:metric/dapp-session-disconnected]]]})))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet-connect/disconnect-dapp
|
||||
@@ -26,10 +29,14 @@
|
||||
{:fx [[:effects.wallet-connect/disconnect
|
||||
{:web3-wallet web3-wallet
|
||||
:topic topic
|
||||
:on-fail on-fail
|
||||
:on-fail (fn []
|
||||
(when on-fail
|
||||
(on-fail)))
|
||||
:on-success (fn []
|
||||
(log/info "Successfully disconnected dApp session" topic)
|
||||
(rf/dispatch [:wallet-connect/delete-session topic])
|
||||
(rf/dispatch [:centralized-metrics/track
|
||||
:metric/dapp-session-disconnected])
|
||||
(when on-success
|
||||
(on-success)))}]]}
|
||||
{:fx [[:dispatch [:wallet-connect/no-internet-toast]]]}))))
|
||||
|
||||
@@ -31,9 +31,12 @@
|
||||
|
||||
:not-enough-assets
|
||||
:t/not-enough-assets-for-transaction)))
|
||||
:button-text (i18n/label :t/buy-eth)
|
||||
:on-button-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content buy-token/view}])}])
|
||||
:button-text (i18n/label :t/add-eth)
|
||||
:on-button-press (rn/use-callback (fn []
|
||||
(rf/dispatch [:centralized-metrics/track
|
||||
:metric/dapp-buy-eth])
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content buy-token/view}])))}])
|
||||
[rn/view {:style style/content-container}
|
||||
(into [rn/view
|
||||
{:style style/data-items-container}]
|
||||
|
||||
@@ -73,3 +73,10 @@
|
||||
(-> db
|
||||
get-db-current-request-event
|
||||
get-request-params))
|
||||
|
||||
(defn get-total-connected-dapps
|
||||
[db]
|
||||
(-> db
|
||||
:wallet-connect/sessions
|
||||
count
|
||||
inc))
|
||||
|
||||
@@ -25,3 +25,17 @@
|
||||
(testing "returns nil if no redirect URL is found"
|
||||
(let [session {:peer {:metadata {}}}]
|
||||
(is (nil? (sut/get-dapp-redirect-url session))))))
|
||||
|
||||
(deftest get-total-connected-dapps-test
|
||||
(testing "returns the total number of connected dApps plus 1"
|
||||
(let [db {:wallet-connect/sessions [{:url "https://dapp1.com"}
|
||||
{:url "https://dapp2.com"}]}]
|
||||
(is (= 3 (sut/get-total-connected-dapps db)))))
|
||||
|
||||
(testing "returns 1 when there are no connected dApps"
|
||||
(let [db {:wallet-connect/sessions []}]
|
||||
(is (= 1 (sut/get-total-connected-dapps db)))))
|
||||
|
||||
(testing "handles nil sessions correctly"
|
||||
(let [db {:wallet-connect/sessions nil}]
|
||||
(is (= 1 (sut/get-total-connected-dapps db))))))
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
[status-im.contexts.preview.quo.component-preview.view :as component-preview]
|
||||
[status-im.contexts.preview.quo.main :as quo.preview]
|
||||
[status-im.contexts.preview.status-im.main :as status-im-preview]
|
||||
[status-im.contexts.profile.backup-recovery-phrase.view :as backup-recovery-phrase]
|
||||
[status-im.contexts.profile.contact.share.view :as share-contact]
|
||||
[status-im.contexts.profile.contact.view :as contact-profile]
|
||||
[status-im.contexts.profile.edit.accent-colour.view :as edit-accent-colour]
|
||||
@@ -107,8 +108,6 @@
|
||||
wallet-import-private-key]
|
||||
[status-im.contexts.wallet.add-account.create-account.key-pair-name.view :as
|
||||
wallet-key-pair-name]
|
||||
[status-im.contexts.wallet.add-account.create-account.new-keypair.backup-recovery-phrase.view :as
|
||||
wallet-backup-recovery-phrase]
|
||||
[status-im.contexts.wallet.add-account.create-account.new-keypair.confirm-backup.view :as
|
||||
wallet-confirm-backup]
|
||||
[status-im.contexts.wallet.add-account.create-account.select-keypair.view :as wallet-select-keypair]
|
||||
@@ -476,9 +475,9 @@
|
||||
:options {:insets {:top? true}}
|
||||
:component wallet-create-account/view}
|
||||
|
||||
{:name :screen/wallet.backup-recovery-phrase
|
||||
{:name :screen/backup-recovery-phrase
|
||||
:options {:insets {:top? true :bottom? true}}
|
||||
:component wallet-backup-recovery-phrase/view}
|
||||
:component backup-recovery-phrase/view}
|
||||
|
||||
{:name :screen/wallet.confirm-backup
|
||||
:options {:insets {:top? true :bottom? true}}
|
||||
@@ -488,7 +487,7 @@
|
||||
:options {:insets {:top? true}}
|
||||
:component wallet-key-pair-name/view}
|
||||
|
||||
{:name :screen/wallet.enter-seed-phrase
|
||||
{:name :screen/use-recovery-phrase
|
||||
:component enter-seed-phrase/view}
|
||||
|
||||
{:name :screen/wallet.share-address
|
||||
|
||||
@@ -345,6 +345,12 @@
|
||||
(fn [{:keys [processing]}]
|
||||
processing))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:profile/recovery-phrase-backed-up?
|
||||
:<- [:profile/profile]
|
||||
(fn [profile]
|
||||
(not (boolean (seq (:mnemonic profile))))))
|
||||
|
||||
;; LINK PREVIEW
|
||||
;; ========================================================================================================
|
||||
|
||||
|
||||
@@ -126,18 +126,23 @@
|
||||
:<- [:wallet/wallet-send]
|
||||
:-> :route)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-send-enough-assets?
|
||||
:<- [:wallet/wallet-send]
|
||||
:-> :enough-assets?)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-send-token
|
||||
:<- [:wallet/wallet-send]
|
||||
:<- [:wallet/network-details]
|
||||
:<- [:wallet/wallet-send-disabled-from-chain-ids]
|
||||
(fn [[wallet-send networks disabled-from-chain-ids]]
|
||||
(let [token (:token wallet-send)
|
||||
enabled-from-chain-ids (->> networks
|
||||
(filter #(not (contains? (set disabled-from-chain-ids)
|
||||
(:chain-id %))))
|
||||
(map :chain-id)
|
||||
set)]
|
||||
(let [token (:token wallet-send)
|
||||
disabled-from-chain-ids? (set disabled-from-chain-ids)
|
||||
enabled-from-chain-ids (->> networks
|
||||
(map :chain-id)
|
||||
(remove disabled-from-chain-ids?)
|
||||
set)]
|
||||
(some-> token
|
||||
(assoc :networks (network-utils/network-list token networks)
|
||||
:available-balance (utils/calculate-total-token-balance token)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
(def regx-eip-3770-address #"^(?:(?:eth:|arb1:|oeth:)(?=:|))*0x[0-9a-fA-F]{40}$")
|
||||
(def regx-metamask-address #"^ethereum:(0x[0-9a-fA-F]{40})(?:@(0x1|0xa|0xa4b1))?$")
|
||||
(def regx-address-contains #"(?i)0x[a-fA-F0-9]{40}")
|
||||
(def zero-address "0x0000000000000000000000000000000000000000")
|
||||
|
||||
(defn normalized-hex
|
||||
[hex]
|
||||
@@ -137,3 +138,6 @@
|
||||
(metamask-address? address)
|
||||
(metamask-address->eth-address address)))
|
||||
|
||||
(defn zero-address?
|
||||
[address]
|
||||
(= address zero-address))
|
||||
|
||||
@@ -47,11 +47,10 @@
|
||||
(if (bignumber? n) n (bignumber n)))
|
||||
|
||||
(defn ->bignumbers
|
||||
[n1 n2]
|
||||
(when-let [bn1 (->bignumber n1)]
|
||||
(when-let [bn2 (->bignumber n2)]
|
||||
(when (and (bignumber? bn1) (bignumber? bn2))
|
||||
[bn1 bn2]))))
|
||||
[& numbers]
|
||||
(let [transformed-numbers (map ->bignumber numbers)]
|
||||
(when (every? bignumber? transformed-numbers)
|
||||
transformed-numbers)))
|
||||
|
||||
(defn greater-than-or-equals
|
||||
[^js n1 ^js n2]
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
|
||||
"owner": "status-im",
|
||||
"repo": "status-go",
|
||||
"version": "v3.2.0",
|
||||
"commit-sha1": "3f613a9281f470a91b5080d35d22e55847ac276e",
|
||||
"src-sha256": "1ghxxlmz0swq6dwabx84m23ikbs1bkzwfgqm4sp7hrnglm7bvikc"
|
||||
"version": "v3.3.0",
|
||||
"commit-sha1": "43659f0c7e1a64102e7f8e38bd532b72714c5819",
|
||||
"src-sha256": "01fpviw1g22f4ni3li2wnhyz0l517jfipvnyfysckds6yi94l0hf"
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import time
|
||||
import pytest
|
||||
from _pytest.outcomes import Failed
|
||||
from selenium.common import TimeoutException, NoSuchElementException
|
||||
|
||||
from base_test_case import MultipleSharedDeviceTestCase, create_shared_drivers
|
||||
from support.api.network_api import NetworkApi
|
||||
from tests import marks, run_in_parallel
|
||||
@@ -192,6 +191,7 @@ class TestWalletMultipleDevice(MultipleSharedDeviceTestCase):
|
||||
|
||||
@pytest.mark.xdist_group(name="new_one_2")
|
||||
@marks.nightly
|
||||
@marks.secured
|
||||
@marks.smoke
|
||||
class TestWalletOneDevice(MultipleSharedDeviceTestCase):
|
||||
|
||||
@@ -199,10 +199,55 @@ class TestWalletOneDevice(MultipleSharedDeviceTestCase):
|
||||
self.network_api = NetworkApi()
|
||||
self.drivers, self.loop = create_shared_drivers(1)
|
||||
self.sign_in_view = SignInView(self.drivers[0])
|
||||
self.sign_in_view.create_user()
|
||||
self.sender, self.receiver = transaction_senders['ETH_1'], transaction_senders['ETH_2']
|
||||
self.total_balance = {'Ether': 0.0052, 'USDCoin': 5.0, 'Status': 10.0, 'Uniswap': 0.627, 'Dai Stablecoin': 0.0}
|
||||
self.mainnet_balance = {'Ether': 0.005, 'USDCoin': 0.0, 'Status': 10.0, 'Uniswap': 0.127, 'Dai Stablecoin': 0.0}
|
||||
self.optimizm_balance = {'Ether': 0.0001, 'USDCoin': 5.0, 'Status': 0, 'Uniswap': 0, 'Dai Stablecoin': 0.0}
|
||||
self.arb_balance = {'Ether': 0.0001, 'USDCoin': 0.0, 'Status': 0.0, 'Uniswap': 0.5, 'Dai Stablecoin': 0.0}
|
||||
self.sender['wallet_address'] = '0x' + self.sender['address']
|
||||
self.receiver['wallet_address'] = '0x' + self.receiver['address']
|
||||
self.sender_username, self.receiver_username = 'sender', 'receiver'
|
||||
self.sign_in_view.recover_access(passphrase=self.sender['passphrase'], username=self.sender_username)
|
||||
|
||||
self.home_view = self.sign_in_view.get_home_view()
|
||||
self.wallet_view = self.home_view.wallet_tab.click()
|
||||
|
||||
@marks.testrail_id(740490)
|
||||
def test_wallet_balance_mainnet(self):
|
||||
self.profile_view = self.home_view.profile_button.click()
|
||||
self.profile_view.switch_network()
|
||||
self.sign_in_view.sign_in()
|
||||
self.sign_in_view.wallet_tab.click()
|
||||
|
||||
self.wallet_view.just_fyi("Checking total balance")
|
||||
real_balance = {}
|
||||
for asset in self.total_balance:
|
||||
real_balance[asset] = self.wallet_view.get_asset(asset).get_amount()
|
||||
|
||||
for asset in self.total_balance:
|
||||
if real_balance[asset] != self.total_balance[asset]:
|
||||
self.errors.append("For the %s the wrong value %s is shown, expected %s in total" %
|
||||
(asset, real_balance[asset], self.total_balance[asset]))
|
||||
expected_balances = {
|
||||
'Mainnet': self.mainnet_balance,
|
||||
'Arbitrum': self.arb_balance,
|
||||
'Optimism': self.optimizm_balance
|
||||
}
|
||||
|
||||
for network in expected_balances:
|
||||
self.wallet_view.just_fyi("Checking total balance on %s network" % network)
|
||||
self.wallet_view.select_network(network)
|
||||
real_balance = {}
|
||||
for asset in expected_balances[network]:
|
||||
real_balance[asset] = self.wallet_view.get_asset(asset).get_amount()
|
||||
for asset in expected_balances[network]:
|
||||
if real_balance[asset] != expected_balances[network][asset]:
|
||||
self.errors.append("For the %s the wrong value %s is shown, expected %s on %s" %
|
||||
(asset, real_balance[asset], expected_balances[network][asset], network))
|
||||
self.wallet_view.select_network(network)
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@marks.testrail_id(727231)
|
||||
def test_wallet_add_remove_regular_account(self):
|
||||
self.wallet_view.just_fyi("Adding new regular account")
|
||||
|
||||
@@ -305,6 +305,7 @@ class ProfileView(BaseView):
|
||||
suffix="/following-sibling::*[1]/android.widget.EditText")
|
||||
self.specify_network_id_input = EditBox(self.driver, translation_id="specify-network-id")
|
||||
self.connect_button = Button(self.driver, accessibility_id="network-connect-button")
|
||||
|
||||
## Toggles
|
||||
self.transaction_management_enabled_toggle = Button(self.driver,
|
||||
accessibility_id="transactions-management-enabled")
|
||||
@@ -360,6 +361,7 @@ class ProfileView(BaseView):
|
||||
self.confirm_testnet_mode_change_button = Button(self.driver, accessibility_id="confirm-testnet-mode-change")
|
||||
|
||||
def switch_network(self):
|
||||
self.driver.info("Toggling test mode")
|
||||
self.profile_wallet_button.click()
|
||||
self.network_settings_button.click()
|
||||
self.testnet_mode_toggle.click()
|
||||
|
||||
@@ -19,7 +19,7 @@ class AssetElement(Button):
|
||||
|
||||
def get_amount(self):
|
||||
element = Text(self.driver, xpath=self.locator + "/../android.widget.TextView[3]")
|
||||
element.scroll_to_element(down_start_y=0.89, down_end_y=0.8)
|
||||
element.scroll_to_element()
|
||||
try:
|
||||
amount = element.text.split()[0]
|
||||
if '<' in amount:
|
||||
|
||||
@@ -51,9 +51,11 @@
|
||||
"add-address-to-watch": "Add address to watch",
|
||||
"add-address-to-watch-description": "Watch a public address or ENS name",
|
||||
"add-an-account": "Add an account",
|
||||
"add-assets": "Add assets",
|
||||
"add-bootnode": "Add bootnode",
|
||||
"add-contact": "Add contact",
|
||||
"add-custom-token": "Add custom token",
|
||||
"add-eth": "Add ETH",
|
||||
"add-favourite": "Add favourite",
|
||||
"add-mailserver": "Add Status node",
|
||||
"add-me-to-your-contacts": "Please add me to your contacts",
|
||||
@@ -267,13 +269,11 @@
|
||||
"bug-report-too-short-description": "Description is too short",
|
||||
"build-yourself": "To use the app without these Terms of Use, you can build your own version",
|
||||
"buy": "Buy",
|
||||
"buy-assets": "Buy assets",
|
||||
"buy-crypto": "Buy crypto",
|
||||
"buy-crypto-choose-a-service": "Choose a service you'd like to use to buy crypto",
|
||||
"buy-crypto-description": "Find a dapp to buy crypto now",
|
||||
"buy-crypto-leaving": "You are leaving Status and entering a third party website to complete your purchase",
|
||||
"buy-crypto-title": "Looks like your wallet is empty",
|
||||
"buy-eth": "Buy ETH",
|
||||
"buy-ethereum": "Buy Ethereum",
|
||||
"buy-keycard": "Buy Keycard",
|
||||
"by-continuing-you-accept": "By continuing you accept our ",
|
||||
@@ -2777,6 +2777,7 @@
|
||||
"watch-only": "Watch-only",
|
||||
"watched-account-removed": "Watched address has been removed",
|
||||
"watched-address": "Watched address",
|
||||
"ways-to-buy-assets": "Ways to buy assets",
|
||||
"wc-brand-guide": "Guidance on using branding such as trademarks and logos",
|
||||
"wc-disclaimer": "Disclaimers (including third party providers), warranties, and legal releases",
|
||||
"wc-dispute": "Dispute resolution provisions",
|
||||
|
||||
Reference in New Issue
Block a user